4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
51 allowDomMove : false, // to stop relocations in parent onRender...
61 * Initialize Events for the element
63 initEvents : function() { },
69 can_build_overlaid : true,
71 container_method : false,
78 // returns the parent component..
79 return Roo.ComponentMgr.get(this.parentId)
85 onRender : function(ct, position)
87 // Roo.log("Call onRender: " + this.xtype);
89 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92 if (this.el.attr('xtype')) {
93 this.el.attr('xtypex', this.el.attr('xtype'));
94 this.el.dom.removeAttribute('xtype');
104 var cfg = Roo.apply({}, this.getAutoCreate());
106 cfg.id = this.id || Roo.id();
108 // fill in the extra attributes
109 if (this.xattr && typeof(this.xattr) =='object') {
110 for (var i in this.xattr) {
111 cfg[i] = this.xattr[i];
116 cfg.dataId = this.dataId;
120 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
123 if (this.style) { // fixme needs to support more complex style data.
124 cfg.style = this.style;
128 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
166 //Roo.log(['addxtype', cn]);
168 cn.parentType = this.xtype; //??
169 cn.parentId = this.id;
171 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 if (typeof(cn.container_method) == 'string') {
173 cntr = cn.container_method;
177 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
179 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
181 var build_from_html = Roo.XComponent.build_from_html;
183 var is_body = (tree.xtype == 'Body') ;
185 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
187 var self_cntr_el = Roo.get(this[cntr](false));
189 // do not try and build conditional elements
190 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
194 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196 return this.addxtypeChild(tree,cntr, is_body);
199 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
202 return this.addxtypeChild(Roo.apply({}, tree),cntr);
205 Roo.log('skipping render');
211 if (!build_from_html) {
215 // this i think handles overlaying multiple children of the same type
216 // with the sam eelement.. - which might be buggy..
218 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
224 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
228 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
235 addxtypeChild : function (tree, cntr, is_body)
237 Roo.debug && Roo.log('addxtypeChild:' + cntr);
239 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243 (typeof(tree['flexy:foreach']) != 'undefined');
247 skip_children = false;
248 // render the element if it's not BODY.
251 // if parent was disabled, then do not try and create the children..
252 if(!this[cntr](true)){
257 cn = Roo.factory(tree);
259 cn.parentType = this.xtype; //??
260 cn.parentId = this.id;
262 var build_from_html = Roo.XComponent.build_from_html;
265 // does the container contain child eleemnts with 'xtype' attributes.
266 // that match this xtype..
267 // note - when we render we create these as well..
268 // so we should check to see if body has xtype set.
269 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
271 var self_cntr_el = Roo.get(this[cntr](false));
272 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
274 //Roo.log(Roo.XComponent.build_from_html);
275 //Roo.log("got echild:");
278 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279 // and are not displayed -this causes this to use up the wrong element when matching.
280 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
283 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
290 //echild.dom.removeAttribute('xtype');
292 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293 Roo.debug && Roo.log(self_cntr_el);
294 Roo.debug && Roo.log(echild);
295 Roo.debug && Roo.log(cn);
301 // if object has flexy:if - then it may or may not be rendered.
302 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
303 // skip a flexy if element.
304 Roo.debug && Roo.log('skipping render');
305 Roo.debug && Roo.log(tree);
307 Roo.debug && Roo.log('skipping all children');
308 skip_children = true;
313 // actually if flexy:foreach is found, we really want to create
314 // multiple copies here...
316 //Roo.log(this[cntr]());
317 // some elements do not have render methods.. like the layouts...
319 if(this[cntr](true) === false){
324 cn.render && cn.render(this[cntr](true));
327 // then add the element..
334 if (typeof (tree.menu) != 'undefined') {
335 tree.menu.parentType = cn.xtype;
336 tree.menu.triggerEl = cn.el;
337 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
341 if (!tree.items || !tree.items.length) {
343 //Roo.log(["no children", this]);
348 var items = tree.items;
351 //Roo.log(items.length);
353 if (!skip_children) {
354 for(var i =0;i < items.length;i++) {
355 // Roo.log(['add child', items[i]]);
356 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
362 //Roo.log("fire childrenrendered");
364 cn.fireEvent('childrenrendered', this);
370 * Set the element that will be used to show or hide
372 setVisibilityEl : function(el)
374 this.visibilityEl = el;
378 * Get the element that will be used to show or hide
380 getVisibilityEl : function()
382 if (typeof(this.visibilityEl) == 'object') {
383 return this.visibilityEl;
386 if (typeof(this.visibilityEl) == 'string') {
387 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
394 * Show a component - removes 'hidden' class
398 if(!this.getVisibilityEl()){
402 this.getVisibilityEl().removeClass('hidden');
407 * Hide a component - adds 'hidden' class
411 if(!this.getVisibilityEl()){
415 this.getVisibilityEl().addClass('hidden');
428 * @class Roo.bootstrap.Body
429 * @extends Roo.bootstrap.Component
430 * Bootstrap Body class
434 * @param {Object} config The config object
437 Roo.bootstrap.Body = function(config){
439 config = config || {};
441 Roo.bootstrap.Body.superclass.constructor.call(this, config);
442 this.el = Roo.get(config.el ? config.el : document.body );
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
450 is_body : true,// just to make sure it's constructed?
455 onRender : function(ct, position)
457 /* Roo.log("Roo.bootstrap.Body - onRender");
458 if (this.cls && this.cls.length) {
459 Roo.get(document.body).addClass(this.cls);
478 * @class Roo.bootstrap.ButtonGroup
479 * @extends Roo.bootstrap.Component
480 * Bootstrap ButtonGroup class
481 * @cfg {String} size lg | sm | xs (default empty normal)
482 * @cfg {String} align vertical | justified (default none)
483 * @cfg {String} direction up | down (default down)
484 * @cfg {Boolean} toolbar false | true
485 * @cfg {Boolean} btn true | false
490 * @param {Object} config The config object
493 Roo.bootstrap.ButtonGroup = function(config){
494 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
505 getAutoCreate : function(){
511 cfg.html = this.html || cfg.html;
522 if (['vertical','justified'].indexOf(this.align)!==-1) {
523 cfg.cls = 'btn-group-' + this.align;
525 if (this.align == 'justified') {
526 console.log(this.items);
530 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531 cfg.cls += ' btn-group-' + this.size;
534 if (this.direction == 'up') {
535 cfg.cls += ' dropup' ;
551 * @class Roo.bootstrap.Button
552 * @extends Roo.bootstrap.Component
553 * Bootstrap Button class
554 * @cfg {String} html The button content
555 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
556 * @cfg {String} size ( lg | sm | xs)
557 * @cfg {String} tag ( a | input | submit)
558 * @cfg {String} href empty or href
559 * @cfg {Boolean} disabled default false;
560 * @cfg {Boolean} isClose default false;
561 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
562 * @cfg {String} badge text for badge
563 * @cfg {String} theme default
564 * @cfg {Boolean} inverse
565 * @cfg {Boolean} toggle
566 * @cfg {String} ontext text for on toggle state
567 * @cfg {String} offtext text for off toggle state
568 * @cfg {Boolean} defaulton
569 * @cfg {Boolean} preventDefault default true
570 * @cfg {Boolean} removeClass remove the standard class..
571 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
574 * Create a new button
575 * @param {Object} config The config object
579 Roo.bootstrap.Button = function(config){
580 Roo.bootstrap.Button.superclass.constructor.call(this, config);
581 this.weightClass = ["btn-default",
593 * When a butotn is pressed
594 * @param {Roo.bootstrap.Button} this
595 * @param {Roo.EventObject} e
600 * After the button has been toggles
601 * @param {Roo.EventObject} e
602 * @param {boolean} pressed (also available as button.pressed)
608 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
626 preventDefault: true,
635 getAutoCreate : function(){
643 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
644 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
651 if (this.toggle == true) {
654 cls: 'slider-frame roo-button',
659 'data-off-text':'OFF',
660 cls: 'slider-button',
666 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667 cfg.cls += ' '+this.weight;
676 cfg["aria-hidden"] = true;
678 cfg.html = "×";
684 if (this.theme==='default') {
685 cfg.cls = 'btn roo-button';
687 //if (this.parentType != 'Navbar') {
688 this.weight = this.weight.length ? this.weight : 'default';
690 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
692 cfg.cls += ' btn-' + this.weight;
694 } else if (this.theme==='glow') {
697 cfg.cls = 'btn-glow roo-button';
699 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
701 cfg.cls += ' ' + this.weight;
707 this.cls += ' inverse';
712 cfg.cls += ' active';
716 cfg.disabled = 'disabled';
720 Roo.log('changing to ul' );
722 this.glyphicon = 'caret';
725 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
727 //gsRoo.log(this.parentType);
728 if (this.parentType === 'Navbar' && !this.parent().bar) {
729 Roo.log('changing to li?');
738 href : this.href || '#'
741 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
742 cfg.cls += ' dropdown';
749 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
751 if (this.glyphicon) {
752 cfg.html = ' ' + cfg.html;
757 cls: 'glyphicon glyphicon-' + this.glyphicon
767 // cfg.cls='btn roo-button';
771 var value = cfg.html;
776 cls: 'glyphicon glyphicon-' + this.glyphicon,
795 cfg.cls += ' dropdown';
796 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
799 if (cfg.tag !== 'a' && this.href !== '') {
800 throw "Tag must be a to set href.";
801 } else if (this.href.length > 0) {
802 cfg.href = this.href;
805 if(this.removeClass){
810 cfg.target = this.target;
815 initEvents: function() {
816 // Roo.log('init events?');
817 // Roo.log(this.el.dom);
820 if (typeof (this.menu) != 'undefined') {
821 this.menu.parentType = this.xtype;
822 this.menu.triggerEl = this.el;
823 this.addxtype(Roo.apply({}, this.menu));
827 if (this.el.hasClass('roo-button')) {
828 this.el.on('click', this.onClick, this);
830 this.el.select('.roo-button').on('click', this.onClick, this);
833 if(this.removeClass){
834 this.el.on('click', this.onClick, this);
837 this.el.enableDisplayMode();
840 onClick : function(e)
847 Roo.log('button on click ');
848 if(this.preventDefault){
851 if (this.pressed === true || this.pressed === false) {
852 this.pressed = !this.pressed;
853 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
854 this.fireEvent('toggle', this, e, this.pressed);
858 this.fireEvent('click', this, e);
862 * Enables this button
866 this.disabled = false;
867 this.el.removeClass('disabled');
871 * Disable this button
875 this.disabled = true;
876 this.el.addClass('disabled');
879 * sets the active state on/off,
880 * @param {Boolean} state (optional) Force a particular state
882 setActive : function(v) {
884 this.el[v ? 'addClass' : 'removeClass']('active');
887 * toggles the current active state
889 toggleActive : function()
891 var active = this.el.hasClass('active');
892 this.setActive(!active);
896 setText : function(str)
898 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
902 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
913 setWeight : function(str)
915 this.el.removeClass(this.weightClass);
916 this.el.addClass('btn-' + str);
930 * @class Roo.bootstrap.Column
931 * @extends Roo.bootstrap.Component
932 * Bootstrap Column class
933 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
934 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
935 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
936 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
937 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
938 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
939 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
940 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
943 * @cfg {Boolean} hidden (true|false) hide the element
944 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
945 * @cfg {String} fa (ban|check|...) font awesome icon
946 * @cfg {Number} fasize (1|2|....) font awsome size
948 * @cfg {String} icon (info-sign|check|...) glyphicon name
950 * @cfg {String} html content of column.
953 * Create a new Column
954 * @param {Object} config The config object
957 Roo.bootstrap.Column = function(config){
958 Roo.bootstrap.Column.superclass.constructor.call(this, config);
961 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
979 getAutoCreate : function(){
980 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
988 ['xs','sm','md','lg'].map(function(size){
989 //Roo.log( size + ':' + settings[size]);
991 if (settings[size+'off'] !== false) {
992 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
995 if (settings[size] === false) {
999 if (!settings[size]) { // 0 = hidden
1000 cfg.cls += ' hidden-' + size;
1003 cfg.cls += ' col-' + size + '-' + settings[size];
1008 cfg.cls += ' hidden';
1011 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1012 cfg.cls +=' alert alert-' + this.alert;
1016 if (this.html.length) {
1017 cfg.html = this.html;
1021 if (this.fasize > 1) {
1022 fasize = ' fa-' + this.fasize + 'x';
1024 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1029 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1048 * @class Roo.bootstrap.Container
1049 * @extends Roo.bootstrap.Component
1050 * Bootstrap Container class
1051 * @cfg {Boolean} jumbotron is it a jumbotron element
1052 * @cfg {String} html content of element
1053 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1054 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1055 * @cfg {String} header content of header (for panel)
1056 * @cfg {String} footer content of footer (for panel)
1057 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1058 * @cfg {String} tag (header|aside|section) type of HTML tag.
1059 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1060 * @cfg {String} fa font awesome icon
1061 * @cfg {String} icon (info-sign|check|...) glyphicon name
1062 * @cfg {Boolean} hidden (true|false) hide the element
1063 * @cfg {Boolean} expandable (true|false) default false
1064 * @cfg {Boolean} expanded (true|false) default true
1065 * @cfg {String} rheader contet on the right of header
1066 * @cfg {Boolean} clickable (true|false) default false
1070 * Create a new Container
1071 * @param {Object} config The config object
1074 Roo.bootstrap.Container = function(config){
1075 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1081 * After the panel has been expand
1083 * @param {Roo.bootstrap.Container} this
1088 * After the panel has been collapsed
1090 * @param {Roo.bootstrap.Container} this
1095 * When a element is chick
1096 * @param {Roo.bootstrap.Container} this
1097 * @param {Roo.EventObject} e
1103 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1121 getChildContainer : function() {
1127 if (this.panel.length) {
1128 return this.el.select('.panel-body',true).first();
1135 getAutoCreate : function(){
1138 tag : this.tag || 'div',
1142 if (this.jumbotron) {
1143 cfg.cls = 'jumbotron';
1148 // - this is applied by the parent..
1150 // cfg.cls = this.cls + '';
1153 if (this.sticky.length) {
1155 var bd = Roo.get(document.body);
1156 if (!bd.hasClass('bootstrap-sticky')) {
1157 bd.addClass('bootstrap-sticky');
1158 Roo.select('html',true).setStyle('height', '100%');
1161 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1165 if (this.well.length) {
1166 switch (this.well) {
1169 cfg.cls +=' well well-' +this.well;
1178 cfg.cls += ' hidden';
1182 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1183 cfg.cls +=' alert alert-' + this.alert;
1188 if (this.panel.length) {
1189 cfg.cls += ' panel panel-' + this.panel;
1191 if (this.header.length) {
1195 if(this.expandable){
1197 cfg.cls = cfg.cls + ' expandable';
1201 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1209 cls : 'panel-title',
1210 html : (this.expandable ? ' ' : '') + this.header
1214 cls: 'panel-header-right',
1220 cls : 'panel-heading',
1221 style : this.expandable ? 'cursor: pointer' : '',
1229 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1234 if (this.footer.length) {
1236 cls : 'panel-footer',
1245 body.html = this.html || cfg.html;
1246 // prefix with the icons..
1248 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1251 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1256 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1257 cfg.cls = 'container';
1263 initEvents: function()
1265 if(this.expandable){
1266 var headerEl = this.headerEl();
1269 headerEl.on('click', this.onToggleClick, this);
1274 this.el.on('click', this.onClick, this);
1279 onToggleClick : function()
1281 var headerEl = this.headerEl();
1297 if(this.fireEvent('expand', this)) {
1299 this.expanded = true;
1301 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1303 this.el.select('.panel-body',true).first().removeClass('hide');
1305 var toggleEl = this.toggleEl();
1311 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1316 collapse : function()
1318 if(this.fireEvent('collapse', this)) {
1320 this.expanded = false;
1322 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1323 this.el.select('.panel-body',true).first().addClass('hide');
1325 var toggleEl = this.toggleEl();
1331 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1335 toggleEl : function()
1337 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1341 return this.el.select('.panel-heading .fa',true).first();
1344 headerEl : function()
1346 if(!this.el || !this.panel.length || !this.header.length){
1350 return this.el.select('.panel-heading',true).first()
1355 if(!this.el || !this.panel.length){
1359 return this.el.select('.panel-body',true).first()
1362 titleEl : function()
1364 if(!this.el || !this.panel.length || !this.header.length){
1368 return this.el.select('.panel-title',true).first();
1371 setTitle : function(v)
1373 var titleEl = this.titleEl();
1379 titleEl.dom.innerHTML = v;
1382 getTitle : function()
1385 var titleEl = this.titleEl();
1391 return titleEl.dom.innerHTML;
1394 setRightTitle : function(v)
1396 var t = this.el.select('.panel-header-right',true).first();
1402 t.dom.innerHTML = v;
1405 onClick : function(e)
1409 this.fireEvent('click', this, e);
1422 * @class Roo.bootstrap.Img
1423 * @extends Roo.bootstrap.Component
1424 * Bootstrap Img class
1425 * @cfg {Boolean} imgResponsive false | true
1426 * @cfg {String} border rounded | circle | thumbnail
1427 * @cfg {String} src image source
1428 * @cfg {String} alt image alternative text
1429 * @cfg {String} href a tag href
1430 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1431 * @cfg {String} xsUrl xs image source
1432 * @cfg {String} smUrl sm image source
1433 * @cfg {String} mdUrl md image source
1434 * @cfg {String} lgUrl lg image source
1437 * Create a new Input
1438 * @param {Object} config The config object
1441 Roo.bootstrap.Img = function(config){
1442 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1448 * The img click event for the img.
1449 * @param {Roo.EventObject} e
1455 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1457 imgResponsive: true,
1467 getAutoCreate : function()
1469 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1470 return this.createSingleImg();
1475 cls: 'roo-image-responsive-group',
1480 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1482 if(!_this[size + 'Url']){
1488 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1489 html: _this.html || cfg.html,
1490 src: _this[size + 'Url']
1493 img.cls += ' roo-image-responsive-' + size;
1495 var s = ['xs', 'sm', 'md', 'lg'];
1497 s.splice(s.indexOf(size), 1);
1499 Roo.each(s, function(ss){
1500 img.cls += ' hidden-' + ss;
1503 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1504 cfg.cls += ' img-' + _this.border;
1508 cfg.alt = _this.alt;
1521 a.target = _this.target;
1525 cfg.cn.push((_this.href) ? a : img);
1532 createSingleImg : function()
1536 cls: (this.imgResponsive) ? 'img-responsive' : '',
1538 src : 'about:blank' // just incase src get's set to undefined?!?
1541 cfg.html = this.html || cfg.html;
1543 cfg.src = this.src || cfg.src;
1545 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1546 cfg.cls += ' img-' + this.border;
1563 a.target = this.target;
1568 return (this.href) ? a : cfg;
1571 initEvents: function()
1574 this.el.on('click', this.onClick, this);
1579 onClick : function(e)
1581 Roo.log('img onclick');
1582 this.fireEvent('click', this, e);
1585 * Sets the url of the image - used to update it
1586 * @param {String} url the url of the image
1589 setSrc : function(url)
1593 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1594 this.el.dom.src = url;
1598 this.el.select('img', true).first().dom.src = url;
1614 * @class Roo.bootstrap.Link
1615 * @extends Roo.bootstrap.Component
1616 * Bootstrap Link Class
1617 * @cfg {String} alt image alternative text
1618 * @cfg {String} href a tag href
1619 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1620 * @cfg {String} html the content of the link.
1621 * @cfg {String} anchor name for the anchor link
1622 * @cfg {String} fa - favicon
1624 * @cfg {Boolean} preventDefault (true | false) default false
1628 * Create a new Input
1629 * @param {Object} config The config object
1632 Roo.bootstrap.Link = function(config){
1633 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1639 * The img click event for the img.
1640 * @param {Roo.EventObject} e
1646 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1650 preventDefault: false,
1656 getAutoCreate : function()
1658 var html = this.html || '';
1660 if (this.fa !== false) {
1661 html = '<i class="fa fa-' + this.fa + '"></i>';
1666 // anchor's do not require html/href...
1667 if (this.anchor === false) {
1669 cfg.href = this.href || '#';
1671 cfg.name = this.anchor;
1672 if (this.html !== false || this.fa !== false) {
1675 if (this.href !== false) {
1676 cfg.href = this.href;
1680 if(this.alt !== false){
1685 if(this.target !== false) {
1686 cfg.target = this.target;
1692 initEvents: function() {
1694 if(!this.href || this.preventDefault){
1695 this.el.on('click', this.onClick, this);
1699 onClick : function(e)
1701 if(this.preventDefault){
1704 //Roo.log('img onclick');
1705 this.fireEvent('click', this, e);
1718 * @class Roo.bootstrap.Header
1719 * @extends Roo.bootstrap.Component
1720 * Bootstrap Header class
1721 * @cfg {String} html content of header
1722 * @cfg {Number} level (1|2|3|4|5|6) default 1
1725 * Create a new Header
1726 * @param {Object} config The config object
1730 Roo.bootstrap.Header = function(config){
1731 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1734 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1742 getAutoCreate : function(){
1747 tag: 'h' + (1 *this.level),
1748 html: this.html || ''
1760 * Ext JS Library 1.1.1
1761 * Copyright(c) 2006-2007, Ext JS, LLC.
1763 * Originally Released Under LGPL - original licence link has changed is not relivant.
1766 * <script type="text/javascript">
1770 * @class Roo.bootstrap.MenuMgr
1771 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1774 Roo.bootstrap.MenuMgr = function(){
1775 var menus, active, groups = {}, attached = false, lastShow = new Date();
1777 // private - called when first menu is created
1780 active = new Roo.util.MixedCollection();
1781 Roo.get(document).addKeyListener(27, function(){
1782 if(active.length > 0){
1790 if(active && active.length > 0){
1791 var c = active.clone();
1801 if(active.length < 1){
1802 Roo.get(document).un("mouseup", onMouseDown);
1810 var last = active.last();
1811 lastShow = new Date();
1814 Roo.get(document).on("mouseup", onMouseDown);
1819 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1820 m.parentMenu.activeChild = m;
1821 }else if(last && last.isVisible()){
1822 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1827 function onBeforeHide(m){
1829 m.activeChild.hide();
1831 if(m.autoHideTimer){
1832 clearTimeout(m.autoHideTimer);
1833 delete m.autoHideTimer;
1838 function onBeforeShow(m){
1839 var pm = m.parentMenu;
1840 if(!pm && !m.allowOtherMenus){
1842 }else if(pm && pm.activeChild && active != m){
1843 pm.activeChild.hide();
1847 // private this should really trigger on mouseup..
1848 function onMouseDown(e){
1849 Roo.log("on Mouse Up");
1851 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1852 Roo.log("MenuManager hideAll");
1861 function onBeforeCheck(mi, state){
1863 var g = groups[mi.group];
1864 for(var i = 0, l = g.length; i < l; i++){
1866 g[i].setChecked(false);
1875 * Hides all menus that are currently visible
1877 hideAll : function(){
1882 register : function(menu){
1886 menus[menu.id] = menu;
1887 menu.on("beforehide", onBeforeHide);
1888 menu.on("hide", onHide);
1889 menu.on("beforeshow", onBeforeShow);
1890 menu.on("show", onShow);
1892 if(g && menu.events["checkchange"]){
1896 groups[g].push(menu);
1897 menu.on("checkchange", onCheck);
1902 * Returns a {@link Roo.menu.Menu} object
1903 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1904 * be used to generate and return a new Menu instance.
1906 get : function(menu){
1907 if(typeof menu == "string"){ // menu id
1909 }else if(menu.events){ // menu instance
1912 /*else if(typeof menu.length == 'number'){ // array of menu items?
1913 return new Roo.bootstrap.Menu({items:menu});
1914 }else{ // otherwise, must be a config
1915 return new Roo.bootstrap.Menu(menu);
1922 unregister : function(menu){
1923 delete menus[menu.id];
1924 menu.un("beforehide", onBeforeHide);
1925 menu.un("hide", onHide);
1926 menu.un("beforeshow", onBeforeShow);
1927 menu.un("show", onShow);
1929 if(g && menu.events["checkchange"]){
1930 groups[g].remove(menu);
1931 menu.un("checkchange", onCheck);
1936 registerCheckable : function(menuItem){
1937 var g = menuItem.group;
1942 groups[g].push(menuItem);
1943 menuItem.on("beforecheckchange", onBeforeCheck);
1948 unregisterCheckable : function(menuItem){
1949 var g = menuItem.group;
1951 groups[g].remove(menuItem);
1952 menuItem.un("beforecheckchange", onBeforeCheck);
1964 * @class Roo.bootstrap.Menu
1965 * @extends Roo.bootstrap.Component
1966 * Bootstrap Menu class - container for MenuItems
1967 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1968 * @cfg {bool} hidden if the menu should be hidden when rendered.
1969 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1970 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1974 * @param {Object} config The config object
1978 Roo.bootstrap.Menu = function(config){
1979 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1980 if (this.registerMenu && this.type != 'treeview') {
1981 Roo.bootstrap.MenuMgr.register(this);
1986 * Fires before this menu is displayed
1987 * @param {Roo.menu.Menu} this
1992 * Fires before this menu is hidden
1993 * @param {Roo.menu.Menu} this
1998 * Fires after this menu is displayed
1999 * @param {Roo.menu.Menu} this
2004 * Fires after this menu is hidden
2005 * @param {Roo.menu.Menu} this
2010 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2011 * @param {Roo.menu.Menu} this
2012 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2013 * @param {Roo.EventObject} e
2018 * Fires when the mouse is hovering over this menu
2019 * @param {Roo.menu.Menu} this
2020 * @param {Roo.EventObject} e
2021 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2026 * Fires when the mouse exits this menu
2027 * @param {Roo.menu.Menu} this
2028 * @param {Roo.EventObject} e
2029 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2034 * Fires when a menu item contained in this menu is clicked
2035 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2036 * @param {Roo.EventObject} e
2040 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2043 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2047 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2050 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2052 registerMenu : true,
2054 menuItems :false, // stores the menu items..
2064 getChildContainer : function() {
2068 getAutoCreate : function(){
2070 //if (['right'].indexOf(this.align)!==-1) {
2071 // cfg.cn[1].cls += ' pull-right'
2077 cls : 'dropdown-menu' ,
2078 style : 'z-index:1000'
2082 if (this.type === 'submenu') {
2083 cfg.cls = 'submenu active';
2085 if (this.type === 'treeview') {
2086 cfg.cls = 'treeview-menu';
2091 initEvents : function() {
2093 // Roo.log("ADD event");
2094 // Roo.log(this.triggerEl.dom);
2096 this.triggerEl.on('click', this.onTriggerClick, this);
2098 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2100 this.triggerEl.addClass('dropdown-toggle');
2103 this.el.on('touchstart' , this.onTouch, this);
2105 this.el.on('click' , this.onClick, this);
2107 this.el.on("mouseover", this.onMouseOver, this);
2108 this.el.on("mouseout", this.onMouseOut, this);
2112 findTargetItem : function(e)
2114 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2118 //Roo.log(t); Roo.log(t.id);
2120 //Roo.log(this.menuitems);
2121 return this.menuitems.get(t.id);
2123 //return this.items.get(t.menuItemId);
2129 onTouch : function(e)
2131 Roo.log("menu.onTouch");
2132 //e.stopEvent(); this make the user popdown broken
2136 onClick : function(e)
2138 Roo.log("menu.onClick");
2140 var t = this.findTargetItem(e);
2141 if(!t || t.isContainer){
2146 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2147 if(t == this.activeItem && t.shouldDeactivate(e)){
2148 this.activeItem.deactivate();
2149 delete this.activeItem;
2153 this.setActiveItem(t, true);
2161 Roo.log('pass click event');
2165 this.fireEvent("click", this, t, e);
2169 if(!t.href.length || t.href == '#'){
2170 (function() { _this.hide(); }).defer(100);
2175 onMouseOver : function(e){
2176 var t = this.findTargetItem(e);
2179 // if(t.canActivate && !t.disabled){
2180 // this.setActiveItem(t, true);
2184 this.fireEvent("mouseover", this, e, t);
2186 isVisible : function(){
2187 return !this.hidden;
2189 onMouseOut : function(e){
2190 var t = this.findTargetItem(e);
2193 // if(t == this.activeItem && t.shouldDeactivate(e)){
2194 // this.activeItem.deactivate();
2195 // delete this.activeItem;
2198 this.fireEvent("mouseout", this, e, t);
2203 * Displays this menu relative to another element
2204 * @param {String/HTMLElement/Roo.Element} element The element to align to
2205 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2206 * the element (defaults to this.defaultAlign)
2207 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2209 show : function(el, pos, parentMenu){
2210 this.parentMenu = parentMenu;
2214 this.fireEvent("beforeshow", this);
2215 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2218 * Displays this menu at a specific xy position
2219 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2220 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2222 showAt : function(xy, parentMenu, /* private: */_e){
2223 this.parentMenu = parentMenu;
2228 this.fireEvent("beforeshow", this);
2229 //xy = this.el.adjustForConstraints(xy);
2233 this.hideMenuItems();
2234 this.hidden = false;
2235 this.triggerEl.addClass('open');
2237 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2238 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2241 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2246 this.fireEvent("show", this);
2252 this.doFocus.defer(50, this);
2256 doFocus : function(){
2258 this.focusEl.focus();
2263 * Hides this menu and optionally all parent menus
2264 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2266 hide : function(deep)
2269 this.hideMenuItems();
2270 if(this.el && this.isVisible()){
2271 this.fireEvent("beforehide", this);
2272 if(this.activeItem){
2273 this.activeItem.deactivate();
2274 this.activeItem = null;
2276 this.triggerEl.removeClass('open');;
2278 this.fireEvent("hide", this);
2280 if(deep === true && this.parentMenu){
2281 this.parentMenu.hide(true);
2285 onTriggerClick : function(e)
2287 Roo.log('trigger click');
2289 var target = e.getTarget();
2291 Roo.log(target.nodeName.toLowerCase());
2293 if(target.nodeName.toLowerCase() === 'i'){
2299 onTriggerPress : function(e)
2301 Roo.log('trigger press');
2302 //Roo.log(e.getTarget());
2303 // Roo.log(this.triggerEl.dom);
2305 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2306 var pel = Roo.get(e.getTarget());
2307 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2308 Roo.log('is treeview or dropdown?');
2312 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2316 if (this.isVisible()) {
2321 this.show(this.triggerEl, false, false);
2324 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2331 hideMenuItems : function()
2333 Roo.log("hide Menu Items");
2337 //$(backdrop).remove()
2338 this.el.select('.open',true).each(function(aa) {
2340 aa.removeClass('open');
2341 //var parent = getParent($(this))
2342 //var relatedTarget = { relatedTarget: this }
2344 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2345 //if (e.isDefaultPrevented()) return
2346 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2349 addxtypeChild : function (tree, cntr) {
2350 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2352 this.menuitems.add(comp);
2364 this.getEl().dom.innerHTML = '';
2365 this.menuitems.clear();
2379 * @class Roo.bootstrap.MenuItem
2380 * @extends Roo.bootstrap.Component
2381 * Bootstrap MenuItem class
2382 * @cfg {String} html the menu label
2383 * @cfg {String} href the link
2384 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2385 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2386 * @cfg {Boolean} active used on sidebars to highlight active itesm
2387 * @cfg {String} fa favicon to show on left of menu item.
2388 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2392 * Create a new MenuItem
2393 * @param {Object} config The config object
2397 Roo.bootstrap.MenuItem = function(config){
2398 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2403 * The raw click event for the entire grid.
2404 * @param {Roo.bootstrap.MenuItem} this
2405 * @param {Roo.EventObject} e
2411 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2415 preventDefault: false,
2416 isContainer : false,
2420 getAutoCreate : function(){
2422 if(this.isContainer){
2425 cls: 'dropdown-menu-item'
2439 if (this.fa !== false) {
2442 cls : 'fa fa-' + this.fa
2451 cls: 'dropdown-menu-item',
2454 if (this.parent().type == 'treeview') {
2455 cfg.cls = 'treeview-menu';
2458 cfg.cls += ' active';
2463 anc.href = this.href || cfg.cn[0].href ;
2464 ctag.html = this.html || cfg.cn[0].html ;
2468 initEvents: function()
2470 if (this.parent().type == 'treeview') {
2471 this.el.select('a').on('click', this.onClick, this);
2475 this.menu.parentType = this.xtype;
2476 this.menu.triggerEl = this.el;
2477 this.menu = this.addxtype(Roo.apply({}, this.menu));
2481 onClick : function(e)
2483 Roo.log('item on click ');
2485 if(this.preventDefault){
2488 //this.parent().hideMenuItems();
2490 this.fireEvent('click', this, e);
2509 * @class Roo.bootstrap.MenuSeparator
2510 * @extends Roo.bootstrap.Component
2511 * Bootstrap MenuSeparator class
2514 * Create a new MenuItem
2515 * @param {Object} config The config object
2519 Roo.bootstrap.MenuSeparator = function(config){
2520 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2523 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2525 getAutoCreate : function(){
2544 * @class Roo.bootstrap.Modal
2545 * @extends Roo.bootstrap.Component
2546 * Bootstrap Modal class
2547 * @cfg {String} title Title of dialog
2548 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2549 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2550 * @cfg {Boolean} specificTitle default false
2551 * @cfg {Array} buttons Array of buttons or standard button set..
2552 * @cfg {String} buttonPosition (left|right|center) default right
2553 * @cfg {Boolean} animate default true
2554 * @cfg {Boolean} allow_close default true
2555 * @cfg {Boolean} fitwindow default false
2556 * @cfg {String} size (sm|lg) default empty
2560 * Create a new Modal Dialog
2561 * @param {Object} config The config object
2564 Roo.bootstrap.Modal = function(config){
2565 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2570 * The raw btnclick event for the button
2571 * @param {Roo.EventObject} e
2576 * Fire when dialog resize
2577 * @param {Roo.bootstrap.Modal} this
2578 * @param {Roo.EventObject} e
2582 this.buttons = this.buttons || [];
2585 this.tmpl = Roo.factory(this.tmpl);
2590 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2592 title : 'test dialog',
2602 specificTitle: false,
2604 buttonPosition: 'right',
2623 onRender : function(ct, position)
2625 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2628 var cfg = Roo.apply({}, this.getAutoCreate());
2631 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2633 //if (!cfg.name.length) {
2637 cfg.cls += ' ' + this.cls;
2640 cfg.style = this.style;
2642 this.el = Roo.get(document.body).createChild(cfg, position);
2644 //var type = this.el.dom.type;
2647 if(this.tabIndex !== undefined){
2648 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2651 this.dialogEl = this.el.select('.modal-dialog',true).first();
2652 this.bodyEl = this.el.select('.modal-body',true).first();
2653 this.closeEl = this.el.select('.modal-header .close', true).first();
2654 this.headerEl = this.el.select('.modal-header',true).first();
2655 this.titleEl = this.el.select('.modal-title',true).first();
2656 this.footerEl = this.el.select('.modal-footer',true).first();
2658 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2659 this.maskEl.enableDisplayMode("block");
2661 //this.el.addClass("x-dlg-modal");
2663 if (this.buttons.length) {
2664 Roo.each(this.buttons, function(bb) {
2665 var b = Roo.apply({}, bb);
2666 b.xns = b.xns || Roo.bootstrap;
2667 b.xtype = b.xtype || 'Button';
2668 if (typeof(b.listeners) == 'undefined') {
2669 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2672 var btn = Roo.factory(b);
2674 btn.render(this.el.select('.modal-footer div').first());
2678 // render the children.
2681 if(typeof(this.items) != 'undefined'){
2682 var items = this.items;
2685 for(var i =0;i < items.length;i++) {
2686 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2690 this.items = nitems;
2692 // where are these used - they used to be body/close/footer
2696 //this.el.addClass([this.fieldClass, this.cls]);
2700 getAutoCreate : function(){
2705 html : this.html || ''
2710 cls : 'modal-title',
2714 if(this.specificTitle){
2720 if (this.allow_close) {
2732 if(this.size.length){
2733 size = 'modal-' + this.size;
2738 style : 'display: none',
2741 cls: "modal-dialog " + size,
2744 cls : "modal-content",
2747 cls : 'modal-header',
2752 cls : 'modal-footer',
2756 cls: 'btn-' + this.buttonPosition
2773 modal.cls += ' fade';
2779 getChildContainer : function() {
2784 getButtonContainer : function() {
2785 return this.el.select('.modal-footer div',true).first();
2788 initEvents : function()
2790 if (this.allow_close) {
2791 this.closeEl.on('click', this.hide, this);
2793 Roo.EventManager.onWindowResize(this.resize, this, true);
2800 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2801 if (this.fitwindow) {
2802 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2803 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2808 setSize : function(w,h)
2818 if (!this.rendered) {
2822 this.el.setStyle('display', 'block');
2824 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2827 this.el.addClass('in');
2830 this.el.addClass('in');
2834 // not sure how we can show data in here..
2836 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2839 Roo.get(document.body).addClass("x-body-masked");
2841 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2842 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2847 this.fireEvent('show', this);
2849 // set zindex here - otherwise it appears to be ignored...
2850 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2853 this.items.forEach( function(e) {
2854 e.layout ? e.layout() : false;
2862 if(this.fireEvent("beforehide", this) !== false){
2864 Roo.get(document.body).removeClass("x-body-masked");
2865 this.el.removeClass('in');
2866 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2868 if(this.animate){ // why
2870 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2872 this.el.setStyle('display', 'none');
2874 this.fireEvent('hide', this);
2878 addButton : function(str, cb)
2882 var b = Roo.apply({}, { html : str } );
2883 b.xns = b.xns || Roo.bootstrap;
2884 b.xtype = b.xtype || 'Button';
2885 if (typeof(b.listeners) == 'undefined') {
2886 b.listeners = { click : cb.createDelegate(this) };
2889 var btn = Roo.factory(b);
2891 btn.render(this.el.select('.modal-footer div').first());
2897 setDefaultButton : function(btn)
2899 //this.el.select('.modal-footer').()
2903 resizeTo: function(w,h)
2907 this.dialogEl.setWidth(w);
2908 if (this.diff === false) {
2909 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2912 this.bodyEl.setHeight(h-this.diff);
2914 this.fireEvent('resize', this);
2917 setContentSize : function(w, h)
2921 onButtonClick: function(btn,e)
2924 this.fireEvent('btnclick', btn.name, e);
2927 * Set the title of the Dialog
2928 * @param {String} str new Title
2930 setTitle: function(str) {
2931 this.titleEl.dom.innerHTML = str;
2934 * Set the body of the Dialog
2935 * @param {String} str new Title
2937 setBody: function(str) {
2938 this.bodyEl.dom.innerHTML = str;
2941 * Set the body of the Dialog using the template
2942 * @param {Obj} data - apply this data to the template and replace the body contents.
2944 applyBody: function(obj)
2947 Roo.log("Error - using apply Body without a template");
2950 this.tmpl.overwrite(this.bodyEl, obj);
2956 Roo.apply(Roo.bootstrap.Modal, {
2958 * Button config that displays a single OK button
2967 * Button config that displays Yes and No buttons
2983 * Button config that displays OK and Cancel buttons
2998 * Button config that displays Yes, No and Cancel buttons
3022 * messagebox - can be used as a replace
3026 * @class Roo.MessageBox
3027 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3031 Roo.Msg.alert('Status', 'Changes saved successfully.');
3033 // Prompt for user data:
3034 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3036 // process text value...
3040 // Show a dialog using config options:
3042 title:'Save Changes?',
3043 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3044 buttons: Roo.Msg.YESNOCANCEL,
3051 Roo.bootstrap.MessageBox = function(){
3052 var dlg, opt, mask, waitTimer;
3053 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3054 var buttons, activeTextEl, bwidth;
3058 var handleButton = function(button){
3060 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3064 var handleHide = function(){
3066 dlg.el.removeClass(opt.cls);
3069 // Roo.TaskMgr.stop(waitTimer);
3070 // waitTimer = null;
3075 var updateButtons = function(b){
3078 buttons["ok"].hide();
3079 buttons["cancel"].hide();
3080 buttons["yes"].hide();
3081 buttons["no"].hide();
3082 //dlg.footer.dom.style.display = 'none';
3085 dlg.footerEl.dom.style.display = '';
3086 for(var k in buttons){
3087 if(typeof buttons[k] != "function"){
3090 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3091 width += buttons[k].el.getWidth()+15;
3101 var handleEsc = function(d, k, e){
3102 if(opt && opt.closable !== false){
3112 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3113 * @return {Roo.BasicDialog} The BasicDialog element
3115 getDialog : function(){
3117 dlg = new Roo.bootstrap.Modal( {
3120 //constraintoviewport:false,
3122 //collapsible : false,
3127 //buttonAlign:"center",
3128 closeClick : function(){
3129 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3132 handleButton("cancel");
3137 dlg.on("hide", handleHide);
3139 //dlg.addKeyListener(27, handleEsc);
3141 this.buttons = buttons;
3142 var bt = this.buttonText;
3143 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3144 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3145 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3146 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3148 bodyEl = dlg.bodyEl.createChild({
3150 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3151 '<textarea class="roo-mb-textarea"></textarea>' +
3152 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3154 msgEl = bodyEl.dom.firstChild;
3155 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3156 textboxEl.enableDisplayMode();
3157 textboxEl.addKeyListener([10,13], function(){
3158 if(dlg.isVisible() && opt && opt.buttons){
3161 }else if(opt.buttons.yes){
3162 handleButton("yes");
3166 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3167 textareaEl.enableDisplayMode();
3168 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3169 progressEl.enableDisplayMode();
3171 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3172 var pf = progressEl.dom.firstChild;
3174 pp = Roo.get(pf.firstChild);
3175 pp.setHeight(pf.offsetHeight);
3183 * Updates the message box body text
3184 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3185 * the XHTML-compliant non-breaking space character '&#160;')
3186 * @return {Roo.MessageBox} This message box
3188 updateText : function(text)
3190 if(!dlg.isVisible() && !opt.width){
3191 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3192 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3194 msgEl.innerHTML = text || ' ';
3196 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3197 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3199 Math.min(opt.width || cw , this.maxWidth),
3200 Math.max(opt.minWidth || this.minWidth, bwidth)
3203 activeTextEl.setWidth(w);
3205 if(dlg.isVisible()){
3206 dlg.fixedcenter = false;
3208 // to big, make it scroll. = But as usual stupid IE does not support
3211 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3212 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3213 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3215 bodyEl.dom.style.height = '';
3216 bodyEl.dom.style.overflowY = '';
3219 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3221 bodyEl.dom.style.overflowX = '';
3224 dlg.setContentSize(w, bodyEl.getHeight());
3225 if(dlg.isVisible()){
3226 dlg.fixedcenter = true;
3232 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3233 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3234 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3235 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3236 * @return {Roo.MessageBox} This message box
3238 updateProgress : function(value, text){
3240 this.updateText(text);
3243 if (pp) { // weird bug on my firefox - for some reason this is not defined
3244 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3245 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3251 * Returns true if the message box is currently displayed
3252 * @return {Boolean} True if the message box is visible, else false
3254 isVisible : function(){
3255 return dlg && dlg.isVisible();
3259 * Hides the message box if it is displayed
3262 if(this.isVisible()){
3268 * Displays a new message box, or reinitializes an existing message box, based on the config options
3269 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3270 * The following config object properties are supported:
3272 Property Type Description
3273 ---------- --------------- ------------------------------------------------------------------------------------
3274 animEl String/Element An id or Element from which the message box should animate as it opens and
3275 closes (defaults to undefined)
3276 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3277 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3278 closable Boolean False to hide the top-right close button (defaults to true). Note that
3279 progress and wait dialogs will ignore this property and always hide the
3280 close button as they can only be closed programmatically.
3281 cls String A custom CSS class to apply to the message box element
3282 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3283 displayed (defaults to 75)
3284 fn Function A callback function to execute after closing the dialog. The arguments to the
3285 function will be btn (the name of the button that was clicked, if applicable,
3286 e.g. "ok"), and text (the value of the active text field, if applicable).
3287 Progress and wait dialogs will ignore this option since they do not respond to
3288 user actions and can only be closed programmatically, so any required function
3289 should be called by the same code after it closes the dialog.
3290 icon String A CSS class that provides a background image to be used as an icon for
3291 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3292 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3293 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3294 modal Boolean False to allow user interaction with the page while the message box is
3295 displayed (defaults to true)
3296 msg String A string that will replace the existing message box body text (defaults
3297 to the XHTML-compliant non-breaking space character ' ')
3298 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3299 progress Boolean True to display a progress bar (defaults to false)
3300 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3301 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3302 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3303 title String The title text
3304 value String The string value to set into the active textbox element if displayed
3305 wait Boolean True to display a progress bar (defaults to false)
3306 width Number The width of the dialog in pixels
3313 msg: 'Please enter your address:',
3315 buttons: Roo.MessageBox.OKCANCEL,
3318 animEl: 'addAddressBtn'
3321 * @param {Object} config Configuration options
3322 * @return {Roo.MessageBox} This message box
3324 show : function(options)
3327 // this causes nightmares if you show one dialog after another
3328 // especially on callbacks..
3330 if(this.isVisible()){
3333 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3334 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3335 Roo.log("New Dialog Message:" + options.msg )
3336 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3337 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3340 var d = this.getDialog();
3342 d.setTitle(opt.title || " ");
3343 d.closeEl.setDisplayed(opt.closable !== false);
3344 activeTextEl = textboxEl;
3345 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3350 textareaEl.setHeight(typeof opt.multiline == "number" ?
3351 opt.multiline : this.defaultTextHeight);
3352 activeTextEl = textareaEl;
3361 progressEl.setDisplayed(opt.progress === true);
3362 this.updateProgress(0);
3363 activeTextEl.dom.value = opt.value || "";
3365 dlg.setDefaultButton(activeTextEl);
3367 var bs = opt.buttons;
3371 }else if(bs && bs.yes){
3372 db = buttons["yes"];
3374 dlg.setDefaultButton(db);
3376 bwidth = updateButtons(opt.buttons);
3377 this.updateText(opt.msg);
3379 d.el.addClass(opt.cls);
3381 d.proxyDrag = opt.proxyDrag === true;
3382 d.modal = opt.modal !== false;
3383 d.mask = opt.modal !== false ? mask : false;
3385 // force it to the end of the z-index stack so it gets a cursor in FF
3386 document.body.appendChild(dlg.el.dom);
3387 d.animateTarget = null;
3388 d.show(options.animEl);
3394 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3395 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3396 * and closing the message box when the process is complete.
3397 * @param {String} title The title bar text
3398 * @param {String} msg The message box body text
3399 * @return {Roo.MessageBox} This message box
3401 progress : function(title, msg){
3408 minWidth: this.minProgressWidth,
3415 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3416 * If a callback function is passed it will be called after the user clicks the button, and the
3417 * id of the button that was clicked will be passed as the only parameter to the callback
3418 * (could also be the top-right close button).
3419 * @param {String} title The title bar text
3420 * @param {String} msg The message box body text
3421 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3422 * @param {Object} scope (optional) The scope of the callback function
3423 * @return {Roo.MessageBox} This message box
3425 alert : function(title, msg, fn, scope)
3440 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3441 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3442 * You are responsible for closing the message box when the process is complete.
3443 * @param {String} msg The message box body text
3444 * @param {String} title (optional) The title bar text
3445 * @return {Roo.MessageBox} This message box
3447 wait : function(msg, title){
3458 waitTimer = Roo.TaskMgr.start({
3460 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3468 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3469 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3470 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3471 * @param {String} title The title bar text
3472 * @param {String} msg The message box body text
3473 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3474 * @param {Object} scope (optional) The scope of the callback function
3475 * @return {Roo.MessageBox} This message box
3477 confirm : function(title, msg, fn, scope){
3481 buttons: this.YESNO,
3490 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3491 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3492 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3493 * (could also be the top-right close button) and the text that was entered will be passed as the two
3494 * parameters to the callback.
3495 * @param {String} title The title bar text
3496 * @param {String} msg The message box body text
3497 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3498 * @param {Object} scope (optional) The scope of the callback function
3499 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3500 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3501 * @return {Roo.MessageBox} This message box
3503 prompt : function(title, msg, fn, scope, multiline){
3507 buttons: this.OKCANCEL,
3512 multiline: multiline,
3519 * Button config that displays a single OK button
3524 * Button config that displays Yes and No buttons
3527 YESNO : {yes:true, no:true},
3529 * Button config that displays OK and Cancel buttons
3532 OKCANCEL : {ok:true, cancel:true},
3534 * Button config that displays Yes, No and Cancel buttons
3537 YESNOCANCEL : {yes:true, no:true, cancel:true},
3540 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3543 defaultTextHeight : 75,
3545 * The maximum width in pixels of the message box (defaults to 600)
3550 * The minimum width in pixels of the message box (defaults to 100)
3555 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3556 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3559 minProgressWidth : 250,
3561 * An object containing the default button text strings that can be overriden for localized language support.
3562 * Supported properties are: ok, cancel, yes and no.
3563 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3576 * Shorthand for {@link Roo.MessageBox}
3578 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3579 Roo.Msg = Roo.Msg || Roo.MessageBox;
3588 * @class Roo.bootstrap.Navbar
3589 * @extends Roo.bootstrap.Component
3590 * Bootstrap Navbar class
3593 * Create a new Navbar
3594 * @param {Object} config The config object
3598 Roo.bootstrap.Navbar = function(config){
3599 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3603 * @event beforetoggle
3604 * Fire before toggle the menu
3605 * @param {Roo.EventObject} e
3607 "beforetoggle" : true
3611 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3620 getAutoCreate : function(){
3623 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3627 initEvents :function ()
3629 //Roo.log(this.el.select('.navbar-toggle',true));
3630 this.el.select('.navbar-toggle',true).on('click', function() {
3631 if(this.fireEvent('beforetoggle', this) !== false){
3632 this.el.select('.navbar-collapse',true).toggleClass('in');
3642 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3644 var size = this.el.getSize();
3645 this.maskEl.setSize(size.width, size.height);
3646 this.maskEl.enableDisplayMode("block");
3655 getChildContainer : function()
3657 if (this.el.select('.collapse').getCount()) {
3658 return this.el.select('.collapse',true).first();
3691 * @class Roo.bootstrap.NavSimplebar
3692 * @extends Roo.bootstrap.Navbar
3693 * Bootstrap Sidebar class
3695 * @cfg {Boolean} inverse is inverted color
3697 * @cfg {String} type (nav | pills | tabs)
3698 * @cfg {Boolean} arrangement stacked | justified
3699 * @cfg {String} align (left | right) alignment
3701 * @cfg {Boolean} main (true|false) main nav bar? default false
3702 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3704 * @cfg {String} tag (header|footer|nav|div) default is nav
3710 * Create a new Sidebar
3711 * @param {Object} config The config object
3715 Roo.bootstrap.NavSimplebar = function(config){
3716 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3719 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3735 getAutoCreate : function(){
3739 tag : this.tag || 'div',
3752 this.type = this.type || 'nav';
3753 if (['tabs','pills'].indexOf(this.type)!==-1) {
3754 cfg.cn[0].cls += ' nav-' + this.type
3758 if (this.type!=='nav') {
3759 Roo.log('nav type must be nav/tabs/pills')
3761 cfg.cn[0].cls += ' navbar-nav'
3767 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3768 cfg.cn[0].cls += ' nav-' + this.arrangement;
3772 if (this.align === 'right') {
3773 cfg.cn[0].cls += ' navbar-right';
3777 cfg.cls += ' navbar-inverse';
3804 * @class Roo.bootstrap.NavHeaderbar
3805 * @extends Roo.bootstrap.NavSimplebar
3806 * Bootstrap Sidebar class
3808 * @cfg {String} brand what is brand
3809 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3810 * @cfg {String} brand_href href of the brand
3811 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3812 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3813 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3814 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3817 * Create a new Sidebar
3818 * @param {Object} config The config object
3822 Roo.bootstrap.NavHeaderbar = function(config){
3823 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3827 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3834 desktopCenter : false,
3837 getAutoCreate : function(){
3840 tag: this.nav || 'nav',
3847 if (this.desktopCenter) {
3848 cn.push({cls : 'container', cn : []});
3855 cls: 'navbar-header',
3860 cls: 'navbar-toggle',
3861 'data-toggle': 'collapse',
3866 html: 'Toggle navigation'
3888 cls: 'collapse navbar-collapse',
3892 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3894 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3895 cfg.cls += ' navbar-' + this.position;
3897 // tag can override this..
3899 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3902 if (this.brand !== '') {
3905 href: this.brand_href ? this.brand_href : '#',
3906 cls: 'navbar-brand',
3914 cfg.cls += ' main-nav';
3922 getHeaderChildContainer : function()
3924 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3925 return this.el.select('.navbar-header',true).first();
3928 return this.getChildContainer();
3932 initEvents : function()
3934 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3936 if (this.autohide) {
3941 Roo.get(document).on('scroll',function(e) {
3942 var ns = Roo.get(document).getScroll().top;
3943 var os = prevScroll;
3947 ft.removeClass('slideDown');
3948 ft.addClass('slideUp');
3951 ft.removeClass('slideUp');
3952 ft.addClass('slideDown');
3973 * @class Roo.bootstrap.NavSidebar
3974 * @extends Roo.bootstrap.Navbar
3975 * Bootstrap Sidebar class
3978 * Create a new Sidebar
3979 * @param {Object} config The config object
3983 Roo.bootstrap.NavSidebar = function(config){
3984 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3987 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3989 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3991 getAutoCreate : function(){
3996 cls: 'sidebar sidebar-nav'
4018 * @class Roo.bootstrap.NavGroup
4019 * @extends Roo.bootstrap.Component
4020 * Bootstrap NavGroup class
4021 * @cfg {String} align (left|right)
4022 * @cfg {Boolean} inverse
4023 * @cfg {String} type (nav|pills|tab) default nav
4024 * @cfg {String} navId - reference Id for navbar.
4028 * Create a new nav group
4029 * @param {Object} config The config object
4032 Roo.bootstrap.NavGroup = function(config){
4033 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4036 Roo.bootstrap.NavGroup.register(this);
4040 * Fires when the active item changes
4041 * @param {Roo.bootstrap.NavGroup} this
4042 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4043 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4050 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4061 getAutoCreate : function()
4063 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4070 if (['tabs','pills'].indexOf(this.type)!==-1) {
4071 cfg.cls += ' nav-' + this.type
4073 if (this.type!=='nav') {
4074 Roo.log('nav type must be nav/tabs/pills')
4076 cfg.cls += ' navbar-nav'
4079 if (this.parent() && this.parent().sidebar) {
4082 cls: 'dashboard-menu sidebar-menu'
4088 if (this.form === true) {
4094 if (this.align === 'right') {
4095 cfg.cls += ' navbar-right';
4097 cfg.cls += ' navbar-left';
4101 if (this.align === 'right') {
4102 cfg.cls += ' navbar-right';
4106 cfg.cls += ' navbar-inverse';
4114 * sets the active Navigation item
4115 * @param {Roo.bootstrap.NavItem} the new current navitem
4117 setActiveItem : function(item)
4120 Roo.each(this.navItems, function(v){
4125 v.setActive(false, true);
4132 item.setActive(true, true);
4133 this.fireEvent('changed', this, item, prev);
4138 * gets the active Navigation item
4139 * @return {Roo.bootstrap.NavItem} the current navitem
4141 getActive : function()
4145 Roo.each(this.navItems, function(v){
4156 indexOfNav : function()
4160 Roo.each(this.navItems, function(v,i){
4171 * adds a Navigation item
4172 * @param {Roo.bootstrap.NavItem} the navitem to add
4174 addItem : function(cfg)
4176 var cn = new Roo.bootstrap.NavItem(cfg);
4178 cn.parentId = this.id;
4179 cn.onRender(this.el, null);
4183 * register a Navigation item
4184 * @param {Roo.bootstrap.NavItem} the navitem to add
4186 register : function(item)
4188 this.navItems.push( item);
4189 item.navId = this.navId;
4194 * clear all the Navigation item
4197 clearAll : function()
4200 this.el.dom.innerHTML = '';
4203 getNavItem: function(tabId)
4206 Roo.each(this.navItems, function(e) {
4207 if (e.tabId == tabId) {
4217 setActiveNext : function()
4219 var i = this.indexOfNav(this.getActive());
4220 if (i > this.navItems.length) {
4223 this.setActiveItem(this.navItems[i+1]);
4225 setActivePrev : function()
4227 var i = this.indexOfNav(this.getActive());
4231 this.setActiveItem(this.navItems[i-1]);
4233 clearWasActive : function(except) {
4234 Roo.each(this.navItems, function(e) {
4235 if (e.tabId != except.tabId && e.was_active) {
4236 e.was_active = false;
4243 getWasActive : function ()
4246 Roo.each(this.navItems, function(e) {
4261 Roo.apply(Roo.bootstrap.NavGroup, {
4265 * register a Navigation Group
4266 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4268 register : function(navgrp)
4270 this.groups[navgrp.navId] = navgrp;
4274 * fetch a Navigation Group based on the navigation ID
4275 * @param {string} the navgroup to add
4276 * @returns {Roo.bootstrap.NavGroup} the navgroup
4278 get: function(navId) {
4279 if (typeof(this.groups[navId]) == 'undefined') {
4281 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4283 return this.groups[navId] ;
4298 * @class Roo.bootstrap.NavItem
4299 * @extends Roo.bootstrap.Component
4300 * Bootstrap Navbar.NavItem class
4301 * @cfg {String} href link to
4302 * @cfg {String} html content of button
4303 * @cfg {String} badge text inside badge
4304 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4305 * @cfg {String} glyphicon name of glyphicon
4306 * @cfg {String} icon name of font awesome icon
4307 * @cfg {Boolean} active Is item active
4308 * @cfg {Boolean} disabled Is item disabled
4310 * @cfg {Boolean} preventDefault (true | false) default false
4311 * @cfg {String} tabId the tab that this item activates.
4312 * @cfg {String} tagtype (a|span) render as a href or span?
4313 * @cfg {Boolean} animateRef (true|false) link to element default false
4316 * Create a new Navbar Item
4317 * @param {Object} config The config object
4319 Roo.bootstrap.NavItem = function(config){
4320 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4325 * The raw click event for the entire grid.
4326 * @param {Roo.EventObject} e
4331 * Fires when the active item active state changes
4332 * @param {Roo.bootstrap.NavItem} this
4333 * @param {boolean} state the new state
4339 * Fires when scroll to element
4340 * @param {Roo.bootstrap.NavItem} this
4341 * @param {Object} options
4342 * @param {Roo.EventObject} e
4350 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4358 preventDefault : false,
4365 getAutoCreate : function(){
4374 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4376 if (this.disabled) {
4377 cfg.cls += ' disabled';
4380 if (this.href || this.html || this.glyphicon || this.icon) {
4384 href : this.href || "#",
4385 html: this.html || ''
4390 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4393 if(this.glyphicon) {
4394 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4399 cfg.cn[0].html += " <span class='caret'></span>";
4403 if (this.badge !== '') {
4405 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4413 initEvents: function()
4415 if (typeof (this.menu) != 'undefined') {
4416 this.menu.parentType = this.xtype;
4417 this.menu.triggerEl = this.el;
4418 this.menu = this.addxtype(Roo.apply({}, this.menu));
4421 this.el.select('a',true).on('click', this.onClick, this);
4423 if(this.tagtype == 'span'){
4424 this.el.select('span',true).on('click', this.onClick, this);
4427 // at this point parent should be available..
4428 this.parent().register(this);
4431 onClick : function(e)
4433 if (e.getTarget('.dropdown-menu-item')) {
4434 // did you click on a menu itemm.... - then don't trigger onclick..
4439 this.preventDefault ||
4442 Roo.log("NavItem - prevent Default?");
4446 if (this.disabled) {
4450 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4451 if (tg && tg.transition) {
4452 Roo.log("waiting for the transitionend");
4458 //Roo.log("fire event clicked");
4459 if(this.fireEvent('click', this, e) === false){
4463 if(this.tagtype == 'span'){
4467 //Roo.log(this.href);
4468 var ael = this.el.select('a',true).first();
4471 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4472 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4473 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4474 return; // ignore... - it's a 'hash' to another page.
4476 Roo.log("NavItem - prevent Default?");
4478 this.scrollToElement(e);
4482 var p = this.parent();
4484 if (['tabs','pills'].indexOf(p.type)!==-1) {
4485 if (typeof(p.setActiveItem) !== 'undefined') {
4486 p.setActiveItem(this);
4490 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4491 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4492 // remove the collapsed menu expand...
4493 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4497 isActive: function () {
4500 setActive : function(state, fire, is_was_active)
4502 if (this.active && !state && this.navId) {
4503 this.was_active = true;
4504 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4506 nv.clearWasActive(this);
4510 this.active = state;
4513 this.el.removeClass('active');
4514 } else if (!this.el.hasClass('active')) {
4515 this.el.addClass('active');
4518 this.fireEvent('changed', this, state);
4521 // show a panel if it's registered and related..
4523 if (!this.navId || !this.tabId || !state || is_was_active) {
4527 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4531 var pan = tg.getPanelByName(this.tabId);
4535 // if we can not flip to new panel - go back to old nav highlight..
4536 if (false == tg.showPanel(pan)) {
4537 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4539 var onav = nv.getWasActive();
4541 onav.setActive(true, false, true);
4550 // this should not be here...
4551 setDisabled : function(state)
4553 this.disabled = state;
4555 this.el.removeClass('disabled');
4556 } else if (!this.el.hasClass('disabled')) {
4557 this.el.addClass('disabled');
4563 * Fetch the element to display the tooltip on.
4564 * @return {Roo.Element} defaults to this.el
4566 tooltipEl : function()
4568 return this.el.select('' + this.tagtype + '', true).first();
4571 scrollToElement : function(e)
4573 var c = document.body;
4576 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4578 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4579 c = document.documentElement;
4582 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4588 var o = target.calcOffsetsTo(c);
4595 this.fireEvent('scrollto', this, options, e);
4597 Roo.get(c).scrollTo('top', options.value, true);
4610 * <span> icon </span>
4611 * <span> text </span>
4612 * <span>badge </span>
4616 * @class Roo.bootstrap.NavSidebarItem
4617 * @extends Roo.bootstrap.NavItem
4618 * Bootstrap Navbar.NavSidebarItem class
4619 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4620 * {Boolean} open is the menu open
4621 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4622 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4623 * {String} buttonSize (sm|md|lg)the extra classes for the button
4624 * {Boolean} showArrow show arrow next to the text (default true)
4626 * Create a new Navbar Button
4627 * @param {Object} config The config object
4629 Roo.bootstrap.NavSidebarItem = function(config){
4630 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4635 * The raw click event for the entire grid.
4636 * @param {Roo.EventObject} e
4641 * Fires when the active item active state changes
4642 * @param {Roo.bootstrap.NavSidebarItem} this
4643 * @param {boolean} state the new state
4651 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4653 badgeWeight : 'default',
4659 buttonWeight : 'default',
4665 getAutoCreate : function(){
4670 href : this.href || '#',
4676 if(this.buttonView){
4679 href : this.href || '#',
4680 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4693 cfg.cls += ' active';
4696 if (this.disabled) {
4697 cfg.cls += ' disabled';
4700 cfg.cls += ' open x-open';
4703 if (this.glyphicon || this.icon) {
4704 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4705 a.cn.push({ tag : 'i', cls : c }) ;
4708 if(!this.buttonView){
4711 html : this.html || ''
4718 if (this.badge !== '') {
4719 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4725 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4728 a.cls += ' dropdown-toggle treeview' ;
4734 initEvents : function()
4736 if (typeof (this.menu) != 'undefined') {
4737 this.menu.parentType = this.xtype;
4738 this.menu.triggerEl = this.el;
4739 this.menu = this.addxtype(Roo.apply({}, this.menu));
4742 this.el.on('click', this.onClick, this);
4744 if(this.badge !== ''){
4745 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4750 onClick : function(e)
4757 if(this.preventDefault){
4761 this.fireEvent('click', this);
4764 disable : function()
4766 this.setDisabled(true);
4771 this.setDisabled(false);
4774 setDisabled : function(state)
4776 if(this.disabled == state){
4780 this.disabled = state;
4783 this.el.addClass('disabled');
4787 this.el.removeClass('disabled');
4792 setActive : function(state)
4794 if(this.active == state){
4798 this.active = state;
4801 this.el.addClass('active');
4805 this.el.removeClass('active');
4810 isActive: function ()
4815 setBadge : function(str)
4821 this.badgeEl.dom.innerHTML = str;
4838 * @class Roo.bootstrap.Row
4839 * @extends Roo.bootstrap.Component
4840 * Bootstrap Row class (contains columns...)
4844 * @param {Object} config The config object
4847 Roo.bootstrap.Row = function(config){
4848 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4851 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4853 getAutoCreate : function(){
4872 * @class Roo.bootstrap.Element
4873 * @extends Roo.bootstrap.Component
4874 * Bootstrap Element class
4875 * @cfg {String} html contents of the element
4876 * @cfg {String} tag tag of the element
4877 * @cfg {String} cls class of the element
4878 * @cfg {Boolean} preventDefault (true|false) default false
4879 * @cfg {Boolean} clickable (true|false) default false
4882 * Create a new Element
4883 * @param {Object} config The config object
4886 Roo.bootstrap.Element = function(config){
4887 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4893 * When a element is chick
4894 * @param {Roo.bootstrap.Element} this
4895 * @param {Roo.EventObject} e
4901 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4906 preventDefault: false,
4909 getAutoCreate : function(){
4913 // cls: this.cls, double assign in parent class Component.js :: onRender
4920 initEvents: function()
4922 Roo.bootstrap.Element.superclass.initEvents.call(this);
4925 this.el.on('click', this.onClick, this);
4930 onClick : function(e)
4932 if(this.preventDefault){
4936 this.fireEvent('click', this, e);
4939 getValue : function()
4941 return this.el.dom.innerHTML;
4944 setValue : function(value)
4946 this.el.dom.innerHTML = value;
4961 * @class Roo.bootstrap.Pagination
4962 * @extends Roo.bootstrap.Component
4963 * Bootstrap Pagination class
4964 * @cfg {String} size xs | sm | md | lg
4965 * @cfg {Boolean} inverse false | true
4968 * Create a new Pagination
4969 * @param {Object} config The config object
4972 Roo.bootstrap.Pagination = function(config){
4973 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4976 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4982 getAutoCreate : function(){
4988 cfg.cls += ' inverse';
4994 cfg.cls += " " + this.cls;
5012 * @class Roo.bootstrap.PaginationItem
5013 * @extends Roo.bootstrap.Component
5014 * Bootstrap PaginationItem class
5015 * @cfg {String} html text
5016 * @cfg {String} href the link
5017 * @cfg {Boolean} preventDefault (true | false) default true
5018 * @cfg {Boolean} active (true | false) default false
5019 * @cfg {Boolean} disabled default false
5023 * Create a new PaginationItem
5024 * @param {Object} config The config object
5028 Roo.bootstrap.PaginationItem = function(config){
5029 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5034 * The raw click event for the entire grid.
5035 * @param {Roo.EventObject} e
5041 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5045 preventDefault: true,
5050 getAutoCreate : function(){
5056 href : this.href ? this.href : '#',
5057 html : this.html ? this.html : ''
5067 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5071 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5077 initEvents: function() {
5079 this.el.on('click', this.onClick, this);
5082 onClick : function(e)
5084 Roo.log('PaginationItem on click ');
5085 if(this.preventDefault){
5093 this.fireEvent('click', this, e);
5109 * @class Roo.bootstrap.Slider
5110 * @extends Roo.bootstrap.Component
5111 * Bootstrap Slider class
5114 * Create a new Slider
5115 * @param {Object} config The config object
5118 Roo.bootstrap.Slider = function(config){
5119 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5122 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5124 getAutoCreate : function(){
5128 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5132 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5144 * Ext JS Library 1.1.1
5145 * Copyright(c) 2006-2007, Ext JS, LLC.
5147 * Originally Released Under LGPL - original licence link has changed is not relivant.
5150 * <script type="text/javascript">
5155 * @class Roo.grid.ColumnModel
5156 * @extends Roo.util.Observable
5157 * This is the default implementation of a ColumnModel used by the Grid. It defines
5158 * the columns in the grid.
5161 var colModel = new Roo.grid.ColumnModel([
5162 {header: "Ticker", width: 60, sortable: true, locked: true},
5163 {header: "Company Name", width: 150, sortable: true},
5164 {header: "Market Cap.", width: 100, sortable: true},
5165 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5166 {header: "Employees", width: 100, sortable: true, resizable: false}
5171 * The config options listed for this class are options which may appear in each
5172 * individual column definition.
5173 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5175 * @param {Object} config An Array of column config objects. See this class's
5176 * config objects for details.
5178 Roo.grid.ColumnModel = function(config){
5180 * The config passed into the constructor
5182 this.config = config;
5185 // if no id, create one
5186 // if the column does not have a dataIndex mapping,
5187 // map it to the order it is in the config
5188 for(var i = 0, len = config.length; i < len; i++){
5190 if(typeof c.dataIndex == "undefined"){
5193 if(typeof c.renderer == "string"){
5194 c.renderer = Roo.util.Format[c.renderer];
5196 if(typeof c.id == "undefined"){
5199 if(c.editor && c.editor.xtype){
5200 c.editor = Roo.factory(c.editor, Roo.grid);
5202 if(c.editor && c.editor.isFormField){
5203 c.editor = new Roo.grid.GridEditor(c.editor);
5205 this.lookup[c.id] = c;
5209 * The width of columns which have no width specified (defaults to 100)
5212 this.defaultWidth = 100;
5215 * Default sortable of columns which have no sortable specified (defaults to false)
5218 this.defaultSortable = false;
5222 * @event widthchange
5223 * Fires when the width of a column changes.
5224 * @param {ColumnModel} this
5225 * @param {Number} columnIndex The column index
5226 * @param {Number} newWidth The new width
5228 "widthchange": true,
5230 * @event headerchange
5231 * Fires when the text of a header changes.
5232 * @param {ColumnModel} this
5233 * @param {Number} columnIndex The column index
5234 * @param {Number} newText The new header text
5236 "headerchange": true,
5238 * @event hiddenchange
5239 * Fires when a column is hidden or "unhidden".
5240 * @param {ColumnModel} this
5241 * @param {Number} columnIndex The column index
5242 * @param {Boolean} hidden true if hidden, false otherwise
5244 "hiddenchange": true,
5246 * @event columnmoved
5247 * Fires when a column is moved.
5248 * @param {ColumnModel} this
5249 * @param {Number} oldIndex
5250 * @param {Number} newIndex
5252 "columnmoved" : true,
5254 * @event columlockchange
5255 * Fires when a column's locked state is changed
5256 * @param {ColumnModel} this
5257 * @param {Number} colIndex
5258 * @param {Boolean} locked true if locked
5260 "columnlockchange" : true
5262 Roo.grid.ColumnModel.superclass.constructor.call(this);
5264 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5266 * @cfg {String} header The header text to display in the Grid view.
5269 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5270 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5271 * specified, the column's index is used as an index into the Record's data Array.
5274 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5275 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5278 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5279 * Defaults to the value of the {@link #defaultSortable} property.
5280 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5283 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5286 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5289 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5292 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5295 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5296 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5297 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5298 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5301 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5304 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5307 * @cfg {String} cursor (Optional)
5310 * @cfg {String} tooltip (Optional)
5313 * @cfg {Number} xs (Optional)
5316 * @cfg {Number} sm (Optional)
5319 * @cfg {Number} md (Optional)
5322 * @cfg {Number} lg (Optional)
5325 * Returns the id of the column at the specified index.
5326 * @param {Number} index The column index
5327 * @return {String} the id
5329 getColumnId : function(index){
5330 return this.config[index].id;
5334 * Returns the column for a specified id.
5335 * @param {String} id The column id
5336 * @return {Object} the column
5338 getColumnById : function(id){
5339 return this.lookup[id];
5344 * Returns the column for a specified dataIndex.
5345 * @param {String} dataIndex The column dataIndex
5346 * @return {Object|Boolean} the column or false if not found
5348 getColumnByDataIndex: function(dataIndex){
5349 var index = this.findColumnIndex(dataIndex);
5350 return index > -1 ? this.config[index] : false;
5354 * Returns the index for a specified column id.
5355 * @param {String} id The column id
5356 * @return {Number} the index, or -1 if not found
5358 getIndexById : function(id){
5359 for(var i = 0, len = this.config.length; i < len; i++){
5360 if(this.config[i].id == id){
5368 * Returns the index for a specified column dataIndex.
5369 * @param {String} dataIndex The column dataIndex
5370 * @return {Number} the index, or -1 if not found
5373 findColumnIndex : function(dataIndex){
5374 for(var i = 0, len = this.config.length; i < len; i++){
5375 if(this.config[i].dataIndex == dataIndex){
5383 moveColumn : function(oldIndex, newIndex){
5384 var c = this.config[oldIndex];
5385 this.config.splice(oldIndex, 1);
5386 this.config.splice(newIndex, 0, c);
5387 this.dataMap = null;
5388 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5391 isLocked : function(colIndex){
5392 return this.config[colIndex].locked === true;
5395 setLocked : function(colIndex, value, suppressEvent){
5396 if(this.isLocked(colIndex) == value){
5399 this.config[colIndex].locked = value;
5401 this.fireEvent("columnlockchange", this, colIndex, value);
5405 getTotalLockedWidth : function(){
5407 for(var i = 0; i < this.config.length; i++){
5408 if(this.isLocked(i) && !this.isHidden(i)){
5409 this.totalWidth += this.getColumnWidth(i);
5415 getLockedCount : function(){
5416 for(var i = 0, len = this.config.length; i < len; i++){
5417 if(!this.isLocked(i)){
5422 return this.config.length;
5426 * Returns the number of columns.
5429 getColumnCount : function(visibleOnly){
5430 if(visibleOnly === true){
5432 for(var i = 0, len = this.config.length; i < len; i++){
5433 if(!this.isHidden(i)){
5439 return this.config.length;
5443 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5444 * @param {Function} fn
5445 * @param {Object} scope (optional)
5446 * @return {Array} result
5448 getColumnsBy : function(fn, scope){
5450 for(var i = 0, len = this.config.length; i < len; i++){
5451 var c = this.config[i];
5452 if(fn.call(scope||this, c, i) === true){
5460 * Returns true if the specified column is sortable.
5461 * @param {Number} col The column index
5464 isSortable : function(col){
5465 if(typeof this.config[col].sortable == "undefined"){
5466 return this.defaultSortable;
5468 return this.config[col].sortable;
5472 * Returns the rendering (formatting) function defined for the column.
5473 * @param {Number} col The column index.
5474 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5476 getRenderer : function(col){
5477 if(!this.config[col].renderer){
5478 return Roo.grid.ColumnModel.defaultRenderer;
5480 return this.config[col].renderer;
5484 * Sets the rendering (formatting) function for a column.
5485 * @param {Number} col The column index
5486 * @param {Function} fn The function to use to process the cell's raw data
5487 * to return HTML markup for the grid view. The render function is called with
5488 * the following parameters:<ul>
5489 * <li>Data value.</li>
5490 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5491 * <li>css A CSS style string to apply to the table cell.</li>
5492 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5493 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5494 * <li>Row index</li>
5495 * <li>Column index</li>
5496 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5498 setRenderer : function(col, fn){
5499 this.config[col].renderer = fn;
5503 * Returns the width for the specified column.
5504 * @param {Number} col The column index
5507 getColumnWidth : function(col){
5508 return this.config[col].width * 1 || this.defaultWidth;
5512 * Sets the width for a column.
5513 * @param {Number} col The column index
5514 * @param {Number} width The new width
5516 setColumnWidth : function(col, width, suppressEvent){
5517 this.config[col].width = width;
5518 this.totalWidth = null;
5520 this.fireEvent("widthchange", this, col, width);
5525 * Returns the total width of all columns.
5526 * @param {Boolean} includeHidden True to include hidden column widths
5529 getTotalWidth : function(includeHidden){
5530 if(!this.totalWidth){
5531 this.totalWidth = 0;
5532 for(var i = 0, len = this.config.length; i < len; i++){
5533 if(includeHidden || !this.isHidden(i)){
5534 this.totalWidth += this.getColumnWidth(i);
5538 return this.totalWidth;
5542 * Returns the header for the specified column.
5543 * @param {Number} col The column index
5546 getColumnHeader : function(col){
5547 return this.config[col].header;
5551 * Sets the header for a column.
5552 * @param {Number} col The column index
5553 * @param {String} header The new header
5555 setColumnHeader : function(col, header){
5556 this.config[col].header = header;
5557 this.fireEvent("headerchange", this, col, header);
5561 * Returns the tooltip for the specified column.
5562 * @param {Number} col The column index
5565 getColumnTooltip : function(col){
5566 return this.config[col].tooltip;
5569 * Sets the tooltip for a column.
5570 * @param {Number} col The column index
5571 * @param {String} tooltip The new tooltip
5573 setColumnTooltip : function(col, tooltip){
5574 this.config[col].tooltip = tooltip;
5578 * Returns the dataIndex for the specified column.
5579 * @param {Number} col The column index
5582 getDataIndex : function(col){
5583 return this.config[col].dataIndex;
5587 * Sets the dataIndex for a column.
5588 * @param {Number} col The column index
5589 * @param {Number} dataIndex The new dataIndex
5591 setDataIndex : function(col, dataIndex){
5592 this.config[col].dataIndex = dataIndex;
5598 * Returns true if the cell is editable.
5599 * @param {Number} colIndex The column index
5600 * @param {Number} rowIndex The row index - this is nto actually used..?
5603 isCellEditable : function(colIndex, rowIndex){
5604 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5608 * Returns the editor defined for the cell/column.
5609 * return false or null to disable editing.
5610 * @param {Number} colIndex The column index
5611 * @param {Number} rowIndex The row index
5614 getCellEditor : function(colIndex, rowIndex){
5615 return this.config[colIndex].editor;
5619 * Sets if a column is editable.
5620 * @param {Number} col The column index
5621 * @param {Boolean} editable True if the column is editable
5623 setEditable : function(col, editable){
5624 this.config[col].editable = editable;
5629 * Returns true if the column is hidden.
5630 * @param {Number} colIndex The column index
5633 isHidden : function(colIndex){
5634 return this.config[colIndex].hidden;
5639 * Returns true if the column width cannot be changed
5641 isFixed : function(colIndex){
5642 return this.config[colIndex].fixed;
5646 * Returns true if the column can be resized
5649 isResizable : function(colIndex){
5650 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5653 * Sets if a column is hidden.
5654 * @param {Number} colIndex The column index
5655 * @param {Boolean} hidden True if the column is hidden
5657 setHidden : function(colIndex, hidden){
5658 this.config[colIndex].hidden = hidden;
5659 this.totalWidth = null;
5660 this.fireEvent("hiddenchange", this, colIndex, hidden);
5664 * Sets the editor for a column.
5665 * @param {Number} col The column index
5666 * @param {Object} editor The editor object
5668 setEditor : function(col, editor){
5669 this.config[col].editor = editor;
5673 Roo.grid.ColumnModel.defaultRenderer = function(value)
5675 if(typeof value == "object") {
5678 if(typeof value == "string" && value.length < 1){
5682 return String.format("{0}", value);
5685 // Alias for backwards compatibility
5686 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5689 * Ext JS Library 1.1.1
5690 * Copyright(c) 2006-2007, Ext JS, LLC.
5692 * Originally Released Under LGPL - original licence link has changed is not relivant.
5695 * <script type="text/javascript">
5699 * @class Roo.LoadMask
5700 * A simple utility class for generically masking elements while loading data. If the element being masked has
5701 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5702 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5703 * element's UpdateManager load indicator and will be destroyed after the initial load.
5705 * Create a new LoadMask
5706 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5707 * @param {Object} config The config object
5709 Roo.LoadMask = function(el, config){
5710 this.el = Roo.get(el);
5711 Roo.apply(this, config);
5713 this.store.on('beforeload', this.onBeforeLoad, this);
5714 this.store.on('load', this.onLoad, this);
5715 this.store.on('loadexception', this.onLoadException, this);
5716 this.removeMask = false;
5718 var um = this.el.getUpdateManager();
5719 um.showLoadIndicator = false; // disable the default indicator
5720 um.on('beforeupdate', this.onBeforeLoad, this);
5721 um.on('update', this.onLoad, this);
5722 um.on('failure', this.onLoad, this);
5723 this.removeMask = true;
5727 Roo.LoadMask.prototype = {
5729 * @cfg {Boolean} removeMask
5730 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5731 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5735 * The text to display in a centered loading message box (defaults to 'Loading...')
5739 * @cfg {String} msgCls
5740 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5742 msgCls : 'x-mask-loading',
5745 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5751 * Disables the mask to prevent it from being displayed
5753 disable : function(){
5754 this.disabled = true;
5758 * Enables the mask so that it can be displayed
5760 enable : function(){
5761 this.disabled = false;
5764 onLoadException : function()
5768 if (typeof(arguments[3]) != 'undefined') {
5769 Roo.MessageBox.alert("Error loading",arguments[3]);
5773 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5774 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5781 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5786 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5790 onBeforeLoad : function(){
5792 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5797 destroy : function(){
5799 this.store.un('beforeload', this.onBeforeLoad, this);
5800 this.store.un('load', this.onLoad, this);
5801 this.store.un('loadexception', this.onLoadException, this);
5803 var um = this.el.getUpdateManager();
5804 um.un('beforeupdate', this.onBeforeLoad, this);
5805 um.un('update', this.onLoad, this);
5806 um.un('failure', this.onLoad, this);
5817 * @class Roo.bootstrap.Table
5818 * @extends Roo.bootstrap.Component
5819 * Bootstrap Table class
5820 * @cfg {String} cls table class
5821 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5822 * @cfg {String} bgcolor Specifies the background color for a table
5823 * @cfg {Number} border Specifies whether the table cells should have borders or not
5824 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5825 * @cfg {Number} cellspacing Specifies the space between cells
5826 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5827 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5828 * @cfg {String} sortable Specifies that the table should be sortable
5829 * @cfg {String} summary Specifies a summary of the content of a table
5830 * @cfg {Number} width Specifies the width of a table
5831 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5833 * @cfg {boolean} striped Should the rows be alternative striped
5834 * @cfg {boolean} bordered Add borders to the table
5835 * @cfg {boolean} hover Add hover highlighting
5836 * @cfg {boolean} condensed Format condensed
5837 * @cfg {boolean} responsive Format condensed
5838 * @cfg {Boolean} loadMask (true|false) default false
5839 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5840 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5841 * @cfg {Boolean} rowSelection (true|false) default false
5842 * @cfg {Boolean} cellSelection (true|false) default false
5843 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5844 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5845 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5849 * Create a new Table
5850 * @param {Object} config The config object
5853 Roo.bootstrap.Table = function(config){
5854 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5859 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5860 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5861 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5862 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5864 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5866 this.sm.grid = this;
5867 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5868 this.sm = this.selModel;
5869 this.sm.xmodule = this.xmodule || false;
5872 if (this.cm && typeof(this.cm.config) == 'undefined') {
5873 this.colModel = new Roo.grid.ColumnModel(this.cm);
5874 this.cm = this.colModel;
5875 this.cm.xmodule = this.xmodule || false;
5878 this.store= Roo.factory(this.store, Roo.data);
5879 this.ds = this.store;
5880 this.ds.xmodule = this.xmodule || false;
5883 if (this.footer && this.store) {
5884 this.footer.dataSource = this.ds;
5885 this.footer = Roo.factory(this.footer);
5892 * Fires when a cell is clicked
5893 * @param {Roo.bootstrap.Table} this
5894 * @param {Roo.Element} el
5895 * @param {Number} rowIndex
5896 * @param {Number} columnIndex
5897 * @param {Roo.EventObject} e
5901 * @event celldblclick
5902 * Fires when a cell is double clicked
5903 * @param {Roo.bootstrap.Table} this
5904 * @param {Roo.Element} el
5905 * @param {Number} rowIndex
5906 * @param {Number} columnIndex
5907 * @param {Roo.EventObject} e
5909 "celldblclick" : true,
5912 * Fires when a row is clicked
5913 * @param {Roo.bootstrap.Table} this
5914 * @param {Roo.Element} el
5915 * @param {Number} rowIndex
5916 * @param {Roo.EventObject} e
5920 * @event rowdblclick
5921 * Fires when a row is double clicked
5922 * @param {Roo.bootstrap.Table} this
5923 * @param {Roo.Element} el
5924 * @param {Number} rowIndex
5925 * @param {Roo.EventObject} e
5927 "rowdblclick" : true,
5930 * Fires when a mouseover occur
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Number} columnIndex
5935 * @param {Roo.EventObject} e
5940 * Fires when a mouseout occur
5941 * @param {Roo.bootstrap.Table} this
5942 * @param {Roo.Element} el
5943 * @param {Number} rowIndex
5944 * @param {Number} columnIndex
5945 * @param {Roo.EventObject} e
5950 * Fires when a row is rendered, so you can change add a style to it.
5951 * @param {Roo.bootstrap.Table} this
5952 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5956 * @event rowsrendered
5957 * Fires when all the rows have been rendered
5958 * @param {Roo.bootstrap.Table} this
5960 'rowsrendered' : true,
5962 * @event contextmenu
5963 * The raw contextmenu event for the entire grid.
5964 * @param {Roo.EventObject} e
5966 "contextmenu" : true,
5968 * @event rowcontextmenu
5969 * Fires when a row is right clicked
5970 * @param {Roo.bootstrap.Table} this
5971 * @param {Number} rowIndex
5972 * @param {Roo.EventObject} e
5974 "rowcontextmenu" : true,
5976 * @event cellcontextmenu
5977 * Fires when a cell is right clicked
5978 * @param {Roo.bootstrap.Table} this
5979 * @param {Number} rowIndex
5980 * @param {Number} cellIndex
5981 * @param {Roo.EventObject} e
5983 "cellcontextmenu" : true,
5985 * @event headercontextmenu
5986 * Fires when a header is right clicked
5987 * @param {Roo.bootstrap.Table} this
5988 * @param {Number} columnIndex
5989 * @param {Roo.EventObject} e
5991 "headercontextmenu" : true
5995 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6021 rowSelection : false,
6022 cellSelection : false,
6025 // Roo.Element - the tbody
6027 // Roo.Element - thead element
6030 container: false, // used by gridpanel...
6034 getAutoCreate : function()
6036 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6043 if (this.scrollBody) {
6044 cfg.cls += ' table-body-fixed';
6047 cfg.cls += ' table-striped';
6051 cfg.cls += ' table-hover';
6053 if (this.bordered) {
6054 cfg.cls += ' table-bordered';
6056 if (this.condensed) {
6057 cfg.cls += ' table-condensed';
6059 if (this.responsive) {
6060 cfg.cls += ' table-responsive';
6064 cfg.cls+= ' ' +this.cls;
6067 // this lot should be simplifed...
6070 cfg.align=this.align;
6073 cfg.bgcolor=this.bgcolor;
6076 cfg.border=this.border;
6078 if (this.cellpadding) {
6079 cfg.cellpadding=this.cellpadding;
6081 if (this.cellspacing) {
6082 cfg.cellspacing=this.cellspacing;
6085 cfg.frame=this.frame;
6088 cfg.rules=this.rules;
6090 if (this.sortable) {
6091 cfg.sortable=this.sortable;
6094 cfg.summary=this.summary;
6097 cfg.width=this.width;
6100 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6103 if(this.store || this.cm){
6104 if(this.headerShow){
6105 cfg.cn.push(this.renderHeader());
6108 cfg.cn.push(this.renderBody());
6110 if(this.footerShow){
6111 cfg.cn.push(this.renderFooter());
6113 // where does this come from?
6114 //cfg.cls+= ' TableGrid';
6117 return { cn : [ cfg ] };
6120 initEvents : function()
6122 if(!this.store || !this.cm){
6125 if (this.selModel) {
6126 this.selModel.initEvents();
6130 //Roo.log('initEvents with ds!!!!');
6132 this.mainBody = this.el.select('tbody', true).first();
6133 this.mainHead = this.el.select('thead', true).first();
6140 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6141 e.on('click', _this.sort, _this);
6144 this.mainBody.on("click", this.onClick, this);
6145 this.mainBody.on("dblclick", this.onDblClick, this);
6147 // why is this done????? = it breaks dialogs??
6148 //this.parent().el.setStyle('position', 'relative');
6152 this.footer.parentId = this.id;
6153 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6156 this.el.select('tfoot tr td').first().addClass('hide');
6160 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6162 this.store.on('load', this.onLoad, this);
6163 this.store.on('beforeload', this.onBeforeLoad, this);
6164 this.store.on('update', this.onUpdate, this);
6165 this.store.on('add', this.onAdd, this);
6166 this.store.on("clear", this.clear, this);
6168 this.el.on("contextmenu", this.onContextMenu, this);
6170 this.mainBody.on('scroll', this.onBodyScroll, this);
6172 this.cm.on("headerchange", this.onHeaderChange, this);
6176 onContextMenu : function(e, t)
6178 this.processEvent("contextmenu", e);
6181 processEvent : function(name, e)
6183 if (name != 'touchstart' ) {
6184 this.fireEvent(name, e);
6187 var t = e.getTarget();
6189 var cell = Roo.get(t);
6195 if(cell.findParent('tfoot', false, true)){
6199 if(cell.findParent('thead', false, true)){
6201 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6202 cell = Roo.get(t).findParent('th', false, true);
6204 Roo.log("failed to find th in thead?");
6205 Roo.log(e.getTarget());
6210 var cellIndex = cell.dom.cellIndex;
6212 var ename = name == 'touchstart' ? 'click' : name;
6213 this.fireEvent("header" + ename, this, cellIndex, e);
6218 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6219 cell = Roo.get(t).findParent('td', false, true);
6221 Roo.log("failed to find th in tbody?");
6222 Roo.log(e.getTarget());
6227 var row = cell.findParent('tr', false, true);
6228 var cellIndex = cell.dom.cellIndex;
6229 var rowIndex = row.dom.rowIndex - 1;
6233 this.fireEvent("row" + name, this, rowIndex, e);
6237 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6243 onMouseover : function(e, el)
6245 var cell = Roo.get(el);
6251 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6252 cell = cell.findParent('td', false, true);
6255 var row = cell.findParent('tr', false, true);
6256 var cellIndex = cell.dom.cellIndex;
6257 var rowIndex = row.dom.rowIndex - 1; // start from 0
6259 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6263 onMouseout : function(e, el)
6265 var cell = Roo.get(el);
6271 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6272 cell = cell.findParent('td', false, true);
6275 var row = cell.findParent('tr', false, true);
6276 var cellIndex = cell.dom.cellIndex;
6277 var rowIndex = row.dom.rowIndex - 1; // start from 0
6279 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6283 onClick : function(e, el)
6285 var cell = Roo.get(el);
6287 if(!cell || (!this.cellSelection && !this.rowSelection)){
6291 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6292 cell = cell.findParent('td', false, true);
6295 if(!cell || typeof(cell) == 'undefined'){
6299 var row = cell.findParent('tr', false, true);
6301 if(!row || typeof(row) == 'undefined'){
6305 var cellIndex = cell.dom.cellIndex;
6306 var rowIndex = this.getRowIndex(row);
6308 // why??? - should these not be based on SelectionModel?
6309 if(this.cellSelection){
6310 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6313 if(this.rowSelection){
6314 this.fireEvent('rowclick', this, row, rowIndex, e);
6320 onDblClick : function(e,el)
6322 var cell = Roo.get(el);
6324 if(!cell || (!this.cellSelection && !this.rowSelection)){
6328 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6329 cell = cell.findParent('td', false, true);
6332 if(!cell || typeof(cell) == 'undefined'){
6336 var row = cell.findParent('tr', false, true);
6338 if(!row || typeof(row) == 'undefined'){
6342 var cellIndex = cell.dom.cellIndex;
6343 var rowIndex = this.getRowIndex(row);
6345 if(this.cellSelection){
6346 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6349 if(this.rowSelection){
6350 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6354 sort : function(e,el)
6356 var col = Roo.get(el);
6358 if(!col.hasClass('sortable')){
6362 var sort = col.attr('sort');
6365 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6369 this.store.sortInfo = {field : sort, direction : dir};
6372 Roo.log("calling footer first");
6373 this.footer.onClick('first');
6376 this.store.load({ params : { start : 0 } });
6380 renderHeader : function()
6388 this.totalWidth = 0;
6390 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6392 var config = cm.config[i];
6397 html: cm.getColumnHeader(i)
6402 if(typeof(config.sortable) != 'undefined' && config.sortable){
6404 c.html = '<i class="glyphicon"></i>' + c.html;
6407 if(typeof(config.lgHeader) != 'undefined'){
6408 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6411 if(typeof(config.mdHeader) != 'undefined'){
6412 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6415 if(typeof(config.smHeader) != 'undefined'){
6416 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6419 if(typeof(config.xsHeader) != 'undefined'){
6420 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6427 if(typeof(config.tooltip) != 'undefined'){
6428 c.tooltip = config.tooltip;
6431 if(typeof(config.colspan) != 'undefined'){
6432 c.colspan = config.colspan;
6435 if(typeof(config.hidden) != 'undefined' && config.hidden){
6436 c.style += ' display:none;';
6439 if(typeof(config.dataIndex) != 'undefined'){
6440 c.sort = config.dataIndex;
6445 if(typeof(config.align) != 'undefined' && config.align.length){
6446 c.style += ' text-align:' + config.align + ';';
6449 if(typeof(config.width) != 'undefined'){
6450 c.style += ' width:' + config.width + 'px;';
6451 this.totalWidth += config.width;
6453 this.totalWidth += 100; // assume minimum of 100 per column?
6456 if(typeof(config.cls) != 'undefined'){
6457 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6460 ['xs','sm','md','lg'].map(function(size){
6462 if(typeof(config[size]) == 'undefined'){
6466 if (!config[size]) { // 0 = hidden
6467 c.cls += ' hidden-' + size;
6471 c.cls += ' col-' + size + '-' + config[size];
6481 renderBody : function()
6491 colspan : this.cm.getColumnCount()
6501 renderFooter : function()
6511 colspan : this.cm.getColumnCount()
6525 // Roo.log('ds onload');
6530 var ds = this.store;
6532 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6533 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6534 if (_this.store.sortInfo) {
6536 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6537 e.select('i', true).addClass(['glyphicon-arrow-up']);
6540 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6541 e.select('i', true).addClass(['glyphicon-arrow-down']);
6546 var tbody = this.mainBody;
6548 if(ds.getCount() > 0){
6549 ds.data.each(function(d,rowIndex){
6550 var row = this.renderRow(cm, ds, rowIndex);
6552 tbody.createChild(row);
6556 if(row.cellObjects.length){
6557 Roo.each(row.cellObjects, function(r){
6558 _this.renderCellObject(r);
6565 Roo.each(this.el.select('tbody td', true).elements, function(e){
6566 e.on('mouseover', _this.onMouseover, _this);
6569 Roo.each(this.el.select('tbody td', true).elements, function(e){
6570 e.on('mouseout', _this.onMouseout, _this);
6572 this.fireEvent('rowsrendered', this);
6573 //if(this.loadMask){
6574 // this.maskEl.hide();
6581 onUpdate : function(ds,record)
6583 this.refreshRow(record);
6587 onRemove : function(ds, record, index, isUpdate){
6588 if(isUpdate !== true){
6589 this.fireEvent("beforerowremoved", this, index, record);
6591 var bt = this.mainBody.dom;
6593 var rows = this.el.select('tbody > tr', true).elements;
6595 if(typeof(rows[index]) != 'undefined'){
6596 bt.removeChild(rows[index].dom);
6599 // if(bt.rows[index]){
6600 // bt.removeChild(bt.rows[index]);
6603 if(isUpdate !== true){
6604 //this.stripeRows(index);
6605 //this.syncRowHeights(index, index);
6607 this.fireEvent("rowremoved", this, index, record);
6611 onAdd : function(ds, records, rowIndex)
6613 //Roo.log('on Add called');
6614 // - note this does not handle multiple adding very well..
6615 var bt = this.mainBody.dom;
6616 for (var i =0 ; i < records.length;i++) {
6617 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6618 //Roo.log(records[i]);
6619 //Roo.log(this.store.getAt(rowIndex+i));
6620 this.insertRow(this.store, rowIndex + i, false);
6627 refreshRow : function(record){
6628 var ds = this.store, index;
6629 if(typeof record == 'number'){
6631 record = ds.getAt(index);
6633 index = ds.indexOf(record);
6635 this.insertRow(ds, index, true);
6637 this.onRemove(ds, record, index+1, true);
6639 //this.syncRowHeights(index, index);
6641 this.fireEvent("rowupdated", this, index, record);
6644 insertRow : function(dm, rowIndex, isUpdate){
6647 this.fireEvent("beforerowsinserted", this, rowIndex);
6649 //var s = this.getScrollState();
6650 var row = this.renderRow(this.cm, this.store, rowIndex);
6651 // insert before rowIndex..
6652 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6656 if(row.cellObjects.length){
6657 Roo.each(row.cellObjects, function(r){
6658 _this.renderCellObject(r);
6663 this.fireEvent("rowsinserted", this, rowIndex);
6664 //this.syncRowHeights(firstRow, lastRow);
6665 //this.stripeRows(firstRow);
6672 getRowDom : function(rowIndex)
6674 var rows = this.el.select('tbody > tr', true).elements;
6676 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6679 // returns the object tree for a tr..
6682 renderRow : function(cm, ds, rowIndex)
6685 var d = ds.getAt(rowIndex);
6692 var cellObjects = [];
6694 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6695 var config = cm.config[i];
6697 var renderer = cm.getRenderer(i);
6701 if(typeof(renderer) !== 'undefined'){
6702 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6704 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6705 // and are rendered into the cells after the row is rendered - using the id for the element.
6707 if(typeof(value) === 'object'){
6717 rowIndex : rowIndex,
6722 this.fireEvent('rowclass', this, rowcfg);
6726 cls : rowcfg.rowClass,
6728 html: (typeof(value) === 'object') ? '' : value
6735 if(typeof(config.colspan) != 'undefined'){
6736 td.colspan = config.colspan;
6739 if(typeof(config.hidden) != 'undefined' && config.hidden){
6740 td.style += ' display:none;';
6743 if(typeof(config.align) != 'undefined' && config.align.length){
6744 td.style += ' text-align:' + config.align + ';';
6747 if(typeof(config.width) != 'undefined'){
6748 td.style += ' width:' + config.width + 'px;';
6751 if(typeof(config.cursor) != 'undefined'){
6752 td.style += ' cursor:' + config.cursor + ';';
6755 if(typeof(config.cls) != 'undefined'){
6756 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6759 ['xs','sm','md','lg'].map(function(size){
6761 if(typeof(config[size]) == 'undefined'){
6765 if (!config[size]) { // 0 = hidden
6766 td.cls += ' hidden-' + size;
6770 td.cls += ' col-' + size + '-' + config[size];
6778 row.cellObjects = cellObjects;
6786 onBeforeLoad : function()
6788 //Roo.log('ds onBeforeLoad');
6792 //if(this.loadMask){
6793 // this.maskEl.show();
6801 this.el.select('tbody', true).first().dom.innerHTML = '';
6804 * Show or hide a row.
6805 * @param {Number} rowIndex to show or hide
6806 * @param {Boolean} state hide
6808 setRowVisibility : function(rowIndex, state)
6810 var bt = this.mainBody.dom;
6812 var rows = this.el.select('tbody > tr', true).elements;
6814 if(typeof(rows[rowIndex]) == 'undefined'){
6817 rows[rowIndex].dom.style.display = state ? '' : 'none';
6821 getSelectionModel : function(){
6823 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6825 return this.selModel;
6828 * Render the Roo.bootstrap object from renderder
6830 renderCellObject : function(r)
6834 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6836 var t = r.cfg.render(r.container);
6839 Roo.each(r.cfg.cn, function(c){
6841 container: t.getChildContainer(),
6844 _this.renderCellObject(child);
6849 getRowIndex : function(row)
6853 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6864 * Returns the grid's underlying element = used by panel.Grid
6865 * @return {Element} The element
6867 getGridEl : function(){
6871 * Forces a resize - used by panel.Grid
6872 * @return {Element} The element
6874 autoSize : function()
6876 //var ctr = Roo.get(this.container.dom.parentElement);
6877 var ctr = Roo.get(this.el.dom);
6879 var thd = this.getGridEl().select('thead',true).first();
6880 var tbd = this.getGridEl().select('tbody', true).first();
6881 var tfd = this.getGridEl().select('tfoot', true).first();
6883 var cw = ctr.getWidth();
6887 tbd.setSize(ctr.getWidth(),
6888 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6890 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6893 cw = Math.max(cw, this.totalWidth);
6894 this.getGridEl().select('tr',true).setWidth(cw);
6895 // resize 'expandable coloumn?
6897 return; // we doe not have a view in this design..
6900 onBodyScroll: function()
6902 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6904 this.mainHead.setStyle({
6905 'position' : 'relative',
6906 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6912 var scrollHeight = this.mainBody.dom.scrollHeight;
6914 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6916 var height = this.mainBody.getHeight();
6918 if(scrollHeight - height == scrollTop) {
6920 var total = this.ds.getTotalCount();
6922 if(this.footer.cursor + this.footer.pageSize < total){
6924 this.footer.ds.load({
6926 start : this.footer.cursor + this.footer.pageSize,
6927 limit : this.footer.pageSize
6937 onHeaderChange : function()
6940 var header = this.renderHeader();
6941 var table = this.el.select('table', true).first();
6943 this.mainHead.remove();
6944 this.mainHead = table.createChild(header, this.mainBody, false);
6959 * @class Roo.bootstrap.TableCell
6960 * @extends Roo.bootstrap.Component
6961 * Bootstrap TableCell class
6962 * @cfg {String} html cell contain text
6963 * @cfg {String} cls cell class
6964 * @cfg {String} tag cell tag (td|th) default td
6965 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6966 * @cfg {String} align Aligns the content in a cell
6967 * @cfg {String} axis Categorizes cells
6968 * @cfg {String} bgcolor Specifies the background color of a cell
6969 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6970 * @cfg {Number} colspan Specifies the number of columns a cell should span
6971 * @cfg {String} headers Specifies one or more header cells a cell is related to
6972 * @cfg {Number} height Sets the height of a cell
6973 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6974 * @cfg {Number} rowspan Sets the number of rows a cell should span
6975 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6976 * @cfg {String} valign Vertical aligns the content in a cell
6977 * @cfg {Number} width Specifies the width of a cell
6980 * Create a new TableCell
6981 * @param {Object} config The config object
6984 Roo.bootstrap.TableCell = function(config){
6985 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6988 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7008 getAutoCreate : function(){
7009 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7029 cfg.align=this.align
7035 cfg.bgcolor=this.bgcolor
7038 cfg.charoff=this.charoff
7041 cfg.colspan=this.colspan
7044 cfg.headers=this.headers
7047 cfg.height=this.height
7050 cfg.nowrap=this.nowrap
7053 cfg.rowspan=this.rowspan
7056 cfg.scope=this.scope
7059 cfg.valign=this.valign
7062 cfg.width=this.width
7081 * @class Roo.bootstrap.TableRow
7082 * @extends Roo.bootstrap.Component
7083 * Bootstrap TableRow class
7084 * @cfg {String} cls row class
7085 * @cfg {String} align Aligns the content in a table row
7086 * @cfg {String} bgcolor Specifies a background color for a table row
7087 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7088 * @cfg {String} valign Vertical aligns the content in a table row
7091 * Create a new TableRow
7092 * @param {Object} config The config object
7095 Roo.bootstrap.TableRow = function(config){
7096 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7099 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7107 getAutoCreate : function(){
7108 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7118 cfg.align = this.align;
7121 cfg.bgcolor = this.bgcolor;
7124 cfg.charoff = this.charoff;
7127 cfg.valign = this.valign;
7145 * @class Roo.bootstrap.TableBody
7146 * @extends Roo.bootstrap.Component
7147 * Bootstrap TableBody class
7148 * @cfg {String} cls element class
7149 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7150 * @cfg {String} align Aligns the content inside the element
7151 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7152 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7155 * Create a new TableBody
7156 * @param {Object} config The config object
7159 Roo.bootstrap.TableBody = function(config){
7160 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7163 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7171 getAutoCreate : function(){
7172 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7186 cfg.align = this.align;
7189 cfg.charoff = this.charoff;
7192 cfg.valign = this.valign;
7199 // initEvents : function()
7206 // this.store = Roo.factory(this.store, Roo.data);
7207 // this.store.on('load', this.onLoad, this);
7209 // this.store.load();
7213 // onLoad: function ()
7215 // this.fireEvent('load', this);
7225 * Ext JS Library 1.1.1
7226 * Copyright(c) 2006-2007, Ext JS, LLC.
7228 * Originally Released Under LGPL - original licence link has changed is not relivant.
7231 * <script type="text/javascript">
7234 // as we use this in bootstrap.
7235 Roo.namespace('Roo.form');
7237 * @class Roo.form.Action
7238 * Internal Class used to handle form actions
7240 * @param {Roo.form.BasicForm} el The form element or its id
7241 * @param {Object} config Configuration options
7246 // define the action interface
7247 Roo.form.Action = function(form, options){
7249 this.options = options || {};
7252 * Client Validation Failed
7255 Roo.form.Action.CLIENT_INVALID = 'client';
7257 * Server Validation Failed
7260 Roo.form.Action.SERVER_INVALID = 'server';
7262 * Connect to Server Failed
7265 Roo.form.Action.CONNECT_FAILURE = 'connect';
7267 * Reading Data from Server Failed
7270 Roo.form.Action.LOAD_FAILURE = 'load';
7272 Roo.form.Action.prototype = {
7274 failureType : undefined,
7275 response : undefined,
7279 run : function(options){
7284 success : function(response){
7289 handleResponse : function(response){
7293 // default connection failure
7294 failure : function(response){
7296 this.response = response;
7297 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7298 this.form.afterAction(this, false);
7301 processResponse : function(response){
7302 this.response = response;
7303 if(!response.responseText){
7306 this.result = this.handleResponse(response);
7310 // utility functions used internally
7311 getUrl : function(appendParams){
7312 var url = this.options.url || this.form.url || this.form.el.dom.action;
7314 var p = this.getParams();
7316 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7322 getMethod : function(){
7323 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7326 getParams : function(){
7327 var bp = this.form.baseParams;
7328 var p = this.options.params;
7330 if(typeof p == "object"){
7331 p = Roo.urlEncode(Roo.applyIf(p, bp));
7332 }else if(typeof p == 'string' && bp){
7333 p += '&' + Roo.urlEncode(bp);
7336 p = Roo.urlEncode(bp);
7341 createCallback : function(){
7343 success: this.success,
7344 failure: this.failure,
7346 timeout: (this.form.timeout*1000),
7347 upload: this.form.fileUpload ? this.success : undefined
7352 Roo.form.Action.Submit = function(form, options){
7353 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7356 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7359 haveProgress : false,
7360 uploadComplete : false,
7362 // uploadProgress indicator.
7363 uploadProgress : function()
7365 if (!this.form.progressUrl) {
7369 if (!this.haveProgress) {
7370 Roo.MessageBox.progress("Uploading", "Uploading");
7372 if (this.uploadComplete) {
7373 Roo.MessageBox.hide();
7377 this.haveProgress = true;
7379 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7381 var c = new Roo.data.Connection();
7383 url : this.form.progressUrl,
7388 success : function(req){
7389 //console.log(data);
7393 rdata = Roo.decode(req.responseText)
7395 Roo.log("Invalid data from server..");
7399 if (!rdata || !rdata.success) {
7401 Roo.MessageBox.alert(Roo.encode(rdata));
7404 var data = rdata.data;
7406 if (this.uploadComplete) {
7407 Roo.MessageBox.hide();
7412 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7413 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7416 this.uploadProgress.defer(2000,this);
7419 failure: function(data) {
7420 Roo.log('progress url failed ');
7431 // run get Values on the form, so it syncs any secondary forms.
7432 this.form.getValues();
7434 var o = this.options;
7435 var method = this.getMethod();
7436 var isPost = method == 'POST';
7437 if(o.clientValidation === false || this.form.isValid()){
7439 if (this.form.progressUrl) {
7440 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7441 (new Date() * 1) + '' + Math.random());
7446 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7447 form:this.form.el.dom,
7448 url:this.getUrl(!isPost),
7450 params:isPost ? this.getParams() : null,
7451 isUpload: this.form.fileUpload
7454 this.uploadProgress();
7456 }else if (o.clientValidation !== false){ // client validation failed
7457 this.failureType = Roo.form.Action.CLIENT_INVALID;
7458 this.form.afterAction(this, false);
7462 success : function(response)
7464 this.uploadComplete= true;
7465 if (this.haveProgress) {
7466 Roo.MessageBox.hide();
7470 var result = this.processResponse(response);
7471 if(result === true || result.success){
7472 this.form.afterAction(this, true);
7476 this.form.markInvalid(result.errors);
7477 this.failureType = Roo.form.Action.SERVER_INVALID;
7479 this.form.afterAction(this, false);
7481 failure : function(response)
7483 this.uploadComplete= true;
7484 if (this.haveProgress) {
7485 Roo.MessageBox.hide();
7488 this.response = response;
7489 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7490 this.form.afterAction(this, false);
7493 handleResponse : function(response){
7494 if(this.form.errorReader){
7495 var rs = this.form.errorReader.read(response);
7498 for(var i = 0, len = rs.records.length; i < len; i++) {
7499 var r = rs.records[i];
7503 if(errors.length < 1){
7507 success : rs.success,
7513 ret = Roo.decode(response.responseText);
7517 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7527 Roo.form.Action.Load = function(form, options){
7528 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7529 this.reader = this.form.reader;
7532 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7537 Roo.Ajax.request(Roo.apply(
7538 this.createCallback(), {
7539 method:this.getMethod(),
7540 url:this.getUrl(false),
7541 params:this.getParams()
7545 success : function(response){
7547 var result = this.processResponse(response);
7548 if(result === true || !result.success || !result.data){
7549 this.failureType = Roo.form.Action.LOAD_FAILURE;
7550 this.form.afterAction(this, false);
7553 this.form.clearInvalid();
7554 this.form.setValues(result.data);
7555 this.form.afterAction(this, true);
7558 handleResponse : function(response){
7559 if(this.form.reader){
7560 var rs = this.form.reader.read(response);
7561 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7563 success : rs.success,
7567 return Roo.decode(response.responseText);
7571 Roo.form.Action.ACTION_TYPES = {
7572 'load' : Roo.form.Action.Load,
7573 'submit' : Roo.form.Action.Submit
7582 * @class Roo.bootstrap.Form
7583 * @extends Roo.bootstrap.Component
7584 * Bootstrap Form class
7585 * @cfg {String} method GET | POST (default POST)
7586 * @cfg {String} labelAlign top | left (default top)
7587 * @cfg {String} align left | right - for navbars
7588 * @cfg {Boolean} loadMask load mask when submit (default true)
7593 * @param {Object} config The config object
7597 Roo.bootstrap.Form = function(config){
7599 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7601 Roo.bootstrap.Form.popover.apply();
7605 * @event clientvalidation
7606 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7607 * @param {Form} this
7608 * @param {Boolean} valid true if the form has passed client-side validation
7610 clientvalidation: true,
7612 * @event beforeaction
7613 * Fires before any action is performed. Return false to cancel the action.
7614 * @param {Form} this
7615 * @param {Action} action The action to be performed
7619 * @event actionfailed
7620 * Fires when an action fails.
7621 * @param {Form} this
7622 * @param {Action} action The action that failed
7624 actionfailed : true,
7626 * @event actioncomplete
7627 * Fires when an action is completed.
7628 * @param {Form} this
7629 * @param {Action} action The action that completed
7631 actioncomplete : true
7635 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7638 * @cfg {String} method
7639 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7644 * The URL to use for form actions if one isn't supplied in the action options.
7647 * @cfg {Boolean} fileUpload
7648 * Set to true if this form is a file upload.
7652 * @cfg {Object} baseParams
7653 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7657 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7661 * @cfg {Sting} align (left|right) for navbar forms
7666 activeAction : null,
7669 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7670 * element by passing it or its id or mask the form itself by passing in true.
7673 waitMsgTarget : false,
7678 * @cfg {Boolean} errorMask (true|false) default false
7683 * @cfg {Number} maskOffset Default 100
7688 * @cfg {Boolean} maskBody
7692 getAutoCreate : function(){
7696 method : this.method || 'POST',
7697 id : this.id || Roo.id(),
7700 if (this.parent().xtype.match(/^Nav/)) {
7701 cfg.cls = 'navbar-form navbar-' + this.align;
7705 if (this.labelAlign == 'left' ) {
7706 cfg.cls += ' form-horizontal';
7712 initEvents : function()
7714 this.el.on('submit', this.onSubmit, this);
7715 // this was added as random key presses on the form where triggering form submit.
7716 this.el.on('keypress', function(e) {
7717 if (e.getCharCode() != 13) {
7720 // we might need to allow it for textareas.. and some other items.
7721 // check e.getTarget().
7723 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7727 Roo.log("keypress blocked");
7735 onSubmit : function(e){
7740 * Returns true if client-side validation on the form is successful.
7743 isValid : function(){
7744 var items = this.getItems();
7748 items.each(function(f){
7754 if(!target && f.el.isVisible(true)){
7760 if(this.errorMask && !valid){
7761 Roo.bootstrap.Form.popover.mask(this, target);
7768 * Returns true if any fields in this form have changed since their original load.
7771 isDirty : function(){
7773 var items = this.getItems();
7774 items.each(function(f){
7784 * Performs a predefined action (submit or load) or custom actions you define on this form.
7785 * @param {String} actionName The name of the action type
7786 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7787 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7788 * accept other config options):
7790 Property Type Description
7791 ---------------- --------------- ----------------------------------------------------------------------------------
7792 url String The url for the action (defaults to the form's url)
7793 method String The form method to use (defaults to the form's method, or POST if not defined)
7794 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7795 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7796 validate the form on the client (defaults to false)
7798 * @return {BasicForm} this
7800 doAction : function(action, options){
7801 if(typeof action == 'string'){
7802 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7804 if(this.fireEvent('beforeaction', this, action) !== false){
7805 this.beforeAction(action);
7806 action.run.defer(100, action);
7812 beforeAction : function(action){
7813 var o = action.options;
7818 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7820 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7823 // not really supported yet.. ??
7825 //if(this.waitMsgTarget === true){
7826 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7827 //}else if(this.waitMsgTarget){
7828 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7829 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7831 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7837 afterAction : function(action, success){
7838 this.activeAction = null;
7839 var o = action.options;
7844 Roo.get(document.body).unmask();
7850 //if(this.waitMsgTarget === true){
7851 // this.el.unmask();
7852 //}else if(this.waitMsgTarget){
7853 // this.waitMsgTarget.unmask();
7855 // Roo.MessageBox.updateProgress(1);
7856 // Roo.MessageBox.hide();
7863 Roo.callback(o.success, o.scope, [this, action]);
7864 this.fireEvent('actioncomplete', this, action);
7868 // failure condition..
7869 // we have a scenario where updates need confirming.
7870 // eg. if a locking scenario exists..
7871 // we look for { errors : { needs_confirm : true }} in the response.
7873 (typeof(action.result) != 'undefined') &&
7874 (typeof(action.result.errors) != 'undefined') &&
7875 (typeof(action.result.errors.needs_confirm) != 'undefined')
7878 Roo.log("not supported yet");
7881 Roo.MessageBox.confirm(
7882 "Change requires confirmation",
7883 action.result.errorMsg,
7888 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7898 Roo.callback(o.failure, o.scope, [this, action]);
7899 // show an error message if no failed handler is set..
7900 if (!this.hasListener('actionfailed')) {
7901 Roo.log("need to add dialog support");
7903 Roo.MessageBox.alert("Error",
7904 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7905 action.result.errorMsg :
7906 "Saving Failed, please check your entries or try again"
7911 this.fireEvent('actionfailed', this, action);
7916 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7917 * @param {String} id The value to search for
7920 findField : function(id){
7921 var items = this.getItems();
7922 var field = items.get(id);
7924 items.each(function(f){
7925 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7932 return field || null;
7935 * Mark fields in this form invalid in bulk.
7936 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7937 * @return {BasicForm} this
7939 markInvalid : function(errors){
7940 if(errors instanceof Array){
7941 for(var i = 0, len = errors.length; i < len; i++){
7942 var fieldError = errors[i];
7943 var f = this.findField(fieldError.id);
7945 f.markInvalid(fieldError.msg);
7951 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7952 field.markInvalid(errors[id]);
7956 //Roo.each(this.childForms || [], function (f) {
7957 // f.markInvalid(errors);
7964 * Set values for fields in this form in bulk.
7965 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7966 * @return {BasicForm} this
7968 setValues : function(values){
7969 if(values instanceof Array){ // array of objects
7970 for(var i = 0, len = values.length; i < len; i++){
7972 var f = this.findField(v.id);
7974 f.setValue(v.value);
7975 if(this.trackResetOnLoad){
7976 f.originalValue = f.getValue();
7980 }else{ // object hash
7983 if(typeof values[id] != 'function' && (field = this.findField(id))){
7985 if (field.setFromData &&
7987 field.displayField &&
7988 // combos' with local stores can
7989 // be queried via setValue()
7990 // to set their value..
7991 (field.store && !field.store.isLocal)
7995 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7996 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7997 field.setFromData(sd);
7999 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8001 field.setFromData(values);
8004 field.setValue(values[id]);
8008 if(this.trackResetOnLoad){
8009 field.originalValue = field.getValue();
8015 //Roo.each(this.childForms || [], function (f) {
8016 // f.setValues(values);
8023 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8024 * they are returned as an array.
8025 * @param {Boolean} asString
8028 getValues : function(asString){
8029 //if (this.childForms) {
8030 // copy values from the child forms
8031 // Roo.each(this.childForms, function (f) {
8032 // this.setValues(f.getValues());
8038 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8039 if(asString === true){
8042 return Roo.urlDecode(fs);
8046 * Returns the fields in this form as an object with key/value pairs.
8047 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8050 getFieldValues : function(with_hidden)
8052 var items = this.getItems();
8054 items.each(function(f){
8060 var v = f.getValue();
8062 if (f.inputType =='radio') {
8063 if (typeof(ret[f.getName()]) == 'undefined') {
8064 ret[f.getName()] = ''; // empty..
8067 if (!f.el.dom.checked) {
8075 if(f.xtype == 'MoneyField'){
8076 ret[f.currencyName] = f.getCurrency();
8079 // not sure if this supported any more..
8080 if ((typeof(v) == 'object') && f.getRawValue) {
8081 v = f.getRawValue() ; // dates..
8083 // combo boxes where name != hiddenName...
8084 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8085 ret[f.name] = f.getRawValue();
8087 ret[f.getName()] = v;
8094 * Clears all invalid messages in this form.
8095 * @return {BasicForm} this
8097 clearInvalid : function(){
8098 var items = this.getItems();
8100 items.each(function(f){
8109 * @return {BasicForm} this
8112 var items = this.getItems();
8113 items.each(function(f){
8117 Roo.each(this.childForms || [], function (f) {
8125 getItems : function()
8127 var r=new Roo.util.MixedCollection(false, function(o){
8128 return o.id || (o.id = Roo.id());
8130 var iter = function(el) {
8137 Roo.each(el.items,function(e) {
8146 hideFields : function(items)
8148 Roo.each(items, function(i){
8150 var f = this.findField(i);
8156 if(f.xtype == 'DateField'){
8157 f.setVisible(false);
8166 showFields : function(items)
8168 Roo.each(items, function(i){
8170 var f = this.findField(i);
8176 if(f.xtype == 'DateField'){
8188 Roo.apply(Roo.bootstrap.Form, {
8215 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8216 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8217 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8218 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8221 this.maskEl.top.enableDisplayMode("block");
8222 this.maskEl.left.enableDisplayMode("block");
8223 this.maskEl.bottom.enableDisplayMode("block");
8224 this.maskEl.right.enableDisplayMode("block");
8226 this.toolTip = new Roo.bootstrap.Tooltip({
8227 cls : 'roo-form-error-popover',
8229 'left' : ['r-l', [-2,0], 'right'],
8230 'right' : ['l-r', [2,0], 'left'],
8231 'bottom' : ['tl-bl', [0,2], 'top'],
8232 'top' : [ 'bl-tl', [0,-2], 'bottom']
8236 this.toolTip.render(Roo.get(document.body));
8238 this.toolTip.el.enableDisplayMode("block");
8240 Roo.get(document.body).on('click', function(){
8244 Roo.get(document.body).on('touchstart', function(){
8248 this.isApplied = true
8251 mask : function(form, target)
8255 this.target = target;
8257 if(!this.form.errorMask || !target.el){
8261 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8263 Roo.log(scrollable);
8265 var ot = this.target.el.calcOffsetsTo(scrollable);
8267 var scrollTo = ot[1] - this.form.maskOffset;
8269 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8271 scrollable.scrollTo('top', scrollTo);
8273 var box = this.target.el.getBox();
8275 var zIndex = Roo.bootstrap.Modal.zIndex++;
8278 this.maskEl.top.setStyle('position', 'absolute');
8279 this.maskEl.top.setStyle('z-index', zIndex);
8280 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8281 this.maskEl.top.setLeft(0);
8282 this.maskEl.top.setTop(0);
8283 this.maskEl.top.show();
8285 this.maskEl.left.setStyle('position', 'absolute');
8286 this.maskEl.left.setStyle('z-index', zIndex);
8287 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8288 this.maskEl.left.setLeft(0);
8289 this.maskEl.left.setTop(box.y - this.padding);
8290 this.maskEl.left.show();
8292 this.maskEl.bottom.setStyle('position', 'absolute');
8293 this.maskEl.bottom.setStyle('z-index', zIndex);
8294 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8295 this.maskEl.bottom.setLeft(0);
8296 this.maskEl.bottom.setTop(box.bottom + this.padding);
8297 this.maskEl.bottom.show();
8299 this.maskEl.right.setStyle('position', 'absolute');
8300 this.maskEl.right.setStyle('z-index', zIndex);
8301 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8302 this.maskEl.right.setLeft(box.right + this.padding);
8303 this.maskEl.right.setTop(box.y - this.padding);
8304 this.maskEl.right.show();
8306 this.toolTip.bindEl = this.target.el;
8308 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8310 var tip = this.target.blankText;
8312 if(this.target.getValue() !== '' ) {
8314 if (this.target.invalidText.length) {
8315 tip = this.target.invalidText;
8316 } else if (this.target.regexText.length){
8317 tip = this.target.regexText;
8321 this.toolTip.show(tip);
8323 this.intervalID = window.setInterval(function() {
8324 Roo.bootstrap.Form.popover.unmask();
8327 window.onwheel = function(){ return false;};
8329 (function(){ this.isMasked = true; }).defer(500, this);
8335 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8339 this.maskEl.top.setStyle('position', 'absolute');
8340 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8341 this.maskEl.top.hide();
8343 this.maskEl.left.setStyle('position', 'absolute');
8344 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8345 this.maskEl.left.hide();
8347 this.maskEl.bottom.setStyle('position', 'absolute');
8348 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8349 this.maskEl.bottom.hide();
8351 this.maskEl.right.setStyle('position', 'absolute');
8352 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8353 this.maskEl.right.hide();
8355 this.toolTip.hide();
8357 this.toolTip.el.hide();
8359 window.onwheel = function(){ return true;};
8361 if(this.intervalID){
8362 window.clearInterval(this.intervalID);
8363 this.intervalID = false;
8366 this.isMasked = false;
8376 * Ext JS Library 1.1.1
8377 * Copyright(c) 2006-2007, Ext JS, LLC.
8379 * Originally Released Under LGPL - original licence link has changed is not relivant.
8382 * <script type="text/javascript">
8385 * @class Roo.form.VTypes
8386 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8389 Roo.form.VTypes = function(){
8390 // closure these in so they are only created once.
8391 var alpha = /^[a-zA-Z_]+$/;
8392 var alphanum = /^[a-zA-Z0-9_]+$/;
8393 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8394 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8396 // All these messages and functions are configurable
8399 * The function used to validate email addresses
8400 * @param {String} value The email address
8402 'email' : function(v){
8403 return email.test(v);
8406 * The error text to display when the email validation function returns false
8409 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8411 * The keystroke filter mask to be applied on email input
8414 'emailMask' : /[a-z0-9_\.\-@]/i,
8417 * The function used to validate URLs
8418 * @param {String} value The URL
8420 'url' : function(v){
8424 * The error text to display when the url validation function returns false
8427 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8430 * The function used to validate alpha values
8431 * @param {String} value The value
8433 'alpha' : function(v){
8434 return alpha.test(v);
8437 * The error text to display when the alpha validation function returns false
8440 'alphaText' : 'This field should only contain letters and _',
8442 * The keystroke filter mask to be applied on alpha input
8445 'alphaMask' : /[a-z_]/i,
8448 * The function used to validate alphanumeric values
8449 * @param {String} value The value
8451 'alphanum' : function(v){
8452 return alphanum.test(v);
8455 * The error text to display when the alphanumeric validation function returns false
8458 'alphanumText' : 'This field should only contain letters, numbers and _',
8460 * The keystroke filter mask to be applied on alphanumeric input
8463 'alphanumMask' : /[a-z0-9_]/i
8473 * @class Roo.bootstrap.Input
8474 * @extends Roo.bootstrap.Component
8475 * Bootstrap Input class
8476 * @cfg {Boolean} disabled is it disabled
8477 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8478 * @cfg {String} name name of the input
8479 * @cfg {string} fieldLabel - the label associated
8480 * @cfg {string} placeholder - placeholder to put in text.
8481 * @cfg {string} before - input group add on before
8482 * @cfg {string} after - input group add on after
8483 * @cfg {string} size - (lg|sm) or leave empty..
8484 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8485 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8486 * @cfg {Number} md colspan out of 12 for computer-sized screens
8487 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8488 * @cfg {string} value default value of the input
8489 * @cfg {Number} labelWidth set the width of label
8490 * @cfg {Number} labellg set the width of label (1-12)
8491 * @cfg {Number} labelmd set the width of label (1-12)
8492 * @cfg {Number} labelsm set the width of label (1-12)
8493 * @cfg {Number} labelxs set the width of label (1-12)
8494 * @cfg {String} labelAlign (top|left)
8495 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8496 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8497 * @cfg {String} indicatorpos (left|right) default left
8499 * @cfg {String} align (left|center|right) Default left
8500 * @cfg {Boolean} forceFeedback (true|false) Default false
8503 * Create a new Input
8504 * @param {Object} config The config object
8507 Roo.bootstrap.Input = function(config){
8509 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8514 * Fires when this field receives input focus.
8515 * @param {Roo.form.Field} this
8520 * Fires when this field loses input focus.
8521 * @param {Roo.form.Field} this
8526 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8527 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8528 * @param {Roo.form.Field} this
8529 * @param {Roo.EventObject} e The event object
8534 * Fires just before the field blurs if the field value has changed.
8535 * @param {Roo.form.Field} this
8536 * @param {Mixed} newValue The new value
8537 * @param {Mixed} oldValue The original value
8542 * Fires after the field has been marked as invalid.
8543 * @param {Roo.form.Field} this
8544 * @param {String} msg The validation message
8549 * Fires after the field has been validated with no errors.
8550 * @param {Roo.form.Field} this
8555 * Fires after the key up
8556 * @param {Roo.form.Field} this
8557 * @param {Roo.EventObject} e The event Object
8563 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8565 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8566 automatic validation (defaults to "keyup").
8568 validationEvent : "keyup",
8570 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8572 validateOnBlur : true,
8574 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8576 validationDelay : 250,
8578 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8580 focusClass : "x-form-focus", // not needed???
8584 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8586 invalidClass : "has-warning",
8589 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8591 validClass : "has-success",
8594 * @cfg {Boolean} hasFeedback (true|false) default true
8599 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8601 invalidFeedbackClass : "glyphicon-warning-sign",
8604 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8606 validFeedbackClass : "glyphicon-ok",
8609 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8611 selectOnFocus : false,
8614 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8618 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8623 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8625 disableKeyFilter : false,
8628 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8632 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8636 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8638 blankText : "Please complete this mandatory field",
8641 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8645 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8647 maxLength : Number.MAX_VALUE,
8649 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8651 minLengthText : "The minimum length for this field is {0}",
8653 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8655 maxLengthText : "The maximum length for this field is {0}",
8659 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8660 * If available, this function will be called only after the basic validators all return true, and will be passed the
8661 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8665 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8666 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8667 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8671 * @cfg {String} regexText -- Depricated - use Invalid Text
8676 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8682 autocomplete: false,
8701 formatedValue : false,
8702 forceFeedback : false,
8704 indicatorpos : 'left',
8711 parentLabelAlign : function()
8714 while (parent.parent()) {
8715 parent = parent.parent();
8716 if (typeof(parent.labelAlign) !='undefined') {
8717 return parent.labelAlign;
8724 getAutoCreate : function()
8726 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8732 if(this.inputType != 'hidden'){
8733 cfg.cls = 'form-group' //input-group
8739 type : this.inputType,
8741 cls : 'form-control',
8742 placeholder : this.placeholder || '',
8743 autocomplete : this.autocomplete || 'new-password'
8747 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8750 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8751 input.maxLength = this.maxLength;
8754 if (this.disabled) {
8755 input.disabled=true;
8758 if (this.readOnly) {
8759 input.readonly=true;
8763 input.name = this.name;
8767 input.cls += ' input-' + this.size;
8771 ['xs','sm','md','lg'].map(function(size){
8772 if (settings[size]) {
8773 cfg.cls += ' col-' + size + '-' + settings[size];
8777 var inputblock = input;
8781 cls: 'glyphicon form-control-feedback'
8784 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8787 cls : 'has-feedback',
8795 if (this.before || this.after) {
8798 cls : 'input-group',
8802 if (this.before && typeof(this.before) == 'string') {
8804 inputblock.cn.push({
8806 cls : 'roo-input-before input-group-addon',
8810 if (this.before && typeof(this.before) == 'object') {
8811 this.before = Roo.factory(this.before);
8813 inputblock.cn.push({
8815 cls : 'roo-input-before input-group-' +
8816 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8820 inputblock.cn.push(input);
8822 if (this.after && typeof(this.after) == 'string') {
8823 inputblock.cn.push({
8825 cls : 'roo-input-after input-group-addon',
8829 if (this.after && typeof(this.after) == 'object') {
8830 this.after = Roo.factory(this.after);
8832 inputblock.cn.push({
8834 cls : 'roo-input-after input-group-' +
8835 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8839 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8840 inputblock.cls += ' has-feedback';
8841 inputblock.cn.push(feedback);
8845 if (align ==='left' && this.fieldLabel.length) {
8847 cfg.cls += ' roo-form-group-label-left';
8852 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8853 tooltip : 'This field is required'
8858 cls : 'control-label',
8859 html : this.fieldLabel
8870 var labelCfg = cfg.cn[1];
8871 var contentCfg = cfg.cn[2];
8873 if(this.indicatorpos == 'right'){
8878 cls : 'control-label',
8882 html : this.fieldLabel
8886 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8887 tooltip : 'This field is required'
8900 labelCfg = cfg.cn[0];
8901 contentCfg = cfg.cn[1];
8905 if(this.labelWidth > 12){
8906 labelCfg.style = "width: " + this.labelWidth + 'px';
8909 if(this.labelWidth < 13 && this.labelmd == 0){
8910 this.labelmd = this.labelWidth;
8913 if(this.labellg > 0){
8914 labelCfg.cls += ' col-lg-' + this.labellg;
8915 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8918 if(this.labelmd > 0){
8919 labelCfg.cls += ' col-md-' + this.labelmd;
8920 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8923 if(this.labelsm > 0){
8924 labelCfg.cls += ' col-sm-' + this.labelsm;
8925 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8928 if(this.labelxs > 0){
8929 labelCfg.cls += ' col-xs-' + this.labelxs;
8930 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8934 } else if ( this.fieldLabel.length) {
8939 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8940 tooltip : 'This field is required'
8944 //cls : 'input-group-addon',
8945 html : this.fieldLabel
8953 if(this.indicatorpos == 'right'){
8958 //cls : 'input-group-addon',
8959 html : this.fieldLabel
8964 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8965 tooltip : 'This field is required'
8985 if (this.parentType === 'Navbar' && this.parent().bar) {
8986 cfg.cls += ' navbar-form';
8989 if (this.parentType === 'NavGroup') {
8990 cfg.cls += ' navbar-form';
8998 * return the real input element.
9000 inputEl: function ()
9002 return this.el.select('input.form-control',true).first();
9005 tooltipEl : function()
9007 return this.inputEl();
9010 indicatorEl : function()
9012 var indicator = this.el.select('i.roo-required-indicator',true).first();
9022 setDisabled : function(v)
9024 var i = this.inputEl().dom;
9026 i.removeAttribute('disabled');
9030 i.setAttribute('disabled','true');
9032 initEvents : function()
9035 this.inputEl().on("keydown" , this.fireKey, this);
9036 this.inputEl().on("focus", this.onFocus, this);
9037 this.inputEl().on("blur", this.onBlur, this);
9039 this.inputEl().relayEvent('keyup', this);
9041 this.indicator = this.indicatorEl();
9044 this.indicator.addClass('invisible');
9048 // reference to original value for reset
9049 this.originalValue = this.getValue();
9050 //Roo.form.TextField.superclass.initEvents.call(this);
9051 if(this.validationEvent == 'keyup'){
9052 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9053 this.inputEl().on('keyup', this.filterValidation, this);
9055 else if(this.validationEvent !== false){
9056 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9059 if(this.selectOnFocus){
9060 this.on("focus", this.preFocus, this);
9063 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9064 this.inputEl().on("keypress", this.filterKeys, this);
9066 this.inputEl().relayEvent('keypress', this);
9069 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9070 this.el.on("click", this.autoSize, this);
9073 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9074 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9077 if (typeof(this.before) == 'object') {
9078 this.before.render(this.el.select('.roo-input-before',true).first());
9080 if (typeof(this.after) == 'object') {
9081 this.after.render(this.el.select('.roo-input-after',true).first());
9086 filterValidation : function(e){
9087 if(!e.isNavKeyPress()){
9088 this.validationTask.delay(this.validationDelay);
9092 * Validates the field value
9093 * @return {Boolean} True if the value is valid, else false
9095 validate : function(){
9096 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9097 if(this.disabled || this.validateValue(this.getRawValue())){
9108 * Validates a value according to the field's validation rules and marks the field as invalid
9109 * if the validation fails
9110 * @param {Mixed} value The value to validate
9111 * @return {Boolean} True if the value is valid, else false
9113 validateValue : function(value)
9115 if(this.getVisibilityEl().hasClass('hidden')){
9119 if(value.length < 1) { // if it's blank
9120 if(this.allowBlank){
9126 if(value.length < this.minLength){
9129 if(value.length > this.maxLength){
9133 var vt = Roo.form.VTypes;
9134 if(!vt[this.vtype](value, this)){
9138 if(typeof this.validator == "function"){
9139 var msg = this.validator(value);
9143 if (typeof(msg) == 'string') {
9144 this.invalidText = msg;
9148 if(this.regex && !this.regex.test(value)){
9156 fireKey : function(e){
9157 //Roo.log('field ' + e.getKey());
9158 if(e.isNavKeyPress()){
9159 this.fireEvent("specialkey", this, e);
9162 focus : function (selectText){
9164 this.inputEl().focus();
9165 if(selectText === true){
9166 this.inputEl().dom.select();
9172 onFocus : function(){
9173 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9174 // this.el.addClass(this.focusClass);
9177 this.hasFocus = true;
9178 this.startValue = this.getValue();
9179 this.fireEvent("focus", this);
9183 beforeBlur : Roo.emptyFn,
9187 onBlur : function(){
9189 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9190 //this.el.removeClass(this.focusClass);
9192 this.hasFocus = false;
9193 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9196 var v = this.getValue();
9197 if(String(v) !== String(this.startValue)){
9198 this.fireEvent('change', this, v, this.startValue);
9200 this.fireEvent("blur", this);
9204 * Resets the current field value to the originally loaded value and clears any validation messages
9207 this.setValue(this.originalValue);
9211 * Returns the name of the field
9212 * @return {Mixed} name The name field
9214 getName: function(){
9218 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9219 * @return {Mixed} value The field value
9221 getValue : function(){
9223 var v = this.inputEl().getValue();
9228 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9229 * @return {Mixed} value The field value
9231 getRawValue : function(){
9232 var v = this.inputEl().getValue();
9238 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9239 * @param {Mixed} value The value to set
9241 setRawValue : function(v){
9242 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9245 selectText : function(start, end){
9246 var v = this.getRawValue();
9248 start = start === undefined ? 0 : start;
9249 end = end === undefined ? v.length : end;
9250 var d = this.inputEl().dom;
9251 if(d.setSelectionRange){
9252 d.setSelectionRange(start, end);
9253 }else if(d.createTextRange){
9254 var range = d.createTextRange();
9255 range.moveStart("character", start);
9256 range.moveEnd("character", v.length-end);
9263 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9264 * @param {Mixed} value The value to set
9266 setValue : function(v){
9269 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9275 processValue : function(value){
9276 if(this.stripCharsRe){
9277 var newValue = value.replace(this.stripCharsRe, '');
9278 if(newValue !== value){
9279 this.setRawValue(newValue);
9286 preFocus : function(){
9288 if(this.selectOnFocus){
9289 this.inputEl().dom.select();
9292 filterKeys : function(e){
9294 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9297 var c = e.getCharCode(), cc = String.fromCharCode(c);
9298 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9301 if(!this.maskRe.test(cc)){
9306 * Clear any invalid styles/messages for this field
9308 clearInvalid : function(){
9310 if(!this.el || this.preventMark){ // not rendered
9315 this.el.removeClass(this.invalidClass);
9317 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9319 var feedback = this.el.select('.form-control-feedback', true).first();
9322 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9327 this.fireEvent('valid', this);
9331 * Mark this field as valid
9333 markValid : function()
9335 if(!this.el || this.preventMark){ // not rendered...
9339 this.el.removeClass([this.invalidClass, this.validClass]);
9341 var feedback = this.el.select('.form-control-feedback', true).first();
9344 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9348 this.indicator.removeClass('visible');
9349 this.indicator.addClass('invisible');
9356 if(this.allowBlank && !this.getRawValue().length){
9360 this.el.addClass(this.validClass);
9362 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9364 var feedback = this.el.select('.form-control-feedback', true).first();
9367 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9368 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9373 this.fireEvent('valid', this);
9377 * Mark this field as invalid
9378 * @param {String} msg The validation message
9380 markInvalid : function(msg)
9382 if(!this.el || this.preventMark){ // not rendered
9386 this.el.removeClass([this.invalidClass, this.validClass]);
9388 var feedback = this.el.select('.form-control-feedback', true).first();
9391 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9398 if(this.allowBlank && !this.getRawValue().length){
9403 this.indicator.removeClass('invisible');
9404 this.indicator.addClass('visible');
9407 this.el.addClass(this.invalidClass);
9409 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9411 var feedback = this.el.select('.form-control-feedback', true).first();
9414 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9416 if(this.getValue().length || this.forceFeedback){
9417 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9424 this.fireEvent('invalid', this, msg);
9427 SafariOnKeyDown : function(event)
9429 // this is a workaround for a password hang bug on chrome/ webkit.
9430 if (this.inputEl().dom.type != 'password') {
9434 var isSelectAll = false;
9436 if(this.inputEl().dom.selectionEnd > 0){
9437 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9439 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9440 event.preventDefault();
9445 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9447 event.preventDefault();
9448 // this is very hacky as keydown always get's upper case.
9450 var cc = String.fromCharCode(event.getCharCode());
9451 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9455 adjustWidth : function(tag, w){
9456 tag = tag.toLowerCase();
9457 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9458 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9462 if(tag == 'textarea'){
9465 }else if(Roo.isOpera){
9469 if(tag == 'textarea'){
9477 setFieldLabel : function(v)
9484 var ar = this.el.select('label > span',true);
9486 if (ar.elements.length) {
9487 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9488 this.fieldLabel = v;
9492 var br = this.el.select('label',true);
9494 if(br.elements.length) {
9495 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9496 this.fieldLabel = v;
9500 Roo.log('Cannot Found any of label > span || label in input');
9504 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9505 this.fieldLabel = v;
9520 * @class Roo.bootstrap.TextArea
9521 * @extends Roo.bootstrap.Input
9522 * Bootstrap TextArea class
9523 * @cfg {Number} cols Specifies the visible width of a text area
9524 * @cfg {Number} rows Specifies the visible number of lines in a text area
9525 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9526 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9527 * @cfg {string} html text
9530 * Create a new TextArea
9531 * @param {Object} config The config object
9534 Roo.bootstrap.TextArea = function(config){
9535 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9539 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9549 getAutoCreate : function(){
9551 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9557 if(this.inputType != 'hidden'){
9558 cfg.cls = 'form-group' //input-group
9566 value : this.value || '',
9567 html: this.html || '',
9568 cls : 'form-control',
9569 placeholder : this.placeholder || ''
9573 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9574 input.maxLength = this.maxLength;
9578 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9582 input.cols = this.cols;
9585 if (this.readOnly) {
9586 input.readonly = true;
9590 input.name = this.name;
9594 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9598 ['xs','sm','md','lg'].map(function(size){
9599 if (settings[size]) {
9600 cfg.cls += ' col-' + size + '-' + settings[size];
9604 var inputblock = input;
9606 if(this.hasFeedback && !this.allowBlank){
9610 cls: 'glyphicon form-control-feedback'
9614 cls : 'has-feedback',
9623 if (this.before || this.after) {
9626 cls : 'input-group',
9630 inputblock.cn.push({
9632 cls : 'input-group-addon',
9637 inputblock.cn.push(input);
9639 if(this.hasFeedback && !this.allowBlank){
9640 inputblock.cls += ' has-feedback';
9641 inputblock.cn.push(feedback);
9645 inputblock.cn.push({
9647 cls : 'input-group-addon',
9654 if (align ==='left' && this.fieldLabel.length) {
9659 cls : 'control-label',
9660 html : this.fieldLabel
9671 if(this.labelWidth > 12){
9672 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9675 if(this.labelWidth < 13 && this.labelmd == 0){
9676 this.labelmd = this.labelWidth;
9679 if(this.labellg > 0){
9680 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9681 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9684 if(this.labelmd > 0){
9685 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9686 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9689 if(this.labelsm > 0){
9690 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9691 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9694 if(this.labelxs > 0){
9695 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9696 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9699 } else if ( this.fieldLabel.length) {
9704 //cls : 'input-group-addon',
9705 html : this.fieldLabel
9723 if (this.disabled) {
9724 input.disabled=true;
9731 * return the real textarea element.
9733 inputEl: function ()
9735 return this.el.select('textarea.form-control',true).first();
9739 * Clear any invalid styles/messages for this field
9741 clearInvalid : function()
9744 if(!this.el || this.preventMark){ // not rendered
9748 var label = this.el.select('label', true).first();
9749 var icon = this.el.select('i.fa-star', true).first();
9755 this.el.removeClass(this.invalidClass);
9757 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9759 var feedback = this.el.select('.form-control-feedback', true).first();
9762 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9767 this.fireEvent('valid', this);
9771 * Mark this field as valid
9773 markValid : function()
9775 if(!this.el || this.preventMark){ // not rendered
9779 this.el.removeClass([this.invalidClass, this.validClass]);
9781 var feedback = this.el.select('.form-control-feedback', true).first();
9784 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9787 if(this.disabled || this.allowBlank){
9791 var label = this.el.select('label', true).first();
9792 var icon = this.el.select('i.fa-star', true).first();
9798 this.el.addClass(this.validClass);
9800 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9802 var feedback = this.el.select('.form-control-feedback', true).first();
9805 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9806 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9811 this.fireEvent('valid', this);
9815 * Mark this field as invalid
9816 * @param {String} msg The validation message
9818 markInvalid : function(msg)
9820 if(!this.el || this.preventMark){ // not rendered
9824 this.el.removeClass([this.invalidClass, this.validClass]);
9826 var feedback = this.el.select('.form-control-feedback', true).first();
9829 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9832 if(this.disabled || this.allowBlank){
9836 var label = this.el.select('label', true).first();
9837 var icon = this.el.select('i.fa-star', true).first();
9839 if(!this.getValue().length && label && !icon){
9840 this.el.createChild({
9842 cls : 'text-danger fa fa-lg fa-star',
9843 tooltip : 'This field is required',
9844 style : 'margin-right:5px;'
9848 this.el.addClass(this.invalidClass);
9850 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9852 var feedback = this.el.select('.form-control-feedback', true).first();
9855 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9857 if(this.getValue().length || this.forceFeedback){
9858 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9865 this.fireEvent('invalid', this, msg);
9873 * trigger field - base class for combo..
9878 * @class Roo.bootstrap.TriggerField
9879 * @extends Roo.bootstrap.Input
9880 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9881 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9882 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9883 * for which you can provide a custom implementation. For example:
9885 var trigger = new Roo.bootstrap.TriggerField();
9886 trigger.onTriggerClick = myTriggerFn;
9887 trigger.applyTo('my-field');
9890 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9891 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9892 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9893 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9894 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9897 * Create a new TriggerField.
9898 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9899 * to the base TextField)
9901 Roo.bootstrap.TriggerField = function(config){
9902 this.mimicing = false;
9903 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9906 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9908 * @cfg {String} triggerClass A CSS class to apply to the trigger
9911 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9916 * @cfg {Boolean} removable (true|false) special filter default false
9920 /** @cfg {Boolean} grow @hide */
9921 /** @cfg {Number} growMin @hide */
9922 /** @cfg {Number} growMax @hide */
9928 autoSize: Roo.emptyFn,
9935 actionMode : 'wrap',
9940 getAutoCreate : function(){
9942 var align = this.labelAlign || this.parentLabelAlign();
9947 cls: 'form-group' //input-group
9954 type : this.inputType,
9955 cls : 'form-control',
9956 autocomplete: 'new-password',
9957 placeholder : this.placeholder || ''
9961 input.name = this.name;
9964 input.cls += ' input-' + this.size;
9967 if (this.disabled) {
9968 input.disabled=true;
9971 var inputblock = input;
9973 if(this.hasFeedback && !this.allowBlank){
9977 cls: 'glyphicon form-control-feedback'
9980 if(this.removable && !this.editable && !this.tickable){
9982 cls : 'has-feedback',
9988 cls : 'roo-combo-removable-btn close'
9995 cls : 'has-feedback',
10004 if(this.removable && !this.editable && !this.tickable){
10006 cls : 'roo-removable',
10012 cls : 'roo-combo-removable-btn close'
10019 if (this.before || this.after) {
10022 cls : 'input-group',
10026 inputblock.cn.push({
10028 cls : 'input-group-addon',
10033 inputblock.cn.push(input);
10035 if(this.hasFeedback && !this.allowBlank){
10036 inputblock.cls += ' has-feedback';
10037 inputblock.cn.push(feedback);
10041 inputblock.cn.push({
10043 cls : 'input-group-addon',
10056 cls: 'form-hidden-field'
10070 cls: 'form-hidden-field'
10074 cls: 'roo-select2-choices',
10078 cls: 'roo-select2-search-field',
10091 cls: 'roo-select2-container input-group',
10096 // cls: 'typeahead typeahead-long dropdown-menu',
10097 // style: 'display:none'
10102 if(!this.multiple && this.showToggleBtn){
10108 if (this.caret != false) {
10111 cls: 'fa fa-' + this.caret
10118 cls : 'input-group-addon btn dropdown-toggle',
10123 cls: 'combobox-clear',
10137 combobox.cls += ' roo-select2-container-multi';
10140 if (align ==='left' && this.fieldLabel.length) {
10142 cfg.cls += ' roo-form-group-label-left';
10147 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10148 tooltip : 'This field is required'
10153 cls : 'control-label',
10154 html : this.fieldLabel
10166 var labelCfg = cfg.cn[1];
10167 var contentCfg = cfg.cn[2];
10169 if(this.indicatorpos == 'right'){
10174 cls : 'control-label',
10178 html : this.fieldLabel
10182 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10183 tooltip : 'This field is required'
10196 labelCfg = cfg.cn[0];
10197 contentCfg = cfg.cn[1];
10200 if(this.labelWidth > 12){
10201 labelCfg.style = "width: " + this.labelWidth + 'px';
10204 if(this.labelWidth < 13 && this.labelmd == 0){
10205 this.labelmd = this.labelWidth;
10208 if(this.labellg > 0){
10209 labelCfg.cls += ' col-lg-' + this.labellg;
10210 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10213 if(this.labelmd > 0){
10214 labelCfg.cls += ' col-md-' + this.labelmd;
10215 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10218 if(this.labelsm > 0){
10219 labelCfg.cls += ' col-sm-' + this.labelsm;
10220 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10223 if(this.labelxs > 0){
10224 labelCfg.cls += ' col-xs-' + this.labelxs;
10225 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10228 } else if ( this.fieldLabel.length) {
10229 // Roo.log(" label");
10233 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10234 tooltip : 'This field is required'
10238 //cls : 'input-group-addon',
10239 html : this.fieldLabel
10247 if(this.indicatorpos == 'right'){
10255 html : this.fieldLabel
10259 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10260 tooltip : 'This field is required'
10273 // Roo.log(" no label && no align");
10280 ['xs','sm','md','lg'].map(function(size){
10281 if (settings[size]) {
10282 cfg.cls += ' col-' + size + '-' + settings[size];
10293 onResize : function(w, h){
10294 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10295 // if(typeof w == 'number'){
10296 // var x = w - this.trigger.getWidth();
10297 // this.inputEl().setWidth(this.adjustWidth('input', x));
10298 // this.trigger.setStyle('left', x+'px');
10303 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10306 getResizeEl : function(){
10307 return this.inputEl();
10311 getPositionEl : function(){
10312 return this.inputEl();
10316 alignErrorIcon : function(){
10317 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10321 initEvents : function(){
10325 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10326 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10327 if(!this.multiple && this.showToggleBtn){
10328 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10329 if(this.hideTrigger){
10330 this.trigger.setDisplayed(false);
10332 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10336 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10339 if(this.removable && !this.editable && !this.tickable){
10340 var close = this.closeTriggerEl();
10343 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10344 close.on('click', this.removeBtnClick, this, close);
10348 //this.trigger.addClassOnOver('x-form-trigger-over');
10349 //this.trigger.addClassOnClick('x-form-trigger-click');
10352 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10356 closeTriggerEl : function()
10358 var close = this.el.select('.roo-combo-removable-btn', true).first();
10359 return close ? close : false;
10362 removeBtnClick : function(e, h, el)
10364 e.preventDefault();
10366 if(this.fireEvent("remove", this) !== false){
10368 this.fireEvent("afterremove", this)
10372 createList : function()
10374 this.list = Roo.get(document.body).createChild({
10376 cls: 'typeahead typeahead-long dropdown-menu',
10377 style: 'display:none'
10380 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10385 initTrigger : function(){
10390 onDestroy : function(){
10392 this.trigger.removeAllListeners();
10393 // this.trigger.remove();
10396 // this.wrap.remove();
10398 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10402 onFocus : function(){
10403 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10405 if(!this.mimicing){
10406 this.wrap.addClass('x-trigger-wrap-focus');
10407 this.mimicing = true;
10408 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10409 if(this.monitorTab){
10410 this.el.on("keydown", this.checkTab, this);
10417 checkTab : function(e){
10418 if(e.getKey() == e.TAB){
10419 this.triggerBlur();
10424 onBlur : function(){
10429 mimicBlur : function(e, t){
10431 if(!this.wrap.contains(t) && this.validateBlur()){
10432 this.triggerBlur();
10438 triggerBlur : function(){
10439 this.mimicing = false;
10440 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10441 if(this.monitorTab){
10442 this.el.un("keydown", this.checkTab, this);
10444 //this.wrap.removeClass('x-trigger-wrap-focus');
10445 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10449 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10450 validateBlur : function(e, t){
10455 onDisable : function(){
10456 this.inputEl().dom.disabled = true;
10457 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10459 // this.wrap.addClass('x-item-disabled');
10464 onEnable : function(){
10465 this.inputEl().dom.disabled = false;
10466 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10468 // this.el.removeClass('x-item-disabled');
10473 onShow : function(){
10474 var ae = this.getActionEl();
10477 ae.dom.style.display = '';
10478 ae.dom.style.visibility = 'visible';
10484 onHide : function(){
10485 var ae = this.getActionEl();
10486 ae.dom.style.display = 'none';
10490 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10491 * by an implementing function.
10493 * @param {EventObject} e
10495 onTriggerClick : Roo.emptyFn
10499 * Ext JS Library 1.1.1
10500 * Copyright(c) 2006-2007, Ext JS, LLC.
10502 * Originally Released Under LGPL - original licence link has changed is not relivant.
10505 * <script type="text/javascript">
10510 * @class Roo.data.SortTypes
10512 * Defines the default sorting (casting?) comparison functions used when sorting data.
10514 Roo.data.SortTypes = {
10516 * Default sort that does nothing
10517 * @param {Mixed} s The value being converted
10518 * @return {Mixed} The comparison value
10520 none : function(s){
10525 * The regular expression used to strip tags
10529 stripTagsRE : /<\/?[^>]+>/gi,
10532 * Strips all HTML tags to sort on text only
10533 * @param {Mixed} s The value being converted
10534 * @return {String} The comparison value
10536 asText : function(s){
10537 return String(s).replace(this.stripTagsRE, "");
10541 * Strips all HTML tags to sort on text only - Case insensitive
10542 * @param {Mixed} s The value being converted
10543 * @return {String} The comparison value
10545 asUCText : function(s){
10546 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10550 * Case insensitive string
10551 * @param {Mixed} s The value being converted
10552 * @return {String} The comparison value
10554 asUCString : function(s) {
10555 return String(s).toUpperCase();
10560 * @param {Mixed} s The value being converted
10561 * @return {Number} The comparison value
10563 asDate : function(s) {
10567 if(s instanceof Date){
10568 return s.getTime();
10570 return Date.parse(String(s));
10575 * @param {Mixed} s The value being converted
10576 * @return {Float} The comparison value
10578 asFloat : function(s) {
10579 var val = parseFloat(String(s).replace(/,/g, ""));
10588 * @param {Mixed} s The value being converted
10589 * @return {Number} The comparison value
10591 asInt : function(s) {
10592 var val = parseInt(String(s).replace(/,/g, ""));
10600 * Ext JS Library 1.1.1
10601 * Copyright(c) 2006-2007, Ext JS, LLC.
10603 * Originally Released Under LGPL - original licence link has changed is not relivant.
10606 * <script type="text/javascript">
10610 * @class Roo.data.Record
10611 * Instances of this class encapsulate both record <em>definition</em> information, and record
10612 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10613 * to access Records cached in an {@link Roo.data.Store} object.<br>
10615 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10616 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10619 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10621 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10622 * {@link #create}. The parameters are the same.
10623 * @param {Array} data An associative Array of data values keyed by the field name.
10624 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10625 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10626 * not specified an integer id is generated.
10628 Roo.data.Record = function(data, id){
10629 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10634 * Generate a constructor for a specific record layout.
10635 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10636 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10637 * Each field definition object may contain the following properties: <ul>
10638 * <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,
10639 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10640 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10641 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10642 * is being used, then this is a string containing the javascript expression to reference the data relative to
10643 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10644 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10645 * this may be omitted.</p></li>
10646 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10647 * <ul><li>auto (Default, implies no conversion)</li>
10652 * <li>date</li></ul></p></li>
10653 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10654 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10655 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10656 * by the Reader into an object that will be stored in the Record. It is passed the
10657 * following parameters:<ul>
10658 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10660 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10662 * <br>usage:<br><pre><code>
10663 var TopicRecord = Roo.data.Record.create(
10664 {name: 'title', mapping: 'topic_title'},
10665 {name: 'author', mapping: 'username'},
10666 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10667 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10668 {name: 'lastPoster', mapping: 'user2'},
10669 {name: 'excerpt', mapping: 'post_text'}
10672 var myNewRecord = new TopicRecord({
10673 title: 'Do my job please',
10676 lastPost: new Date(),
10677 lastPoster: 'Animal',
10678 excerpt: 'No way dude!'
10680 myStore.add(myNewRecord);
10685 Roo.data.Record.create = function(o){
10686 var f = function(){
10687 f.superclass.constructor.apply(this, arguments);
10689 Roo.extend(f, Roo.data.Record);
10690 var p = f.prototype;
10691 p.fields = new Roo.util.MixedCollection(false, function(field){
10694 for(var i = 0, len = o.length; i < len; i++){
10695 p.fields.add(new Roo.data.Field(o[i]));
10697 f.getField = function(name){
10698 return p.fields.get(name);
10703 Roo.data.Record.AUTO_ID = 1000;
10704 Roo.data.Record.EDIT = 'edit';
10705 Roo.data.Record.REJECT = 'reject';
10706 Roo.data.Record.COMMIT = 'commit';
10708 Roo.data.Record.prototype = {
10710 * Readonly flag - true if this record has been modified.
10719 join : function(store){
10720 this.store = store;
10724 * Set the named field to the specified value.
10725 * @param {String} name The name of the field to set.
10726 * @param {Object} value The value to set the field to.
10728 set : function(name, value){
10729 if(this.data[name] == value){
10733 if(!this.modified){
10734 this.modified = {};
10736 if(typeof this.modified[name] == 'undefined'){
10737 this.modified[name] = this.data[name];
10739 this.data[name] = value;
10740 if(!this.editing && this.store){
10741 this.store.afterEdit(this);
10746 * Get the value of the named field.
10747 * @param {String} name The name of the field to get the value of.
10748 * @return {Object} The value of the field.
10750 get : function(name){
10751 return this.data[name];
10755 beginEdit : function(){
10756 this.editing = true;
10757 this.modified = {};
10761 cancelEdit : function(){
10762 this.editing = false;
10763 delete this.modified;
10767 endEdit : function(){
10768 this.editing = false;
10769 if(this.dirty && this.store){
10770 this.store.afterEdit(this);
10775 * Usually called by the {@link Roo.data.Store} which owns the Record.
10776 * Rejects all changes made to the Record since either creation, or the last commit operation.
10777 * Modified fields are reverted to their original values.
10779 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10780 * of reject operations.
10782 reject : function(){
10783 var m = this.modified;
10785 if(typeof m[n] != "function"){
10786 this.data[n] = m[n];
10789 this.dirty = false;
10790 delete this.modified;
10791 this.editing = false;
10793 this.store.afterReject(this);
10798 * Usually called by the {@link Roo.data.Store} which owns the Record.
10799 * Commits all changes made to the Record since either creation, or the last commit operation.
10801 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10802 * of commit operations.
10804 commit : function(){
10805 this.dirty = false;
10806 delete this.modified;
10807 this.editing = false;
10809 this.store.afterCommit(this);
10814 hasError : function(){
10815 return this.error != null;
10819 clearError : function(){
10824 * Creates a copy of this record.
10825 * @param {String} id (optional) A new record id if you don't want to use this record's id
10828 copy : function(newId) {
10829 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10833 * Ext JS Library 1.1.1
10834 * Copyright(c) 2006-2007, Ext JS, LLC.
10836 * Originally Released Under LGPL - original licence link has changed is not relivant.
10839 * <script type="text/javascript">
10845 * @class Roo.data.Store
10846 * @extends Roo.util.Observable
10847 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10848 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10850 * 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
10851 * has no knowledge of the format of the data returned by the Proxy.<br>
10853 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10854 * instances from the data object. These records are cached and made available through accessor functions.
10856 * Creates a new Store.
10857 * @param {Object} config A config object containing the objects needed for the Store to access data,
10858 * and read the data into Records.
10860 Roo.data.Store = function(config){
10861 this.data = new Roo.util.MixedCollection(false);
10862 this.data.getKey = function(o){
10865 this.baseParams = {};
10867 this.paramNames = {
10872 "multisort" : "_multisort"
10875 if(config && config.data){
10876 this.inlineData = config.data;
10877 delete config.data;
10880 Roo.apply(this, config);
10882 if(this.reader){ // reader passed
10883 this.reader = Roo.factory(this.reader, Roo.data);
10884 this.reader.xmodule = this.xmodule || false;
10885 if(!this.recordType){
10886 this.recordType = this.reader.recordType;
10888 if(this.reader.onMetaChange){
10889 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10893 if(this.recordType){
10894 this.fields = this.recordType.prototype.fields;
10896 this.modified = [];
10900 * @event datachanged
10901 * Fires when the data cache has changed, and a widget which is using this Store
10902 * as a Record cache should refresh its view.
10903 * @param {Store} this
10905 datachanged : true,
10907 * @event metachange
10908 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10909 * @param {Store} this
10910 * @param {Object} meta The JSON metadata
10915 * Fires when Records have been added to the Store
10916 * @param {Store} this
10917 * @param {Roo.data.Record[]} records The array of Records added
10918 * @param {Number} index The index at which the record(s) were added
10923 * Fires when a Record has been removed from the Store
10924 * @param {Store} this
10925 * @param {Roo.data.Record} record The Record that was removed
10926 * @param {Number} index The index at which the record was removed
10931 * Fires when a Record has been updated
10932 * @param {Store} this
10933 * @param {Roo.data.Record} record The Record that was updated
10934 * @param {String} operation The update operation being performed. Value may be one of:
10936 Roo.data.Record.EDIT
10937 Roo.data.Record.REJECT
10938 Roo.data.Record.COMMIT
10944 * Fires when the data cache has been cleared.
10945 * @param {Store} this
10949 * @event beforeload
10950 * Fires before a request is made for a new data object. If the beforeload handler returns false
10951 * the load action will be canceled.
10952 * @param {Store} this
10953 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10957 * @event beforeloadadd
10958 * Fires after a new set of Records has been loaded.
10959 * @param {Store} this
10960 * @param {Roo.data.Record[]} records The Records that were loaded
10961 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10963 beforeloadadd : true,
10966 * Fires after a new set of Records has been loaded, before they are added to the store.
10967 * @param {Store} this
10968 * @param {Roo.data.Record[]} records The Records that were loaded
10969 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10970 * @params {Object} return from reader
10974 * @event loadexception
10975 * Fires if an exception occurs in the Proxy during loading.
10976 * Called with the signature of the Proxy's "loadexception" event.
10977 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10980 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10981 * @param {Object} load options
10982 * @param {Object} jsonData from your request (normally this contains the Exception)
10984 loadexception : true
10988 this.proxy = Roo.factory(this.proxy, Roo.data);
10989 this.proxy.xmodule = this.xmodule || false;
10990 this.relayEvents(this.proxy, ["loadexception"]);
10992 this.sortToggle = {};
10993 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10995 Roo.data.Store.superclass.constructor.call(this);
10997 if(this.inlineData){
10998 this.loadData(this.inlineData);
10999 delete this.inlineData;
11003 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11005 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11006 * without a remote query - used by combo/forms at present.
11010 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11013 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11016 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11017 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11020 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11021 * on any HTTP request
11024 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11027 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11031 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11032 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11034 remoteSort : false,
11037 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11038 * loaded or when a record is removed. (defaults to false).
11040 pruneModifiedRecords : false,
11043 lastOptions : null,
11046 * Add Records to the Store and fires the add event.
11047 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11049 add : function(records){
11050 records = [].concat(records);
11051 for(var i = 0, len = records.length; i < len; i++){
11052 records[i].join(this);
11054 var index = this.data.length;
11055 this.data.addAll(records);
11056 this.fireEvent("add", this, records, index);
11060 * Remove a Record from the Store and fires the remove event.
11061 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11063 remove : function(record){
11064 var index = this.data.indexOf(record);
11065 this.data.removeAt(index);
11066 if(this.pruneModifiedRecords){
11067 this.modified.remove(record);
11069 this.fireEvent("remove", this, record, index);
11073 * Remove all Records from the Store and fires the clear event.
11075 removeAll : function(){
11077 if(this.pruneModifiedRecords){
11078 this.modified = [];
11080 this.fireEvent("clear", this);
11084 * Inserts Records to the Store at the given index and fires the add event.
11085 * @param {Number} index The start index at which to insert the passed Records.
11086 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11088 insert : function(index, records){
11089 records = [].concat(records);
11090 for(var i = 0, len = records.length; i < len; i++){
11091 this.data.insert(index, records[i]);
11092 records[i].join(this);
11094 this.fireEvent("add", this, records, index);
11098 * Get the index within the cache of the passed Record.
11099 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11100 * @return {Number} The index of the passed Record. Returns -1 if not found.
11102 indexOf : function(record){
11103 return this.data.indexOf(record);
11107 * Get the index within the cache of the Record with the passed id.
11108 * @param {String} id The id of the Record to find.
11109 * @return {Number} The index of the Record. Returns -1 if not found.
11111 indexOfId : function(id){
11112 return this.data.indexOfKey(id);
11116 * Get the Record with the specified id.
11117 * @param {String} id The id of the Record to find.
11118 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11120 getById : function(id){
11121 return this.data.key(id);
11125 * Get the Record at the specified index.
11126 * @param {Number} index The index of the Record to find.
11127 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11129 getAt : function(index){
11130 return this.data.itemAt(index);
11134 * Returns a range of Records between specified indices.
11135 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11136 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11137 * @return {Roo.data.Record[]} An array of Records
11139 getRange : function(start, end){
11140 return this.data.getRange(start, end);
11144 storeOptions : function(o){
11145 o = Roo.apply({}, o);
11148 this.lastOptions = o;
11152 * Loads the Record cache from the configured Proxy using the configured Reader.
11154 * If using remote paging, then the first load call must specify the <em>start</em>
11155 * and <em>limit</em> properties in the options.params property to establish the initial
11156 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11158 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11159 * and this call will return before the new data has been loaded. Perform any post-processing
11160 * in a callback function, or in a "load" event handler.</strong>
11162 * @param {Object} options An object containing properties which control loading options:<ul>
11163 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11164 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11165 * passed the following arguments:<ul>
11166 * <li>r : Roo.data.Record[]</li>
11167 * <li>options: Options object from the load call</li>
11168 * <li>success: Boolean success indicator</li></ul></li>
11169 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11170 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11173 load : function(options){
11174 options = options || {};
11175 if(this.fireEvent("beforeload", this, options) !== false){
11176 this.storeOptions(options);
11177 var p = Roo.apply(options.params || {}, this.baseParams);
11178 // if meta was not loaded from remote source.. try requesting it.
11179 if (!this.reader.metaFromRemote) {
11180 p._requestMeta = 1;
11182 if(this.sortInfo && this.remoteSort){
11183 var pn = this.paramNames;
11184 p[pn["sort"]] = this.sortInfo.field;
11185 p[pn["dir"]] = this.sortInfo.direction;
11187 if (this.multiSort) {
11188 var pn = this.paramNames;
11189 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11192 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11197 * Reloads the Record cache from the configured Proxy using the configured Reader and
11198 * the options from the last load operation performed.
11199 * @param {Object} options (optional) An object containing properties which may override the options
11200 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11201 * the most recently used options are reused).
11203 reload : function(options){
11204 this.load(Roo.applyIf(options||{}, this.lastOptions));
11208 // Called as a callback by the Reader during a load operation.
11209 loadRecords : function(o, options, success){
11210 if(!o || success === false){
11211 if(success !== false){
11212 this.fireEvent("load", this, [], options, o);
11214 if(options.callback){
11215 options.callback.call(options.scope || this, [], options, false);
11219 // if data returned failure - throw an exception.
11220 if (o.success === false) {
11221 // show a message if no listener is registered.
11222 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11223 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11225 // loadmask wil be hooked into this..
11226 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11229 var r = o.records, t = o.totalRecords || r.length;
11231 this.fireEvent("beforeloadadd", this, r, options, o);
11233 if(!options || options.add !== true){
11234 if(this.pruneModifiedRecords){
11235 this.modified = [];
11237 for(var i = 0, len = r.length; i < len; i++){
11241 this.data = this.snapshot;
11242 delete this.snapshot;
11245 this.data.addAll(r);
11246 this.totalLength = t;
11248 this.fireEvent("datachanged", this);
11250 this.totalLength = Math.max(t, this.data.length+r.length);
11254 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11256 var e = new Roo.data.Record({});
11258 e.set(this.parent.displayField, this.parent.emptyTitle);
11259 e.set(this.parent.valueField, '');
11264 this.fireEvent("load", this, r, options, o);
11265 if(options.callback){
11266 options.callback.call(options.scope || this, r, options, true);
11272 * Loads data from a passed data block. A Reader which understands the format of the data
11273 * must have been configured in the constructor.
11274 * @param {Object} data The data block from which to read the Records. The format of the data expected
11275 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11276 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11278 loadData : function(o, append){
11279 var r = this.reader.readRecords(o);
11280 this.loadRecords(r, {add: append}, true);
11284 * Gets the number of cached records.
11286 * <em>If using paging, this may not be the total size of the dataset. If the data object
11287 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11288 * the data set size</em>
11290 getCount : function(){
11291 return this.data.length || 0;
11295 * Gets the total number of records in the dataset as returned by the server.
11297 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11298 * the dataset size</em>
11300 getTotalCount : function(){
11301 return this.totalLength || 0;
11305 * Returns the sort state of the Store as an object with two properties:
11307 field {String} The name of the field by which the Records are sorted
11308 direction {String} The sort order, "ASC" or "DESC"
11311 getSortState : function(){
11312 return this.sortInfo;
11316 applySort : function(){
11317 if(this.sortInfo && !this.remoteSort){
11318 var s = this.sortInfo, f = s.field;
11319 var st = this.fields.get(f).sortType;
11320 var fn = function(r1, r2){
11321 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11322 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11324 this.data.sort(s.direction, fn);
11325 if(this.snapshot && this.snapshot != this.data){
11326 this.snapshot.sort(s.direction, fn);
11332 * Sets the default sort column and order to be used by the next load operation.
11333 * @param {String} fieldName The name of the field to sort by.
11334 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11336 setDefaultSort : function(field, dir){
11337 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11341 * Sort the Records.
11342 * If remote sorting is used, the sort is performed on the server, and the cache is
11343 * reloaded. If local sorting is used, the cache is sorted internally.
11344 * @param {String} fieldName The name of the field to sort by.
11345 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11347 sort : function(fieldName, dir){
11348 var f = this.fields.get(fieldName);
11350 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11352 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11353 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11358 this.sortToggle[f.name] = dir;
11359 this.sortInfo = {field: f.name, direction: dir};
11360 if(!this.remoteSort){
11362 this.fireEvent("datachanged", this);
11364 this.load(this.lastOptions);
11369 * Calls the specified function for each of the Records in the cache.
11370 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11371 * Returning <em>false</em> aborts and exits the iteration.
11372 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11374 each : function(fn, scope){
11375 this.data.each(fn, scope);
11379 * Gets all records modified since the last commit. Modified records are persisted across load operations
11380 * (e.g., during paging).
11381 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11383 getModifiedRecords : function(){
11384 return this.modified;
11388 createFilterFn : function(property, value, anyMatch){
11389 if(!value.exec){ // not a regex
11390 value = String(value);
11391 if(value.length == 0){
11394 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11396 return function(r){
11397 return value.test(r.data[property]);
11402 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11403 * @param {String} property A field on your records
11404 * @param {Number} start The record index to start at (defaults to 0)
11405 * @param {Number} end The last record index to include (defaults to length - 1)
11406 * @return {Number} The sum
11408 sum : function(property, start, end){
11409 var rs = this.data.items, v = 0;
11410 start = start || 0;
11411 end = (end || end === 0) ? end : rs.length-1;
11413 for(var i = start; i <= end; i++){
11414 v += (rs[i].data[property] || 0);
11420 * Filter the records by a specified property.
11421 * @param {String} field A field on your records
11422 * @param {String/RegExp} value Either a string that the field
11423 * should start with or a RegExp to test against the field
11424 * @param {Boolean} anyMatch True to match any part not just the beginning
11426 filter : function(property, value, anyMatch){
11427 var fn = this.createFilterFn(property, value, anyMatch);
11428 return fn ? this.filterBy(fn) : this.clearFilter();
11432 * Filter by a function. The specified function will be called with each
11433 * record in this data source. If the function returns true the record is included,
11434 * otherwise it is filtered.
11435 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11436 * @param {Object} scope (optional) The scope of the function (defaults to this)
11438 filterBy : function(fn, scope){
11439 this.snapshot = this.snapshot || this.data;
11440 this.data = this.queryBy(fn, scope||this);
11441 this.fireEvent("datachanged", this);
11445 * Query the records by a specified property.
11446 * @param {String} field A field on your records
11447 * @param {String/RegExp} value Either a string that the field
11448 * should start with or a RegExp to test against the field
11449 * @param {Boolean} anyMatch True to match any part not just the beginning
11450 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11452 query : function(property, value, anyMatch){
11453 var fn = this.createFilterFn(property, value, anyMatch);
11454 return fn ? this.queryBy(fn) : this.data.clone();
11458 * Query by a function. The specified function will be called with each
11459 * record in this data source. If the function returns true the record is included
11461 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11462 * @param {Object} scope (optional) The scope of the function (defaults to this)
11463 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11465 queryBy : function(fn, scope){
11466 var data = this.snapshot || this.data;
11467 return data.filterBy(fn, scope||this);
11471 * Collects unique values for a particular dataIndex from this store.
11472 * @param {String} dataIndex The property to collect
11473 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11474 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11475 * @return {Array} An array of the unique values
11477 collect : function(dataIndex, allowNull, bypassFilter){
11478 var d = (bypassFilter === true && this.snapshot) ?
11479 this.snapshot.items : this.data.items;
11480 var v, sv, r = [], l = {};
11481 for(var i = 0, len = d.length; i < len; i++){
11482 v = d[i].data[dataIndex];
11484 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11493 * Revert to a view of the Record cache with no filtering applied.
11494 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11496 clearFilter : function(suppressEvent){
11497 if(this.snapshot && this.snapshot != this.data){
11498 this.data = this.snapshot;
11499 delete this.snapshot;
11500 if(suppressEvent !== true){
11501 this.fireEvent("datachanged", this);
11507 afterEdit : function(record){
11508 if(this.modified.indexOf(record) == -1){
11509 this.modified.push(record);
11511 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11515 afterReject : function(record){
11516 this.modified.remove(record);
11517 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11521 afterCommit : function(record){
11522 this.modified.remove(record);
11523 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11527 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11528 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11530 commitChanges : function(){
11531 var m = this.modified.slice(0);
11532 this.modified = [];
11533 for(var i = 0, len = m.length; i < len; i++){
11539 * Cancel outstanding changes on all changed records.
11541 rejectChanges : function(){
11542 var m = this.modified.slice(0);
11543 this.modified = [];
11544 for(var i = 0, len = m.length; i < len; i++){
11549 onMetaChange : function(meta, rtype, o){
11550 this.recordType = rtype;
11551 this.fields = rtype.prototype.fields;
11552 delete this.snapshot;
11553 this.sortInfo = meta.sortInfo || this.sortInfo;
11554 this.modified = [];
11555 this.fireEvent('metachange', this, this.reader.meta);
11558 moveIndex : function(data, type)
11560 var index = this.indexOf(data);
11562 var newIndex = index + type;
11566 this.insert(newIndex, data);
11571 * Ext JS Library 1.1.1
11572 * Copyright(c) 2006-2007, Ext JS, LLC.
11574 * Originally Released Under LGPL - original licence link has changed is not relivant.
11577 * <script type="text/javascript">
11581 * @class Roo.data.SimpleStore
11582 * @extends Roo.data.Store
11583 * Small helper class to make creating Stores from Array data easier.
11584 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11585 * @cfg {Array} fields An array of field definition objects, or field name strings.
11586 * @cfg {Array} data The multi-dimensional array of data
11588 * @param {Object} config
11590 Roo.data.SimpleStore = function(config){
11591 Roo.data.SimpleStore.superclass.constructor.call(this, {
11593 reader: new Roo.data.ArrayReader({
11596 Roo.data.Record.create(config.fields)
11598 proxy : new Roo.data.MemoryProxy(config.data)
11602 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11604 * Ext JS Library 1.1.1
11605 * Copyright(c) 2006-2007, Ext JS, LLC.
11607 * Originally Released Under LGPL - original licence link has changed is not relivant.
11610 * <script type="text/javascript">
11615 * @extends Roo.data.Store
11616 * @class Roo.data.JsonStore
11617 * Small helper class to make creating Stores for JSON data easier. <br/>
11619 var store = new Roo.data.JsonStore({
11620 url: 'get-images.php',
11622 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11625 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11626 * JsonReader and HttpProxy (unless inline data is provided).</b>
11627 * @cfg {Array} fields An array of field definition objects, or field name strings.
11629 * @param {Object} config
11631 Roo.data.JsonStore = function(c){
11632 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11633 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11634 reader: new Roo.data.JsonReader(c, c.fields)
11637 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11639 * Ext JS Library 1.1.1
11640 * Copyright(c) 2006-2007, Ext JS, LLC.
11642 * Originally Released Under LGPL - original licence link has changed is not relivant.
11645 * <script type="text/javascript">
11649 Roo.data.Field = function(config){
11650 if(typeof config == "string"){
11651 config = {name: config};
11653 Roo.apply(this, config);
11656 this.type = "auto";
11659 var st = Roo.data.SortTypes;
11660 // named sortTypes are supported, here we look them up
11661 if(typeof this.sortType == "string"){
11662 this.sortType = st[this.sortType];
11665 // set default sortType for strings and dates
11666 if(!this.sortType){
11669 this.sortType = st.asUCString;
11672 this.sortType = st.asDate;
11675 this.sortType = st.none;
11680 var stripRe = /[\$,%]/g;
11682 // prebuilt conversion function for this field, instead of
11683 // switching every time we're reading a value
11685 var cv, dateFormat = this.dateFormat;
11690 cv = function(v){ return v; };
11693 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11697 return v !== undefined && v !== null && v !== '' ?
11698 parseInt(String(v).replace(stripRe, ""), 10) : '';
11703 return v !== undefined && v !== null && v !== '' ?
11704 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11709 cv = function(v){ return v === true || v === "true" || v == 1; };
11716 if(v instanceof Date){
11720 if(dateFormat == "timestamp"){
11721 return new Date(v*1000);
11723 return Date.parseDate(v, dateFormat);
11725 var parsed = Date.parse(v);
11726 return parsed ? new Date(parsed) : null;
11735 Roo.data.Field.prototype = {
11743 * Ext JS Library 1.1.1
11744 * Copyright(c) 2006-2007, Ext JS, LLC.
11746 * Originally Released Under LGPL - original licence link has changed is not relivant.
11749 * <script type="text/javascript">
11752 // Base class for reading structured data from a data source. This class is intended to be
11753 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11756 * @class Roo.data.DataReader
11757 * Base class for reading structured data from a data source. This class is intended to be
11758 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11761 Roo.data.DataReader = function(meta, recordType){
11765 this.recordType = recordType instanceof Array ?
11766 Roo.data.Record.create(recordType) : recordType;
11769 Roo.data.DataReader.prototype = {
11771 * Create an empty record
11772 * @param {Object} data (optional) - overlay some values
11773 * @return {Roo.data.Record} record created.
11775 newRow : function(d) {
11777 this.recordType.prototype.fields.each(function(c) {
11779 case 'int' : da[c.name] = 0; break;
11780 case 'date' : da[c.name] = new Date(); break;
11781 case 'float' : da[c.name] = 0.0; break;
11782 case 'boolean' : da[c.name] = false; break;
11783 default : da[c.name] = ""; break;
11787 return new this.recordType(Roo.apply(da, d));
11792 * Ext JS Library 1.1.1
11793 * Copyright(c) 2006-2007, Ext JS, LLC.
11795 * Originally Released Under LGPL - original licence link has changed is not relivant.
11798 * <script type="text/javascript">
11802 * @class Roo.data.DataProxy
11803 * @extends Roo.data.Observable
11804 * This class is an abstract base class for implementations which provide retrieval of
11805 * unformatted data objects.<br>
11807 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11808 * (of the appropriate type which knows how to parse the data object) to provide a block of
11809 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11811 * Custom implementations must implement the load method as described in
11812 * {@link Roo.data.HttpProxy#load}.
11814 Roo.data.DataProxy = function(){
11817 * @event beforeload
11818 * Fires before a network request is made to retrieve a data object.
11819 * @param {Object} This DataProxy object.
11820 * @param {Object} params The params parameter to the load function.
11825 * Fires before the load method's callback is called.
11826 * @param {Object} This DataProxy object.
11827 * @param {Object} o The data object.
11828 * @param {Object} arg The callback argument object passed to the load function.
11832 * @event loadexception
11833 * Fires if an Exception occurs during data retrieval.
11834 * @param {Object} This DataProxy object.
11835 * @param {Object} o The data object.
11836 * @param {Object} arg The callback argument object passed to the load function.
11837 * @param {Object} e The Exception.
11839 loadexception : true
11841 Roo.data.DataProxy.superclass.constructor.call(this);
11844 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11847 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11851 * Ext JS Library 1.1.1
11852 * Copyright(c) 2006-2007, Ext JS, LLC.
11854 * Originally Released Under LGPL - original licence link has changed is not relivant.
11857 * <script type="text/javascript">
11860 * @class Roo.data.MemoryProxy
11861 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11862 * to the Reader when its load method is called.
11864 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11866 Roo.data.MemoryProxy = function(data){
11870 Roo.data.MemoryProxy.superclass.constructor.call(this);
11874 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11877 * Load data from the requested source (in this case an in-memory
11878 * data object passed to the constructor), read the data object into
11879 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11880 * process that block using the passed callback.
11881 * @param {Object} params This parameter is not used by the MemoryProxy class.
11882 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11883 * object into a block of Roo.data.Records.
11884 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11885 * The function must be passed <ul>
11886 * <li>The Record block object</li>
11887 * <li>The "arg" argument from the load function</li>
11888 * <li>A boolean success indicator</li>
11890 * @param {Object} scope The scope in which to call the callback
11891 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11893 load : function(params, reader, callback, scope, arg){
11894 params = params || {};
11897 result = reader.readRecords(this.data);
11899 this.fireEvent("loadexception", this, arg, null, e);
11900 callback.call(scope, null, arg, false);
11903 callback.call(scope, result, arg, true);
11907 update : function(params, records){
11912 * Ext JS Library 1.1.1
11913 * Copyright(c) 2006-2007, Ext JS, LLC.
11915 * Originally Released Under LGPL - original licence link has changed is not relivant.
11918 * <script type="text/javascript">
11921 * @class Roo.data.HttpProxy
11922 * @extends Roo.data.DataProxy
11923 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11924 * configured to reference a certain URL.<br><br>
11926 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11927 * from which the running page was served.<br><br>
11929 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11931 * Be aware that to enable the browser to parse an XML document, the server must set
11932 * the Content-Type header in the HTTP response to "text/xml".
11934 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11935 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11936 * will be used to make the request.
11938 Roo.data.HttpProxy = function(conn){
11939 Roo.data.HttpProxy.superclass.constructor.call(this);
11940 // is conn a conn config or a real conn?
11942 this.useAjax = !conn || !conn.events;
11946 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11947 // thse are take from connection...
11950 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11953 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11954 * extra parameters to each request made by this object. (defaults to undefined)
11957 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11958 * to each request made by this object. (defaults to undefined)
11961 * @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)
11964 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11967 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11973 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11977 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11978 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11979 * a finer-grained basis than the DataProxy events.
11981 getConnection : function(){
11982 return this.useAjax ? Roo.Ajax : this.conn;
11986 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11987 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11988 * process that block using the passed callback.
11989 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11990 * for the request to the remote server.
11991 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11992 * object into a block of Roo.data.Records.
11993 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11994 * The function must be passed <ul>
11995 * <li>The Record block object</li>
11996 * <li>The "arg" argument from the load function</li>
11997 * <li>A boolean success indicator</li>
11999 * @param {Object} scope The scope in which to call the callback
12000 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12002 load : function(params, reader, callback, scope, arg){
12003 if(this.fireEvent("beforeload", this, params) !== false){
12005 params : params || {},
12007 callback : callback,
12012 callback : this.loadResponse,
12016 Roo.applyIf(o, this.conn);
12017 if(this.activeRequest){
12018 Roo.Ajax.abort(this.activeRequest);
12020 this.activeRequest = Roo.Ajax.request(o);
12022 this.conn.request(o);
12025 callback.call(scope||this, null, arg, false);
12030 loadResponse : function(o, success, response){
12031 delete this.activeRequest;
12033 this.fireEvent("loadexception", this, o, response);
12034 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12039 result = o.reader.read(response);
12041 this.fireEvent("loadexception", this, o, response, e);
12042 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12046 this.fireEvent("load", this, o, o.request.arg);
12047 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12051 update : function(dataSet){
12056 updateResponse : function(dataSet){
12061 * Ext JS Library 1.1.1
12062 * Copyright(c) 2006-2007, Ext JS, LLC.
12064 * Originally Released Under LGPL - original licence link has changed is not relivant.
12067 * <script type="text/javascript">
12071 * @class Roo.data.ScriptTagProxy
12072 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12073 * other than the originating domain of the running page.<br><br>
12075 * <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
12076 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12078 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12079 * source code that is used as the source inside a <script> tag.<br><br>
12081 * In order for the browser to process the returned data, the server must wrap the data object
12082 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12083 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12084 * depending on whether the callback name was passed:
12087 boolean scriptTag = false;
12088 String cb = request.getParameter("callback");
12091 response.setContentType("text/javascript");
12093 response.setContentType("application/x-json");
12095 Writer out = response.getWriter();
12097 out.write(cb + "(");
12099 out.print(dataBlock.toJsonString());
12106 * @param {Object} config A configuration object.
12108 Roo.data.ScriptTagProxy = function(config){
12109 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12110 Roo.apply(this, config);
12111 this.head = document.getElementsByTagName("head")[0];
12114 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12116 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12118 * @cfg {String} url The URL from which to request the data object.
12121 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12125 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12126 * the server the name of the callback function set up by the load call to process the returned data object.
12127 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12128 * javascript output which calls this named function passing the data object as its only parameter.
12130 callbackParam : "callback",
12132 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12133 * name to the request.
12138 * Load data from the configured URL, read the data object into
12139 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12140 * process that block using the passed callback.
12141 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12142 * for the request to the remote server.
12143 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12144 * object into a block of Roo.data.Records.
12145 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12146 * The function must be passed <ul>
12147 * <li>The Record block object</li>
12148 * <li>The "arg" argument from the load function</li>
12149 * <li>A boolean success indicator</li>
12151 * @param {Object} scope The scope in which to call the callback
12152 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12154 load : function(params, reader, callback, scope, arg){
12155 if(this.fireEvent("beforeload", this, params) !== false){
12157 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12159 var url = this.url;
12160 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12162 url += "&_dc=" + (new Date().getTime());
12164 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12167 cb : "stcCallback"+transId,
12168 scriptId : "stcScript"+transId,
12172 callback : callback,
12178 window[trans.cb] = function(o){
12179 conn.handleResponse(o, trans);
12182 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12184 if(this.autoAbort !== false){
12188 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12190 var script = document.createElement("script");
12191 script.setAttribute("src", url);
12192 script.setAttribute("type", "text/javascript");
12193 script.setAttribute("id", trans.scriptId);
12194 this.head.appendChild(script);
12196 this.trans = trans;
12198 callback.call(scope||this, null, arg, false);
12203 isLoading : function(){
12204 return this.trans ? true : false;
12208 * Abort the current server request.
12210 abort : function(){
12211 if(this.isLoading()){
12212 this.destroyTrans(this.trans);
12217 destroyTrans : function(trans, isLoaded){
12218 this.head.removeChild(document.getElementById(trans.scriptId));
12219 clearTimeout(trans.timeoutId);
12221 window[trans.cb] = undefined;
12223 delete window[trans.cb];
12226 // if hasn't been loaded, wait for load to remove it to prevent script error
12227 window[trans.cb] = function(){
12228 window[trans.cb] = undefined;
12230 delete window[trans.cb];
12237 handleResponse : function(o, trans){
12238 this.trans = false;
12239 this.destroyTrans(trans, true);
12242 result = trans.reader.readRecords(o);
12244 this.fireEvent("loadexception", this, o, trans.arg, e);
12245 trans.callback.call(trans.scope||window, null, trans.arg, false);
12248 this.fireEvent("load", this, o, trans.arg);
12249 trans.callback.call(trans.scope||window, result, trans.arg, true);
12253 handleFailure : function(trans){
12254 this.trans = false;
12255 this.destroyTrans(trans, false);
12256 this.fireEvent("loadexception", this, null, trans.arg);
12257 trans.callback.call(trans.scope||window, null, trans.arg, false);
12261 * Ext JS Library 1.1.1
12262 * Copyright(c) 2006-2007, Ext JS, LLC.
12264 * Originally Released Under LGPL - original licence link has changed is not relivant.
12267 * <script type="text/javascript">
12271 * @class Roo.data.JsonReader
12272 * @extends Roo.data.DataReader
12273 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12274 * based on mappings in a provided Roo.data.Record constructor.
12276 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12277 * in the reply previously.
12282 var RecordDef = Roo.data.Record.create([
12283 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12284 {name: 'occupation'} // This field will use "occupation" as the mapping.
12286 var myReader = new Roo.data.JsonReader({
12287 totalProperty: "results", // The property which contains the total dataset size (optional)
12288 root: "rows", // The property which contains an Array of row objects
12289 id: "id" // The property within each row object that provides an ID for the record (optional)
12293 * This would consume a JSON file like this:
12295 { 'results': 2, 'rows': [
12296 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12297 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12300 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12301 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12302 * paged from the remote server.
12303 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12304 * @cfg {String} root name of the property which contains the Array of row objects.
12305 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12306 * @cfg {Array} fields Array of field definition objects
12308 * Create a new JsonReader
12309 * @param {Object} meta Metadata configuration options
12310 * @param {Object} recordType Either an Array of field definition objects,
12311 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12313 Roo.data.JsonReader = function(meta, recordType){
12316 // set some defaults:
12317 Roo.applyIf(meta, {
12318 totalProperty: 'total',
12319 successProperty : 'success',
12324 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12326 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12329 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12330 * Used by Store query builder to append _requestMeta to params.
12333 metaFromRemote : false,
12335 * This method is only used by a DataProxy which has retrieved data from a remote server.
12336 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12337 * @return {Object} data A data block which is used by an Roo.data.Store object as
12338 * a cache of Roo.data.Records.
12340 read : function(response){
12341 var json = response.responseText;
12343 var o = /* eval:var:o */ eval("("+json+")");
12345 throw {message: "JsonReader.read: Json object not found"};
12351 this.metaFromRemote = true;
12352 this.meta = o.metaData;
12353 this.recordType = Roo.data.Record.create(o.metaData.fields);
12354 this.onMetaChange(this.meta, this.recordType, o);
12356 return this.readRecords(o);
12359 // private function a store will implement
12360 onMetaChange : function(meta, recordType, o){
12367 simpleAccess: function(obj, subsc) {
12374 getJsonAccessor: function(){
12376 return function(expr) {
12378 return(re.test(expr))
12379 ? new Function("obj", "return obj." + expr)
12384 return Roo.emptyFn;
12389 * Create a data block containing Roo.data.Records from an XML document.
12390 * @param {Object} o An object which contains an Array of row objects in the property specified
12391 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12392 * which contains the total size of the dataset.
12393 * @return {Object} data A data block which is used by an Roo.data.Store object as
12394 * a cache of Roo.data.Records.
12396 readRecords : function(o){
12398 * After any data loads, the raw JSON data is available for further custom processing.
12402 var s = this.meta, Record = this.recordType,
12403 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12405 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12407 if(s.totalProperty) {
12408 this.getTotal = this.getJsonAccessor(s.totalProperty);
12410 if(s.successProperty) {
12411 this.getSuccess = this.getJsonAccessor(s.successProperty);
12413 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12415 var g = this.getJsonAccessor(s.id);
12416 this.getId = function(rec) {
12418 return (r === undefined || r === "") ? null : r;
12421 this.getId = function(){return null;};
12424 for(var jj = 0; jj < fl; jj++){
12426 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12427 this.ef[jj] = this.getJsonAccessor(map);
12431 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12432 if(s.totalProperty){
12433 var vt = parseInt(this.getTotal(o), 10);
12438 if(s.successProperty){
12439 var vs = this.getSuccess(o);
12440 if(vs === false || vs === 'false'){
12445 for(var i = 0; i < c; i++){
12448 var id = this.getId(n);
12449 for(var j = 0; j < fl; j++){
12451 var v = this.ef[j](n);
12453 Roo.log('missing convert for ' + f.name);
12457 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12459 var record = new Record(values, id);
12461 records[i] = record;
12467 totalRecords : totalRecords
12472 * Ext JS Library 1.1.1
12473 * Copyright(c) 2006-2007, Ext JS, LLC.
12475 * Originally Released Under LGPL - original licence link has changed is not relivant.
12478 * <script type="text/javascript">
12482 * @class Roo.data.ArrayReader
12483 * @extends Roo.data.DataReader
12484 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12485 * Each element of that Array represents a row of data fields. The
12486 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12487 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12491 var RecordDef = Roo.data.Record.create([
12492 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12493 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12495 var myReader = new Roo.data.ArrayReader({
12496 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12500 * This would consume an Array like this:
12502 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12504 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12506 * Create a new JsonReader
12507 * @param {Object} meta Metadata configuration options.
12508 * @param {Object} recordType Either an Array of field definition objects
12509 * as specified to {@link Roo.data.Record#create},
12510 * or an {@link Roo.data.Record} object
12511 * created using {@link Roo.data.Record#create}.
12513 Roo.data.ArrayReader = function(meta, recordType){
12514 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12517 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12519 * Create a data block containing Roo.data.Records from an XML document.
12520 * @param {Object} o An Array of row objects which represents the dataset.
12521 * @return {Object} data A data block which is used by an Roo.data.Store object as
12522 * a cache of Roo.data.Records.
12524 readRecords : function(o){
12525 var sid = this.meta ? this.meta.id : null;
12526 var recordType = this.recordType, fields = recordType.prototype.fields;
12529 for(var i = 0; i < root.length; i++){
12532 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12533 for(var j = 0, jlen = fields.length; j < jlen; j++){
12534 var f = fields.items[j];
12535 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12536 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12538 values[f.name] = v;
12540 var record = new recordType(values, id);
12542 records[records.length] = record;
12546 totalRecords : records.length
12555 * @class Roo.bootstrap.ComboBox
12556 * @extends Roo.bootstrap.TriggerField
12557 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12558 * @cfg {Boolean} append (true|false) default false
12559 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12560 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12561 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12562 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12563 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12564 * @cfg {Boolean} animate default true
12565 * @cfg {Boolean} emptyResultText only for touch device
12566 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12567 * @cfg {String} emptyTitle default ''
12569 * Create a new ComboBox.
12570 * @param {Object} config Configuration options
12572 Roo.bootstrap.ComboBox = function(config){
12573 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12577 * Fires when the dropdown list is expanded
12578 * @param {Roo.bootstrap.ComboBox} combo This combo box
12583 * Fires when the dropdown list is collapsed
12584 * @param {Roo.bootstrap.ComboBox} combo This combo box
12588 * @event beforeselect
12589 * Fires before a list item is selected. Return false to cancel the selection.
12590 * @param {Roo.bootstrap.ComboBox} combo This combo box
12591 * @param {Roo.data.Record} record The data record returned from the underlying store
12592 * @param {Number} index The index of the selected item in the dropdown list
12594 'beforeselect' : true,
12597 * Fires when a list item is selected
12598 * @param {Roo.bootstrap.ComboBox} combo This combo box
12599 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12600 * @param {Number} index The index of the selected item in the dropdown list
12604 * @event beforequery
12605 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12606 * The event object passed has these properties:
12607 * @param {Roo.bootstrap.ComboBox} combo This combo box
12608 * @param {String} query The query
12609 * @param {Boolean} forceAll true to force "all" query
12610 * @param {Boolean} cancel true to cancel the query
12611 * @param {Object} e The query event object
12613 'beforequery': true,
12616 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12617 * @param {Roo.bootstrap.ComboBox} combo This combo box
12622 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12623 * @param {Roo.bootstrap.ComboBox} combo This combo box
12624 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12629 * Fires when the remove value from the combobox array
12630 * @param {Roo.bootstrap.ComboBox} combo This combo box
12634 * @event afterremove
12635 * Fires when the remove value from the combobox array
12636 * @param {Roo.bootstrap.ComboBox} combo This combo box
12638 'afterremove' : true,
12640 * @event specialfilter
12641 * Fires when specialfilter
12642 * @param {Roo.bootstrap.ComboBox} combo This combo box
12644 'specialfilter' : true,
12647 * Fires when tick the element
12648 * @param {Roo.bootstrap.ComboBox} combo This combo box
12652 * @event touchviewdisplay
12653 * Fires when touch view require special display (default is using displayField)
12654 * @param {Roo.bootstrap.ComboBox} combo This combo box
12655 * @param {Object} cfg set html .
12657 'touchviewdisplay' : true
12662 this.tickItems = [];
12664 this.selectedIndex = -1;
12665 if(this.mode == 'local'){
12666 if(config.queryDelay === undefined){
12667 this.queryDelay = 10;
12669 if(config.minChars === undefined){
12675 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12678 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12679 * rendering into an Roo.Editor, defaults to false)
12682 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12683 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12686 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12689 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12690 * the dropdown list (defaults to undefined, with no header element)
12694 * @cfg {String/Roo.Template} tpl The template to use to render the output
12698 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12700 listWidth: undefined,
12702 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12703 * mode = 'remote' or 'text' if mode = 'local')
12705 displayField: undefined,
12708 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12709 * mode = 'remote' or 'value' if mode = 'local').
12710 * Note: use of a valueField requires the user make a selection
12711 * in order for a value to be mapped.
12713 valueField: undefined,
12715 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12720 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12721 * field's data value (defaults to the underlying DOM element's name)
12723 hiddenName: undefined,
12725 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12729 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12731 selectedClass: 'active',
12734 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12738 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12739 * anchor positions (defaults to 'tl-bl')
12741 listAlign: 'tl-bl?',
12743 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12747 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12748 * query specified by the allQuery config option (defaults to 'query')
12750 triggerAction: 'query',
12752 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12753 * (defaults to 4, does not apply if editable = false)
12757 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12758 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12762 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12763 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12767 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12768 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12772 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12773 * when editable = true (defaults to false)
12775 selectOnFocus:false,
12777 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12779 queryParam: 'query',
12781 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12782 * when mode = 'remote' (defaults to 'Loading...')
12784 loadingText: 'Loading...',
12786 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12790 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12794 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12795 * traditional select (defaults to true)
12799 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12803 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12807 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12808 * listWidth has a higher value)
12812 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12813 * allow the user to set arbitrary text into the field (defaults to false)
12815 forceSelection:false,
12817 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12818 * if typeAhead = true (defaults to 250)
12820 typeAheadDelay : 250,
12822 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12823 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12825 valueNotFoundText : undefined,
12827 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12829 blockFocus : false,
12832 * @cfg {Boolean} disableClear Disable showing of clear button.
12834 disableClear : false,
12836 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12838 alwaysQuery : false,
12841 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12846 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12848 invalidClass : "has-warning",
12851 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12853 validClass : "has-success",
12856 * @cfg {Boolean} specialFilter (true|false) special filter default false
12858 specialFilter : false,
12861 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12863 mobileTouchView : true,
12866 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12868 useNativeIOS : false,
12870 ios_options : false,
12882 btnPosition : 'right',
12883 triggerList : true,
12884 showToggleBtn : true,
12886 emptyResultText: 'Empty',
12887 triggerText : 'Select',
12890 // element that contains real text value.. (when hidden is used..)
12892 getAutoCreate : function()
12897 * Render classic select for iso
12900 if(Roo.isIOS && this.useNativeIOS){
12901 cfg = this.getAutoCreateNativeIOS();
12909 if(Roo.isTouch && this.mobileTouchView){
12910 cfg = this.getAutoCreateTouchView();
12917 if(!this.tickable){
12918 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12923 * ComboBox with tickable selections
12926 var align = this.labelAlign || this.parentLabelAlign();
12929 cls : 'form-group roo-combobox-tickable' //input-group
12932 var btn_text_select = '';
12933 var btn_text_done = '';
12934 var btn_text_cancel = '';
12936 if (this.btn_text_show) {
12937 btn_text_select = 'Select';
12938 btn_text_done = 'Done';
12939 btn_text_cancel = 'Cancel';
12944 cls : 'tickable-buttons',
12949 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12950 //html : this.triggerText
12951 html: btn_text_select
12957 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12959 html: btn_text_done
12965 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12967 html: btn_text_cancel
12973 buttons.cn.unshift({
12975 cls: 'roo-select2-search-field-input'
12981 Roo.each(buttons.cn, function(c){
12983 c.cls += ' btn-' + _this.size;
12986 if (_this.disabled) {
12997 cls: 'form-hidden-field'
13001 cls: 'roo-select2-choices',
13005 cls: 'roo-select2-search-field',
13016 cls: 'roo-select2-container input-group roo-select2-container-multi',
13021 // cls: 'typeahead typeahead-long dropdown-menu',
13022 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13027 if(this.hasFeedback && !this.allowBlank){
13031 cls: 'glyphicon form-control-feedback'
13034 combobox.cn.push(feedback);
13038 if (align ==='left' && this.fieldLabel.length) {
13040 cfg.cls += ' roo-form-group-label-left';
13045 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13046 tooltip : 'This field is required'
13051 cls : 'control-label',
13052 html : this.fieldLabel
13064 var labelCfg = cfg.cn[1];
13065 var contentCfg = cfg.cn[2];
13068 if(this.indicatorpos == 'right'){
13074 cls : 'control-label',
13078 html : this.fieldLabel
13082 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13083 tooltip : 'This field is required'
13098 labelCfg = cfg.cn[0];
13099 contentCfg = cfg.cn[1];
13103 if(this.labelWidth > 12){
13104 labelCfg.style = "width: " + this.labelWidth + 'px';
13107 if(this.labelWidth < 13 && this.labelmd == 0){
13108 this.labelmd = this.labelWidth;
13111 if(this.labellg > 0){
13112 labelCfg.cls += ' col-lg-' + this.labellg;
13113 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13116 if(this.labelmd > 0){
13117 labelCfg.cls += ' col-md-' + this.labelmd;
13118 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13121 if(this.labelsm > 0){
13122 labelCfg.cls += ' col-sm-' + this.labelsm;
13123 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13126 if(this.labelxs > 0){
13127 labelCfg.cls += ' col-xs-' + this.labelxs;
13128 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13132 } else if ( this.fieldLabel.length) {
13133 // Roo.log(" label");
13137 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13138 tooltip : 'This field is required'
13142 //cls : 'input-group-addon',
13143 html : this.fieldLabel
13148 if(this.indicatorpos == 'right'){
13152 //cls : 'input-group-addon',
13153 html : this.fieldLabel
13157 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13158 tooltip : 'This field is required'
13167 // Roo.log(" no label && no align");
13174 ['xs','sm','md','lg'].map(function(size){
13175 if (settings[size]) {
13176 cfg.cls += ' col-' + size + '-' + settings[size];
13184 _initEventsCalled : false,
13187 initEvents: function()
13189 if (this._initEventsCalled) { // as we call render... prevent looping...
13192 this._initEventsCalled = true;
13195 throw "can not find store for combo";
13198 this.indicator = this.indicatorEl();
13200 this.store = Roo.factory(this.store, Roo.data);
13201 this.store.parent = this;
13203 // if we are building from html. then this element is so complex, that we can not really
13204 // use the rendered HTML.
13205 // so we have to trash and replace the previous code.
13206 if (Roo.XComponent.build_from_html) {
13207 // remove this element....
13208 var e = this.el.dom, k=0;
13209 while (e ) { e = e.previousSibling; ++k;}
13214 this.rendered = false;
13216 this.render(this.parent().getChildContainer(true), k);
13219 if(Roo.isIOS && this.useNativeIOS){
13220 this.initIOSView();
13228 if(Roo.isTouch && this.mobileTouchView){
13229 this.initTouchView();
13234 this.initTickableEvents();
13238 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13240 if(this.hiddenName){
13242 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13244 this.hiddenField.dom.value =
13245 this.hiddenValue !== undefined ? this.hiddenValue :
13246 this.value !== undefined ? this.value : '';
13248 // prevent input submission
13249 this.el.dom.removeAttribute('name');
13250 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13255 // this.el.dom.setAttribute('autocomplete', 'off');
13258 var cls = 'x-combo-list';
13260 //this.list = new Roo.Layer({
13261 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13267 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13268 _this.list.setWidth(lw);
13271 this.list.on('mouseover', this.onViewOver, this);
13272 this.list.on('mousemove', this.onViewMove, this);
13273 this.list.on('scroll', this.onViewScroll, this);
13276 this.list.swallowEvent('mousewheel');
13277 this.assetHeight = 0;
13280 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13281 this.assetHeight += this.header.getHeight();
13284 this.innerList = this.list.createChild({cls:cls+'-inner'});
13285 this.innerList.on('mouseover', this.onViewOver, this);
13286 this.innerList.on('mousemove', this.onViewMove, this);
13287 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13289 if(this.allowBlank && !this.pageSize && !this.disableClear){
13290 this.footer = this.list.createChild({cls:cls+'-ft'});
13291 this.pageTb = new Roo.Toolbar(this.footer);
13295 this.footer = this.list.createChild({cls:cls+'-ft'});
13296 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13297 {pageSize: this.pageSize});
13301 if (this.pageTb && this.allowBlank && !this.disableClear) {
13303 this.pageTb.add(new Roo.Toolbar.Fill(), {
13304 cls: 'x-btn-icon x-btn-clear',
13306 handler: function()
13309 _this.clearValue();
13310 _this.onSelect(false, -1);
13315 this.assetHeight += this.footer.getHeight();
13320 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13323 this.view = new Roo.View(this.list, this.tpl, {
13324 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13326 //this.view.wrapEl.setDisplayed(false);
13327 this.view.on('click', this.onViewClick, this);
13330 this.store.on('beforeload', this.onBeforeLoad, this);
13331 this.store.on('load', this.onLoad, this);
13332 this.store.on('loadexception', this.onLoadException, this);
13334 if(this.resizable){
13335 this.resizer = new Roo.Resizable(this.list, {
13336 pinned:true, handles:'se'
13338 this.resizer.on('resize', function(r, w, h){
13339 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13340 this.listWidth = w;
13341 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13342 this.restrictHeight();
13344 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13347 if(!this.editable){
13348 this.editable = true;
13349 this.setEditable(false);
13354 if (typeof(this.events.add.listeners) != 'undefined') {
13356 this.addicon = this.wrap.createChild(
13357 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13359 this.addicon.on('click', function(e) {
13360 this.fireEvent('add', this);
13363 if (typeof(this.events.edit.listeners) != 'undefined') {
13365 this.editicon = this.wrap.createChild(
13366 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13367 if (this.addicon) {
13368 this.editicon.setStyle('margin-left', '40px');
13370 this.editicon.on('click', function(e) {
13372 // we fire even if inothing is selected..
13373 this.fireEvent('edit', this, this.lastData );
13379 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13380 "up" : function(e){
13381 this.inKeyMode = true;
13385 "down" : function(e){
13386 if(!this.isExpanded()){
13387 this.onTriggerClick();
13389 this.inKeyMode = true;
13394 "enter" : function(e){
13395 // this.onViewClick();
13399 if(this.fireEvent("specialkey", this, e)){
13400 this.onViewClick(false);
13406 "esc" : function(e){
13410 "tab" : function(e){
13413 if(this.fireEvent("specialkey", this, e)){
13414 this.onViewClick(false);
13422 doRelay : function(foo, bar, hname){
13423 if(hname == 'down' || this.scope.isExpanded()){
13424 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13433 this.queryDelay = Math.max(this.queryDelay || 10,
13434 this.mode == 'local' ? 10 : 250);
13437 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13439 if(this.typeAhead){
13440 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13442 if(this.editable !== false){
13443 this.inputEl().on("keyup", this.onKeyUp, this);
13445 if(this.forceSelection){
13446 this.inputEl().on('blur', this.doForce, this);
13450 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13451 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13455 initTickableEvents: function()
13459 if(this.hiddenName){
13461 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13463 this.hiddenField.dom.value =
13464 this.hiddenValue !== undefined ? this.hiddenValue :
13465 this.value !== undefined ? this.value : '';
13467 // prevent input submission
13468 this.el.dom.removeAttribute('name');
13469 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13474 // this.list = this.el.select('ul.dropdown-menu',true).first();
13476 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13477 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13478 if(this.triggerList){
13479 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13482 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13483 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13485 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13486 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13488 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13489 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13491 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13492 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13493 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13496 this.cancelBtn.hide();
13501 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13502 _this.list.setWidth(lw);
13505 this.list.on('mouseover', this.onViewOver, this);
13506 this.list.on('mousemove', this.onViewMove, this);
13508 this.list.on('scroll', this.onViewScroll, this);
13511 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>';
13514 this.view = new Roo.View(this.list, this.tpl, {
13515 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13518 //this.view.wrapEl.setDisplayed(false);
13519 this.view.on('click', this.onViewClick, this);
13523 this.store.on('beforeload', this.onBeforeLoad, this);
13524 this.store.on('load', this.onLoad, this);
13525 this.store.on('loadexception', this.onLoadException, this);
13528 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13529 "up" : function(e){
13530 this.inKeyMode = true;
13534 "down" : function(e){
13535 this.inKeyMode = true;
13539 "enter" : function(e){
13540 if(this.fireEvent("specialkey", this, e)){
13541 this.onViewClick(false);
13547 "esc" : function(e){
13548 this.onTickableFooterButtonClick(e, false, false);
13551 "tab" : function(e){
13552 this.fireEvent("specialkey", this, e);
13554 this.onTickableFooterButtonClick(e, false, false);
13561 doRelay : function(e, fn, key){
13562 if(this.scope.isExpanded()){
13563 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13572 this.queryDelay = Math.max(this.queryDelay || 10,
13573 this.mode == 'local' ? 10 : 250);
13576 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13578 if(this.typeAhead){
13579 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13582 if(this.editable !== false){
13583 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13586 this.indicator = this.indicatorEl();
13588 if(this.indicator){
13589 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13590 this.indicator.hide();
13595 onDestroy : function(){
13597 this.view.setStore(null);
13598 this.view.el.removeAllListeners();
13599 this.view.el.remove();
13600 this.view.purgeListeners();
13603 this.list.dom.innerHTML = '';
13607 this.store.un('beforeload', this.onBeforeLoad, this);
13608 this.store.un('load', this.onLoad, this);
13609 this.store.un('loadexception', this.onLoadException, this);
13611 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13615 fireKey : function(e){
13616 if(e.isNavKeyPress() && !this.list.isVisible()){
13617 this.fireEvent("specialkey", this, e);
13622 onResize: function(w, h){
13623 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13625 // if(typeof w != 'number'){
13626 // // we do not handle it!?!?
13629 // var tw = this.trigger.getWidth();
13630 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13631 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13633 // this.inputEl().setWidth( this.adjustWidth('input', x));
13635 // //this.trigger.setStyle('left', x+'px');
13637 // if(this.list && this.listWidth === undefined){
13638 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13639 // this.list.setWidth(lw);
13640 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13648 * Allow or prevent the user from directly editing the field text. If false is passed,
13649 * the user will only be able to select from the items defined in the dropdown list. This method
13650 * is the runtime equivalent of setting the 'editable' config option at config time.
13651 * @param {Boolean} value True to allow the user to directly edit the field text
13653 setEditable : function(value){
13654 if(value == this.editable){
13657 this.editable = value;
13659 this.inputEl().dom.setAttribute('readOnly', true);
13660 this.inputEl().on('mousedown', this.onTriggerClick, this);
13661 this.inputEl().addClass('x-combo-noedit');
13663 this.inputEl().dom.setAttribute('readOnly', false);
13664 this.inputEl().un('mousedown', this.onTriggerClick, this);
13665 this.inputEl().removeClass('x-combo-noedit');
13671 onBeforeLoad : function(combo,opts){
13672 if(!this.hasFocus){
13676 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13678 this.restrictHeight();
13679 this.selectedIndex = -1;
13683 onLoad : function(){
13685 this.hasQuery = false;
13687 if(!this.hasFocus){
13691 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13692 this.loading.hide();
13695 if(this.store.getCount() > 0){
13698 this.restrictHeight();
13699 if(this.lastQuery == this.allQuery){
13700 if(this.editable && !this.tickable){
13701 this.inputEl().dom.select();
13705 !this.selectByValue(this.value, true) &&
13708 !this.store.lastOptions ||
13709 typeof(this.store.lastOptions.add) == 'undefined' ||
13710 this.store.lastOptions.add != true
13713 this.select(0, true);
13716 if(this.autoFocus){
13719 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13720 this.taTask.delay(this.typeAheadDelay);
13724 this.onEmptyResults();
13730 onLoadException : function()
13732 this.hasQuery = false;
13734 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13735 this.loading.hide();
13738 if(this.tickable && this.editable){
13743 // only causes errors at present
13744 //Roo.log(this.store.reader.jsonData);
13745 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13747 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13753 onTypeAhead : function(){
13754 if(this.store.getCount() > 0){
13755 var r = this.store.getAt(0);
13756 var newValue = r.data[this.displayField];
13757 var len = newValue.length;
13758 var selStart = this.getRawValue().length;
13760 if(selStart != len){
13761 this.setRawValue(newValue);
13762 this.selectText(selStart, newValue.length);
13768 onSelect : function(record, index){
13770 if(this.fireEvent('beforeselect', this, record, index) !== false){
13772 this.setFromData(index > -1 ? record.data : false);
13775 this.fireEvent('select', this, record, index);
13780 * Returns the currently selected field value or empty string if no value is set.
13781 * @return {String} value The selected value
13783 getValue : function()
13785 if(Roo.isIOS && this.useNativeIOS){
13786 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13790 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13793 if(this.valueField){
13794 return typeof this.value != 'undefined' ? this.value : '';
13796 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13800 getRawValue : function()
13802 if(Roo.isIOS && this.useNativeIOS){
13803 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13806 var v = this.inputEl().getValue();
13812 * Clears any text/value currently set in the field
13814 clearValue : function(){
13816 if(this.hiddenField){
13817 this.hiddenField.dom.value = '';
13820 this.setRawValue('');
13821 this.lastSelectionText = '';
13822 this.lastData = false;
13824 var close = this.closeTriggerEl();
13835 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13836 * will be displayed in the field. If the value does not match the data value of an existing item,
13837 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13838 * Otherwise the field will be blank (although the value will still be set).
13839 * @param {String} value The value to match
13841 setValue : function(v)
13843 if(Roo.isIOS && this.useNativeIOS){
13844 this.setIOSValue(v);
13854 if(this.valueField){
13855 var r = this.findRecord(this.valueField, v);
13857 text = r.data[this.displayField];
13858 }else if(this.valueNotFoundText !== undefined){
13859 text = this.valueNotFoundText;
13862 this.lastSelectionText = text;
13863 if(this.hiddenField){
13864 this.hiddenField.dom.value = v;
13866 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13869 var close = this.closeTriggerEl();
13872 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13878 * @property {Object} the last set data for the element
13883 * Sets the value of the field based on a object which is related to the record format for the store.
13884 * @param {Object} value the value to set as. or false on reset?
13886 setFromData : function(o){
13893 var dv = ''; // display value
13894 var vv = ''; // value value..
13896 if (this.displayField) {
13897 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13899 // this is an error condition!!!
13900 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13903 if(this.valueField){
13904 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13907 var close = this.closeTriggerEl();
13910 if(dv.length || vv * 1 > 0){
13912 this.blockFocus=true;
13918 if(this.hiddenField){
13919 this.hiddenField.dom.value = vv;
13921 this.lastSelectionText = dv;
13922 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13926 // no hidden field.. - we store the value in 'value', but still display
13927 // display field!!!!
13928 this.lastSelectionText = dv;
13929 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13936 reset : function(){
13937 // overridden so that last data is reset..
13944 this.setValue(this.originalValue);
13945 //this.clearInvalid();
13946 this.lastData = false;
13948 this.view.clearSelections();
13954 findRecord : function(prop, value){
13956 if(this.store.getCount() > 0){
13957 this.store.each(function(r){
13958 if(r.data[prop] == value){
13968 getName: function()
13970 // returns hidden if it's set..
13971 if (!this.rendered) {return ''};
13972 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13976 onViewMove : function(e, t){
13977 this.inKeyMode = false;
13981 onViewOver : function(e, t){
13982 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13985 var item = this.view.findItemFromChild(t);
13988 var index = this.view.indexOf(item);
13989 this.select(index, false);
13994 onViewClick : function(view, doFocus, el, e)
13996 var index = this.view.getSelectedIndexes()[0];
13998 var r = this.store.getAt(index);
14002 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14009 Roo.each(this.tickItems, function(v,k){
14011 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14013 _this.tickItems.splice(k, 1);
14015 if(typeof(e) == 'undefined' && view == false){
14016 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14028 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14029 this.tickItems.push(r.data);
14032 if(typeof(e) == 'undefined' && view == false){
14033 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14040 this.onSelect(r, index);
14042 if(doFocus !== false && !this.blockFocus){
14043 this.inputEl().focus();
14048 restrictHeight : function(){
14049 //this.innerList.dom.style.height = '';
14050 //var inner = this.innerList.dom;
14051 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14052 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14053 //this.list.beginUpdate();
14054 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14055 this.list.alignTo(this.inputEl(), this.listAlign);
14056 this.list.alignTo(this.inputEl(), this.listAlign);
14057 //this.list.endUpdate();
14061 onEmptyResults : function(){
14063 if(this.tickable && this.editable){
14064 this.hasFocus = false;
14065 this.restrictHeight();
14073 * Returns true if the dropdown list is expanded, else false.
14075 isExpanded : function(){
14076 return this.list.isVisible();
14080 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14081 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14082 * @param {String} value The data value of the item to select
14083 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14084 * selected item if it is not currently in view (defaults to true)
14085 * @return {Boolean} True if the value matched an item in the list, else false
14087 selectByValue : function(v, scrollIntoView){
14088 if(v !== undefined && v !== null){
14089 var r = this.findRecord(this.valueField || this.displayField, v);
14091 this.select(this.store.indexOf(r), scrollIntoView);
14099 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14100 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14101 * @param {Number} index The zero-based index of the list item to select
14102 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14103 * selected item if it is not currently in view (defaults to true)
14105 select : function(index, scrollIntoView){
14106 this.selectedIndex = index;
14107 this.view.select(index);
14108 if(scrollIntoView !== false){
14109 var el = this.view.getNode(index);
14111 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14114 this.list.scrollChildIntoView(el, false);
14120 selectNext : function(){
14121 var ct = this.store.getCount();
14123 if(this.selectedIndex == -1){
14125 }else if(this.selectedIndex < ct-1){
14126 this.select(this.selectedIndex+1);
14132 selectPrev : function(){
14133 var ct = this.store.getCount();
14135 if(this.selectedIndex == -1){
14137 }else if(this.selectedIndex != 0){
14138 this.select(this.selectedIndex-1);
14144 onKeyUp : function(e){
14145 if(this.editable !== false && !e.isSpecialKey()){
14146 this.lastKey = e.getKey();
14147 this.dqTask.delay(this.queryDelay);
14152 validateBlur : function(){
14153 return !this.list || !this.list.isVisible();
14157 initQuery : function(){
14159 var v = this.getRawValue();
14161 if(this.tickable && this.editable){
14162 v = this.tickableInputEl().getValue();
14169 doForce : function(){
14170 if(this.inputEl().dom.value.length > 0){
14171 this.inputEl().dom.value =
14172 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14178 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14179 * query allowing the query action to be canceled if needed.
14180 * @param {String} query The SQL query to execute
14181 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14182 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14183 * saved in the current store (defaults to false)
14185 doQuery : function(q, forceAll){
14187 if(q === undefined || q === null){
14192 forceAll: forceAll,
14196 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14201 forceAll = qe.forceAll;
14202 if(forceAll === true || (q.length >= this.minChars)){
14204 this.hasQuery = true;
14206 if(this.lastQuery != q || this.alwaysQuery){
14207 this.lastQuery = q;
14208 if(this.mode == 'local'){
14209 this.selectedIndex = -1;
14211 this.store.clearFilter();
14214 if(this.specialFilter){
14215 this.fireEvent('specialfilter', this);
14220 this.store.filter(this.displayField, q);
14223 this.store.fireEvent("datachanged", this.store);
14230 this.store.baseParams[this.queryParam] = q;
14232 var options = {params : this.getParams(q)};
14235 options.add = true;
14236 options.params.start = this.page * this.pageSize;
14239 this.store.load(options);
14242 * this code will make the page width larger, at the beginning, the list not align correctly,
14243 * we should expand the list on onLoad
14244 * so command out it
14249 this.selectedIndex = -1;
14254 this.loadNext = false;
14258 getParams : function(q){
14260 //p[this.queryParam] = q;
14264 p.limit = this.pageSize;
14270 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14272 collapse : function(){
14273 if(!this.isExpanded()){
14279 this.hasFocus = false;
14283 this.cancelBtn.hide();
14284 this.trigger.show();
14287 this.tickableInputEl().dom.value = '';
14288 this.tickableInputEl().blur();
14293 Roo.get(document).un('mousedown', this.collapseIf, this);
14294 Roo.get(document).un('mousewheel', this.collapseIf, this);
14295 if (!this.editable) {
14296 Roo.get(document).un('keydown', this.listKeyPress, this);
14298 this.fireEvent('collapse', this);
14304 collapseIf : function(e){
14305 var in_combo = e.within(this.el);
14306 var in_list = e.within(this.list);
14307 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14309 if (in_combo || in_list || is_list) {
14310 //e.stopPropagation();
14315 this.onTickableFooterButtonClick(e, false, false);
14323 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14325 expand : function(){
14327 if(this.isExpanded() || !this.hasFocus){
14331 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14332 this.list.setWidth(lw);
14338 this.restrictHeight();
14342 this.tickItems = Roo.apply([], this.item);
14345 this.cancelBtn.show();
14346 this.trigger.hide();
14349 this.tickableInputEl().focus();
14354 Roo.get(document).on('mousedown', this.collapseIf, this);
14355 Roo.get(document).on('mousewheel', this.collapseIf, this);
14356 if (!this.editable) {
14357 Roo.get(document).on('keydown', this.listKeyPress, this);
14360 this.fireEvent('expand', this);
14364 // Implements the default empty TriggerField.onTriggerClick function
14365 onTriggerClick : function(e)
14367 Roo.log('trigger click');
14369 if(this.disabled || !this.triggerList){
14374 this.loadNext = false;
14376 if(this.isExpanded()){
14378 if (!this.blockFocus) {
14379 this.inputEl().focus();
14383 this.hasFocus = true;
14384 if(this.triggerAction == 'all') {
14385 this.doQuery(this.allQuery, true);
14387 this.doQuery(this.getRawValue());
14389 if (!this.blockFocus) {
14390 this.inputEl().focus();
14395 onTickableTriggerClick : function(e)
14402 this.loadNext = false;
14403 this.hasFocus = true;
14405 if(this.triggerAction == 'all') {
14406 this.doQuery(this.allQuery, true);
14408 this.doQuery(this.getRawValue());
14412 onSearchFieldClick : function(e)
14414 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14415 this.onTickableFooterButtonClick(e, false, false);
14419 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14424 this.loadNext = false;
14425 this.hasFocus = true;
14427 if(this.triggerAction == 'all') {
14428 this.doQuery(this.allQuery, true);
14430 this.doQuery(this.getRawValue());
14434 listKeyPress : function(e)
14436 //Roo.log('listkeypress');
14437 // scroll to first matching element based on key pres..
14438 if (e.isSpecialKey()) {
14441 var k = String.fromCharCode(e.getKey()).toUpperCase();
14444 var csel = this.view.getSelectedNodes();
14445 var cselitem = false;
14447 var ix = this.view.indexOf(csel[0]);
14448 cselitem = this.store.getAt(ix);
14449 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14455 this.store.each(function(v) {
14457 // start at existing selection.
14458 if (cselitem.id == v.id) {
14464 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14465 match = this.store.indexOf(v);
14471 if (match === false) {
14472 return true; // no more action?
14475 this.view.select(match);
14476 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14477 sn.scrollIntoView(sn.dom.parentNode, false);
14480 onViewScroll : function(e, t){
14482 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){
14486 this.hasQuery = true;
14488 this.loading = this.list.select('.loading', true).first();
14490 if(this.loading === null){
14491 this.list.createChild({
14493 cls: 'loading roo-select2-more-results roo-select2-active',
14494 html: 'Loading more results...'
14497 this.loading = this.list.select('.loading', true).first();
14499 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14501 this.loading.hide();
14504 this.loading.show();
14509 this.loadNext = true;
14511 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14516 addItem : function(o)
14518 var dv = ''; // display value
14520 if (this.displayField) {
14521 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14523 // this is an error condition!!!
14524 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14531 var choice = this.choices.createChild({
14533 cls: 'roo-select2-search-choice',
14542 cls: 'roo-select2-search-choice-close fa fa-times',
14547 }, this.searchField);
14549 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14551 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14559 this.inputEl().dom.value = '';
14564 onRemoveItem : function(e, _self, o)
14566 e.preventDefault();
14568 this.lastItem = Roo.apply([], this.item);
14570 var index = this.item.indexOf(o.data) * 1;
14573 Roo.log('not this item?!');
14577 this.item.splice(index, 1);
14582 this.fireEvent('remove', this, e);
14588 syncValue : function()
14590 if(!this.item.length){
14597 Roo.each(this.item, function(i){
14598 if(_this.valueField){
14599 value.push(i[_this.valueField]);
14606 this.value = value.join(',');
14608 if(this.hiddenField){
14609 this.hiddenField.dom.value = this.value;
14612 this.store.fireEvent("datachanged", this.store);
14617 clearItem : function()
14619 if(!this.multiple){
14625 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14633 if(this.tickable && !Roo.isTouch){
14634 this.view.refresh();
14638 inputEl: function ()
14640 if(Roo.isIOS && this.useNativeIOS){
14641 return this.el.select('select.roo-ios-select', true).first();
14644 if(Roo.isTouch && this.mobileTouchView){
14645 return this.el.select('input.form-control',true).first();
14649 return this.searchField;
14652 return this.el.select('input.form-control',true).first();
14655 onTickableFooterButtonClick : function(e, btn, el)
14657 e.preventDefault();
14659 this.lastItem = Roo.apply([], this.item);
14661 if(btn && btn.name == 'cancel'){
14662 this.tickItems = Roo.apply([], this.item);
14671 Roo.each(this.tickItems, function(o){
14679 validate : function()
14681 if(this.getVisibilityEl().hasClass('hidden')){
14685 var v = this.getRawValue();
14688 v = this.getValue();
14691 if(this.disabled || this.allowBlank || v.length){
14696 this.markInvalid();
14700 tickableInputEl : function()
14702 if(!this.tickable || !this.editable){
14703 return this.inputEl();
14706 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14710 getAutoCreateTouchView : function()
14715 cls: 'form-group' //input-group
14721 type : this.inputType,
14722 cls : 'form-control x-combo-noedit',
14723 autocomplete: 'new-password',
14724 placeholder : this.placeholder || '',
14729 input.name = this.name;
14733 input.cls += ' input-' + this.size;
14736 if (this.disabled) {
14737 input.disabled = true;
14748 inputblock.cls += ' input-group';
14750 inputblock.cn.unshift({
14752 cls : 'input-group-addon',
14757 if(this.removable && !this.multiple){
14758 inputblock.cls += ' roo-removable';
14760 inputblock.cn.push({
14763 cls : 'roo-combo-removable-btn close'
14767 if(this.hasFeedback && !this.allowBlank){
14769 inputblock.cls += ' has-feedback';
14771 inputblock.cn.push({
14773 cls: 'glyphicon form-control-feedback'
14780 inputblock.cls += (this.before) ? '' : ' input-group';
14782 inputblock.cn.push({
14784 cls : 'input-group-addon',
14795 cls: 'form-hidden-field'
14809 cls: 'form-hidden-field'
14813 cls: 'roo-select2-choices',
14817 cls: 'roo-select2-search-field',
14830 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14836 if(!this.multiple && this.showToggleBtn){
14843 if (this.caret != false) {
14846 cls: 'fa fa-' + this.caret
14853 cls : 'input-group-addon btn dropdown-toggle',
14858 cls: 'combobox-clear',
14872 combobox.cls += ' roo-select2-container-multi';
14875 var align = this.labelAlign || this.parentLabelAlign();
14877 if (align ==='left' && this.fieldLabel.length) {
14882 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14883 tooltip : 'This field is required'
14887 cls : 'control-label',
14888 html : this.fieldLabel
14899 var labelCfg = cfg.cn[1];
14900 var contentCfg = cfg.cn[2];
14903 if(this.indicatorpos == 'right'){
14908 cls : 'control-label',
14912 html : this.fieldLabel
14916 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14917 tooltip : 'This field is required'
14930 labelCfg = cfg.cn[0];
14931 contentCfg = cfg.cn[1];
14936 if(this.labelWidth > 12){
14937 labelCfg.style = "width: " + this.labelWidth + 'px';
14940 if(this.labelWidth < 13 && this.labelmd == 0){
14941 this.labelmd = this.labelWidth;
14944 if(this.labellg > 0){
14945 labelCfg.cls += ' col-lg-' + this.labellg;
14946 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14949 if(this.labelmd > 0){
14950 labelCfg.cls += ' col-md-' + this.labelmd;
14951 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14954 if(this.labelsm > 0){
14955 labelCfg.cls += ' col-sm-' + this.labelsm;
14956 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14959 if(this.labelxs > 0){
14960 labelCfg.cls += ' col-xs-' + this.labelxs;
14961 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14965 } else if ( this.fieldLabel.length) {
14969 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14970 tooltip : 'This field is required'
14974 cls : 'control-label',
14975 html : this.fieldLabel
14986 if(this.indicatorpos == 'right'){
14990 cls : 'control-label',
14991 html : this.fieldLabel,
14995 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14996 tooltip : 'This field is required'
15013 var settings = this;
15015 ['xs','sm','md','lg'].map(function(size){
15016 if (settings[size]) {
15017 cfg.cls += ' col-' + size + '-' + settings[size];
15024 initTouchView : function()
15026 this.renderTouchView();
15028 this.touchViewEl.on('scroll', function(){
15029 this.el.dom.scrollTop = 0;
15032 this.originalValue = this.getValue();
15034 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15036 this.inputEl().on("click", this.showTouchView, this);
15037 if (this.triggerEl) {
15038 this.triggerEl.on("click", this.showTouchView, this);
15042 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15043 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15045 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15047 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15048 this.store.on('load', this.onTouchViewLoad, this);
15049 this.store.on('loadexception', this.onTouchViewLoadException, this);
15051 if(this.hiddenName){
15053 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15055 this.hiddenField.dom.value =
15056 this.hiddenValue !== undefined ? this.hiddenValue :
15057 this.value !== undefined ? this.value : '';
15059 this.el.dom.removeAttribute('name');
15060 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15064 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15065 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15068 if(this.removable && !this.multiple){
15069 var close = this.closeTriggerEl();
15071 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15072 close.on('click', this.removeBtnClick, this, close);
15076 * fix the bug in Safari iOS8
15078 this.inputEl().on("focus", function(e){
15079 document.activeElement.blur();
15087 renderTouchView : function()
15089 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15090 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15092 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15093 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15095 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15096 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15097 this.touchViewBodyEl.setStyle('overflow', 'auto');
15099 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15100 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15102 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15103 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15107 showTouchView : function()
15113 this.touchViewHeaderEl.hide();
15115 if(this.modalTitle.length){
15116 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15117 this.touchViewHeaderEl.show();
15120 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15121 this.touchViewEl.show();
15123 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15125 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15126 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15128 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15130 if(this.modalTitle.length){
15131 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15134 this.touchViewBodyEl.setHeight(bodyHeight);
15138 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15140 this.touchViewEl.addClass('in');
15143 this.doTouchViewQuery();
15147 hideTouchView : function()
15149 this.touchViewEl.removeClass('in');
15153 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15155 this.touchViewEl.setStyle('display', 'none');
15160 setTouchViewValue : function()
15167 Roo.each(this.tickItems, function(o){
15172 this.hideTouchView();
15175 doTouchViewQuery : function()
15184 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15188 if(!this.alwaysQuery || this.mode == 'local'){
15189 this.onTouchViewLoad();
15196 onTouchViewBeforeLoad : function(combo,opts)
15202 onTouchViewLoad : function()
15204 if(this.store.getCount() < 1){
15205 this.onTouchViewEmptyResults();
15209 this.clearTouchView();
15211 var rawValue = this.getRawValue();
15213 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15215 this.tickItems = [];
15217 this.store.data.each(function(d, rowIndex){
15218 var row = this.touchViewListGroup.createChild(template);
15220 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15221 row.addClass(d.data.cls);
15224 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15227 html : d.data[this.displayField]
15230 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15231 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15234 row.removeClass('selected');
15235 if(!this.multiple && this.valueField &&
15236 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15239 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15240 row.addClass('selected');
15243 if(this.multiple && this.valueField &&
15244 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15248 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15249 this.tickItems.push(d.data);
15252 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15256 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15258 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15260 if(this.modalTitle.length){
15261 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15264 var listHeight = this.touchViewListGroup.getHeight();
15268 if(firstChecked && listHeight > bodyHeight){
15269 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15274 onTouchViewLoadException : function()
15276 this.hideTouchView();
15279 onTouchViewEmptyResults : function()
15281 this.clearTouchView();
15283 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15285 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15289 clearTouchView : function()
15291 this.touchViewListGroup.dom.innerHTML = '';
15294 onTouchViewClick : function(e, el, o)
15296 e.preventDefault();
15299 var rowIndex = o.rowIndex;
15301 var r = this.store.getAt(rowIndex);
15303 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15305 if(!this.multiple){
15306 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15307 c.dom.removeAttribute('checked');
15310 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15312 this.setFromData(r.data);
15314 var close = this.closeTriggerEl();
15320 this.hideTouchView();
15322 this.fireEvent('select', this, r, rowIndex);
15327 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15328 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15329 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15333 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15334 this.addItem(r.data);
15335 this.tickItems.push(r.data);
15339 getAutoCreateNativeIOS : function()
15342 cls: 'form-group' //input-group,
15347 cls : 'roo-ios-select'
15351 combobox.name = this.name;
15354 if (this.disabled) {
15355 combobox.disabled = true;
15358 var settings = this;
15360 ['xs','sm','md','lg'].map(function(size){
15361 if (settings[size]) {
15362 cfg.cls += ' col-' + size + '-' + settings[size];
15372 initIOSView : function()
15374 this.store.on('load', this.onIOSViewLoad, this);
15379 onIOSViewLoad : function()
15381 if(this.store.getCount() < 1){
15385 this.clearIOSView();
15387 if(this.allowBlank) {
15389 var default_text = '-- SELECT --';
15391 if(this.placeholder.length){
15392 default_text = this.placeholder;
15395 if(this.emptyTitle.length){
15396 default_text += ' - ' + this.emptyTitle + ' -';
15399 var opt = this.inputEl().createChild({
15402 html : default_text
15406 o[this.valueField] = 0;
15407 o[this.displayField] = default_text;
15409 this.ios_options.push({
15416 this.store.data.each(function(d, rowIndex){
15420 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15421 html = d.data[this.displayField];
15426 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15427 value = d.data[this.valueField];
15436 if(this.value == d.data[this.valueField]){
15437 option['selected'] = true;
15440 var opt = this.inputEl().createChild(option);
15442 this.ios_options.push({
15449 this.inputEl().on('change', function(){
15450 this.fireEvent('select', this);
15455 clearIOSView: function()
15457 this.inputEl().dom.innerHTML = '';
15459 this.ios_options = [];
15462 setIOSValue: function(v)
15466 if(!this.ios_options){
15470 Roo.each(this.ios_options, function(opts){
15472 opts.el.dom.removeAttribute('selected');
15474 if(opts.data[this.valueField] != v){
15478 opts.el.dom.setAttribute('selected', true);
15484 * @cfg {Boolean} grow
15488 * @cfg {Number} growMin
15492 * @cfg {Number} growMax
15501 Roo.apply(Roo.bootstrap.ComboBox, {
15505 cls: 'modal-header',
15527 cls: 'list-group-item',
15531 cls: 'roo-combobox-list-group-item-value'
15535 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15549 listItemCheckbox : {
15551 cls: 'list-group-item',
15555 cls: 'roo-combobox-list-group-item-value'
15559 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15575 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15580 cls: 'modal-footer',
15588 cls: 'col-xs-6 text-left',
15591 cls: 'btn btn-danger roo-touch-view-cancel',
15597 cls: 'col-xs-6 text-right',
15600 cls: 'btn btn-success roo-touch-view-ok',
15611 Roo.apply(Roo.bootstrap.ComboBox, {
15613 touchViewTemplate : {
15615 cls: 'modal fade roo-combobox-touch-view',
15619 cls: 'modal-dialog',
15620 style : 'position:fixed', // we have to fix position....
15624 cls: 'modal-content',
15626 Roo.bootstrap.ComboBox.header,
15627 Roo.bootstrap.ComboBox.body,
15628 Roo.bootstrap.ComboBox.footer
15637 * Ext JS Library 1.1.1
15638 * Copyright(c) 2006-2007, Ext JS, LLC.
15640 * Originally Released Under LGPL - original licence link has changed is not relivant.
15643 * <script type="text/javascript">
15648 * @extends Roo.util.Observable
15649 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15650 * This class also supports single and multi selection modes. <br>
15651 * Create a data model bound view:
15653 var store = new Roo.data.Store(...);
15655 var view = new Roo.View({
15657 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15659 singleSelect: true,
15660 selectedClass: "ydataview-selected",
15664 // listen for node click?
15665 view.on("click", function(vw, index, node, e){
15666 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15670 dataModel.load("foobar.xml");
15672 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15674 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15675 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15677 * Note: old style constructor is still suported (container, template, config)
15680 * Create a new View
15681 * @param {Object} config The config object
15684 Roo.View = function(config, depreciated_tpl, depreciated_config){
15686 this.parent = false;
15688 if (typeof(depreciated_tpl) == 'undefined') {
15689 // new way.. - universal constructor.
15690 Roo.apply(this, config);
15691 this.el = Roo.get(this.el);
15694 this.el = Roo.get(config);
15695 this.tpl = depreciated_tpl;
15696 Roo.apply(this, depreciated_config);
15698 this.wrapEl = this.el.wrap().wrap();
15699 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15702 if(typeof(this.tpl) == "string"){
15703 this.tpl = new Roo.Template(this.tpl);
15705 // support xtype ctors..
15706 this.tpl = new Roo.factory(this.tpl, Roo);
15710 this.tpl.compile();
15715 * @event beforeclick
15716 * Fires before a click is processed. Returns false to cancel the default action.
15717 * @param {Roo.View} this
15718 * @param {Number} index The index of the target node
15719 * @param {HTMLElement} node The target node
15720 * @param {Roo.EventObject} e The raw event object
15722 "beforeclick" : true,
15725 * Fires when a template node is clicked.
15726 * @param {Roo.View} this
15727 * @param {Number} index The index of the target node
15728 * @param {HTMLElement} node The target node
15729 * @param {Roo.EventObject} e The raw event object
15734 * Fires when a template node is double clicked.
15735 * @param {Roo.View} this
15736 * @param {Number} index The index of the target node
15737 * @param {HTMLElement} node The target node
15738 * @param {Roo.EventObject} e The raw event object
15742 * @event contextmenu
15743 * Fires when a template node is right clicked.
15744 * @param {Roo.View} this
15745 * @param {Number} index The index of the target node
15746 * @param {HTMLElement} node The target node
15747 * @param {Roo.EventObject} e The raw event object
15749 "contextmenu" : true,
15751 * @event selectionchange
15752 * Fires when the selected nodes change.
15753 * @param {Roo.View} this
15754 * @param {Array} selections Array of the selected nodes
15756 "selectionchange" : true,
15759 * @event beforeselect
15760 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15761 * @param {Roo.View} this
15762 * @param {HTMLElement} node The node to be selected
15763 * @param {Array} selections Array of currently selected nodes
15765 "beforeselect" : true,
15767 * @event preparedata
15768 * Fires on every row to render, to allow you to change the data.
15769 * @param {Roo.View} this
15770 * @param {Object} data to be rendered (change this)
15772 "preparedata" : true
15780 "click": this.onClick,
15781 "dblclick": this.onDblClick,
15782 "contextmenu": this.onContextMenu,
15786 this.selections = [];
15788 this.cmp = new Roo.CompositeElementLite([]);
15790 this.store = Roo.factory(this.store, Roo.data);
15791 this.setStore(this.store, true);
15794 if ( this.footer && this.footer.xtype) {
15796 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15798 this.footer.dataSource = this.store;
15799 this.footer.container = fctr;
15800 this.footer = Roo.factory(this.footer, Roo);
15801 fctr.insertFirst(this.el);
15803 // this is a bit insane - as the paging toolbar seems to detach the el..
15804 // dom.parentNode.parentNode.parentNode
15805 // they get detached?
15809 Roo.View.superclass.constructor.call(this);
15814 Roo.extend(Roo.View, Roo.util.Observable, {
15817 * @cfg {Roo.data.Store} store Data store to load data from.
15822 * @cfg {String|Roo.Element} el The container element.
15827 * @cfg {String|Roo.Template} tpl The template used by this View
15831 * @cfg {String} dataName the named area of the template to use as the data area
15832 * Works with domtemplates roo-name="name"
15836 * @cfg {String} selectedClass The css class to add to selected nodes
15838 selectedClass : "x-view-selected",
15840 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15845 * @cfg {String} text to display on mask (default Loading)
15849 * @cfg {Boolean} multiSelect Allow multiple selection
15851 multiSelect : false,
15853 * @cfg {Boolean} singleSelect Allow single selection
15855 singleSelect: false,
15858 * @cfg {Boolean} toggleSelect - selecting
15860 toggleSelect : false,
15863 * @cfg {Boolean} tickable - selecting
15868 * Returns the element this view is bound to.
15869 * @return {Roo.Element}
15871 getEl : function(){
15872 return this.wrapEl;
15878 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15880 refresh : function(){
15881 //Roo.log('refresh');
15884 // if we are using something like 'domtemplate', then
15885 // the what gets used is:
15886 // t.applySubtemplate(NAME, data, wrapping data..)
15887 // the outer template then get' applied with
15888 // the store 'extra data'
15889 // and the body get's added to the
15890 // roo-name="data" node?
15891 // <span class='roo-tpl-{name}'></span> ?????
15895 this.clearSelections();
15896 this.el.update("");
15898 var records = this.store.getRange();
15899 if(records.length < 1) {
15901 // is this valid?? = should it render a template??
15903 this.el.update(this.emptyText);
15907 if (this.dataName) {
15908 this.el.update(t.apply(this.store.meta)); //????
15909 el = this.el.child('.roo-tpl-' + this.dataName);
15912 for(var i = 0, len = records.length; i < len; i++){
15913 var data = this.prepareData(records[i].data, i, records[i]);
15914 this.fireEvent("preparedata", this, data, i, records[i]);
15916 var d = Roo.apply({}, data);
15919 Roo.apply(d, {'roo-id' : Roo.id()});
15923 Roo.each(this.parent.item, function(item){
15924 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15927 Roo.apply(d, {'roo-data-checked' : 'checked'});
15931 html[html.length] = Roo.util.Format.trim(
15933 t.applySubtemplate(this.dataName, d, this.store.meta) :
15940 el.update(html.join(""));
15941 this.nodes = el.dom.childNodes;
15942 this.updateIndexes(0);
15947 * Function to override to reformat the data that is sent to
15948 * the template for each node.
15949 * DEPRICATED - use the preparedata event handler.
15950 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15951 * a JSON object for an UpdateManager bound view).
15953 prepareData : function(data, index, record)
15955 this.fireEvent("preparedata", this, data, index, record);
15959 onUpdate : function(ds, record){
15960 // Roo.log('on update');
15961 this.clearSelections();
15962 var index = this.store.indexOf(record);
15963 var n = this.nodes[index];
15964 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15965 n.parentNode.removeChild(n);
15966 this.updateIndexes(index, index);
15972 onAdd : function(ds, records, index)
15974 //Roo.log(['on Add', ds, records, index] );
15975 this.clearSelections();
15976 if(this.nodes.length == 0){
15980 var n = this.nodes[index];
15981 for(var i = 0, len = records.length; i < len; i++){
15982 var d = this.prepareData(records[i].data, i, records[i]);
15984 this.tpl.insertBefore(n, d);
15987 this.tpl.append(this.el, d);
15990 this.updateIndexes(index);
15993 onRemove : function(ds, record, index){
15994 // Roo.log('onRemove');
15995 this.clearSelections();
15996 var el = this.dataName ?
15997 this.el.child('.roo-tpl-' + this.dataName) :
16000 el.dom.removeChild(this.nodes[index]);
16001 this.updateIndexes(index);
16005 * Refresh an individual node.
16006 * @param {Number} index
16008 refreshNode : function(index){
16009 this.onUpdate(this.store, this.store.getAt(index));
16012 updateIndexes : function(startIndex, endIndex){
16013 var ns = this.nodes;
16014 startIndex = startIndex || 0;
16015 endIndex = endIndex || ns.length - 1;
16016 for(var i = startIndex; i <= endIndex; i++){
16017 ns[i].nodeIndex = i;
16022 * Changes the data store this view uses and refresh the view.
16023 * @param {Store} store
16025 setStore : function(store, initial){
16026 if(!initial && this.store){
16027 this.store.un("datachanged", this.refresh);
16028 this.store.un("add", this.onAdd);
16029 this.store.un("remove", this.onRemove);
16030 this.store.un("update", this.onUpdate);
16031 this.store.un("clear", this.refresh);
16032 this.store.un("beforeload", this.onBeforeLoad);
16033 this.store.un("load", this.onLoad);
16034 this.store.un("loadexception", this.onLoad);
16038 store.on("datachanged", this.refresh, this);
16039 store.on("add", this.onAdd, this);
16040 store.on("remove", this.onRemove, this);
16041 store.on("update", this.onUpdate, this);
16042 store.on("clear", this.refresh, this);
16043 store.on("beforeload", this.onBeforeLoad, this);
16044 store.on("load", this.onLoad, this);
16045 store.on("loadexception", this.onLoad, this);
16053 * onbeforeLoad - masks the loading area.
16056 onBeforeLoad : function(store,opts)
16058 //Roo.log('onBeforeLoad');
16060 this.el.update("");
16062 this.el.mask(this.mask ? this.mask : "Loading" );
16064 onLoad : function ()
16071 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16072 * @param {HTMLElement} node
16073 * @return {HTMLElement} The template node
16075 findItemFromChild : function(node){
16076 var el = this.dataName ?
16077 this.el.child('.roo-tpl-' + this.dataName,true) :
16080 if(!node || node.parentNode == el){
16083 var p = node.parentNode;
16084 while(p && p != el){
16085 if(p.parentNode == el){
16094 onClick : function(e){
16095 var item = this.findItemFromChild(e.getTarget());
16097 var index = this.indexOf(item);
16098 if(this.onItemClick(item, index, e) !== false){
16099 this.fireEvent("click", this, index, item, e);
16102 this.clearSelections();
16107 onContextMenu : function(e){
16108 var item = this.findItemFromChild(e.getTarget());
16110 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16115 onDblClick : function(e){
16116 var item = this.findItemFromChild(e.getTarget());
16118 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16122 onItemClick : function(item, index, e)
16124 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16127 if (this.toggleSelect) {
16128 var m = this.isSelected(item) ? 'unselect' : 'select';
16131 _t[m](item, true, false);
16134 if(this.multiSelect || this.singleSelect){
16135 if(this.multiSelect && e.shiftKey && this.lastSelection){
16136 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16138 this.select(item, this.multiSelect && e.ctrlKey);
16139 this.lastSelection = item;
16142 if(!this.tickable){
16143 e.preventDefault();
16151 * Get the number of selected nodes.
16154 getSelectionCount : function(){
16155 return this.selections.length;
16159 * Get the currently selected nodes.
16160 * @return {Array} An array of HTMLElements
16162 getSelectedNodes : function(){
16163 return this.selections;
16167 * Get the indexes of the selected nodes.
16170 getSelectedIndexes : function(){
16171 var indexes = [], s = this.selections;
16172 for(var i = 0, len = s.length; i < len; i++){
16173 indexes.push(s[i].nodeIndex);
16179 * Clear all selections
16180 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16182 clearSelections : function(suppressEvent){
16183 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16184 this.cmp.elements = this.selections;
16185 this.cmp.removeClass(this.selectedClass);
16186 this.selections = [];
16187 if(!suppressEvent){
16188 this.fireEvent("selectionchange", this, this.selections);
16194 * Returns true if the passed node is selected
16195 * @param {HTMLElement/Number} node The node or node index
16196 * @return {Boolean}
16198 isSelected : function(node){
16199 var s = this.selections;
16203 node = this.getNode(node);
16204 return s.indexOf(node) !== -1;
16209 * @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
16210 * @param {Boolean} keepExisting (optional) true to keep existing selections
16211 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16213 select : function(nodeInfo, keepExisting, suppressEvent){
16214 if(nodeInfo instanceof Array){
16216 this.clearSelections(true);
16218 for(var i = 0, len = nodeInfo.length; i < len; i++){
16219 this.select(nodeInfo[i], true, true);
16223 var node = this.getNode(nodeInfo);
16224 if(!node || this.isSelected(node)){
16225 return; // already selected.
16228 this.clearSelections(true);
16231 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16232 Roo.fly(node).addClass(this.selectedClass);
16233 this.selections.push(node);
16234 if(!suppressEvent){
16235 this.fireEvent("selectionchange", this, this.selections);
16243 * @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
16244 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16245 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16247 unselect : function(nodeInfo, keepExisting, suppressEvent)
16249 if(nodeInfo instanceof Array){
16250 Roo.each(this.selections, function(s) {
16251 this.unselect(s, nodeInfo);
16255 var node = this.getNode(nodeInfo);
16256 if(!node || !this.isSelected(node)){
16257 //Roo.log("not selected");
16258 return; // not selected.
16262 Roo.each(this.selections, function(s) {
16264 Roo.fly(node).removeClass(this.selectedClass);
16271 this.selections= ns;
16272 this.fireEvent("selectionchange", this, this.selections);
16276 * Gets a template node.
16277 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16278 * @return {HTMLElement} The node or null if it wasn't found
16280 getNode : function(nodeInfo){
16281 if(typeof nodeInfo == "string"){
16282 return document.getElementById(nodeInfo);
16283 }else if(typeof nodeInfo == "number"){
16284 return this.nodes[nodeInfo];
16290 * Gets a range template nodes.
16291 * @param {Number} startIndex
16292 * @param {Number} endIndex
16293 * @return {Array} An array of nodes
16295 getNodes : function(start, end){
16296 var ns = this.nodes;
16297 start = start || 0;
16298 end = typeof end == "undefined" ? ns.length - 1 : end;
16301 for(var i = start; i <= end; i++){
16305 for(var i = start; i >= end; i--){
16313 * Finds the index of the passed node
16314 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16315 * @return {Number} The index of the node or -1
16317 indexOf : function(node){
16318 node = this.getNode(node);
16319 if(typeof node.nodeIndex == "number"){
16320 return node.nodeIndex;
16322 var ns = this.nodes;
16323 for(var i = 0, len = ns.length; i < len; i++){
16334 * based on jquery fullcalendar
16338 Roo.bootstrap = Roo.bootstrap || {};
16340 * @class Roo.bootstrap.Calendar
16341 * @extends Roo.bootstrap.Component
16342 * Bootstrap Calendar class
16343 * @cfg {Boolean} loadMask (true|false) default false
16344 * @cfg {Object} header generate the user specific header of the calendar, default false
16347 * Create a new Container
16348 * @param {Object} config The config object
16353 Roo.bootstrap.Calendar = function(config){
16354 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16358 * Fires when a date is selected
16359 * @param {DatePicker} this
16360 * @param {Date} date The selected date
16364 * @event monthchange
16365 * Fires when the displayed month changes
16366 * @param {DatePicker} this
16367 * @param {Date} date The selected month
16369 'monthchange': true,
16371 * @event evententer
16372 * Fires when mouse over an event
16373 * @param {Calendar} this
16374 * @param {event} Event
16376 'evententer': true,
16378 * @event eventleave
16379 * Fires when the mouse leaves an
16380 * @param {Calendar} this
16383 'eventleave': true,
16385 * @event eventclick
16386 * Fires when the mouse click an
16387 * @param {Calendar} this
16396 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16399 * @cfg {Number} startDay
16400 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16408 getAutoCreate : function(){
16411 var fc_button = function(name, corner, style, content ) {
16412 return Roo.apply({},{
16414 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16416 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16419 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16430 style : 'width:100%',
16437 cls : 'fc-header-left',
16439 fc_button('prev', 'left', 'arrow', '‹' ),
16440 fc_button('next', 'right', 'arrow', '›' ),
16441 { tag: 'span', cls: 'fc-header-space' },
16442 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16450 cls : 'fc-header-center',
16454 cls: 'fc-header-title',
16457 html : 'month / year'
16465 cls : 'fc-header-right',
16467 /* fc_button('month', 'left', '', 'month' ),
16468 fc_button('week', '', '', 'week' ),
16469 fc_button('day', 'right', '', 'day' )
16481 header = this.header;
16484 var cal_heads = function() {
16486 // fixme - handle this.
16488 for (var i =0; i < Date.dayNames.length; i++) {
16489 var d = Date.dayNames[i];
16492 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16493 html : d.substring(0,3)
16497 ret[0].cls += ' fc-first';
16498 ret[6].cls += ' fc-last';
16501 var cal_cell = function(n) {
16504 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16509 cls: 'fc-day-number',
16513 cls: 'fc-day-content',
16517 style: 'position: relative;' // height: 17px;
16529 var cal_rows = function() {
16532 for (var r = 0; r < 6; r++) {
16539 for (var i =0; i < Date.dayNames.length; i++) {
16540 var d = Date.dayNames[i];
16541 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16544 row.cn[0].cls+=' fc-first';
16545 row.cn[0].cn[0].style = 'min-height:90px';
16546 row.cn[6].cls+=' fc-last';
16550 ret[0].cls += ' fc-first';
16551 ret[4].cls += ' fc-prev-last';
16552 ret[5].cls += ' fc-last';
16559 cls: 'fc-border-separate',
16560 style : 'width:100%',
16568 cls : 'fc-first fc-last',
16586 cls : 'fc-content',
16587 style : "position: relative;",
16590 cls : 'fc-view fc-view-month fc-grid',
16591 style : 'position: relative',
16592 unselectable : 'on',
16595 cls : 'fc-event-container',
16596 style : 'position:absolute;z-index:8;top:0;left:0;'
16614 initEvents : function()
16617 throw "can not find store for calendar";
16623 style: "text-align:center",
16627 style: "background-color:white;width:50%;margin:250 auto",
16631 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16642 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16644 var size = this.el.select('.fc-content', true).first().getSize();
16645 this.maskEl.setSize(size.width, size.height);
16646 this.maskEl.enableDisplayMode("block");
16647 if(!this.loadMask){
16648 this.maskEl.hide();
16651 this.store = Roo.factory(this.store, Roo.data);
16652 this.store.on('load', this.onLoad, this);
16653 this.store.on('beforeload', this.onBeforeLoad, this);
16657 this.cells = this.el.select('.fc-day',true);
16658 //Roo.log(this.cells);
16659 this.textNodes = this.el.query('.fc-day-number');
16660 this.cells.addClassOnOver('fc-state-hover');
16662 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16663 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16664 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16665 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16667 this.on('monthchange', this.onMonthChange, this);
16669 this.update(new Date().clearTime());
16672 resize : function() {
16673 var sz = this.el.getSize();
16675 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16676 this.el.select('.fc-day-content div',true).setHeight(34);
16681 showPrevMonth : function(e){
16682 this.update(this.activeDate.add("mo", -1));
16684 showToday : function(e){
16685 this.update(new Date().clearTime());
16688 showNextMonth : function(e){
16689 this.update(this.activeDate.add("mo", 1));
16693 showPrevYear : function(){
16694 this.update(this.activeDate.add("y", -1));
16698 showNextYear : function(){
16699 this.update(this.activeDate.add("y", 1));
16704 update : function(date)
16706 var vd = this.activeDate;
16707 this.activeDate = date;
16708 // if(vd && this.el){
16709 // var t = date.getTime();
16710 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16711 // Roo.log('using add remove');
16713 // this.fireEvent('monthchange', this, date);
16715 // this.cells.removeClass("fc-state-highlight");
16716 // this.cells.each(function(c){
16717 // if(c.dateValue == t){
16718 // c.addClass("fc-state-highlight");
16719 // setTimeout(function(){
16720 // try{c.dom.firstChild.focus();}catch(e){}
16730 var days = date.getDaysInMonth();
16732 var firstOfMonth = date.getFirstDateOfMonth();
16733 var startingPos = firstOfMonth.getDay()-this.startDay;
16735 if(startingPos < this.startDay){
16739 var pm = date.add(Date.MONTH, -1);
16740 var prevStart = pm.getDaysInMonth()-startingPos;
16742 this.cells = this.el.select('.fc-day',true);
16743 this.textNodes = this.el.query('.fc-day-number');
16744 this.cells.addClassOnOver('fc-state-hover');
16746 var cells = this.cells.elements;
16747 var textEls = this.textNodes;
16749 Roo.each(cells, function(cell){
16750 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16753 days += startingPos;
16755 // convert everything to numbers so it's fast
16756 var day = 86400000;
16757 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16760 //Roo.log(prevStart);
16762 var today = new Date().clearTime().getTime();
16763 var sel = date.clearTime().getTime();
16764 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16765 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16766 var ddMatch = this.disabledDatesRE;
16767 var ddText = this.disabledDatesText;
16768 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16769 var ddaysText = this.disabledDaysText;
16770 var format = this.format;
16772 var setCellClass = function(cal, cell){
16776 //Roo.log('set Cell Class');
16778 var t = d.getTime();
16782 cell.dateValue = t;
16784 cell.className += " fc-today";
16785 cell.className += " fc-state-highlight";
16786 cell.title = cal.todayText;
16789 // disable highlight in other month..
16790 //cell.className += " fc-state-highlight";
16795 cell.className = " fc-state-disabled";
16796 cell.title = cal.minText;
16800 cell.className = " fc-state-disabled";
16801 cell.title = cal.maxText;
16805 if(ddays.indexOf(d.getDay()) != -1){
16806 cell.title = ddaysText;
16807 cell.className = " fc-state-disabled";
16810 if(ddMatch && format){
16811 var fvalue = d.dateFormat(format);
16812 if(ddMatch.test(fvalue)){
16813 cell.title = ddText.replace("%0", fvalue);
16814 cell.className = " fc-state-disabled";
16818 if (!cell.initialClassName) {
16819 cell.initialClassName = cell.dom.className;
16822 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16827 for(; i < startingPos; i++) {
16828 textEls[i].innerHTML = (++prevStart);
16829 d.setDate(d.getDate()+1);
16831 cells[i].className = "fc-past fc-other-month";
16832 setCellClass(this, cells[i]);
16837 for(; i < days; i++){
16838 intDay = i - startingPos + 1;
16839 textEls[i].innerHTML = (intDay);
16840 d.setDate(d.getDate()+1);
16842 cells[i].className = ''; // "x-date-active";
16843 setCellClass(this, cells[i]);
16847 for(; i < 42; i++) {
16848 textEls[i].innerHTML = (++extraDays);
16849 d.setDate(d.getDate()+1);
16851 cells[i].className = "fc-future fc-other-month";
16852 setCellClass(this, cells[i]);
16855 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16857 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16859 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16860 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16862 if(totalRows != 6){
16863 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16864 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16867 this.fireEvent('monthchange', this, date);
16871 if(!this.internalRender){
16872 var main = this.el.dom.firstChild;
16873 var w = main.offsetWidth;
16874 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16875 Roo.fly(main).setWidth(w);
16876 this.internalRender = true;
16877 // opera does not respect the auto grow header center column
16878 // then, after it gets a width opera refuses to recalculate
16879 // without a second pass
16880 if(Roo.isOpera && !this.secondPass){
16881 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16882 this.secondPass = true;
16883 this.update.defer(10, this, [date]);
16890 findCell : function(dt) {
16891 dt = dt.clearTime().getTime();
16893 this.cells.each(function(c){
16894 //Roo.log("check " +c.dateValue + '?=' + dt);
16895 if(c.dateValue == dt){
16905 findCells : function(ev) {
16906 var s = ev.start.clone().clearTime().getTime();
16908 var e= ev.end.clone().clearTime().getTime();
16911 this.cells.each(function(c){
16912 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16914 if(c.dateValue > e){
16917 if(c.dateValue < s){
16926 // findBestRow: function(cells)
16930 // for (var i =0 ; i < cells.length;i++) {
16931 // ret = Math.max(cells[i].rows || 0,ret);
16938 addItem : function(ev)
16940 // look for vertical location slot in
16941 var cells = this.findCells(ev);
16943 // ev.row = this.findBestRow(cells);
16945 // work out the location.
16949 for(var i =0; i < cells.length; i++) {
16951 cells[i].row = cells[0].row;
16954 cells[i].row = cells[i].row + 1;
16964 if (crow.start.getY() == cells[i].getY()) {
16966 crow.end = cells[i];
16983 cells[0].events.push(ev);
16985 this.calevents.push(ev);
16988 clearEvents: function() {
16990 if(!this.calevents){
16994 Roo.each(this.cells.elements, function(c){
17000 Roo.each(this.calevents, function(e) {
17001 Roo.each(e.els, function(el) {
17002 el.un('mouseenter' ,this.onEventEnter, this);
17003 el.un('mouseleave' ,this.onEventLeave, this);
17008 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17014 renderEvents: function()
17018 this.cells.each(function(c) {
17027 if(c.row != c.events.length){
17028 r = 4 - (4 - (c.row - c.events.length));
17031 c.events = ev.slice(0, r);
17032 c.more = ev.slice(r);
17034 if(c.more.length && c.more.length == 1){
17035 c.events.push(c.more.pop());
17038 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17042 this.cells.each(function(c) {
17044 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17047 for (var e = 0; e < c.events.length; e++){
17048 var ev = c.events[e];
17049 var rows = ev.rows;
17051 for(var i = 0; i < rows.length; i++) {
17053 // how many rows should it span..
17056 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17057 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17059 unselectable : "on",
17062 cls: 'fc-event-inner',
17066 // cls: 'fc-event-time',
17067 // html : cells.length > 1 ? '' : ev.time
17071 cls: 'fc-event-title',
17072 html : String.format('{0}', ev.title)
17079 cls: 'ui-resizable-handle ui-resizable-e',
17080 html : '  '
17087 cfg.cls += ' fc-event-start';
17089 if ((i+1) == rows.length) {
17090 cfg.cls += ' fc-event-end';
17093 var ctr = _this.el.select('.fc-event-container',true).first();
17094 var cg = ctr.createChild(cfg);
17096 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17097 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17099 var r = (c.more.length) ? 1 : 0;
17100 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17101 cg.setWidth(ebox.right - sbox.x -2);
17103 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17104 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17105 cg.on('click', _this.onEventClick, _this, ev);
17116 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17117 style : 'position: absolute',
17118 unselectable : "on",
17121 cls: 'fc-event-inner',
17125 cls: 'fc-event-title',
17133 cls: 'ui-resizable-handle ui-resizable-e',
17134 html : '  '
17140 var ctr = _this.el.select('.fc-event-container',true).first();
17141 var cg = ctr.createChild(cfg);
17143 var sbox = c.select('.fc-day-content',true).first().getBox();
17144 var ebox = c.select('.fc-day-content',true).first().getBox();
17146 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17147 cg.setWidth(ebox.right - sbox.x -2);
17149 cg.on('click', _this.onMoreEventClick, _this, c.more);
17159 onEventEnter: function (e, el,event,d) {
17160 this.fireEvent('evententer', this, el, event);
17163 onEventLeave: function (e, el,event,d) {
17164 this.fireEvent('eventleave', this, el, event);
17167 onEventClick: function (e, el,event,d) {
17168 this.fireEvent('eventclick', this, el, event);
17171 onMonthChange: function () {
17175 onMoreEventClick: function(e, el, more)
17179 this.calpopover.placement = 'right';
17180 this.calpopover.setTitle('More');
17182 this.calpopover.setContent('');
17184 var ctr = this.calpopover.el.select('.popover-content', true).first();
17186 Roo.each(more, function(m){
17188 cls : 'fc-event-hori fc-event-draggable',
17191 var cg = ctr.createChild(cfg);
17193 cg.on('click', _this.onEventClick, _this, m);
17196 this.calpopover.show(el);
17201 onLoad: function ()
17203 this.calevents = [];
17206 if(this.store.getCount() > 0){
17207 this.store.data.each(function(d){
17210 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17211 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17212 time : d.data.start_time,
17213 title : d.data.title,
17214 description : d.data.description,
17215 venue : d.data.venue
17220 this.renderEvents();
17222 if(this.calevents.length && this.loadMask){
17223 this.maskEl.hide();
17227 onBeforeLoad: function()
17229 this.clearEvents();
17231 this.maskEl.show();
17245 * @class Roo.bootstrap.Popover
17246 * @extends Roo.bootstrap.Component
17247 * Bootstrap Popover class
17248 * @cfg {String} html contents of the popover (or false to use children..)
17249 * @cfg {String} title of popover (or false to hide)
17250 * @cfg {String} placement how it is placed
17251 * @cfg {String} trigger click || hover (or false to trigger manually)
17252 * @cfg {String} over what (parent or false to trigger manually.)
17253 * @cfg {Number} delay - delay before showing
17256 * Create a new Popover
17257 * @param {Object} config The config object
17260 Roo.bootstrap.Popover = function(config){
17261 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17267 * After the popover show
17269 * @param {Roo.bootstrap.Popover} this
17274 * After the popover hide
17276 * @param {Roo.bootstrap.Popover} this
17282 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17284 title: 'Fill in a title',
17287 placement : 'right',
17288 trigger : 'hover', // hover
17294 can_build_overlaid : false,
17296 getChildContainer : function()
17298 return this.el.select('.popover-content',true).first();
17301 getAutoCreate : function(){
17304 cls : 'popover roo-dynamic',
17305 style: 'display:block',
17311 cls : 'popover-inner',
17315 cls: 'popover-title',
17319 cls : 'popover-content',
17330 setTitle: function(str)
17333 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17335 setContent: function(str)
17338 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17340 // as it get's added to the bottom of the page.
17341 onRender : function(ct, position)
17343 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17345 var cfg = Roo.apply({}, this.getAutoCreate());
17349 cfg.cls += ' ' + this.cls;
17352 cfg.style = this.style;
17354 //Roo.log("adding to ");
17355 this.el = Roo.get(document.body).createChild(cfg, position);
17356 // Roo.log(this.el);
17361 initEvents : function()
17363 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17364 this.el.enableDisplayMode('block');
17366 if (this.over === false) {
17369 if (this.triggers === false) {
17372 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17373 var triggers = this.trigger ? this.trigger.split(' ') : [];
17374 Roo.each(triggers, function(trigger) {
17376 if (trigger == 'click') {
17377 on_el.on('click', this.toggle, this);
17378 } else if (trigger != 'manual') {
17379 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17380 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17382 on_el.on(eventIn ,this.enter, this);
17383 on_el.on(eventOut, this.leave, this);
17394 toggle : function () {
17395 this.hoverState == 'in' ? this.leave() : this.enter();
17398 enter : function () {
17400 clearTimeout(this.timeout);
17402 this.hoverState = 'in';
17404 if (!this.delay || !this.delay.show) {
17409 this.timeout = setTimeout(function () {
17410 if (_t.hoverState == 'in') {
17413 }, this.delay.show)
17416 leave : function() {
17417 clearTimeout(this.timeout);
17419 this.hoverState = 'out';
17421 if (!this.delay || !this.delay.hide) {
17426 this.timeout = setTimeout(function () {
17427 if (_t.hoverState == 'out') {
17430 }, this.delay.hide)
17433 show : function (on_el)
17436 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17440 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17441 if (this.html !== false) {
17442 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17444 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17445 if (!this.title.length) {
17446 this.el.select('.popover-title',true).hide();
17449 var placement = typeof this.placement == 'function' ?
17450 this.placement.call(this, this.el, on_el) :
17453 var autoToken = /\s?auto?\s?/i;
17454 var autoPlace = autoToken.test(placement);
17456 placement = placement.replace(autoToken, '') || 'top';
17460 //this.el.setXY([0,0]);
17462 this.el.dom.style.display='block';
17463 this.el.addClass(placement);
17465 //this.el.appendTo(on_el);
17467 var p = this.getPosition();
17468 var box = this.el.getBox();
17473 var align = Roo.bootstrap.Popover.alignment[placement];
17476 this.el.alignTo(on_el, align[0],align[1]);
17477 //var arrow = this.el.select('.arrow',true).first();
17478 //arrow.set(align[2],
17480 this.el.addClass('in');
17483 if (this.el.hasClass('fade')) {
17487 this.hoverState = 'in';
17489 this.fireEvent('show', this);
17494 this.el.setXY([0,0]);
17495 this.el.removeClass('in');
17497 this.hoverState = null;
17499 this.fireEvent('hide', this);
17504 Roo.bootstrap.Popover.alignment = {
17505 'left' : ['r-l', [-10,0], 'right'],
17506 'right' : ['l-r', [10,0], 'left'],
17507 'bottom' : ['t-b', [0,10], 'top'],
17508 'top' : [ 'b-t', [0,-10], 'bottom']
17519 * @class Roo.bootstrap.Progress
17520 * @extends Roo.bootstrap.Component
17521 * Bootstrap Progress class
17522 * @cfg {Boolean} striped striped of the progress bar
17523 * @cfg {Boolean} active animated of the progress bar
17527 * Create a new Progress
17528 * @param {Object} config The config object
17531 Roo.bootstrap.Progress = function(config){
17532 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17535 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17540 getAutoCreate : function(){
17548 cfg.cls += ' progress-striped';
17552 cfg.cls += ' active';
17571 * @class Roo.bootstrap.ProgressBar
17572 * @extends Roo.bootstrap.Component
17573 * Bootstrap ProgressBar class
17574 * @cfg {Number} aria_valuenow aria-value now
17575 * @cfg {Number} aria_valuemin aria-value min
17576 * @cfg {Number} aria_valuemax aria-value max
17577 * @cfg {String} label label for the progress bar
17578 * @cfg {String} panel (success | info | warning | danger )
17579 * @cfg {String} role role of the progress bar
17580 * @cfg {String} sr_only text
17584 * Create a new ProgressBar
17585 * @param {Object} config The config object
17588 Roo.bootstrap.ProgressBar = function(config){
17589 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17592 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17596 aria_valuemax : 100,
17602 getAutoCreate : function()
17607 cls: 'progress-bar',
17608 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17620 cfg.role = this.role;
17623 if(this.aria_valuenow){
17624 cfg['aria-valuenow'] = this.aria_valuenow;
17627 if(this.aria_valuemin){
17628 cfg['aria-valuemin'] = this.aria_valuemin;
17631 if(this.aria_valuemax){
17632 cfg['aria-valuemax'] = this.aria_valuemax;
17635 if(this.label && !this.sr_only){
17636 cfg.html = this.label;
17640 cfg.cls += ' progress-bar-' + this.panel;
17646 update : function(aria_valuenow)
17648 this.aria_valuenow = aria_valuenow;
17650 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17665 * @class Roo.bootstrap.TabGroup
17666 * @extends Roo.bootstrap.Column
17667 * Bootstrap Column class
17668 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17669 * @cfg {Boolean} carousel true to make the group behave like a carousel
17670 * @cfg {Boolean} bullets show bullets for the panels
17671 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17672 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17673 * @cfg {Boolean} showarrow (true|false) show arrow default true
17676 * Create a new TabGroup
17677 * @param {Object} config The config object
17680 Roo.bootstrap.TabGroup = function(config){
17681 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17683 this.navId = Roo.id();
17686 Roo.bootstrap.TabGroup.register(this);
17690 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17693 transition : false,
17698 slideOnTouch : false,
17701 getAutoCreate : function()
17703 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17705 cfg.cls += ' tab-content';
17707 if (this.carousel) {
17708 cfg.cls += ' carousel slide';
17711 cls : 'carousel-inner',
17715 if(this.bullets && !Roo.isTouch){
17718 cls : 'carousel-bullets',
17722 if(this.bullets_cls){
17723 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17730 cfg.cn[0].cn.push(bullets);
17733 if(this.showarrow){
17734 cfg.cn[0].cn.push({
17736 class : 'carousel-arrow',
17740 class : 'carousel-prev',
17744 class : 'fa fa-chevron-left'
17750 class : 'carousel-next',
17754 class : 'fa fa-chevron-right'
17767 initEvents: function()
17769 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17770 // this.el.on("touchstart", this.onTouchStart, this);
17773 if(this.autoslide){
17776 this.slideFn = window.setInterval(function() {
17777 _this.showPanelNext();
17781 if(this.showarrow){
17782 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17783 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17789 // onTouchStart : function(e, el, o)
17791 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17795 // this.showPanelNext();
17799 getChildContainer : function()
17801 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17805 * register a Navigation item
17806 * @param {Roo.bootstrap.NavItem} the navitem to add
17808 register : function(item)
17810 this.tabs.push( item);
17811 item.navId = this.navId; // not really needed..
17816 getActivePanel : function()
17819 Roo.each(this.tabs, function(t) {
17829 getPanelByName : function(n)
17832 Roo.each(this.tabs, function(t) {
17833 if (t.tabId == n) {
17841 indexOfPanel : function(p)
17844 Roo.each(this.tabs, function(t,i) {
17845 if (t.tabId == p.tabId) {
17854 * show a specific panel
17855 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17856 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17858 showPanel : function (pan)
17860 if(this.transition || typeof(pan) == 'undefined'){
17861 Roo.log("waiting for the transitionend");
17865 if (typeof(pan) == 'number') {
17866 pan = this.tabs[pan];
17869 if (typeof(pan) == 'string') {
17870 pan = this.getPanelByName(pan);
17873 var cur = this.getActivePanel();
17876 Roo.log('pan or acitve pan is undefined');
17880 if (pan.tabId == this.getActivePanel().tabId) {
17884 if (false === cur.fireEvent('beforedeactivate')) {
17888 if(this.bullets > 0 && !Roo.isTouch){
17889 this.setActiveBullet(this.indexOfPanel(pan));
17892 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17894 this.transition = true;
17895 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17896 var lr = dir == 'next' ? 'left' : 'right';
17897 pan.el.addClass(dir); // or prev
17898 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17899 cur.el.addClass(lr); // or right
17900 pan.el.addClass(lr);
17903 cur.el.on('transitionend', function() {
17904 Roo.log("trans end?");
17906 pan.el.removeClass([lr,dir]);
17907 pan.setActive(true);
17909 cur.el.removeClass([lr]);
17910 cur.setActive(false);
17912 _this.transition = false;
17914 }, this, { single: true } );
17919 cur.setActive(false);
17920 pan.setActive(true);
17925 showPanelNext : function()
17927 var i = this.indexOfPanel(this.getActivePanel());
17929 if (i >= this.tabs.length - 1 && !this.autoslide) {
17933 if (i >= this.tabs.length - 1 && this.autoslide) {
17937 this.showPanel(this.tabs[i+1]);
17940 showPanelPrev : function()
17942 var i = this.indexOfPanel(this.getActivePanel());
17944 if (i < 1 && !this.autoslide) {
17948 if (i < 1 && this.autoslide) {
17949 i = this.tabs.length;
17952 this.showPanel(this.tabs[i-1]);
17956 addBullet: function()
17958 if(!this.bullets || Roo.isTouch){
17961 var ctr = this.el.select('.carousel-bullets',true).first();
17962 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17963 var bullet = ctr.createChild({
17964 cls : 'bullet bullet-' + i
17965 },ctr.dom.lastChild);
17970 bullet.on('click', (function(e, el, o, ii, t){
17972 e.preventDefault();
17974 this.showPanel(ii);
17976 if(this.autoslide && this.slideFn){
17977 clearInterval(this.slideFn);
17978 this.slideFn = window.setInterval(function() {
17979 _this.showPanelNext();
17983 }).createDelegate(this, [i, bullet], true));
17988 setActiveBullet : function(i)
17994 Roo.each(this.el.select('.bullet', true).elements, function(el){
17995 el.removeClass('selected');
17998 var bullet = this.el.select('.bullet-' + i, true).first();
18004 bullet.addClass('selected');
18015 Roo.apply(Roo.bootstrap.TabGroup, {
18019 * register a Navigation Group
18020 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18022 register : function(navgrp)
18024 this.groups[navgrp.navId] = navgrp;
18028 * fetch a Navigation Group based on the navigation ID
18029 * if one does not exist , it will get created.
18030 * @param {string} the navgroup to add
18031 * @returns {Roo.bootstrap.NavGroup} the navgroup
18033 get: function(navId) {
18034 if (typeof(this.groups[navId]) == 'undefined') {
18035 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18037 return this.groups[navId] ;
18052 * @class Roo.bootstrap.TabPanel
18053 * @extends Roo.bootstrap.Component
18054 * Bootstrap TabPanel class
18055 * @cfg {Boolean} active panel active
18056 * @cfg {String} html panel content
18057 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18058 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18059 * @cfg {String} href click to link..
18063 * Create a new TabPanel
18064 * @param {Object} config The config object
18067 Roo.bootstrap.TabPanel = function(config){
18068 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18072 * Fires when the active status changes
18073 * @param {Roo.bootstrap.TabPanel} this
18074 * @param {Boolean} state the new state
18079 * @event beforedeactivate
18080 * Fires before a tab is de-activated - can be used to do validation on a form.
18081 * @param {Roo.bootstrap.TabPanel} this
18082 * @return {Boolean} false if there is an error
18085 'beforedeactivate': true
18088 this.tabId = this.tabId || Roo.id();
18092 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18100 getAutoCreate : function(){
18103 // item is needed for carousel - not sure if it has any effect otherwise
18104 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18105 html: this.html || ''
18109 cfg.cls += ' active';
18113 cfg.tabId = this.tabId;
18120 initEvents: function()
18122 var p = this.parent();
18124 this.navId = this.navId || p.navId;
18126 if (typeof(this.navId) != 'undefined') {
18127 // not really needed.. but just in case.. parent should be a NavGroup.
18128 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18132 var i = tg.tabs.length - 1;
18134 if(this.active && tg.bullets > 0 && i < tg.bullets){
18135 tg.setActiveBullet(i);
18139 this.el.on('click', this.onClick, this);
18142 this.el.on("touchstart", this.onTouchStart, this);
18143 this.el.on("touchmove", this.onTouchMove, this);
18144 this.el.on("touchend", this.onTouchEnd, this);
18149 onRender : function(ct, position)
18151 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18154 setActive : function(state)
18156 Roo.log("panel - set active " + this.tabId + "=" + state);
18158 this.active = state;
18160 this.el.removeClass('active');
18162 } else if (!this.el.hasClass('active')) {
18163 this.el.addClass('active');
18166 this.fireEvent('changed', this, state);
18169 onClick : function(e)
18171 e.preventDefault();
18173 if(!this.href.length){
18177 window.location.href = this.href;
18186 onTouchStart : function(e)
18188 this.swiping = false;
18190 this.startX = e.browserEvent.touches[0].clientX;
18191 this.startY = e.browserEvent.touches[0].clientY;
18194 onTouchMove : function(e)
18196 this.swiping = true;
18198 this.endX = e.browserEvent.touches[0].clientX;
18199 this.endY = e.browserEvent.touches[0].clientY;
18202 onTouchEnd : function(e)
18209 var tabGroup = this.parent();
18211 if(this.endX > this.startX){ // swiping right
18212 tabGroup.showPanelPrev();
18216 if(this.startX > this.endX){ // swiping left
18217 tabGroup.showPanelNext();
18236 * @class Roo.bootstrap.DateField
18237 * @extends Roo.bootstrap.Input
18238 * Bootstrap DateField class
18239 * @cfg {Number} weekStart default 0
18240 * @cfg {String} viewMode default empty, (months|years)
18241 * @cfg {String} minViewMode default empty, (months|years)
18242 * @cfg {Number} startDate default -Infinity
18243 * @cfg {Number} endDate default Infinity
18244 * @cfg {Boolean} todayHighlight default false
18245 * @cfg {Boolean} todayBtn default false
18246 * @cfg {Boolean} calendarWeeks default false
18247 * @cfg {Object} daysOfWeekDisabled default empty
18248 * @cfg {Boolean} singleMode default false (true | false)
18250 * @cfg {Boolean} keyboardNavigation default true
18251 * @cfg {String} language default en
18254 * Create a new DateField
18255 * @param {Object} config The config object
18258 Roo.bootstrap.DateField = function(config){
18259 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18263 * Fires when this field show.
18264 * @param {Roo.bootstrap.DateField} this
18265 * @param {Mixed} date The date value
18270 * Fires when this field hide.
18271 * @param {Roo.bootstrap.DateField} this
18272 * @param {Mixed} date The date value
18277 * Fires when select a date.
18278 * @param {Roo.bootstrap.DateField} this
18279 * @param {Mixed} date The date value
18283 * @event beforeselect
18284 * Fires when before select a date.
18285 * @param {Roo.bootstrap.DateField} this
18286 * @param {Mixed} date The date value
18288 beforeselect : true
18292 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18295 * @cfg {String} format
18296 * The default date format string which can be overriden for localization support. The format must be
18297 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18301 * @cfg {String} altFormats
18302 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18303 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18305 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18313 todayHighlight : false,
18319 keyboardNavigation: true,
18321 calendarWeeks: false,
18323 startDate: -Infinity,
18327 daysOfWeekDisabled: [],
18331 singleMode : false,
18333 UTCDate: function()
18335 return new Date(Date.UTC.apply(Date, arguments));
18338 UTCToday: function()
18340 var today = new Date();
18341 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18344 getDate: function() {
18345 var d = this.getUTCDate();
18346 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18349 getUTCDate: function() {
18353 setDate: function(d) {
18354 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18357 setUTCDate: function(d) {
18359 this.setValue(this.formatDate(this.date));
18362 onRender: function(ct, position)
18365 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18367 this.language = this.language || 'en';
18368 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18369 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18371 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18372 this.format = this.format || 'm/d/y';
18373 this.isInline = false;
18374 this.isInput = true;
18375 this.component = this.el.select('.add-on', true).first() || false;
18376 this.component = (this.component && this.component.length === 0) ? false : this.component;
18377 this.hasInput = this.component && this.inputEl().length;
18379 if (typeof(this.minViewMode === 'string')) {
18380 switch (this.minViewMode) {
18382 this.minViewMode = 1;
18385 this.minViewMode = 2;
18388 this.minViewMode = 0;
18393 if (typeof(this.viewMode === 'string')) {
18394 switch (this.viewMode) {
18407 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18409 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18411 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18413 this.picker().on('mousedown', this.onMousedown, this);
18414 this.picker().on('click', this.onClick, this);
18416 this.picker().addClass('datepicker-dropdown');
18418 this.startViewMode = this.viewMode;
18420 if(this.singleMode){
18421 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18422 v.setVisibilityMode(Roo.Element.DISPLAY);
18426 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18427 v.setStyle('width', '189px');
18431 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18432 if(!this.calendarWeeks){
18437 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18438 v.attr('colspan', function(i, val){
18439 return parseInt(val) + 1;
18444 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18446 this.setStartDate(this.startDate);
18447 this.setEndDate(this.endDate);
18449 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18456 if(this.isInline) {
18461 picker : function()
18463 return this.pickerEl;
18464 // return this.el.select('.datepicker', true).first();
18467 fillDow: function()
18469 var dowCnt = this.weekStart;
18478 if(this.calendarWeeks){
18486 while (dowCnt < this.weekStart + 7) {
18490 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18494 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18497 fillMonths: function()
18500 var months = this.picker().select('>.datepicker-months td', true).first();
18502 months.dom.innerHTML = '';
18508 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18511 months.createChild(month);
18518 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;
18520 if (this.date < this.startDate) {
18521 this.viewDate = new Date(this.startDate);
18522 } else if (this.date > this.endDate) {
18523 this.viewDate = new Date(this.endDate);
18525 this.viewDate = new Date(this.date);
18533 var d = new Date(this.viewDate),
18534 year = d.getUTCFullYear(),
18535 month = d.getUTCMonth(),
18536 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18537 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18538 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18539 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18540 currentDate = this.date && this.date.valueOf(),
18541 today = this.UTCToday();
18543 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18545 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18547 // this.picker.select('>tfoot th.today').
18548 // .text(dates[this.language].today)
18549 // .toggle(this.todayBtn !== false);
18551 this.updateNavArrows();
18554 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18556 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18558 prevMonth.setUTCDate(day);
18560 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18562 var nextMonth = new Date(prevMonth);
18564 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18566 nextMonth = nextMonth.valueOf();
18568 var fillMonths = false;
18570 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18572 while(prevMonth.valueOf() < nextMonth) {
18575 if (prevMonth.getUTCDay() === this.weekStart) {
18577 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18585 if(this.calendarWeeks){
18586 // ISO 8601: First week contains first thursday.
18587 // ISO also states week starts on Monday, but we can be more abstract here.
18589 // Start of current week: based on weekstart/current date
18590 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18591 // Thursday of this week
18592 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18593 // First Thursday of year, year from thursday
18594 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18595 // Calendar week: ms between thursdays, div ms per day, div 7 days
18596 calWeek = (th - yth) / 864e5 / 7 + 1;
18598 fillMonths.cn.push({
18606 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18608 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18611 if (this.todayHighlight &&
18612 prevMonth.getUTCFullYear() == today.getFullYear() &&
18613 prevMonth.getUTCMonth() == today.getMonth() &&
18614 prevMonth.getUTCDate() == today.getDate()) {
18615 clsName += ' today';
18618 if (currentDate && prevMonth.valueOf() === currentDate) {
18619 clsName += ' active';
18622 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18623 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18624 clsName += ' disabled';
18627 fillMonths.cn.push({
18629 cls: 'day ' + clsName,
18630 html: prevMonth.getDate()
18633 prevMonth.setDate(prevMonth.getDate()+1);
18636 var currentYear = this.date && this.date.getUTCFullYear();
18637 var currentMonth = this.date && this.date.getUTCMonth();
18639 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18641 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18642 v.removeClass('active');
18644 if(currentYear === year && k === currentMonth){
18645 v.addClass('active');
18648 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18649 v.addClass('disabled');
18655 year = parseInt(year/10, 10) * 10;
18657 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18659 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18662 for (var i = -1; i < 11; i++) {
18663 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18665 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18673 showMode: function(dir)
18676 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18679 Roo.each(this.picker().select('>div',true).elements, function(v){
18680 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18683 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18688 if(this.isInline) {
18692 this.picker().removeClass(['bottom', 'top']);
18694 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18696 * place to the top of element!
18700 this.picker().addClass('top');
18701 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18706 this.picker().addClass('bottom');
18708 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18711 parseDate : function(value)
18713 if(!value || value instanceof Date){
18716 var v = Date.parseDate(value, this.format);
18717 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18718 v = Date.parseDate(value, 'Y-m-d');
18720 if(!v && this.altFormats){
18721 if(!this.altFormatsArray){
18722 this.altFormatsArray = this.altFormats.split("|");
18724 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18725 v = Date.parseDate(value, this.altFormatsArray[i]);
18731 formatDate : function(date, fmt)
18733 return (!date || !(date instanceof Date)) ?
18734 date : date.dateFormat(fmt || this.format);
18737 onFocus : function()
18739 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18743 onBlur : function()
18745 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18747 var d = this.inputEl().getValue();
18756 this.picker().show();
18760 this.fireEvent('show', this, this.date);
18765 if(this.isInline) {
18768 this.picker().hide();
18769 this.viewMode = this.startViewMode;
18772 this.fireEvent('hide', this, this.date);
18776 onMousedown: function(e)
18778 e.stopPropagation();
18779 e.preventDefault();
18784 Roo.bootstrap.DateField.superclass.keyup.call(this);
18788 setValue: function(v)
18790 if(this.fireEvent('beforeselect', this, v) !== false){
18791 var d = new Date(this.parseDate(v) ).clearTime();
18793 if(isNaN(d.getTime())){
18794 this.date = this.viewDate = '';
18795 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18799 v = this.formatDate(d);
18801 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18803 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18807 this.fireEvent('select', this, this.date);
18811 getValue: function()
18813 return this.formatDate(this.date);
18816 fireKey: function(e)
18818 if (!this.picker().isVisible()){
18819 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18825 var dateChanged = false,
18827 newDate, newViewDate;
18832 e.preventDefault();
18836 if (!this.keyboardNavigation) {
18839 dir = e.keyCode == 37 ? -1 : 1;
18842 newDate = this.moveYear(this.date, dir);
18843 newViewDate = this.moveYear(this.viewDate, dir);
18844 } else if (e.shiftKey){
18845 newDate = this.moveMonth(this.date, dir);
18846 newViewDate = this.moveMonth(this.viewDate, dir);
18848 newDate = new Date(this.date);
18849 newDate.setUTCDate(this.date.getUTCDate() + dir);
18850 newViewDate = new Date(this.viewDate);
18851 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18853 if (this.dateWithinRange(newDate)){
18854 this.date = newDate;
18855 this.viewDate = newViewDate;
18856 this.setValue(this.formatDate(this.date));
18858 e.preventDefault();
18859 dateChanged = true;
18864 if (!this.keyboardNavigation) {
18867 dir = e.keyCode == 38 ? -1 : 1;
18869 newDate = this.moveYear(this.date, dir);
18870 newViewDate = this.moveYear(this.viewDate, dir);
18871 } else if (e.shiftKey){
18872 newDate = this.moveMonth(this.date, dir);
18873 newViewDate = this.moveMonth(this.viewDate, dir);
18875 newDate = new Date(this.date);
18876 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18877 newViewDate = new Date(this.viewDate);
18878 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18880 if (this.dateWithinRange(newDate)){
18881 this.date = newDate;
18882 this.viewDate = newViewDate;
18883 this.setValue(this.formatDate(this.date));
18885 e.preventDefault();
18886 dateChanged = true;
18890 this.setValue(this.formatDate(this.date));
18892 e.preventDefault();
18895 this.setValue(this.formatDate(this.date));
18909 onClick: function(e)
18911 e.stopPropagation();
18912 e.preventDefault();
18914 var target = e.getTarget();
18916 if(target.nodeName.toLowerCase() === 'i'){
18917 target = Roo.get(target).dom.parentNode;
18920 var nodeName = target.nodeName;
18921 var className = target.className;
18922 var html = target.innerHTML;
18923 //Roo.log(nodeName);
18925 switch(nodeName.toLowerCase()) {
18927 switch(className) {
18933 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18934 switch(this.viewMode){
18936 this.viewDate = this.moveMonth(this.viewDate, dir);
18940 this.viewDate = this.moveYear(this.viewDate, dir);
18946 var date = new Date();
18947 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18949 this.setValue(this.formatDate(this.date));
18956 if (className.indexOf('disabled') < 0) {
18957 this.viewDate.setUTCDate(1);
18958 if (className.indexOf('month') > -1) {
18959 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18961 var year = parseInt(html, 10) || 0;
18962 this.viewDate.setUTCFullYear(year);
18966 if(this.singleMode){
18967 this.setValue(this.formatDate(this.viewDate));
18978 //Roo.log(className);
18979 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18980 var day = parseInt(html, 10) || 1;
18981 var year = this.viewDate.getUTCFullYear(),
18982 month = this.viewDate.getUTCMonth();
18984 if (className.indexOf('old') > -1) {
18991 } else if (className.indexOf('new') > -1) {
18999 //Roo.log([year,month,day]);
19000 this.date = this.UTCDate(year, month, day,0,0,0,0);
19001 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19003 //Roo.log(this.formatDate(this.date));
19004 this.setValue(this.formatDate(this.date));
19011 setStartDate: function(startDate)
19013 this.startDate = startDate || -Infinity;
19014 if (this.startDate !== -Infinity) {
19015 this.startDate = this.parseDate(this.startDate);
19018 this.updateNavArrows();
19021 setEndDate: function(endDate)
19023 this.endDate = endDate || Infinity;
19024 if (this.endDate !== Infinity) {
19025 this.endDate = this.parseDate(this.endDate);
19028 this.updateNavArrows();
19031 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19033 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19034 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19035 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19037 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19038 return parseInt(d, 10);
19041 this.updateNavArrows();
19044 updateNavArrows: function()
19046 if(this.singleMode){
19050 var d = new Date(this.viewDate),
19051 year = d.getUTCFullYear(),
19052 month = d.getUTCMonth();
19054 Roo.each(this.picker().select('.prev', true).elements, function(v){
19056 switch (this.viewMode) {
19059 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19065 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19072 Roo.each(this.picker().select('.next', true).elements, function(v){
19074 switch (this.viewMode) {
19077 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19083 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19091 moveMonth: function(date, dir)
19096 var new_date = new Date(date.valueOf()),
19097 day = new_date.getUTCDate(),
19098 month = new_date.getUTCMonth(),
19099 mag = Math.abs(dir),
19101 dir = dir > 0 ? 1 : -1;
19104 // If going back one month, make sure month is not current month
19105 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19107 return new_date.getUTCMonth() == month;
19109 // If going forward one month, make sure month is as expected
19110 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19112 return new_date.getUTCMonth() != new_month;
19114 new_month = month + dir;
19115 new_date.setUTCMonth(new_month);
19116 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19117 if (new_month < 0 || new_month > 11) {
19118 new_month = (new_month + 12) % 12;
19121 // For magnitudes >1, move one month at a time...
19122 for (var i=0; i<mag; i++) {
19123 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19124 new_date = this.moveMonth(new_date, dir);
19126 // ...then reset the day, keeping it in the new month
19127 new_month = new_date.getUTCMonth();
19128 new_date.setUTCDate(day);
19130 return new_month != new_date.getUTCMonth();
19133 // Common date-resetting loop -- if date is beyond end of month, make it
19136 new_date.setUTCDate(--day);
19137 new_date.setUTCMonth(new_month);
19142 moveYear: function(date, dir)
19144 return this.moveMonth(date, dir*12);
19147 dateWithinRange: function(date)
19149 return date >= this.startDate && date <= this.endDate;
19155 this.picker().remove();
19158 validateValue : function(value)
19160 if(this.getVisibilityEl().hasClass('hidden')){
19164 if(value.length < 1) {
19165 if(this.allowBlank){
19171 if(value.length < this.minLength){
19174 if(value.length > this.maxLength){
19178 var vt = Roo.form.VTypes;
19179 if(!vt[this.vtype](value, this)){
19183 if(typeof this.validator == "function"){
19184 var msg = this.validator(value);
19190 if(this.regex && !this.regex.test(value)){
19194 if(typeof(this.parseDate(value)) == 'undefined'){
19198 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19202 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19210 setVisible : function(visible)
19216 this.getEl().removeClass('hidden');
19222 this.getEl().addClass('hidden');
19227 Roo.apply(Roo.bootstrap.DateField, {
19238 html: '<i class="fa fa-arrow-left"/>'
19248 html: '<i class="fa fa-arrow-right"/>'
19290 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19291 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19292 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19293 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19294 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19307 navFnc: 'FullYear',
19312 navFnc: 'FullYear',
19317 Roo.apply(Roo.bootstrap.DateField, {
19321 cls: 'datepicker dropdown-menu roo-dynamic',
19325 cls: 'datepicker-days',
19329 cls: 'table-condensed',
19331 Roo.bootstrap.DateField.head,
19335 Roo.bootstrap.DateField.footer
19342 cls: 'datepicker-months',
19346 cls: 'table-condensed',
19348 Roo.bootstrap.DateField.head,
19349 Roo.bootstrap.DateField.content,
19350 Roo.bootstrap.DateField.footer
19357 cls: 'datepicker-years',
19361 cls: 'table-condensed',
19363 Roo.bootstrap.DateField.head,
19364 Roo.bootstrap.DateField.content,
19365 Roo.bootstrap.DateField.footer
19384 * @class Roo.bootstrap.TimeField
19385 * @extends Roo.bootstrap.Input
19386 * Bootstrap DateField class
19390 * Create a new TimeField
19391 * @param {Object} config The config object
19394 Roo.bootstrap.TimeField = function(config){
19395 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19399 * Fires when this field show.
19400 * @param {Roo.bootstrap.DateField} thisthis
19401 * @param {Mixed} date The date value
19406 * Fires when this field hide.
19407 * @param {Roo.bootstrap.DateField} this
19408 * @param {Mixed} date The date value
19413 * Fires when select a date.
19414 * @param {Roo.bootstrap.DateField} this
19415 * @param {Mixed} date The date value
19421 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19424 * @cfg {String} format
19425 * The default time format string which can be overriden for localization support. The format must be
19426 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19430 onRender: function(ct, position)
19433 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19435 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19437 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19439 this.pop = this.picker().select('>.datepicker-time',true).first();
19440 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19442 this.picker().on('mousedown', this.onMousedown, this);
19443 this.picker().on('click', this.onClick, this);
19445 this.picker().addClass('datepicker-dropdown');
19450 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19451 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19452 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19453 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19454 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19455 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19459 fireKey: function(e){
19460 if (!this.picker().isVisible()){
19461 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19467 e.preventDefault();
19475 this.onTogglePeriod();
19478 this.onIncrementMinutes();
19481 this.onDecrementMinutes();
19490 onClick: function(e) {
19491 e.stopPropagation();
19492 e.preventDefault();
19495 picker : function()
19497 return this.el.select('.datepicker', true).first();
19500 fillTime: function()
19502 var time = this.pop.select('tbody', true).first();
19504 time.dom.innerHTML = '';
19519 cls: 'hours-up glyphicon glyphicon-chevron-up'
19539 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19560 cls: 'timepicker-hour',
19575 cls: 'timepicker-minute',
19590 cls: 'btn btn-primary period',
19612 cls: 'hours-down glyphicon glyphicon-chevron-down'
19632 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19650 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19657 var hours = this.time.getHours();
19658 var minutes = this.time.getMinutes();
19671 hours = hours - 12;
19675 hours = '0' + hours;
19679 minutes = '0' + minutes;
19682 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19683 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19684 this.pop.select('button', true).first().dom.innerHTML = period;
19690 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19692 var cls = ['bottom'];
19694 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19701 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19706 this.picker().addClass(cls.join('-'));
19710 Roo.each(cls, function(c){
19712 _this.picker().setTop(_this.inputEl().getHeight());
19716 _this.picker().setTop(0 - _this.picker().getHeight());
19721 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19725 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19732 onFocus : function()
19734 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19738 onBlur : function()
19740 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19746 this.picker().show();
19751 this.fireEvent('show', this, this.date);
19756 this.picker().hide();
19759 this.fireEvent('hide', this, this.date);
19762 setTime : function()
19765 this.setValue(this.time.format(this.format));
19767 this.fireEvent('select', this, this.date);
19772 onMousedown: function(e){
19773 e.stopPropagation();
19774 e.preventDefault();
19777 onIncrementHours: function()
19779 Roo.log('onIncrementHours');
19780 this.time = this.time.add(Date.HOUR, 1);
19785 onDecrementHours: function()
19787 Roo.log('onDecrementHours');
19788 this.time = this.time.add(Date.HOUR, -1);
19792 onIncrementMinutes: function()
19794 Roo.log('onIncrementMinutes');
19795 this.time = this.time.add(Date.MINUTE, 1);
19799 onDecrementMinutes: function()
19801 Roo.log('onDecrementMinutes');
19802 this.time = this.time.add(Date.MINUTE, -1);
19806 onTogglePeriod: function()
19808 Roo.log('onTogglePeriod');
19809 this.time = this.time.add(Date.HOUR, 12);
19816 Roo.apply(Roo.bootstrap.TimeField, {
19846 cls: 'btn btn-info ok',
19858 Roo.apply(Roo.bootstrap.TimeField, {
19862 cls: 'datepicker dropdown-menu',
19866 cls: 'datepicker-time',
19870 cls: 'table-condensed',
19872 Roo.bootstrap.TimeField.content,
19873 Roo.bootstrap.TimeField.footer
19892 * @class Roo.bootstrap.MonthField
19893 * @extends Roo.bootstrap.Input
19894 * Bootstrap MonthField class
19896 * @cfg {String} language default en
19899 * Create a new MonthField
19900 * @param {Object} config The config object
19903 Roo.bootstrap.MonthField = function(config){
19904 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19909 * Fires when this field show.
19910 * @param {Roo.bootstrap.MonthField} this
19911 * @param {Mixed} date The date value
19916 * Fires when this field hide.
19917 * @param {Roo.bootstrap.MonthField} this
19918 * @param {Mixed} date The date value
19923 * Fires when select a date.
19924 * @param {Roo.bootstrap.MonthField} this
19925 * @param {String} oldvalue The old value
19926 * @param {String} newvalue The new value
19932 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19934 onRender: function(ct, position)
19937 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19939 this.language = this.language || 'en';
19940 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19941 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19943 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19944 this.isInline = false;
19945 this.isInput = true;
19946 this.component = this.el.select('.add-on', true).first() || false;
19947 this.component = (this.component && this.component.length === 0) ? false : this.component;
19948 this.hasInput = this.component && this.inputEL().length;
19950 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19952 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19954 this.picker().on('mousedown', this.onMousedown, this);
19955 this.picker().on('click', this.onClick, this);
19957 this.picker().addClass('datepicker-dropdown');
19959 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19960 v.setStyle('width', '189px');
19967 if(this.isInline) {
19973 setValue: function(v, suppressEvent)
19975 var o = this.getValue();
19977 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19981 if(suppressEvent !== true){
19982 this.fireEvent('select', this, o, v);
19987 getValue: function()
19992 onClick: function(e)
19994 e.stopPropagation();
19995 e.preventDefault();
19997 var target = e.getTarget();
19999 if(target.nodeName.toLowerCase() === 'i'){
20000 target = Roo.get(target).dom.parentNode;
20003 var nodeName = target.nodeName;
20004 var className = target.className;
20005 var html = target.innerHTML;
20007 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20011 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20013 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20019 picker : function()
20021 return this.pickerEl;
20024 fillMonths: function()
20027 var months = this.picker().select('>.datepicker-months td', true).first();
20029 months.dom.innerHTML = '';
20035 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20038 months.createChild(month);
20047 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20048 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20051 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20052 e.removeClass('active');
20054 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20055 e.addClass('active');
20062 if(this.isInline) {
20066 this.picker().removeClass(['bottom', 'top']);
20068 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20070 * place to the top of element!
20074 this.picker().addClass('top');
20075 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20080 this.picker().addClass('bottom');
20082 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20085 onFocus : function()
20087 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20091 onBlur : function()
20093 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20095 var d = this.inputEl().getValue();
20104 this.picker().show();
20105 this.picker().select('>.datepicker-months', true).first().show();
20109 this.fireEvent('show', this, this.date);
20114 if(this.isInline) {
20117 this.picker().hide();
20118 this.fireEvent('hide', this, this.date);
20122 onMousedown: function(e)
20124 e.stopPropagation();
20125 e.preventDefault();
20130 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20134 fireKey: function(e)
20136 if (!this.picker().isVisible()){
20137 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20148 e.preventDefault();
20152 dir = e.keyCode == 37 ? -1 : 1;
20154 this.vIndex = this.vIndex + dir;
20156 if(this.vIndex < 0){
20160 if(this.vIndex > 11){
20164 if(isNaN(this.vIndex)){
20168 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20174 dir = e.keyCode == 38 ? -1 : 1;
20176 this.vIndex = this.vIndex + dir * 4;
20178 if(this.vIndex < 0){
20182 if(this.vIndex > 11){
20186 if(isNaN(this.vIndex)){
20190 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20195 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20196 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20200 e.preventDefault();
20203 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20204 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20220 this.picker().remove();
20225 Roo.apply(Roo.bootstrap.MonthField, {
20244 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20245 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20250 Roo.apply(Roo.bootstrap.MonthField, {
20254 cls: 'datepicker dropdown-menu roo-dynamic',
20258 cls: 'datepicker-months',
20262 cls: 'table-condensed',
20264 Roo.bootstrap.DateField.content
20284 * @class Roo.bootstrap.CheckBox
20285 * @extends Roo.bootstrap.Input
20286 * Bootstrap CheckBox class
20288 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20289 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20290 * @cfg {String} boxLabel The text that appears beside the checkbox
20291 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20292 * @cfg {Boolean} checked initnal the element
20293 * @cfg {Boolean} inline inline the element (default false)
20294 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20295 * @cfg {String} tooltip label tooltip
20298 * Create a new CheckBox
20299 * @param {Object} config The config object
20302 Roo.bootstrap.CheckBox = function(config){
20303 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20308 * Fires when the element is checked or unchecked.
20309 * @param {Roo.bootstrap.CheckBox} this This input
20310 * @param {Boolean} checked The new checked value
20315 * Fires when the element is click.
20316 * @param {Roo.bootstrap.CheckBox} this This input
20323 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20325 inputType: 'checkbox',
20334 getAutoCreate : function()
20336 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20342 cfg.cls = 'form-group ' + this.inputType; //input-group
20345 cfg.cls += ' ' + this.inputType + '-inline';
20351 type : this.inputType,
20352 value : this.inputValue,
20353 cls : 'roo-' + this.inputType, //'form-box',
20354 placeholder : this.placeholder || ''
20358 if(this.inputType != 'radio'){
20362 cls : 'roo-hidden-value',
20363 value : this.checked ? this.inputValue : this.valueOff
20368 if (this.weight) { // Validity check?
20369 cfg.cls += " " + this.inputType + "-" + this.weight;
20372 if (this.disabled) {
20373 input.disabled=true;
20377 input.checked = this.checked;
20382 input.name = this.name;
20384 if(this.inputType != 'radio'){
20385 hidden.name = this.name;
20386 input.name = '_hidden_' + this.name;
20391 input.cls += ' input-' + this.size;
20396 ['xs','sm','md','lg'].map(function(size){
20397 if (settings[size]) {
20398 cfg.cls += ' col-' + size + '-' + settings[size];
20402 var inputblock = input;
20404 if (this.before || this.after) {
20407 cls : 'input-group',
20412 inputblock.cn.push({
20414 cls : 'input-group-addon',
20419 inputblock.cn.push(input);
20421 if(this.inputType != 'radio'){
20422 inputblock.cn.push(hidden);
20426 inputblock.cn.push({
20428 cls : 'input-group-addon',
20435 if (align ==='left' && this.fieldLabel.length) {
20436 // Roo.log("left and has label");
20441 cls : 'control-label',
20442 html : this.fieldLabel
20452 if(this.labelWidth > 12){
20453 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20456 if(this.labelWidth < 13 && this.labelmd == 0){
20457 this.labelmd = this.labelWidth;
20460 if(this.labellg > 0){
20461 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20462 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20465 if(this.labelmd > 0){
20466 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20467 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20470 if(this.labelsm > 0){
20471 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20472 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20475 if(this.labelxs > 0){
20476 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20477 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20480 } else if ( this.fieldLabel.length) {
20481 // Roo.log(" label");
20485 tag: this.boxLabel ? 'span' : 'label',
20487 cls: 'control-label box-input-label',
20488 //cls : 'input-group-addon',
20489 html : this.fieldLabel
20498 // Roo.log(" no label && no align");
20499 cfg.cn = [ inputblock ] ;
20505 var boxLabelCfg = {
20507 //'for': id, // box label is handled by onclick - so no for...
20509 html: this.boxLabel
20513 boxLabelCfg.tooltip = this.tooltip;
20516 cfg.cn.push(boxLabelCfg);
20519 if(this.inputType != 'radio'){
20520 cfg.cn.push(hidden);
20528 * return the real input element.
20530 inputEl: function ()
20532 return this.el.select('input.roo-' + this.inputType,true).first();
20534 hiddenEl: function ()
20536 return this.el.select('input.roo-hidden-value',true).first();
20539 labelEl: function()
20541 return this.el.select('label.control-label',true).first();
20543 /* depricated... */
20547 return this.labelEl();
20550 boxLabelEl: function()
20552 return this.el.select('label.box-label',true).first();
20555 initEvents : function()
20557 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20559 this.inputEl().on('click', this.onClick, this);
20561 if (this.boxLabel) {
20562 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20565 this.startValue = this.getValue();
20568 Roo.bootstrap.CheckBox.register(this);
20572 onClick : function(e)
20574 if(this.fireEvent('click', this, e) !== false){
20575 this.setChecked(!this.checked);
20580 setChecked : function(state,suppressEvent)
20582 this.startValue = this.getValue();
20584 if(this.inputType == 'radio'){
20586 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20587 e.dom.checked = false;
20590 this.inputEl().dom.checked = true;
20592 this.inputEl().dom.value = this.inputValue;
20594 if(suppressEvent !== true){
20595 this.fireEvent('check', this, true);
20603 this.checked = state;
20605 this.inputEl().dom.checked = state;
20608 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20610 if(suppressEvent !== true){
20611 this.fireEvent('check', this, state);
20617 getValue : function()
20619 if(this.inputType == 'radio'){
20620 return this.getGroupValue();
20623 return this.hiddenEl().dom.value;
20627 getGroupValue : function()
20629 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20633 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20636 setValue : function(v,suppressEvent)
20638 if(this.inputType == 'radio'){
20639 this.setGroupValue(v, suppressEvent);
20643 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20648 setGroupValue : function(v, suppressEvent)
20650 this.startValue = this.getValue();
20652 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20653 e.dom.checked = false;
20655 if(e.dom.value == v){
20656 e.dom.checked = true;
20660 if(suppressEvent !== true){
20661 this.fireEvent('check', this, true);
20669 validate : function()
20671 if(this.getVisibilityEl().hasClass('hidden')){
20677 (this.inputType == 'radio' && this.validateRadio()) ||
20678 (this.inputType == 'checkbox' && this.validateCheckbox())
20684 this.markInvalid();
20688 validateRadio : function()
20690 if(this.getVisibilityEl().hasClass('hidden')){
20694 if(this.allowBlank){
20700 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20701 if(!e.dom.checked){
20713 validateCheckbox : function()
20716 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20717 //return (this.getValue() == this.inputValue) ? true : false;
20720 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20728 for(var i in group){
20729 if(group[i].el.isVisible(true)){
20737 for(var i in group){
20742 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20749 * Mark this field as valid
20751 markValid : function()
20755 this.fireEvent('valid', this);
20757 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20760 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20767 if(this.inputType == 'radio'){
20768 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20769 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20770 e.findParent('.form-group', false, true).addClass(_this.validClass);
20777 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20778 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20782 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20788 for(var i in group){
20789 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20790 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20795 * Mark this field as invalid
20796 * @param {String} msg The validation message
20798 markInvalid : function(msg)
20800 if(this.allowBlank){
20806 this.fireEvent('invalid', this, msg);
20808 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20811 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20815 label.markInvalid();
20818 if(this.inputType == 'radio'){
20819 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20820 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20821 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20828 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20829 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20833 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20839 for(var i in group){
20840 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20841 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20846 clearInvalid : function()
20848 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20850 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20852 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20854 if (label && label.iconEl) {
20855 label.iconEl.removeClass(label.validClass);
20856 label.iconEl.removeClass(label.invalidClass);
20860 disable : function()
20862 if(this.inputType != 'radio'){
20863 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20870 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20871 _this.getActionEl().addClass(this.disabledClass);
20872 e.dom.disabled = true;
20876 this.disabled = true;
20877 this.fireEvent("disable", this);
20881 enable : function()
20883 if(this.inputType != 'radio'){
20884 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20891 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20892 _this.getActionEl().removeClass(this.disabledClass);
20893 e.dom.disabled = false;
20897 this.disabled = false;
20898 this.fireEvent("enable", this);
20902 setBoxLabel : function(v)
20907 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20913 Roo.apply(Roo.bootstrap.CheckBox, {
20918 * register a CheckBox Group
20919 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20921 register : function(checkbox)
20923 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20924 this.groups[checkbox.groupId] = {};
20927 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20931 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20935 * fetch a CheckBox Group based on the group ID
20936 * @param {string} the group ID
20937 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20939 get: function(groupId) {
20940 if (typeof(this.groups[groupId]) == 'undefined') {
20944 return this.groups[groupId] ;
20957 * @class Roo.bootstrap.Radio
20958 * @extends Roo.bootstrap.Component
20959 * Bootstrap Radio class
20960 * @cfg {String} boxLabel - the label associated
20961 * @cfg {String} value - the value of radio
20964 * Create a new Radio
20965 * @param {Object} config The config object
20967 Roo.bootstrap.Radio = function(config){
20968 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20972 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20978 getAutoCreate : function()
20982 cls : 'form-group radio',
20987 html : this.boxLabel
20995 initEvents : function()
20997 this.parent().register(this);
20999 this.el.on('click', this.onClick, this);
21003 onClick : function(e)
21005 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21006 this.setChecked(true);
21010 setChecked : function(state, suppressEvent)
21012 this.parent().setValue(this.value, suppressEvent);
21016 setBoxLabel : function(v)
21021 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21036 * @class Roo.bootstrap.SecurePass
21037 * @extends Roo.bootstrap.Input
21038 * Bootstrap SecurePass class
21042 * Create a new SecurePass
21043 * @param {Object} config The config object
21046 Roo.bootstrap.SecurePass = function (config) {
21047 // these go here, so the translation tool can replace them..
21049 PwdEmpty: "Please type a password, and then retype it to confirm.",
21050 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21051 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21052 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21053 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21054 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21055 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21056 TooWeak: "Your password is Too Weak."
21058 this.meterLabel = "Password strength:";
21059 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21060 this.meterClass = [
21061 "roo-password-meter-tooweak",
21062 "roo-password-meter-weak",
21063 "roo-password-meter-medium",
21064 "roo-password-meter-strong",
21065 "roo-password-meter-grey"
21070 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21073 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21075 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21077 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21078 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21079 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21080 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21081 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21082 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21083 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21093 * @cfg {String/Object} Label for the strength meter (defaults to
21094 * 'Password strength:')
21099 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21100 * ['Weak', 'Medium', 'Strong'])
21103 pwdStrengths: false,
21116 initEvents: function ()
21118 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21120 if (this.el.is('input[type=password]') && Roo.isSafari) {
21121 this.el.on('keydown', this.SafariOnKeyDown, this);
21124 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21127 onRender: function (ct, position)
21129 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21130 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21131 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21133 this.trigger.createChild({
21138 cls: 'roo-password-meter-grey col-xs-12',
21141 //width: this.meterWidth + 'px'
21145 cls: 'roo-password-meter-text'
21151 if (this.hideTrigger) {
21152 this.trigger.setDisplayed(false);
21154 this.setSize(this.width || '', this.height || '');
21157 onDestroy: function ()
21159 if (this.trigger) {
21160 this.trigger.removeAllListeners();
21161 this.trigger.remove();
21164 this.wrap.remove();
21166 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21169 checkStrength: function ()
21171 var pwd = this.inputEl().getValue();
21172 if (pwd == this._lastPwd) {
21177 if (this.ClientSideStrongPassword(pwd)) {
21179 } else if (this.ClientSideMediumPassword(pwd)) {
21181 } else if (this.ClientSideWeakPassword(pwd)) {
21187 Roo.log('strength1: ' + strength);
21189 //var pm = this.trigger.child('div/div/div').dom;
21190 var pm = this.trigger.child('div/div');
21191 pm.removeClass(this.meterClass);
21192 pm.addClass(this.meterClass[strength]);
21195 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21197 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21199 this._lastPwd = pwd;
21203 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21205 this._lastPwd = '';
21207 var pm = this.trigger.child('div/div');
21208 pm.removeClass(this.meterClass);
21209 pm.addClass('roo-password-meter-grey');
21212 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21215 this.inputEl().dom.type='password';
21218 validateValue: function (value)
21221 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21224 if (value.length == 0) {
21225 if (this.allowBlank) {
21226 this.clearInvalid();
21230 this.markInvalid(this.errors.PwdEmpty);
21231 this.errorMsg = this.errors.PwdEmpty;
21239 if ('[\x21-\x7e]*'.match(value)) {
21240 this.markInvalid(this.errors.PwdBadChar);
21241 this.errorMsg = this.errors.PwdBadChar;
21244 if (value.length < 6) {
21245 this.markInvalid(this.errors.PwdShort);
21246 this.errorMsg = this.errors.PwdShort;
21249 if (value.length > 16) {
21250 this.markInvalid(this.errors.PwdLong);
21251 this.errorMsg = this.errors.PwdLong;
21255 if (this.ClientSideStrongPassword(value)) {
21257 } else if (this.ClientSideMediumPassword(value)) {
21259 } else if (this.ClientSideWeakPassword(value)) {
21266 if (strength < 2) {
21267 //this.markInvalid(this.errors.TooWeak);
21268 this.errorMsg = this.errors.TooWeak;
21273 console.log('strength2: ' + strength);
21275 //var pm = this.trigger.child('div/div/div').dom;
21277 var pm = this.trigger.child('div/div');
21278 pm.removeClass(this.meterClass);
21279 pm.addClass(this.meterClass[strength]);
21281 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21283 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21285 this.errorMsg = '';
21289 CharacterSetChecks: function (type)
21292 this.fResult = false;
21295 isctype: function (character, type)
21298 case this.kCapitalLetter:
21299 if (character >= 'A' && character <= 'Z') {
21304 case this.kSmallLetter:
21305 if (character >= 'a' && character <= 'z') {
21311 if (character >= '0' && character <= '9') {
21316 case this.kPunctuation:
21317 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21328 IsLongEnough: function (pwd, size)
21330 return !(pwd == null || isNaN(size) || pwd.length < size);
21333 SpansEnoughCharacterSets: function (word, nb)
21335 if (!this.IsLongEnough(word, nb))
21340 var characterSetChecks = new Array(
21341 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21342 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21345 for (var index = 0; index < word.length; ++index) {
21346 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21347 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21348 characterSetChecks[nCharSet].fResult = true;
21355 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21356 if (characterSetChecks[nCharSet].fResult) {
21361 if (nCharSets < nb) {
21367 ClientSideStrongPassword: function (pwd)
21369 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21372 ClientSideMediumPassword: function (pwd)
21374 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21377 ClientSideWeakPassword: function (pwd)
21379 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21382 })//<script type="text/javascript">
21385 * Based Ext JS Library 1.1.1
21386 * Copyright(c) 2006-2007, Ext JS, LLC.
21392 * @class Roo.HtmlEditorCore
21393 * @extends Roo.Component
21394 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21396 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21399 Roo.HtmlEditorCore = function(config){
21402 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21407 * @event initialize
21408 * Fires when the editor is fully initialized (including the iframe)
21409 * @param {Roo.HtmlEditorCore} this
21414 * Fires when the editor is first receives the focus. Any insertion must wait
21415 * until after this event.
21416 * @param {Roo.HtmlEditorCore} this
21420 * @event beforesync
21421 * Fires before the textarea is updated with content from the editor iframe. Return false
21422 * to cancel the sync.
21423 * @param {Roo.HtmlEditorCore} this
21424 * @param {String} html
21428 * @event beforepush
21429 * Fires before the iframe editor is updated with content from the textarea. Return false
21430 * to cancel the push.
21431 * @param {Roo.HtmlEditorCore} this
21432 * @param {String} html
21437 * Fires when the textarea is updated with content from the editor iframe.
21438 * @param {Roo.HtmlEditorCore} this
21439 * @param {String} html
21444 * Fires when the iframe editor is updated with content from the textarea.
21445 * @param {Roo.HtmlEditorCore} this
21446 * @param {String} html
21451 * @event editorevent
21452 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21453 * @param {Roo.HtmlEditorCore} this
21459 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21461 // defaults : white / black...
21462 this.applyBlacklists();
21469 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21473 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21479 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21484 * @cfg {Number} height (in pixels)
21488 * @cfg {Number} width (in pixels)
21493 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21496 stylesheets: false,
21501 // private properties
21502 validationEvent : false,
21504 initialized : false,
21506 sourceEditMode : false,
21507 onFocus : Roo.emptyFn,
21509 hideMode:'offsets',
21513 // blacklist + whitelisted elements..
21520 * Protected method that will not generally be called directly. It
21521 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21522 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21524 getDocMarkup : function(){
21528 // inherit styels from page...??
21529 if (this.stylesheets === false) {
21531 Roo.get(document.head).select('style').each(function(node) {
21532 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21535 Roo.get(document.head).select('link').each(function(node) {
21536 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21539 } else if (!this.stylesheets.length) {
21541 st = '<style type="text/css">' +
21542 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21545 st = '<style type="text/css">' +
21550 st += '<style type="text/css">' +
21551 'IMG { cursor: pointer } ' +
21554 var cls = 'roo-htmleditor-body';
21556 if(this.bodyCls.length){
21557 cls += ' ' + this.bodyCls;
21560 return '<html><head>' + st +
21561 //<style type="text/css">' +
21562 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21564 ' </head><body class="' + cls + '"></body></html>';
21568 onRender : function(ct, position)
21571 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21572 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21575 this.el.dom.style.border = '0 none';
21576 this.el.dom.setAttribute('tabIndex', -1);
21577 this.el.addClass('x-hidden hide');
21581 if(Roo.isIE){ // fix IE 1px bogus margin
21582 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21586 this.frameId = Roo.id();
21590 var iframe = this.owner.wrap.createChild({
21592 cls: 'form-control', // bootstrap..
21594 name: this.frameId,
21595 frameBorder : 'no',
21596 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21601 this.iframe = iframe.dom;
21603 this.assignDocWin();
21605 this.doc.designMode = 'on';
21608 this.doc.write(this.getDocMarkup());
21612 var task = { // must defer to wait for browser to be ready
21614 //console.log("run task?" + this.doc.readyState);
21615 this.assignDocWin();
21616 if(this.doc.body || this.doc.readyState == 'complete'){
21618 this.doc.designMode="on";
21622 Roo.TaskMgr.stop(task);
21623 this.initEditor.defer(10, this);
21630 Roo.TaskMgr.start(task);
21635 onResize : function(w, h)
21637 Roo.log('resize: ' +w + ',' + h );
21638 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21642 if(typeof w == 'number'){
21644 this.iframe.style.width = w + 'px';
21646 if(typeof h == 'number'){
21648 this.iframe.style.height = h + 'px';
21650 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21657 * Toggles the editor between standard and source edit mode.
21658 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21660 toggleSourceEdit : function(sourceEditMode){
21662 this.sourceEditMode = sourceEditMode === true;
21664 if(this.sourceEditMode){
21666 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21669 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21670 //this.iframe.className = '';
21673 //this.setSize(this.owner.wrap.getSize());
21674 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21681 * Protected method that will not generally be called directly. If you need/want
21682 * custom HTML cleanup, this is the method you should override.
21683 * @param {String} html The HTML to be cleaned
21684 * return {String} The cleaned HTML
21686 cleanHtml : function(html){
21687 html = String(html);
21688 if(html.length > 5){
21689 if(Roo.isSafari){ // strip safari nonsense
21690 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21693 if(html == ' '){
21700 * HTML Editor -> Textarea
21701 * Protected method that will not generally be called directly. Syncs the contents
21702 * of the editor iframe with the textarea.
21704 syncValue : function(){
21705 if(this.initialized){
21706 var bd = (this.doc.body || this.doc.documentElement);
21707 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21708 var html = bd.innerHTML;
21710 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21711 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21713 html = '<div style="'+m[0]+'">' + html + '</div>';
21716 html = this.cleanHtml(html);
21717 // fix up the special chars.. normaly like back quotes in word...
21718 // however we do not want to do this with chinese..
21719 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21720 var cc = b.charCodeAt();
21722 (cc >= 0x4E00 && cc < 0xA000 ) ||
21723 (cc >= 0x3400 && cc < 0x4E00 ) ||
21724 (cc >= 0xf900 && cc < 0xfb00 )
21730 if(this.owner.fireEvent('beforesync', this, html) !== false){
21731 this.el.dom.value = html;
21732 this.owner.fireEvent('sync', this, html);
21738 * Protected method that will not generally be called directly. Pushes the value of the textarea
21739 * into the iframe editor.
21741 pushValue : function(){
21742 if(this.initialized){
21743 var v = this.el.dom.value.trim();
21745 // if(v.length < 1){
21749 if(this.owner.fireEvent('beforepush', this, v) !== false){
21750 var d = (this.doc.body || this.doc.documentElement);
21752 this.cleanUpPaste();
21753 this.el.dom.value = d.innerHTML;
21754 this.owner.fireEvent('push', this, v);
21760 deferFocus : function(){
21761 this.focus.defer(10, this);
21765 focus : function(){
21766 if(this.win && !this.sourceEditMode){
21773 assignDocWin: function()
21775 var iframe = this.iframe;
21778 this.doc = iframe.contentWindow.document;
21779 this.win = iframe.contentWindow;
21781 // if (!Roo.get(this.frameId)) {
21784 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21785 // this.win = Roo.get(this.frameId).dom.contentWindow;
21787 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21791 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21792 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21797 initEditor : function(){
21798 //console.log("INIT EDITOR");
21799 this.assignDocWin();
21803 this.doc.designMode="on";
21805 this.doc.write(this.getDocMarkup());
21808 var dbody = (this.doc.body || this.doc.documentElement);
21809 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21810 // this copies styles from the containing element into thsi one..
21811 // not sure why we need all of this..
21812 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21814 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21815 //ss['background-attachment'] = 'fixed'; // w3c
21816 dbody.bgProperties = 'fixed'; // ie
21817 //Roo.DomHelper.applyStyles(dbody, ss);
21818 Roo.EventManager.on(this.doc, {
21819 //'mousedown': this.onEditorEvent,
21820 'mouseup': this.onEditorEvent,
21821 'dblclick': this.onEditorEvent,
21822 'click': this.onEditorEvent,
21823 'keyup': this.onEditorEvent,
21828 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21830 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21831 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21833 this.initialized = true;
21835 this.owner.fireEvent('initialize', this);
21840 onDestroy : function(){
21846 //for (var i =0; i < this.toolbars.length;i++) {
21847 // // fixme - ask toolbars for heights?
21848 // this.toolbars[i].onDestroy();
21851 //this.wrap.dom.innerHTML = '';
21852 //this.wrap.remove();
21857 onFirstFocus : function(){
21859 this.assignDocWin();
21862 this.activated = true;
21865 if(Roo.isGecko){ // prevent silly gecko errors
21867 var s = this.win.getSelection();
21868 if(!s.focusNode || s.focusNode.nodeType != 3){
21869 var r = s.getRangeAt(0);
21870 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21875 this.execCmd('useCSS', true);
21876 this.execCmd('styleWithCSS', false);
21879 this.owner.fireEvent('activate', this);
21883 adjustFont: function(btn){
21884 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21885 //if(Roo.isSafari){ // safari
21888 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21889 if(Roo.isSafari){ // safari
21890 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21891 v = (v < 10) ? 10 : v;
21892 v = (v > 48) ? 48 : v;
21893 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21898 v = Math.max(1, v+adjust);
21900 this.execCmd('FontSize', v );
21903 onEditorEvent : function(e)
21905 this.owner.fireEvent('editorevent', this, e);
21906 // this.updateToolbar();
21907 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21910 insertTag : function(tg)
21912 // could be a bit smarter... -> wrap the current selected tRoo..
21913 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21915 range = this.createRange(this.getSelection());
21916 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21917 wrappingNode.appendChild(range.extractContents());
21918 range.insertNode(wrappingNode);
21925 this.execCmd("formatblock", tg);
21929 insertText : function(txt)
21933 var range = this.createRange();
21934 range.deleteContents();
21935 //alert(Sender.getAttribute('label'));
21937 range.insertNode(this.doc.createTextNode(txt));
21943 * Executes a Midas editor command on the editor document and performs necessary focus and
21944 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21945 * @param {String} cmd The Midas command
21946 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21948 relayCmd : function(cmd, value){
21950 this.execCmd(cmd, value);
21951 this.owner.fireEvent('editorevent', this);
21952 //this.updateToolbar();
21953 this.owner.deferFocus();
21957 * Executes a Midas editor command directly on the editor document.
21958 * For visual commands, you should use {@link #relayCmd} instead.
21959 * <b>This should only be called after the editor is initialized.</b>
21960 * @param {String} cmd The Midas command
21961 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21963 execCmd : function(cmd, value){
21964 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21971 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21973 * @param {String} text | dom node..
21975 insertAtCursor : function(text)
21978 if(!this.activated){
21984 var r = this.doc.selection.createRange();
21995 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21999 // from jquery ui (MIT licenced)
22001 var win = this.win;
22003 if (win.getSelection && win.getSelection().getRangeAt) {
22004 range = win.getSelection().getRangeAt(0);
22005 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22006 range.insertNode(node);
22007 } else if (win.document.selection && win.document.selection.createRange) {
22008 // no firefox support
22009 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22010 win.document.selection.createRange().pasteHTML(txt);
22012 // no firefox support
22013 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22014 this.execCmd('InsertHTML', txt);
22023 mozKeyPress : function(e){
22025 var c = e.getCharCode(), cmd;
22028 c = String.fromCharCode(c).toLowerCase();
22042 this.cleanUpPaste.defer(100, this);
22050 e.preventDefault();
22058 fixKeys : function(){ // load time branching for fastest keydown performance
22060 return function(e){
22061 var k = e.getKey(), r;
22064 r = this.doc.selection.createRange();
22067 r.pasteHTML('    ');
22074 r = this.doc.selection.createRange();
22076 var target = r.parentElement();
22077 if(!target || target.tagName.toLowerCase() != 'li'){
22079 r.pasteHTML('<br />');
22085 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22086 this.cleanUpPaste.defer(100, this);
22092 }else if(Roo.isOpera){
22093 return function(e){
22094 var k = e.getKey();
22098 this.execCmd('InsertHTML','    ');
22101 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22102 this.cleanUpPaste.defer(100, this);
22107 }else if(Roo.isSafari){
22108 return function(e){
22109 var k = e.getKey();
22113 this.execCmd('InsertText','\t');
22117 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22118 this.cleanUpPaste.defer(100, this);
22126 getAllAncestors: function()
22128 var p = this.getSelectedNode();
22131 a.push(p); // push blank onto stack..
22132 p = this.getParentElement();
22136 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22140 a.push(this.doc.body);
22144 lastSelNode : false,
22147 getSelection : function()
22149 this.assignDocWin();
22150 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22153 getSelectedNode: function()
22155 // this may only work on Gecko!!!
22157 // should we cache this!!!!
22162 var range = this.createRange(this.getSelection()).cloneRange();
22165 var parent = range.parentElement();
22167 var testRange = range.duplicate();
22168 testRange.moveToElementText(parent);
22169 if (testRange.inRange(range)) {
22172 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22175 parent = parent.parentElement;
22180 // is ancestor a text element.
22181 var ac = range.commonAncestorContainer;
22182 if (ac.nodeType == 3) {
22183 ac = ac.parentNode;
22186 var ar = ac.childNodes;
22189 var other_nodes = [];
22190 var has_other_nodes = false;
22191 for (var i=0;i<ar.length;i++) {
22192 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22195 // fullly contained node.
22197 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22202 // probably selected..
22203 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22204 other_nodes.push(ar[i]);
22208 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22213 has_other_nodes = true;
22215 if (!nodes.length && other_nodes.length) {
22216 nodes= other_nodes;
22218 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22224 createRange: function(sel)
22226 // this has strange effects when using with
22227 // top toolbar - not sure if it's a great idea.
22228 //this.editor.contentWindow.focus();
22229 if (typeof sel != "undefined") {
22231 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22233 return this.doc.createRange();
22236 return this.doc.createRange();
22239 getParentElement: function()
22242 this.assignDocWin();
22243 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22245 var range = this.createRange(sel);
22248 var p = range.commonAncestorContainer;
22249 while (p.nodeType == 3) { // text node
22260 * Range intersection.. the hard stuff...
22264 * [ -- selected range --- ]
22268 * if end is before start or hits it. fail.
22269 * if start is after end or hits it fail.
22271 * if either hits (but other is outside. - then it's not
22277 // @see http://www.thismuchiknow.co.uk/?p=64.
22278 rangeIntersectsNode : function(range, node)
22280 var nodeRange = node.ownerDocument.createRange();
22282 nodeRange.selectNode(node);
22284 nodeRange.selectNodeContents(node);
22287 var rangeStartRange = range.cloneRange();
22288 rangeStartRange.collapse(true);
22290 var rangeEndRange = range.cloneRange();
22291 rangeEndRange.collapse(false);
22293 var nodeStartRange = nodeRange.cloneRange();
22294 nodeStartRange.collapse(true);
22296 var nodeEndRange = nodeRange.cloneRange();
22297 nodeEndRange.collapse(false);
22299 return rangeStartRange.compareBoundaryPoints(
22300 Range.START_TO_START, nodeEndRange) == -1 &&
22301 rangeEndRange.compareBoundaryPoints(
22302 Range.START_TO_START, nodeStartRange) == 1;
22306 rangeCompareNode : function(range, node)
22308 var nodeRange = node.ownerDocument.createRange();
22310 nodeRange.selectNode(node);
22312 nodeRange.selectNodeContents(node);
22316 range.collapse(true);
22318 nodeRange.collapse(true);
22320 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22321 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22323 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22325 var nodeIsBefore = ss == 1;
22326 var nodeIsAfter = ee == -1;
22328 if (nodeIsBefore && nodeIsAfter) {
22331 if (!nodeIsBefore && nodeIsAfter) {
22332 return 1; //right trailed.
22335 if (nodeIsBefore && !nodeIsAfter) {
22336 return 2; // left trailed.
22342 // private? - in a new class?
22343 cleanUpPaste : function()
22345 // cleans up the whole document..
22346 Roo.log('cleanuppaste');
22348 this.cleanUpChildren(this.doc.body);
22349 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22350 if (clean != this.doc.body.innerHTML) {
22351 this.doc.body.innerHTML = clean;
22356 cleanWordChars : function(input) {// change the chars to hex code
22357 var he = Roo.HtmlEditorCore;
22359 var output = input;
22360 Roo.each(he.swapCodes, function(sw) {
22361 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22363 output = output.replace(swapper, sw[1]);
22370 cleanUpChildren : function (n)
22372 if (!n.childNodes.length) {
22375 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22376 this.cleanUpChild(n.childNodes[i]);
22383 cleanUpChild : function (node)
22386 //console.log(node);
22387 if (node.nodeName == "#text") {
22388 // clean up silly Windows -- stuff?
22391 if (node.nodeName == "#comment") {
22392 node.parentNode.removeChild(node);
22393 // clean up silly Windows -- stuff?
22396 var lcname = node.tagName.toLowerCase();
22397 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22398 // whitelist of tags..
22400 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22402 node.parentNode.removeChild(node);
22407 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22409 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22410 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22412 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22413 // remove_keep_children = true;
22416 if (remove_keep_children) {
22417 this.cleanUpChildren(node);
22418 // inserts everything just before this node...
22419 while (node.childNodes.length) {
22420 var cn = node.childNodes[0];
22421 node.removeChild(cn);
22422 node.parentNode.insertBefore(cn, node);
22424 node.parentNode.removeChild(node);
22428 if (!node.attributes || !node.attributes.length) {
22429 this.cleanUpChildren(node);
22433 function cleanAttr(n,v)
22436 if (v.match(/^\./) || v.match(/^\//)) {
22439 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22442 if (v.match(/^#/)) {
22445 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22446 node.removeAttribute(n);
22450 var cwhite = this.cwhite;
22451 var cblack = this.cblack;
22453 function cleanStyle(n,v)
22455 if (v.match(/expression/)) { //XSS?? should we even bother..
22456 node.removeAttribute(n);
22460 var parts = v.split(/;/);
22463 Roo.each(parts, function(p) {
22464 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22468 var l = p.split(':').shift().replace(/\s+/g,'');
22469 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22471 if ( cwhite.length && cblack.indexOf(l) > -1) {
22472 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22473 //node.removeAttribute(n);
22477 // only allow 'c whitelisted system attributes'
22478 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22479 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22480 //node.removeAttribute(n);
22490 if (clean.length) {
22491 node.setAttribute(n, clean.join(';'));
22493 node.removeAttribute(n);
22499 for (var i = node.attributes.length-1; i > -1 ; i--) {
22500 var a = node.attributes[i];
22503 if (a.name.toLowerCase().substr(0,2)=='on') {
22504 node.removeAttribute(a.name);
22507 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22508 node.removeAttribute(a.name);
22511 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22512 cleanAttr(a.name,a.value); // fixme..
22515 if (a.name == 'style') {
22516 cleanStyle(a.name,a.value);
22519 /// clean up MS crap..
22520 // tecnically this should be a list of valid class'es..
22523 if (a.name == 'class') {
22524 if (a.value.match(/^Mso/)) {
22525 node.className = '';
22528 if (a.value.match(/^body$/)) {
22529 node.className = '';
22540 this.cleanUpChildren(node);
22546 * Clean up MS wordisms...
22548 cleanWord : function(node)
22553 this.cleanWord(this.doc.body);
22556 if (node.nodeName == "#text") {
22557 // clean up silly Windows -- stuff?
22560 if (node.nodeName == "#comment") {
22561 node.parentNode.removeChild(node);
22562 // clean up silly Windows -- stuff?
22566 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22567 node.parentNode.removeChild(node);
22571 // remove - but keep children..
22572 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22573 while (node.childNodes.length) {
22574 var cn = node.childNodes[0];
22575 node.removeChild(cn);
22576 node.parentNode.insertBefore(cn, node);
22578 node.parentNode.removeChild(node);
22579 this.iterateChildren(node, this.cleanWord);
22583 if (node.className.length) {
22585 var cn = node.className.split(/\W+/);
22587 Roo.each(cn, function(cls) {
22588 if (cls.match(/Mso[a-zA-Z]+/)) {
22593 node.className = cna.length ? cna.join(' ') : '';
22595 node.removeAttribute("class");
22599 if (node.hasAttribute("lang")) {
22600 node.removeAttribute("lang");
22603 if (node.hasAttribute("style")) {
22605 var styles = node.getAttribute("style").split(";");
22607 Roo.each(styles, function(s) {
22608 if (!s.match(/:/)) {
22611 var kv = s.split(":");
22612 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22615 // what ever is left... we allow.
22618 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22619 if (!nstyle.length) {
22620 node.removeAttribute('style');
22623 this.iterateChildren(node, this.cleanWord);
22629 * iterateChildren of a Node, calling fn each time, using this as the scole..
22630 * @param {DomNode} node node to iterate children of.
22631 * @param {Function} fn method of this class to call on each item.
22633 iterateChildren : function(node, fn)
22635 if (!node.childNodes.length) {
22638 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22639 fn.call(this, node.childNodes[i])
22645 * cleanTableWidths.
22647 * Quite often pasting from word etc.. results in tables with column and widths.
22648 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22651 cleanTableWidths : function(node)
22656 this.cleanTableWidths(this.doc.body);
22661 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22664 Roo.log(node.tagName);
22665 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22666 this.iterateChildren(node, this.cleanTableWidths);
22669 if (node.hasAttribute('width')) {
22670 node.removeAttribute('width');
22674 if (node.hasAttribute("style")) {
22677 var styles = node.getAttribute("style").split(";");
22679 Roo.each(styles, function(s) {
22680 if (!s.match(/:/)) {
22683 var kv = s.split(":");
22684 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22687 // what ever is left... we allow.
22690 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22691 if (!nstyle.length) {
22692 node.removeAttribute('style');
22696 this.iterateChildren(node, this.cleanTableWidths);
22704 domToHTML : function(currentElement, depth, nopadtext) {
22706 depth = depth || 0;
22707 nopadtext = nopadtext || false;
22709 if (!currentElement) {
22710 return this.domToHTML(this.doc.body);
22713 //Roo.log(currentElement);
22715 var allText = false;
22716 var nodeName = currentElement.nodeName;
22717 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22719 if (nodeName == '#text') {
22721 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22726 if (nodeName != 'BODY') {
22729 // Prints the node tagName, such as <A>, <IMG>, etc
22732 for(i = 0; i < currentElement.attributes.length;i++) {
22734 var aname = currentElement.attributes.item(i).name;
22735 if (!currentElement.attributes.item(i).value.length) {
22738 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22741 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22750 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22753 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22758 // Traverse the tree
22760 var currentElementChild = currentElement.childNodes.item(i);
22761 var allText = true;
22762 var innerHTML = '';
22764 while (currentElementChild) {
22765 // Formatting code (indent the tree so it looks nice on the screen)
22766 var nopad = nopadtext;
22767 if (lastnode == 'SPAN') {
22771 if (currentElementChild.nodeName == '#text') {
22772 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22773 toadd = nopadtext ? toadd : toadd.trim();
22774 if (!nopad && toadd.length > 80) {
22775 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22777 innerHTML += toadd;
22780 currentElementChild = currentElement.childNodes.item(i);
22786 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22788 // Recursively traverse the tree structure of the child node
22789 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22790 lastnode = currentElementChild.nodeName;
22792 currentElementChild=currentElement.childNodes.item(i);
22798 // The remaining code is mostly for formatting the tree
22799 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22804 ret+= "</"+tagName+">";
22810 applyBlacklists : function()
22812 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22813 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22817 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22818 if (b.indexOf(tag) > -1) {
22821 this.white.push(tag);
22825 Roo.each(w, function(tag) {
22826 if (b.indexOf(tag) > -1) {
22829 if (this.white.indexOf(tag) > -1) {
22832 this.white.push(tag);
22837 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22838 if (w.indexOf(tag) > -1) {
22841 this.black.push(tag);
22845 Roo.each(b, function(tag) {
22846 if (w.indexOf(tag) > -1) {
22849 if (this.black.indexOf(tag) > -1) {
22852 this.black.push(tag);
22857 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22858 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22862 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22863 if (b.indexOf(tag) > -1) {
22866 this.cwhite.push(tag);
22870 Roo.each(w, function(tag) {
22871 if (b.indexOf(tag) > -1) {
22874 if (this.cwhite.indexOf(tag) > -1) {
22877 this.cwhite.push(tag);
22882 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22883 if (w.indexOf(tag) > -1) {
22886 this.cblack.push(tag);
22890 Roo.each(b, function(tag) {
22891 if (w.indexOf(tag) > -1) {
22894 if (this.cblack.indexOf(tag) > -1) {
22897 this.cblack.push(tag);
22902 setStylesheets : function(stylesheets)
22904 if(typeof(stylesheets) == 'string'){
22905 Roo.get(this.iframe.contentDocument.head).createChild({
22907 rel : 'stylesheet',
22916 Roo.each(stylesheets, function(s) {
22921 Roo.get(_this.iframe.contentDocument.head).createChild({
22923 rel : 'stylesheet',
22932 removeStylesheets : function()
22936 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22941 setStyle : function(style)
22943 Roo.get(this.iframe.contentDocument.head).createChild({
22952 // hide stuff that is not compatible
22966 * @event specialkey
22970 * @cfg {String} fieldClass @hide
22973 * @cfg {String} focusClass @hide
22976 * @cfg {String} autoCreate @hide
22979 * @cfg {String} inputType @hide
22982 * @cfg {String} invalidClass @hide
22985 * @cfg {String} invalidText @hide
22988 * @cfg {String} msgFx @hide
22991 * @cfg {String} validateOnBlur @hide
22995 Roo.HtmlEditorCore.white = [
22996 'area', 'br', 'img', 'input', 'hr', 'wbr',
22998 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22999 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23000 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23001 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23002 'table', 'ul', 'xmp',
23004 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23007 'dir', 'menu', 'ol', 'ul', 'dl',
23013 Roo.HtmlEditorCore.black = [
23014 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23016 'base', 'basefont', 'bgsound', 'blink', 'body',
23017 'frame', 'frameset', 'head', 'html', 'ilayer',
23018 'iframe', 'layer', 'link', 'meta', 'object',
23019 'script', 'style' ,'title', 'xml' // clean later..
23021 Roo.HtmlEditorCore.clean = [
23022 'script', 'style', 'title', 'xml'
23024 Roo.HtmlEditorCore.remove = [
23029 Roo.HtmlEditorCore.ablack = [
23033 Roo.HtmlEditorCore.aclean = [
23034 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23038 Roo.HtmlEditorCore.pwhite= [
23039 'http', 'https', 'mailto'
23042 // white listed style attributes.
23043 Roo.HtmlEditorCore.cwhite= [
23044 // 'text-align', /// default is to allow most things..
23050 // black listed style attributes.
23051 Roo.HtmlEditorCore.cblack= [
23052 // 'font-size' -- this can be set by the project
23056 Roo.HtmlEditorCore.swapCodes =[
23075 * @class Roo.bootstrap.HtmlEditor
23076 * @extends Roo.bootstrap.TextArea
23077 * Bootstrap HtmlEditor class
23080 * Create a new HtmlEditor
23081 * @param {Object} config The config object
23084 Roo.bootstrap.HtmlEditor = function(config){
23085 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23086 if (!this.toolbars) {
23087 this.toolbars = [];
23090 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23093 * @event initialize
23094 * Fires when the editor is fully initialized (including the iframe)
23095 * @param {HtmlEditor} this
23100 * Fires when the editor is first receives the focus. Any insertion must wait
23101 * until after this event.
23102 * @param {HtmlEditor} this
23106 * @event beforesync
23107 * Fires before the textarea is updated with content from the editor iframe. Return false
23108 * to cancel the sync.
23109 * @param {HtmlEditor} this
23110 * @param {String} html
23114 * @event beforepush
23115 * Fires before the iframe editor is updated with content from the textarea. Return false
23116 * to cancel the push.
23117 * @param {HtmlEditor} this
23118 * @param {String} html
23123 * Fires when the textarea is updated with content from the editor iframe.
23124 * @param {HtmlEditor} this
23125 * @param {String} html
23130 * Fires when the iframe editor is updated with content from the textarea.
23131 * @param {HtmlEditor} this
23132 * @param {String} html
23136 * @event editmodechange
23137 * Fires when the editor switches edit modes
23138 * @param {HtmlEditor} this
23139 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23141 editmodechange: true,
23143 * @event editorevent
23144 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23145 * @param {HtmlEditor} this
23149 * @event firstfocus
23150 * Fires when on first focus - needed by toolbars..
23151 * @param {HtmlEditor} this
23156 * Auto save the htmlEditor value as a file into Events
23157 * @param {HtmlEditor} this
23161 * @event savedpreview
23162 * preview the saved version of htmlEditor
23163 * @param {HtmlEditor} this
23170 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23174 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23179 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23184 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23189 * @cfg {Number} height (in pixels)
23193 * @cfg {Number} width (in pixels)
23198 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23201 stylesheets: false,
23206 // private properties
23207 validationEvent : false,
23209 initialized : false,
23212 onFocus : Roo.emptyFn,
23214 hideMode:'offsets',
23216 tbContainer : false,
23220 toolbarContainer :function() {
23221 return this.wrap.select('.x-html-editor-tb',true).first();
23225 * Protected method that will not generally be called directly. It
23226 * is called when the editor creates its toolbar. Override this method if you need to
23227 * add custom toolbar buttons.
23228 * @param {HtmlEditor} editor
23230 createToolbar : function(){
23231 Roo.log('renewing');
23232 Roo.log("create toolbars");
23234 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23235 this.toolbars[0].render(this.toolbarContainer());
23239 // if (!editor.toolbars || !editor.toolbars.length) {
23240 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23243 // for (var i =0 ; i < editor.toolbars.length;i++) {
23244 // editor.toolbars[i] = Roo.factory(
23245 // typeof(editor.toolbars[i]) == 'string' ?
23246 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23247 // Roo.bootstrap.HtmlEditor);
23248 // editor.toolbars[i].init(editor);
23254 onRender : function(ct, position)
23256 // Roo.log("Call onRender: " + this.xtype);
23258 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23260 this.wrap = this.inputEl().wrap({
23261 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23264 this.editorcore.onRender(ct, position);
23266 if (this.resizable) {
23267 this.resizeEl = new Roo.Resizable(this.wrap, {
23271 minHeight : this.height,
23272 height: this.height,
23273 handles : this.resizable,
23276 resize : function(r, w, h) {
23277 _t.onResize(w,h); // -something
23283 this.createToolbar(this);
23286 if(!this.width && this.resizable){
23287 this.setSize(this.wrap.getSize());
23289 if (this.resizeEl) {
23290 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23291 // should trigger onReize..
23297 onResize : function(w, h)
23299 Roo.log('resize: ' +w + ',' + h );
23300 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23304 if(this.inputEl() ){
23305 if(typeof w == 'number'){
23306 var aw = w - this.wrap.getFrameWidth('lr');
23307 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23310 if(typeof h == 'number'){
23311 var tbh = -11; // fixme it needs to tool bar size!
23312 for (var i =0; i < this.toolbars.length;i++) {
23313 // fixme - ask toolbars for heights?
23314 tbh += this.toolbars[i].el.getHeight();
23315 //if (this.toolbars[i].footer) {
23316 // tbh += this.toolbars[i].footer.el.getHeight();
23324 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23325 ah -= 5; // knock a few pixes off for look..
23326 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23330 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23331 this.editorcore.onResize(ew,eh);
23336 * Toggles the editor between standard and source edit mode.
23337 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23339 toggleSourceEdit : function(sourceEditMode)
23341 this.editorcore.toggleSourceEdit(sourceEditMode);
23343 if(this.editorcore.sourceEditMode){
23344 Roo.log('editor - showing textarea');
23347 // Roo.log(this.syncValue());
23349 this.inputEl().removeClass(['hide', 'x-hidden']);
23350 this.inputEl().dom.removeAttribute('tabIndex');
23351 this.inputEl().focus();
23353 Roo.log('editor - hiding textarea');
23355 // Roo.log(this.pushValue());
23358 this.inputEl().addClass(['hide', 'x-hidden']);
23359 this.inputEl().dom.setAttribute('tabIndex', -1);
23360 //this.deferFocus();
23363 if(this.resizable){
23364 this.setSize(this.wrap.getSize());
23367 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23370 // private (for BoxComponent)
23371 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23373 // private (for BoxComponent)
23374 getResizeEl : function(){
23378 // private (for BoxComponent)
23379 getPositionEl : function(){
23384 initEvents : function(){
23385 this.originalValue = this.getValue();
23389 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23392 // markInvalid : Roo.emptyFn,
23394 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23397 // clearInvalid : Roo.emptyFn,
23399 setValue : function(v){
23400 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23401 this.editorcore.pushValue();
23406 deferFocus : function(){
23407 this.focus.defer(10, this);
23411 focus : function(){
23412 this.editorcore.focus();
23418 onDestroy : function(){
23424 for (var i =0; i < this.toolbars.length;i++) {
23425 // fixme - ask toolbars for heights?
23426 this.toolbars[i].onDestroy();
23429 this.wrap.dom.innerHTML = '';
23430 this.wrap.remove();
23435 onFirstFocus : function(){
23436 //Roo.log("onFirstFocus");
23437 this.editorcore.onFirstFocus();
23438 for (var i =0; i < this.toolbars.length;i++) {
23439 this.toolbars[i].onFirstFocus();
23445 syncValue : function()
23447 this.editorcore.syncValue();
23450 pushValue : function()
23452 this.editorcore.pushValue();
23456 // hide stuff that is not compatible
23470 * @event specialkey
23474 * @cfg {String} fieldClass @hide
23477 * @cfg {String} focusClass @hide
23480 * @cfg {String} autoCreate @hide
23483 * @cfg {String} inputType @hide
23486 * @cfg {String} invalidClass @hide
23489 * @cfg {String} invalidText @hide
23492 * @cfg {String} msgFx @hide
23495 * @cfg {String} validateOnBlur @hide
23504 Roo.namespace('Roo.bootstrap.htmleditor');
23506 * @class Roo.bootstrap.HtmlEditorToolbar1
23511 new Roo.bootstrap.HtmlEditor({
23514 new Roo.bootstrap.HtmlEditorToolbar1({
23515 disable : { fonts: 1 , format: 1, ..., ... , ...],
23521 * @cfg {Object} disable List of elements to disable..
23522 * @cfg {Array} btns List of additional buttons.
23526 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23529 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23532 Roo.apply(this, config);
23534 // default disabled, based on 'good practice'..
23535 this.disable = this.disable || {};
23536 Roo.applyIf(this.disable, {
23539 specialElements : true
23541 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23543 this.editor = config.editor;
23544 this.editorcore = config.editor.editorcore;
23546 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23548 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23549 // dont call parent... till later.
23551 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23556 editorcore : false,
23561 "h1","h2","h3","h4","h5","h6",
23563 "abbr", "acronym", "address", "cite", "samp", "var",
23567 onRender : function(ct, position)
23569 // Roo.log("Call onRender: " + this.xtype);
23571 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23573 this.el.dom.style.marginBottom = '0';
23575 var editorcore = this.editorcore;
23576 var editor= this.editor;
23579 var btn = function(id,cmd , toggle, handler, html){
23581 var event = toggle ? 'toggle' : 'click';
23586 xns: Roo.bootstrap,
23589 enableToggle:toggle !== false,
23591 pressed : toggle ? false : null,
23594 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23595 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23601 // var cb_box = function...
23606 xns: Roo.bootstrap,
23607 glyphicon : 'font',
23611 xns: Roo.bootstrap,
23615 Roo.each(this.formats, function(f) {
23616 style.menu.items.push({
23618 xns: Roo.bootstrap,
23619 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23624 editorcore.insertTag(this.tagname);
23631 children.push(style);
23633 btn('bold',false,true);
23634 btn('italic',false,true);
23635 btn('align-left', 'justifyleft',true);
23636 btn('align-center', 'justifycenter',true);
23637 btn('align-right' , 'justifyright',true);
23638 btn('link', false, false, function(btn) {
23639 //Roo.log("create link?");
23640 var url = prompt(this.createLinkText, this.defaultLinkValue);
23641 if(url && url != 'http:/'+'/'){
23642 this.editorcore.relayCmd('createlink', url);
23645 btn('list','insertunorderedlist',true);
23646 btn('pencil', false,true, function(btn){
23648 this.toggleSourceEdit(btn.pressed);
23651 if (this.editor.btns.length > 0) {
23652 for (var i = 0; i<this.editor.btns.length; i++) {
23653 children.push(this.editor.btns[i]);
23661 xns: Roo.bootstrap,
23666 xns: Roo.bootstrap,
23671 cog.menu.items.push({
23673 xns: Roo.bootstrap,
23674 html : Clean styles,
23679 editorcore.insertTag(this.tagname);
23688 this.xtype = 'NavSimplebar';
23690 for(var i=0;i< children.length;i++) {
23692 this.buttons.add(this.addxtypeChild(children[i]));
23696 editor.on('editorevent', this.updateToolbar, this);
23698 onBtnClick : function(id)
23700 this.editorcore.relayCmd(id);
23701 this.editorcore.focus();
23705 * Protected method that will not generally be called directly. It triggers
23706 * a toolbar update by reading the markup state of the current selection in the editor.
23708 updateToolbar: function(){
23710 if(!this.editorcore.activated){
23711 this.editor.onFirstFocus(); // is this neeed?
23715 var btns = this.buttons;
23716 var doc = this.editorcore.doc;
23717 btns.get('bold').setActive(doc.queryCommandState('bold'));
23718 btns.get('italic').setActive(doc.queryCommandState('italic'));
23719 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23721 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23722 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23723 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23725 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23726 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23729 var ans = this.editorcore.getAllAncestors();
23730 if (this.formatCombo) {
23733 var store = this.formatCombo.store;
23734 this.formatCombo.setValue("");
23735 for (var i =0; i < ans.length;i++) {
23736 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23738 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23746 // hides menus... - so this cant be on a menu...
23747 Roo.bootstrap.MenuMgr.hideAll();
23749 Roo.bootstrap.MenuMgr.hideAll();
23750 //this.editorsyncValue();
23752 onFirstFocus: function() {
23753 this.buttons.each(function(item){
23757 toggleSourceEdit : function(sourceEditMode){
23760 if(sourceEditMode){
23761 Roo.log("disabling buttons");
23762 this.buttons.each( function(item){
23763 if(item.cmd != 'pencil'){
23769 Roo.log("enabling buttons");
23770 if(this.editorcore.initialized){
23771 this.buttons.each( function(item){
23777 Roo.log("calling toggole on editor");
23778 // tell the editor that it's been pressed..
23779 this.editor.toggleSourceEdit(sourceEditMode);
23789 * @class Roo.bootstrap.Table.AbstractSelectionModel
23790 * @extends Roo.util.Observable
23791 * Abstract base class for grid SelectionModels. It provides the interface that should be
23792 * implemented by descendant classes. This class should not be directly instantiated.
23795 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23796 this.locked = false;
23797 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23801 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23802 /** @ignore Called by the grid automatically. Do not call directly. */
23803 init : function(grid){
23809 * Locks the selections.
23812 this.locked = true;
23816 * Unlocks the selections.
23818 unlock : function(){
23819 this.locked = false;
23823 * Returns true if the selections are locked.
23824 * @return {Boolean}
23826 isLocked : function(){
23827 return this.locked;
23831 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23832 * @class Roo.bootstrap.Table.RowSelectionModel
23833 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23834 * It supports multiple selections and keyboard selection/navigation.
23836 * @param {Object} config
23839 Roo.bootstrap.Table.RowSelectionModel = function(config){
23840 Roo.apply(this, config);
23841 this.selections = new Roo.util.MixedCollection(false, function(o){
23846 this.lastActive = false;
23850 * @event selectionchange
23851 * Fires when the selection changes
23852 * @param {SelectionModel} this
23854 "selectionchange" : true,
23856 * @event afterselectionchange
23857 * Fires after the selection changes (eg. by key press or clicking)
23858 * @param {SelectionModel} this
23860 "afterselectionchange" : true,
23862 * @event beforerowselect
23863 * Fires when a row is selected being selected, return false to cancel.
23864 * @param {SelectionModel} this
23865 * @param {Number} rowIndex The selected index
23866 * @param {Boolean} keepExisting False if other selections will be cleared
23868 "beforerowselect" : true,
23871 * Fires when a row is selected.
23872 * @param {SelectionModel} this
23873 * @param {Number} rowIndex The selected index
23874 * @param {Roo.data.Record} r The record
23876 "rowselect" : true,
23878 * @event rowdeselect
23879 * Fires when a row is deselected.
23880 * @param {SelectionModel} this
23881 * @param {Number} rowIndex The selected index
23883 "rowdeselect" : true
23885 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23886 this.locked = false;
23889 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23891 * @cfg {Boolean} singleSelect
23892 * True to allow selection of only one row at a time (defaults to false)
23894 singleSelect : false,
23897 initEvents : function()
23900 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23901 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23902 //}else{ // allow click to work like normal
23903 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23905 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23906 this.grid.on("rowclick", this.handleMouseDown, this);
23908 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23909 "up" : function(e){
23911 this.selectPrevious(e.shiftKey);
23912 }else if(this.last !== false && this.lastActive !== false){
23913 var last = this.last;
23914 this.selectRange(this.last, this.lastActive-1);
23915 this.grid.getView().focusRow(this.lastActive);
23916 if(last !== false){
23920 this.selectFirstRow();
23922 this.fireEvent("afterselectionchange", this);
23924 "down" : function(e){
23926 this.selectNext(e.shiftKey);
23927 }else if(this.last !== false && this.lastActive !== false){
23928 var last = this.last;
23929 this.selectRange(this.last, this.lastActive+1);
23930 this.grid.getView().focusRow(this.lastActive);
23931 if(last !== false){
23935 this.selectFirstRow();
23937 this.fireEvent("afterselectionchange", this);
23941 this.grid.store.on('load', function(){
23942 this.selections.clear();
23945 var view = this.grid.view;
23946 view.on("refresh", this.onRefresh, this);
23947 view.on("rowupdated", this.onRowUpdated, this);
23948 view.on("rowremoved", this.onRemove, this);
23953 onRefresh : function()
23955 var ds = this.grid.store, i, v = this.grid.view;
23956 var s = this.selections;
23957 s.each(function(r){
23958 if((i = ds.indexOfId(r.id)) != -1){
23967 onRemove : function(v, index, r){
23968 this.selections.remove(r);
23972 onRowUpdated : function(v, index, r){
23973 if(this.isSelected(r)){
23974 v.onRowSelect(index);
23980 * @param {Array} records The records to select
23981 * @param {Boolean} keepExisting (optional) True to keep existing selections
23983 selectRecords : function(records, keepExisting)
23986 this.clearSelections();
23988 var ds = this.grid.store;
23989 for(var i = 0, len = records.length; i < len; i++){
23990 this.selectRow(ds.indexOf(records[i]), true);
23995 * Gets the number of selected rows.
23998 getCount : function(){
23999 return this.selections.length;
24003 * Selects the first row in the grid.
24005 selectFirstRow : function(){
24010 * Select the last row.
24011 * @param {Boolean} keepExisting (optional) True to keep existing selections
24013 selectLastRow : function(keepExisting){
24014 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24015 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24019 * Selects the row immediately following the last selected row.
24020 * @param {Boolean} keepExisting (optional) True to keep existing selections
24022 selectNext : function(keepExisting)
24024 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24025 this.selectRow(this.last+1, keepExisting);
24026 this.grid.getView().focusRow(this.last);
24031 * Selects the row that precedes the last selected row.
24032 * @param {Boolean} keepExisting (optional) True to keep existing selections
24034 selectPrevious : function(keepExisting){
24036 this.selectRow(this.last-1, keepExisting);
24037 this.grid.getView().focusRow(this.last);
24042 * Returns the selected records
24043 * @return {Array} Array of selected records
24045 getSelections : function(){
24046 return [].concat(this.selections.items);
24050 * Returns the first selected record.
24053 getSelected : function(){
24054 return this.selections.itemAt(0);
24059 * Clears all selections.
24061 clearSelections : function(fast)
24067 var ds = this.grid.store;
24068 var s = this.selections;
24069 s.each(function(r){
24070 this.deselectRow(ds.indexOfId(r.id));
24074 this.selections.clear();
24081 * Selects all rows.
24083 selectAll : function(){
24087 this.selections.clear();
24088 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24089 this.selectRow(i, true);
24094 * Returns True if there is a selection.
24095 * @return {Boolean}
24097 hasSelection : function(){
24098 return this.selections.length > 0;
24102 * Returns True if the specified row is selected.
24103 * @param {Number/Record} record The record or index of the record to check
24104 * @return {Boolean}
24106 isSelected : function(index){
24107 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24108 return (r && this.selections.key(r.id) ? true : false);
24112 * Returns True if the specified record id is selected.
24113 * @param {String} id The id of record to check
24114 * @return {Boolean}
24116 isIdSelected : function(id){
24117 return (this.selections.key(id) ? true : false);
24122 handleMouseDBClick : function(e, t){
24126 handleMouseDown : function(e, t)
24128 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24129 if(this.isLocked() || rowIndex < 0 ){
24132 if(e.shiftKey && this.last !== false){
24133 var last = this.last;
24134 this.selectRange(last, rowIndex, e.ctrlKey);
24135 this.last = last; // reset the last
24139 var isSelected = this.isSelected(rowIndex);
24140 //Roo.log("select row:" + rowIndex);
24142 this.deselectRow(rowIndex);
24144 this.selectRow(rowIndex, true);
24148 if(e.button !== 0 && isSelected){
24149 alert('rowIndex 2: ' + rowIndex);
24150 view.focusRow(rowIndex);
24151 }else if(e.ctrlKey && isSelected){
24152 this.deselectRow(rowIndex);
24153 }else if(!isSelected){
24154 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24155 view.focusRow(rowIndex);
24159 this.fireEvent("afterselectionchange", this);
24162 handleDragableRowClick : function(grid, rowIndex, e)
24164 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24165 this.selectRow(rowIndex, false);
24166 grid.view.focusRow(rowIndex);
24167 this.fireEvent("afterselectionchange", this);
24172 * Selects multiple rows.
24173 * @param {Array} rows Array of the indexes of the row to select
24174 * @param {Boolean} keepExisting (optional) True to keep existing selections
24176 selectRows : function(rows, keepExisting){
24178 this.clearSelections();
24180 for(var i = 0, len = rows.length; i < len; i++){
24181 this.selectRow(rows[i], true);
24186 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24187 * @param {Number} startRow The index of the first row in the range
24188 * @param {Number} endRow The index of the last row in the range
24189 * @param {Boolean} keepExisting (optional) True to retain existing selections
24191 selectRange : function(startRow, endRow, keepExisting){
24196 this.clearSelections();
24198 if(startRow <= endRow){
24199 for(var i = startRow; i <= endRow; i++){
24200 this.selectRow(i, true);
24203 for(var i = startRow; i >= endRow; i--){
24204 this.selectRow(i, true);
24210 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24211 * @param {Number} startRow The index of the first row in the range
24212 * @param {Number} endRow The index of the last row in the range
24214 deselectRange : function(startRow, endRow, preventViewNotify){
24218 for(var i = startRow; i <= endRow; i++){
24219 this.deselectRow(i, preventViewNotify);
24225 * @param {Number} row The index of the row to select
24226 * @param {Boolean} keepExisting (optional) True to keep existing selections
24228 selectRow : function(index, keepExisting, preventViewNotify)
24230 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24233 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24234 if(!keepExisting || this.singleSelect){
24235 this.clearSelections();
24238 var r = this.grid.store.getAt(index);
24239 //console.log('selectRow - record id :' + r.id);
24241 this.selections.add(r);
24242 this.last = this.lastActive = index;
24243 if(!preventViewNotify){
24244 var proxy = new Roo.Element(
24245 this.grid.getRowDom(index)
24247 proxy.addClass('bg-info info');
24249 this.fireEvent("rowselect", this, index, r);
24250 this.fireEvent("selectionchange", this);
24256 * @param {Number} row The index of the row to deselect
24258 deselectRow : function(index, preventViewNotify)
24263 if(this.last == index){
24266 if(this.lastActive == index){
24267 this.lastActive = false;
24270 var r = this.grid.store.getAt(index);
24275 this.selections.remove(r);
24276 //.console.log('deselectRow - record id :' + r.id);
24277 if(!preventViewNotify){
24279 var proxy = new Roo.Element(
24280 this.grid.getRowDom(index)
24282 proxy.removeClass('bg-info info');
24284 this.fireEvent("rowdeselect", this, index);
24285 this.fireEvent("selectionchange", this);
24289 restoreLast : function(){
24291 this.last = this._last;
24296 acceptsNav : function(row, col, cm){
24297 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24301 onEditorKey : function(field, e){
24302 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24307 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24309 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24311 }else if(k == e.ENTER && !e.ctrlKey){
24315 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24317 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24319 }else if(k == e.ESC){
24323 g.startEditing(newCell[0], newCell[1]);
24329 * Ext JS Library 1.1.1
24330 * Copyright(c) 2006-2007, Ext JS, LLC.
24332 * Originally Released Under LGPL - original licence link has changed is not relivant.
24335 * <script type="text/javascript">
24339 * @class Roo.bootstrap.PagingToolbar
24340 * @extends Roo.bootstrap.NavSimplebar
24341 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24343 * Create a new PagingToolbar
24344 * @param {Object} config The config object
24345 * @param {Roo.data.Store} store
24347 Roo.bootstrap.PagingToolbar = function(config)
24349 // old args format still supported... - xtype is prefered..
24350 // created from xtype...
24352 this.ds = config.dataSource;
24354 if (config.store && !this.ds) {
24355 this.store= Roo.factory(config.store, Roo.data);
24356 this.ds = this.store;
24357 this.ds.xmodule = this.xmodule || false;
24360 this.toolbarItems = [];
24361 if (config.items) {
24362 this.toolbarItems = config.items;
24365 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24370 this.bind(this.ds);
24373 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24377 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24379 * @cfg {Roo.data.Store} dataSource
24380 * The underlying data store providing the paged data
24383 * @cfg {String/HTMLElement/Element} container
24384 * container The id or element that will contain the toolbar
24387 * @cfg {Boolean} displayInfo
24388 * True to display the displayMsg (defaults to false)
24391 * @cfg {Number} pageSize
24392 * The number of records to display per page (defaults to 20)
24396 * @cfg {String} displayMsg
24397 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24399 displayMsg : 'Displaying {0} - {1} of {2}',
24401 * @cfg {String} emptyMsg
24402 * The message to display when no records are found (defaults to "No data to display")
24404 emptyMsg : 'No data to display',
24406 * Customizable piece of the default paging text (defaults to "Page")
24409 beforePageText : "Page",
24411 * Customizable piece of the default paging text (defaults to "of %0")
24414 afterPageText : "of {0}",
24416 * Customizable piece of the default paging text (defaults to "First Page")
24419 firstText : "First Page",
24421 * Customizable piece of the default paging text (defaults to "Previous Page")
24424 prevText : "Previous Page",
24426 * Customizable piece of the default paging text (defaults to "Next Page")
24429 nextText : "Next Page",
24431 * Customizable piece of the default paging text (defaults to "Last Page")
24434 lastText : "Last Page",
24436 * Customizable piece of the default paging text (defaults to "Refresh")
24439 refreshText : "Refresh",
24443 onRender : function(ct, position)
24445 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24446 this.navgroup.parentId = this.id;
24447 this.navgroup.onRender(this.el, null);
24448 // add the buttons to the navgroup
24450 if(this.displayInfo){
24451 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24452 this.displayEl = this.el.select('.x-paging-info', true).first();
24453 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24454 // this.displayEl = navel.el.select('span',true).first();
24460 Roo.each(_this.buttons, function(e){ // this might need to use render????
24461 Roo.factory(e).onRender(_this.el, null);
24465 Roo.each(_this.toolbarItems, function(e) {
24466 _this.navgroup.addItem(e);
24470 this.first = this.navgroup.addItem({
24471 tooltip: this.firstText,
24473 icon : 'fa fa-backward',
24475 preventDefault: true,
24476 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24479 this.prev = this.navgroup.addItem({
24480 tooltip: this.prevText,
24482 icon : 'fa fa-step-backward',
24484 preventDefault: true,
24485 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24487 //this.addSeparator();
24490 var field = this.navgroup.addItem( {
24492 cls : 'x-paging-position',
24494 html : this.beforePageText +
24495 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24496 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24499 this.field = field.el.select('input', true).first();
24500 this.field.on("keydown", this.onPagingKeydown, this);
24501 this.field.on("focus", function(){this.dom.select();});
24504 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24505 //this.field.setHeight(18);
24506 //this.addSeparator();
24507 this.next = this.navgroup.addItem({
24508 tooltip: this.nextText,
24510 html : ' <i class="fa fa-step-forward">',
24512 preventDefault: true,
24513 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24515 this.last = this.navgroup.addItem({
24516 tooltip: this.lastText,
24517 icon : 'fa fa-forward',
24520 preventDefault: true,
24521 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24523 //this.addSeparator();
24524 this.loading = this.navgroup.addItem({
24525 tooltip: this.refreshText,
24526 icon: 'fa fa-refresh',
24527 preventDefault: true,
24528 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24534 updateInfo : function(){
24535 if(this.displayEl){
24536 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24537 var msg = count == 0 ?
24541 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24543 this.displayEl.update(msg);
24548 onLoad : function(ds, r, o)
24550 this.cursor = o.params.start ? o.params.start : 0;
24552 var d = this.getPageData(),
24557 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24558 this.field.dom.value = ap;
24559 this.first.setDisabled(ap == 1);
24560 this.prev.setDisabled(ap == 1);
24561 this.next.setDisabled(ap == ps);
24562 this.last.setDisabled(ap == ps);
24563 this.loading.enable();
24568 getPageData : function(){
24569 var total = this.ds.getTotalCount();
24572 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24573 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24578 onLoadError : function(){
24579 this.loading.enable();
24583 onPagingKeydown : function(e){
24584 var k = e.getKey();
24585 var d = this.getPageData();
24587 var v = this.field.dom.value, pageNum;
24588 if(!v || isNaN(pageNum = parseInt(v, 10))){
24589 this.field.dom.value = d.activePage;
24592 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24593 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24596 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))
24598 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24599 this.field.dom.value = pageNum;
24600 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24603 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24605 var v = this.field.dom.value, pageNum;
24606 var increment = (e.shiftKey) ? 10 : 1;
24607 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24610 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24611 this.field.dom.value = d.activePage;
24614 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24616 this.field.dom.value = parseInt(v, 10) + increment;
24617 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24618 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24625 beforeLoad : function(){
24627 this.loading.disable();
24632 onClick : function(which){
24641 ds.load({params:{start: 0, limit: this.pageSize}});
24644 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24647 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24650 var total = ds.getTotalCount();
24651 var extra = total % this.pageSize;
24652 var lastStart = extra ? (total - extra) : total-this.pageSize;
24653 ds.load({params:{start: lastStart, limit: this.pageSize}});
24656 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24662 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24663 * @param {Roo.data.Store} store The data store to unbind
24665 unbind : function(ds){
24666 ds.un("beforeload", this.beforeLoad, this);
24667 ds.un("load", this.onLoad, this);
24668 ds.un("loadexception", this.onLoadError, this);
24669 ds.un("remove", this.updateInfo, this);
24670 ds.un("add", this.updateInfo, this);
24671 this.ds = undefined;
24675 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24676 * @param {Roo.data.Store} store The data store to bind
24678 bind : function(ds){
24679 ds.on("beforeload", this.beforeLoad, this);
24680 ds.on("load", this.onLoad, this);
24681 ds.on("loadexception", this.onLoadError, this);
24682 ds.on("remove", this.updateInfo, this);
24683 ds.on("add", this.updateInfo, this);
24694 * @class Roo.bootstrap.MessageBar
24695 * @extends Roo.bootstrap.Component
24696 * Bootstrap MessageBar class
24697 * @cfg {String} html contents of the MessageBar
24698 * @cfg {String} weight (info | success | warning | danger) default info
24699 * @cfg {String} beforeClass insert the bar before the given class
24700 * @cfg {Boolean} closable (true | false) default false
24701 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24704 * Create a new Element
24705 * @param {Object} config The config object
24708 Roo.bootstrap.MessageBar = function(config){
24709 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24712 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24718 beforeClass: 'bootstrap-sticky-wrap',
24720 getAutoCreate : function(){
24724 cls: 'alert alert-dismissable alert-' + this.weight,
24729 html: this.html || ''
24735 cfg.cls += ' alert-messages-fixed';
24749 onRender : function(ct, position)
24751 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24754 var cfg = Roo.apply({}, this.getAutoCreate());
24758 cfg.cls += ' ' + this.cls;
24761 cfg.style = this.style;
24763 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24765 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24768 this.el.select('>button.close').on('click', this.hide, this);
24774 if (!this.rendered) {
24780 this.fireEvent('show', this);
24786 if (!this.rendered) {
24792 this.fireEvent('hide', this);
24795 update : function()
24797 // var e = this.el.dom.firstChild;
24799 // if(this.closable){
24800 // e = e.nextSibling;
24803 // e.data = this.html || '';
24805 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24821 * @class Roo.bootstrap.Graph
24822 * @extends Roo.bootstrap.Component
24823 * Bootstrap Graph class
24827 @cfg {String} graphtype bar | vbar | pie
24828 @cfg {number} g_x coodinator | centre x (pie)
24829 @cfg {number} g_y coodinator | centre y (pie)
24830 @cfg {number} g_r radius (pie)
24831 @cfg {number} g_height height of the chart (respected by all elements in the set)
24832 @cfg {number} g_width width of the chart (respected by all elements in the set)
24833 @cfg {Object} title The title of the chart
24836 -opts (object) options for the chart
24838 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24839 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24841 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.
24842 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24844 o stretch (boolean)
24846 -opts (object) options for the pie
24849 o startAngle (number)
24850 o endAngle (number)
24854 * Create a new Input
24855 * @param {Object} config The config object
24858 Roo.bootstrap.Graph = function(config){
24859 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24865 * The img click event for the img.
24866 * @param {Roo.EventObject} e
24872 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24883 //g_colors: this.colors,
24890 getAutoCreate : function(){
24901 onRender : function(ct,position){
24904 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24906 if (typeof(Raphael) == 'undefined') {
24907 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24911 this.raphael = Raphael(this.el.dom);
24913 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24914 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24915 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24916 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24918 r.text(160, 10, "Single Series Chart").attr(txtattr);
24919 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24920 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24921 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24923 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24924 r.barchart(330, 10, 300, 220, data1);
24925 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24926 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24929 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24930 // r.barchart(30, 30, 560, 250, xdata, {
24931 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24932 // axis : "0 0 1 1",
24933 // axisxlabels : xdata
24934 // //yvalues : cols,
24937 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24939 // this.load(null,xdata,{
24940 // axis : "0 0 1 1",
24941 // axisxlabels : xdata
24946 load : function(graphtype,xdata,opts)
24948 this.raphael.clear();
24950 graphtype = this.graphtype;
24955 var r = this.raphael,
24956 fin = function () {
24957 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24959 fout = function () {
24960 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24962 pfin = function() {
24963 this.sector.stop();
24964 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24967 this.label[0].stop();
24968 this.label[0].attr({ r: 7.5 });
24969 this.label[1].attr({ "font-weight": 800 });
24972 pfout = function() {
24973 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24976 this.label[0].animate({ r: 5 }, 500, "bounce");
24977 this.label[1].attr({ "font-weight": 400 });
24983 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24986 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24989 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24990 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24992 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24999 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25004 setTitle: function(o)
25009 initEvents: function() {
25012 this.el.on('click', this.onClick, this);
25016 onClick : function(e)
25018 Roo.log('img onclick');
25019 this.fireEvent('click', this, e);
25031 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25034 * @class Roo.bootstrap.dash.NumberBox
25035 * @extends Roo.bootstrap.Component
25036 * Bootstrap NumberBox class
25037 * @cfg {String} headline Box headline
25038 * @cfg {String} content Box content
25039 * @cfg {String} icon Box icon
25040 * @cfg {String} footer Footer text
25041 * @cfg {String} fhref Footer href
25044 * Create a new NumberBox
25045 * @param {Object} config The config object
25049 Roo.bootstrap.dash.NumberBox = function(config){
25050 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25054 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25063 getAutoCreate : function(){
25067 cls : 'small-box ',
25075 cls : 'roo-headline',
25076 html : this.headline
25080 cls : 'roo-content',
25081 html : this.content
25095 cls : 'ion ' + this.icon
25104 cls : 'small-box-footer',
25105 href : this.fhref || '#',
25109 cfg.cn.push(footer);
25116 onRender : function(ct,position){
25117 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25124 setHeadline: function (value)
25126 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25129 setFooter: function (value, href)
25131 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25134 this.el.select('a.small-box-footer',true).first().attr('href', href);
25139 setContent: function (value)
25141 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25144 initEvents: function()
25158 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25161 * @class Roo.bootstrap.dash.TabBox
25162 * @extends Roo.bootstrap.Component
25163 * Bootstrap TabBox class
25164 * @cfg {String} title Title of the TabBox
25165 * @cfg {String} icon Icon of the TabBox
25166 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25167 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25170 * Create a new TabBox
25171 * @param {Object} config The config object
25175 Roo.bootstrap.dash.TabBox = function(config){
25176 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25181 * When a pane is added
25182 * @param {Roo.bootstrap.dash.TabPane} pane
25186 * @event activatepane
25187 * When a pane is activated
25188 * @param {Roo.bootstrap.dash.TabPane} pane
25190 "activatepane" : true
25198 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25203 tabScrollable : false,
25205 getChildContainer : function()
25207 return this.el.select('.tab-content', true).first();
25210 getAutoCreate : function(){
25214 cls: 'pull-left header',
25222 cls: 'fa ' + this.icon
25228 cls: 'nav nav-tabs pull-right',
25234 if(this.tabScrollable){
25241 cls: 'nav nav-tabs pull-right',
25252 cls: 'nav-tabs-custom',
25257 cls: 'tab-content no-padding',
25265 initEvents : function()
25267 //Roo.log('add add pane handler');
25268 this.on('addpane', this.onAddPane, this);
25271 * Updates the box title
25272 * @param {String} html to set the title to.
25274 setTitle : function(value)
25276 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25278 onAddPane : function(pane)
25280 this.panes.push(pane);
25281 //Roo.log('addpane');
25283 // tabs are rendere left to right..
25284 if(!this.showtabs){
25288 var ctr = this.el.select('.nav-tabs', true).first();
25291 var existing = ctr.select('.nav-tab',true);
25292 var qty = existing.getCount();;
25295 var tab = ctr.createChild({
25297 cls : 'nav-tab' + (qty ? '' : ' active'),
25305 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25308 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25310 pane.el.addClass('active');
25315 onTabClick : function(ev,un,ob,pane)
25317 //Roo.log('tab - prev default');
25318 ev.preventDefault();
25321 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25322 pane.tab.addClass('active');
25323 //Roo.log(pane.title);
25324 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25325 // technically we should have a deactivate event.. but maybe add later.
25326 // and it should not de-activate the selected tab...
25327 this.fireEvent('activatepane', pane);
25328 pane.el.addClass('active');
25329 pane.fireEvent('activate');
25334 getActivePane : function()
25337 Roo.each(this.panes, function(p) {
25338 if(p.el.hasClass('active')){
25359 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25361 * @class Roo.bootstrap.TabPane
25362 * @extends Roo.bootstrap.Component
25363 * Bootstrap TabPane class
25364 * @cfg {Boolean} active (false | true) Default false
25365 * @cfg {String} title title of panel
25369 * Create a new TabPane
25370 * @param {Object} config The config object
25373 Roo.bootstrap.dash.TabPane = function(config){
25374 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25380 * When a pane is activated
25381 * @param {Roo.bootstrap.dash.TabPane} pane
25388 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25393 // the tabBox that this is attached to.
25396 getAutoCreate : function()
25404 cfg.cls += ' active';
25409 initEvents : function()
25411 //Roo.log('trigger add pane handler');
25412 this.parent().fireEvent('addpane', this)
25416 * Updates the tab title
25417 * @param {String} html to set the title to.
25419 setTitle: function(str)
25425 this.tab.select('a', true).first().dom.innerHTML = str;
25442 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25445 * @class Roo.bootstrap.menu.Menu
25446 * @extends Roo.bootstrap.Component
25447 * Bootstrap Menu class - container for Menu
25448 * @cfg {String} html Text of the menu
25449 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25450 * @cfg {String} icon Font awesome icon
25451 * @cfg {String} pos Menu align to (top | bottom) default bottom
25455 * Create a new Menu
25456 * @param {Object} config The config object
25460 Roo.bootstrap.menu.Menu = function(config){
25461 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25465 * @event beforeshow
25466 * Fires before this menu is displayed
25467 * @param {Roo.bootstrap.menu.Menu} this
25471 * @event beforehide
25472 * Fires before this menu is hidden
25473 * @param {Roo.bootstrap.menu.Menu} this
25478 * Fires after this menu is displayed
25479 * @param {Roo.bootstrap.menu.Menu} this
25484 * Fires after this menu is hidden
25485 * @param {Roo.bootstrap.menu.Menu} this
25490 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25491 * @param {Roo.bootstrap.menu.Menu} this
25492 * @param {Roo.EventObject} e
25499 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25503 weight : 'default',
25508 getChildContainer : function() {
25509 if(this.isSubMenu){
25513 return this.el.select('ul.dropdown-menu', true).first();
25516 getAutoCreate : function()
25521 cls : 'roo-menu-text',
25529 cls : 'fa ' + this.icon
25540 cls : 'dropdown-button btn btn-' + this.weight,
25545 cls : 'dropdown-toggle btn btn-' + this.weight,
25555 cls : 'dropdown-menu'
25561 if(this.pos == 'top'){
25562 cfg.cls += ' dropup';
25565 if(this.isSubMenu){
25568 cls : 'dropdown-menu'
25575 onRender : function(ct, position)
25577 this.isSubMenu = ct.hasClass('dropdown-submenu');
25579 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25582 initEvents : function()
25584 if(this.isSubMenu){
25588 this.hidden = true;
25590 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25591 this.triggerEl.on('click', this.onTriggerPress, this);
25593 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25594 this.buttonEl.on('click', this.onClick, this);
25600 if(this.isSubMenu){
25604 return this.el.select('ul.dropdown-menu', true).first();
25607 onClick : function(e)
25609 this.fireEvent("click", this, e);
25612 onTriggerPress : function(e)
25614 if (this.isVisible()) {
25621 isVisible : function(){
25622 return !this.hidden;
25627 this.fireEvent("beforeshow", this);
25629 this.hidden = false;
25630 this.el.addClass('open');
25632 Roo.get(document).on("mouseup", this.onMouseUp, this);
25634 this.fireEvent("show", this);
25641 this.fireEvent("beforehide", this);
25643 this.hidden = true;
25644 this.el.removeClass('open');
25646 Roo.get(document).un("mouseup", this.onMouseUp);
25648 this.fireEvent("hide", this);
25651 onMouseUp : function()
25665 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25668 * @class Roo.bootstrap.menu.Item
25669 * @extends Roo.bootstrap.Component
25670 * Bootstrap MenuItem class
25671 * @cfg {Boolean} submenu (true | false) default false
25672 * @cfg {String} html text of the item
25673 * @cfg {String} href the link
25674 * @cfg {Boolean} disable (true | false) default false
25675 * @cfg {Boolean} preventDefault (true | false) default true
25676 * @cfg {String} icon Font awesome icon
25677 * @cfg {String} pos Submenu align to (left | right) default right
25681 * Create a new Item
25682 * @param {Object} config The config object
25686 Roo.bootstrap.menu.Item = function(config){
25687 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25691 * Fires when the mouse is hovering over this menu
25692 * @param {Roo.bootstrap.menu.Item} this
25693 * @param {Roo.EventObject} e
25698 * Fires when the mouse exits this menu
25699 * @param {Roo.bootstrap.menu.Item} this
25700 * @param {Roo.EventObject} e
25706 * The raw click event for the entire grid.
25707 * @param {Roo.EventObject} e
25713 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25718 preventDefault: true,
25723 getAutoCreate : function()
25728 cls : 'roo-menu-item-text',
25736 cls : 'fa ' + this.icon
25745 href : this.href || '#',
25752 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25756 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25758 if(this.pos == 'left'){
25759 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25766 initEvents : function()
25768 this.el.on('mouseover', this.onMouseOver, this);
25769 this.el.on('mouseout', this.onMouseOut, this);
25771 this.el.select('a', true).first().on('click', this.onClick, this);
25775 onClick : function(e)
25777 if(this.preventDefault){
25778 e.preventDefault();
25781 this.fireEvent("click", this, e);
25784 onMouseOver : function(e)
25786 if(this.submenu && this.pos == 'left'){
25787 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25790 this.fireEvent("mouseover", this, e);
25793 onMouseOut : function(e)
25795 this.fireEvent("mouseout", this, e);
25807 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25810 * @class Roo.bootstrap.menu.Separator
25811 * @extends Roo.bootstrap.Component
25812 * Bootstrap Separator class
25815 * Create a new Separator
25816 * @param {Object} config The config object
25820 Roo.bootstrap.menu.Separator = function(config){
25821 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25824 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25826 getAutoCreate : function(){
25847 * @class Roo.bootstrap.Tooltip
25848 * Bootstrap Tooltip class
25849 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25850 * to determine which dom element triggers the tooltip.
25852 * It needs to add support for additional attributes like tooltip-position
25855 * Create a new Toolti
25856 * @param {Object} config The config object
25859 Roo.bootstrap.Tooltip = function(config){
25860 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25862 this.alignment = Roo.bootstrap.Tooltip.alignment;
25864 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25865 this.alignment = config.alignment;
25870 Roo.apply(Roo.bootstrap.Tooltip, {
25872 * @function init initialize tooltip monitoring.
25876 currentTip : false,
25877 currentRegion : false,
25883 Roo.get(document).on('mouseover', this.enter ,this);
25884 Roo.get(document).on('mouseout', this.leave, this);
25887 this.currentTip = new Roo.bootstrap.Tooltip();
25890 enter : function(ev)
25892 var dom = ev.getTarget();
25894 //Roo.log(['enter',dom]);
25895 var el = Roo.fly(dom);
25896 if (this.currentEl) {
25898 //Roo.log(this.currentEl);
25899 //Roo.log(this.currentEl.contains(dom));
25900 if (this.currentEl == el) {
25903 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25909 if (this.currentTip.el) {
25910 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25914 if(!el || el.dom == document){
25920 // you can not look for children, as if el is the body.. then everythign is the child..
25921 if (!el.attr('tooltip')) { //
25922 if (!el.select("[tooltip]").elements.length) {
25925 // is the mouse over this child...?
25926 bindEl = el.select("[tooltip]").first();
25927 var xy = ev.getXY();
25928 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25929 //Roo.log("not in region.");
25932 //Roo.log("child element over..");
25935 this.currentEl = bindEl;
25936 this.currentTip.bind(bindEl);
25937 this.currentRegion = Roo.lib.Region.getRegion(dom);
25938 this.currentTip.enter();
25941 leave : function(ev)
25943 var dom = ev.getTarget();
25944 //Roo.log(['leave',dom]);
25945 if (!this.currentEl) {
25950 if (dom != this.currentEl.dom) {
25953 var xy = ev.getXY();
25954 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25957 // only activate leave if mouse cursor is outside... bounding box..
25962 if (this.currentTip) {
25963 this.currentTip.leave();
25965 //Roo.log('clear currentEl');
25966 this.currentEl = false;
25971 'left' : ['r-l', [-2,0], 'right'],
25972 'right' : ['l-r', [2,0], 'left'],
25973 'bottom' : ['t-b', [0,2], 'top'],
25974 'top' : [ 'b-t', [0,-2], 'bottom']
25980 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25985 delay : null, // can be { show : 300 , hide: 500}
25989 hoverState : null, //???
25991 placement : 'bottom',
25995 getAutoCreate : function(){
26002 cls : 'tooltip-arrow'
26005 cls : 'tooltip-inner'
26012 bind : function(el)
26018 enter : function () {
26020 if (this.timeout != null) {
26021 clearTimeout(this.timeout);
26024 this.hoverState = 'in';
26025 //Roo.log("enter - show");
26026 if (!this.delay || !this.delay.show) {
26031 this.timeout = setTimeout(function () {
26032 if (_t.hoverState == 'in') {
26035 }, this.delay.show);
26039 clearTimeout(this.timeout);
26041 this.hoverState = 'out';
26042 if (!this.delay || !this.delay.hide) {
26048 this.timeout = setTimeout(function () {
26049 //Roo.log("leave - timeout");
26051 if (_t.hoverState == 'out') {
26053 Roo.bootstrap.Tooltip.currentEl = false;
26058 show : function (msg)
26061 this.render(document.body);
26064 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26066 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26068 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26070 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26072 var placement = typeof this.placement == 'function' ?
26073 this.placement.call(this, this.el, on_el) :
26076 var autoToken = /\s?auto?\s?/i;
26077 var autoPlace = autoToken.test(placement);
26079 placement = placement.replace(autoToken, '') || 'top';
26083 //this.el.setXY([0,0]);
26085 //this.el.dom.style.display='block';
26087 //this.el.appendTo(on_el);
26089 var p = this.getPosition();
26090 var box = this.el.getBox();
26096 var align = this.alignment[placement];
26098 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26100 if(placement == 'top' || placement == 'bottom'){
26102 placement = 'right';
26105 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26106 placement = 'left';
26109 var scroll = Roo.select('body', true).first().getScroll();
26111 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26117 this.el.alignTo(this.bindEl, align[0],align[1]);
26118 //var arrow = this.el.select('.arrow',true).first();
26119 //arrow.set(align[2],
26121 this.el.addClass(placement);
26123 this.el.addClass('in fade');
26125 this.hoverState = null;
26127 if (this.el.hasClass('fade')) {
26138 //this.el.setXY([0,0]);
26139 this.el.removeClass('in');
26155 * @class Roo.bootstrap.LocationPicker
26156 * @extends Roo.bootstrap.Component
26157 * Bootstrap LocationPicker class
26158 * @cfg {Number} latitude Position when init default 0
26159 * @cfg {Number} longitude Position when init default 0
26160 * @cfg {Number} zoom default 15
26161 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26162 * @cfg {Boolean} mapTypeControl default false
26163 * @cfg {Boolean} disableDoubleClickZoom default false
26164 * @cfg {Boolean} scrollwheel default true
26165 * @cfg {Boolean} streetViewControl default false
26166 * @cfg {Number} radius default 0
26167 * @cfg {String} locationName
26168 * @cfg {Boolean} draggable default true
26169 * @cfg {Boolean} enableAutocomplete default false
26170 * @cfg {Boolean} enableReverseGeocode default true
26171 * @cfg {String} markerTitle
26174 * Create a new LocationPicker
26175 * @param {Object} config The config object
26179 Roo.bootstrap.LocationPicker = function(config){
26181 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26186 * Fires when the picker initialized.
26187 * @param {Roo.bootstrap.LocationPicker} this
26188 * @param {Google Location} location
26192 * @event positionchanged
26193 * Fires when the picker position changed.
26194 * @param {Roo.bootstrap.LocationPicker} this
26195 * @param {Google Location} location
26197 positionchanged : true,
26200 * Fires when the map resize.
26201 * @param {Roo.bootstrap.LocationPicker} this
26206 * Fires when the map show.
26207 * @param {Roo.bootstrap.LocationPicker} this
26212 * Fires when the map hide.
26213 * @param {Roo.bootstrap.LocationPicker} this
26218 * Fires when click the map.
26219 * @param {Roo.bootstrap.LocationPicker} this
26220 * @param {Map event} e
26224 * @event mapRightClick
26225 * Fires when right click the map.
26226 * @param {Roo.bootstrap.LocationPicker} this
26227 * @param {Map event} e
26229 mapRightClick : true,
26231 * @event markerClick
26232 * Fires when click the marker.
26233 * @param {Roo.bootstrap.LocationPicker} this
26234 * @param {Map event} e
26236 markerClick : true,
26238 * @event markerRightClick
26239 * Fires when right click the marker.
26240 * @param {Roo.bootstrap.LocationPicker} this
26241 * @param {Map event} e
26243 markerRightClick : true,
26245 * @event OverlayViewDraw
26246 * Fires when OverlayView Draw
26247 * @param {Roo.bootstrap.LocationPicker} this
26249 OverlayViewDraw : true,
26251 * @event OverlayViewOnAdd
26252 * Fires when OverlayView Draw
26253 * @param {Roo.bootstrap.LocationPicker} this
26255 OverlayViewOnAdd : true,
26257 * @event OverlayViewOnRemove
26258 * Fires when OverlayView Draw
26259 * @param {Roo.bootstrap.LocationPicker} this
26261 OverlayViewOnRemove : true,
26263 * @event OverlayViewShow
26264 * Fires when OverlayView Draw
26265 * @param {Roo.bootstrap.LocationPicker} this
26266 * @param {Pixel} cpx
26268 OverlayViewShow : true,
26270 * @event OverlayViewHide
26271 * Fires when OverlayView Draw
26272 * @param {Roo.bootstrap.LocationPicker} this
26274 OverlayViewHide : true,
26276 * @event loadexception
26277 * Fires when load google lib failed.
26278 * @param {Roo.bootstrap.LocationPicker} this
26280 loadexception : true
26285 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26287 gMapContext: false,
26293 mapTypeControl: false,
26294 disableDoubleClickZoom: false,
26296 streetViewControl: false,
26300 enableAutocomplete: false,
26301 enableReverseGeocode: true,
26304 getAutoCreate: function()
26309 cls: 'roo-location-picker'
26315 initEvents: function(ct, position)
26317 if(!this.el.getWidth() || this.isApplied()){
26321 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26326 initial: function()
26328 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26329 this.fireEvent('loadexception', this);
26333 if(!this.mapTypeId){
26334 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26337 this.gMapContext = this.GMapContext();
26339 this.initOverlayView();
26341 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26345 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26346 _this.setPosition(_this.gMapContext.marker.position);
26349 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26350 _this.fireEvent('mapClick', this, event);
26354 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26355 _this.fireEvent('mapRightClick', this, event);
26359 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26360 _this.fireEvent('markerClick', this, event);
26364 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26365 _this.fireEvent('markerRightClick', this, event);
26369 this.setPosition(this.gMapContext.location);
26371 this.fireEvent('initial', this, this.gMapContext.location);
26374 initOverlayView: function()
26378 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26382 _this.fireEvent('OverlayViewDraw', _this);
26387 _this.fireEvent('OverlayViewOnAdd', _this);
26390 onRemove: function()
26392 _this.fireEvent('OverlayViewOnRemove', _this);
26395 show: function(cpx)
26397 _this.fireEvent('OverlayViewShow', _this, cpx);
26402 _this.fireEvent('OverlayViewHide', _this);
26408 fromLatLngToContainerPixel: function(event)
26410 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26413 isApplied: function()
26415 return this.getGmapContext() == false ? false : true;
26418 getGmapContext: function()
26420 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26423 GMapContext: function()
26425 var position = new google.maps.LatLng(this.latitude, this.longitude);
26427 var _map = new google.maps.Map(this.el.dom, {
26430 mapTypeId: this.mapTypeId,
26431 mapTypeControl: this.mapTypeControl,
26432 disableDoubleClickZoom: this.disableDoubleClickZoom,
26433 scrollwheel: this.scrollwheel,
26434 streetViewControl: this.streetViewControl,
26435 locationName: this.locationName,
26436 draggable: this.draggable,
26437 enableAutocomplete: this.enableAutocomplete,
26438 enableReverseGeocode: this.enableReverseGeocode
26441 var _marker = new google.maps.Marker({
26442 position: position,
26444 title: this.markerTitle,
26445 draggable: this.draggable
26452 location: position,
26453 radius: this.radius,
26454 locationName: this.locationName,
26455 addressComponents: {
26456 formatted_address: null,
26457 addressLine1: null,
26458 addressLine2: null,
26460 streetNumber: null,
26464 stateOrProvince: null
26467 domContainer: this.el.dom,
26468 geodecoder: new google.maps.Geocoder()
26472 drawCircle: function(center, radius, options)
26474 if (this.gMapContext.circle != null) {
26475 this.gMapContext.circle.setMap(null);
26479 options = Roo.apply({}, options, {
26480 strokeColor: "#0000FF",
26481 strokeOpacity: .35,
26483 fillColor: "#0000FF",
26487 options.map = this.gMapContext.map;
26488 options.radius = radius;
26489 options.center = center;
26490 this.gMapContext.circle = new google.maps.Circle(options);
26491 return this.gMapContext.circle;
26497 setPosition: function(location)
26499 this.gMapContext.location = location;
26500 this.gMapContext.marker.setPosition(location);
26501 this.gMapContext.map.panTo(location);
26502 this.drawCircle(location, this.gMapContext.radius, {});
26506 if (this.gMapContext.settings.enableReverseGeocode) {
26507 this.gMapContext.geodecoder.geocode({
26508 latLng: this.gMapContext.location
26509 }, function(results, status) {
26511 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26512 _this.gMapContext.locationName = results[0].formatted_address;
26513 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26515 _this.fireEvent('positionchanged', this, location);
26522 this.fireEvent('positionchanged', this, location);
26527 google.maps.event.trigger(this.gMapContext.map, "resize");
26529 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26531 this.fireEvent('resize', this);
26534 setPositionByLatLng: function(latitude, longitude)
26536 this.setPosition(new google.maps.LatLng(latitude, longitude));
26539 getCurrentPosition: function()
26542 latitude: this.gMapContext.location.lat(),
26543 longitude: this.gMapContext.location.lng()
26547 getAddressName: function()
26549 return this.gMapContext.locationName;
26552 getAddressComponents: function()
26554 return this.gMapContext.addressComponents;
26557 address_component_from_google_geocode: function(address_components)
26561 for (var i = 0; i < address_components.length; i++) {
26562 var component = address_components[i];
26563 if (component.types.indexOf("postal_code") >= 0) {
26564 result.postalCode = component.short_name;
26565 } else if (component.types.indexOf("street_number") >= 0) {
26566 result.streetNumber = component.short_name;
26567 } else if (component.types.indexOf("route") >= 0) {
26568 result.streetName = component.short_name;
26569 } else if (component.types.indexOf("neighborhood") >= 0) {
26570 result.city = component.short_name;
26571 } else if (component.types.indexOf("locality") >= 0) {
26572 result.city = component.short_name;
26573 } else if (component.types.indexOf("sublocality") >= 0) {
26574 result.district = component.short_name;
26575 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26576 result.stateOrProvince = component.short_name;
26577 } else if (component.types.indexOf("country") >= 0) {
26578 result.country = component.short_name;
26582 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26583 result.addressLine2 = "";
26587 setZoomLevel: function(zoom)
26589 this.gMapContext.map.setZoom(zoom);
26602 this.fireEvent('show', this);
26613 this.fireEvent('hide', this);
26618 Roo.apply(Roo.bootstrap.LocationPicker, {
26620 OverlayView : function(map, options)
26622 options = options || {};
26636 * @class Roo.bootstrap.Alert
26637 * @extends Roo.bootstrap.Component
26638 * Bootstrap Alert class
26639 * @cfg {String} title The title of alert
26640 * @cfg {String} html The content of alert
26641 * @cfg {String} weight ( success | info | warning | danger )
26642 * @cfg {String} faicon font-awesomeicon
26645 * Create a new alert
26646 * @param {Object} config The config object
26650 Roo.bootstrap.Alert = function(config){
26651 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26655 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26662 getAutoCreate : function()
26671 cls : 'roo-alert-icon'
26676 cls : 'roo-alert-title',
26681 cls : 'roo-alert-text',
26688 cfg.cn[0].cls += ' fa ' + this.faicon;
26692 cfg.cls += ' alert-' + this.weight;
26698 initEvents: function()
26700 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26703 setTitle : function(str)
26705 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26708 setText : function(str)
26710 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26713 setWeight : function(weight)
26716 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26719 this.weight = weight;
26721 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26724 setIcon : function(icon)
26727 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26730 this.faicon = icon;
26732 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26753 * @class Roo.bootstrap.UploadCropbox
26754 * @extends Roo.bootstrap.Component
26755 * Bootstrap UploadCropbox class
26756 * @cfg {String} emptyText show when image has been loaded
26757 * @cfg {String} rotateNotify show when image too small to rotate
26758 * @cfg {Number} errorTimeout default 3000
26759 * @cfg {Number} minWidth default 300
26760 * @cfg {Number} minHeight default 300
26761 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26762 * @cfg {Boolean} isDocument (true|false) default false
26763 * @cfg {String} url action url
26764 * @cfg {String} paramName default 'imageUpload'
26765 * @cfg {String} method default POST
26766 * @cfg {Boolean} loadMask (true|false) default true
26767 * @cfg {Boolean} loadingText default 'Loading...'
26770 * Create a new UploadCropbox
26771 * @param {Object} config The config object
26774 Roo.bootstrap.UploadCropbox = function(config){
26775 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26779 * @event beforeselectfile
26780 * Fire before select file
26781 * @param {Roo.bootstrap.UploadCropbox} this
26783 "beforeselectfile" : true,
26786 * Fire after initEvent
26787 * @param {Roo.bootstrap.UploadCropbox} this
26792 * Fire after initEvent
26793 * @param {Roo.bootstrap.UploadCropbox} this
26794 * @param {String} data
26799 * Fire when preparing the file data
26800 * @param {Roo.bootstrap.UploadCropbox} this
26801 * @param {Object} file
26806 * Fire when get exception
26807 * @param {Roo.bootstrap.UploadCropbox} this
26808 * @param {XMLHttpRequest} xhr
26810 "exception" : true,
26812 * @event beforeloadcanvas
26813 * Fire before load the canvas
26814 * @param {Roo.bootstrap.UploadCropbox} this
26815 * @param {String} src
26817 "beforeloadcanvas" : true,
26820 * Fire when trash image
26821 * @param {Roo.bootstrap.UploadCropbox} this
26826 * Fire when download the image
26827 * @param {Roo.bootstrap.UploadCropbox} this
26831 * @event footerbuttonclick
26832 * Fire when footerbuttonclick
26833 * @param {Roo.bootstrap.UploadCropbox} this
26834 * @param {String} type
26836 "footerbuttonclick" : true,
26840 * @param {Roo.bootstrap.UploadCropbox} this
26845 * Fire when rotate the image
26846 * @param {Roo.bootstrap.UploadCropbox} this
26847 * @param {String} pos
26852 * Fire when inspect the file
26853 * @param {Roo.bootstrap.UploadCropbox} this
26854 * @param {Object} file
26859 * Fire when xhr upload the file
26860 * @param {Roo.bootstrap.UploadCropbox} this
26861 * @param {Object} data
26866 * Fire when arrange the file data
26867 * @param {Roo.bootstrap.UploadCropbox} this
26868 * @param {Object} formData
26873 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26876 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26878 emptyText : 'Click to upload image',
26879 rotateNotify : 'Image is too small to rotate',
26880 errorTimeout : 3000,
26894 cropType : 'image/jpeg',
26896 canvasLoaded : false,
26897 isDocument : false,
26899 paramName : 'imageUpload',
26901 loadingText : 'Loading...',
26904 getAutoCreate : function()
26908 cls : 'roo-upload-cropbox',
26912 cls : 'roo-upload-cropbox-selector',
26917 cls : 'roo-upload-cropbox-body',
26918 style : 'cursor:pointer',
26922 cls : 'roo-upload-cropbox-preview'
26926 cls : 'roo-upload-cropbox-thumb'
26930 cls : 'roo-upload-cropbox-empty-notify',
26931 html : this.emptyText
26935 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26936 html : this.rotateNotify
26942 cls : 'roo-upload-cropbox-footer',
26945 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26955 onRender : function(ct, position)
26957 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26959 if (this.buttons.length) {
26961 Roo.each(this.buttons, function(bb) {
26963 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26965 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26971 this.maskEl = this.el;
26975 initEvents : function()
26977 this.urlAPI = (window.createObjectURL && window) ||
26978 (window.URL && URL.revokeObjectURL && URL) ||
26979 (window.webkitURL && webkitURL);
26981 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26982 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26984 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26985 this.selectorEl.hide();
26987 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26988 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26990 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26991 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26992 this.thumbEl.hide();
26994 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26995 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26997 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26998 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26999 this.errorEl.hide();
27001 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27002 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27003 this.footerEl.hide();
27005 this.setThumbBoxSize();
27011 this.fireEvent('initial', this);
27018 window.addEventListener("resize", function() { _this.resize(); } );
27020 this.bodyEl.on('click', this.beforeSelectFile, this);
27023 this.bodyEl.on('touchstart', this.onTouchStart, this);
27024 this.bodyEl.on('touchmove', this.onTouchMove, this);
27025 this.bodyEl.on('touchend', this.onTouchEnd, this);
27029 this.bodyEl.on('mousedown', this.onMouseDown, this);
27030 this.bodyEl.on('mousemove', this.onMouseMove, this);
27031 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27032 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27033 Roo.get(document).on('mouseup', this.onMouseUp, this);
27036 this.selectorEl.on('change', this.onFileSelected, this);
27042 this.baseScale = 1;
27044 this.baseRotate = 1;
27045 this.dragable = false;
27046 this.pinching = false;
27049 this.cropData = false;
27050 this.notifyEl.dom.innerHTML = this.emptyText;
27052 this.selectorEl.dom.value = '';
27056 resize : function()
27058 if(this.fireEvent('resize', this) != false){
27059 this.setThumbBoxPosition();
27060 this.setCanvasPosition();
27064 onFooterButtonClick : function(e, el, o, type)
27067 case 'rotate-left' :
27068 this.onRotateLeft(e);
27070 case 'rotate-right' :
27071 this.onRotateRight(e);
27074 this.beforeSelectFile(e);
27089 this.fireEvent('footerbuttonclick', this, type);
27092 beforeSelectFile : function(e)
27094 e.preventDefault();
27096 if(this.fireEvent('beforeselectfile', this) != false){
27097 this.selectorEl.dom.click();
27101 onFileSelected : function(e)
27103 e.preventDefault();
27105 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27109 var file = this.selectorEl.dom.files[0];
27111 if(this.fireEvent('inspect', this, file) != false){
27112 this.prepare(file);
27117 trash : function(e)
27119 this.fireEvent('trash', this);
27122 download : function(e)
27124 this.fireEvent('download', this);
27127 loadCanvas : function(src)
27129 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27133 this.imageEl = document.createElement('img');
27137 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27139 this.imageEl.src = src;
27143 onLoadCanvas : function()
27145 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27146 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27148 this.bodyEl.un('click', this.beforeSelectFile, this);
27150 this.notifyEl.hide();
27151 this.thumbEl.show();
27152 this.footerEl.show();
27154 this.baseRotateLevel();
27156 if(this.isDocument){
27157 this.setThumbBoxSize();
27160 this.setThumbBoxPosition();
27162 this.baseScaleLevel();
27168 this.canvasLoaded = true;
27171 this.maskEl.unmask();
27176 setCanvasPosition : function()
27178 if(!this.canvasEl){
27182 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27183 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27185 this.previewEl.setLeft(pw);
27186 this.previewEl.setTop(ph);
27190 onMouseDown : function(e)
27194 this.dragable = true;
27195 this.pinching = false;
27197 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27198 this.dragable = false;
27202 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27203 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27207 onMouseMove : function(e)
27211 if(!this.canvasLoaded){
27215 if (!this.dragable){
27219 var minX = Math.ceil(this.thumbEl.getLeft(true));
27220 var minY = Math.ceil(this.thumbEl.getTop(true));
27222 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27223 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27225 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27226 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27228 x = x - this.mouseX;
27229 y = y - this.mouseY;
27231 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27232 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27234 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27235 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27237 this.previewEl.setLeft(bgX);
27238 this.previewEl.setTop(bgY);
27240 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27241 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27244 onMouseUp : function(e)
27248 this.dragable = false;
27251 onMouseWheel : function(e)
27255 this.startScale = this.scale;
27257 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27259 if(!this.zoomable()){
27260 this.scale = this.startScale;
27269 zoomable : function()
27271 var minScale = this.thumbEl.getWidth() / this.minWidth;
27273 if(this.minWidth < this.minHeight){
27274 minScale = this.thumbEl.getHeight() / this.minHeight;
27277 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27278 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27282 (this.rotate == 0 || this.rotate == 180) &&
27284 width > this.imageEl.OriginWidth ||
27285 height > this.imageEl.OriginHeight ||
27286 (width < this.minWidth && height < this.minHeight)
27294 (this.rotate == 90 || this.rotate == 270) &&
27296 width > this.imageEl.OriginWidth ||
27297 height > this.imageEl.OriginHeight ||
27298 (width < this.minHeight && height < this.minWidth)
27305 !this.isDocument &&
27306 (this.rotate == 0 || this.rotate == 180) &&
27308 width < this.minWidth ||
27309 width > this.imageEl.OriginWidth ||
27310 height < this.minHeight ||
27311 height > this.imageEl.OriginHeight
27318 !this.isDocument &&
27319 (this.rotate == 90 || this.rotate == 270) &&
27321 width < this.minHeight ||
27322 width > this.imageEl.OriginWidth ||
27323 height < this.minWidth ||
27324 height > this.imageEl.OriginHeight
27334 onRotateLeft : function(e)
27336 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27338 var minScale = this.thumbEl.getWidth() / this.minWidth;
27340 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27341 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27343 this.startScale = this.scale;
27345 while (this.getScaleLevel() < minScale){
27347 this.scale = this.scale + 1;
27349 if(!this.zoomable()){
27354 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27355 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27360 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27367 this.scale = this.startScale;
27369 this.onRotateFail();
27374 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27376 if(this.isDocument){
27377 this.setThumbBoxSize();
27378 this.setThumbBoxPosition();
27379 this.setCanvasPosition();
27384 this.fireEvent('rotate', this, 'left');
27388 onRotateRight : function(e)
27390 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27392 var minScale = this.thumbEl.getWidth() / this.minWidth;
27394 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27395 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27397 this.startScale = this.scale;
27399 while (this.getScaleLevel() < minScale){
27401 this.scale = this.scale + 1;
27403 if(!this.zoomable()){
27408 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27409 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27414 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27421 this.scale = this.startScale;
27423 this.onRotateFail();
27428 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27430 if(this.isDocument){
27431 this.setThumbBoxSize();
27432 this.setThumbBoxPosition();
27433 this.setCanvasPosition();
27438 this.fireEvent('rotate', this, 'right');
27441 onRotateFail : function()
27443 this.errorEl.show(true);
27447 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27452 this.previewEl.dom.innerHTML = '';
27454 var canvasEl = document.createElement("canvas");
27456 var contextEl = canvasEl.getContext("2d");
27458 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27459 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27460 var center = this.imageEl.OriginWidth / 2;
27462 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27463 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27464 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27465 center = this.imageEl.OriginHeight / 2;
27468 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27470 contextEl.translate(center, center);
27471 contextEl.rotate(this.rotate * Math.PI / 180);
27473 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27475 this.canvasEl = document.createElement("canvas");
27477 this.contextEl = this.canvasEl.getContext("2d");
27479 switch (this.rotate) {
27482 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27483 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27485 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27490 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27491 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27493 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27494 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);
27498 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27503 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27504 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27506 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27507 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);
27511 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);
27516 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27517 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27519 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27520 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27524 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);
27531 this.previewEl.appendChild(this.canvasEl);
27533 this.setCanvasPosition();
27538 if(!this.canvasLoaded){
27542 var imageCanvas = document.createElement("canvas");
27544 var imageContext = imageCanvas.getContext("2d");
27546 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27547 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27549 var center = imageCanvas.width / 2;
27551 imageContext.translate(center, center);
27553 imageContext.rotate(this.rotate * Math.PI / 180);
27555 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27557 var canvas = document.createElement("canvas");
27559 var context = canvas.getContext("2d");
27561 canvas.width = this.minWidth;
27562 canvas.height = this.minHeight;
27564 switch (this.rotate) {
27567 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27568 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27570 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27571 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27573 var targetWidth = this.minWidth - 2 * x;
27574 var targetHeight = this.minHeight - 2 * y;
27578 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27579 scale = targetWidth / width;
27582 if(x > 0 && y == 0){
27583 scale = targetHeight / height;
27586 if(x > 0 && y > 0){
27587 scale = targetWidth / width;
27589 if(width < height){
27590 scale = targetHeight / height;
27594 context.scale(scale, scale);
27596 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27597 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27599 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27600 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27602 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27607 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27608 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27610 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27611 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27613 var targetWidth = this.minWidth - 2 * x;
27614 var targetHeight = this.minHeight - 2 * y;
27618 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27619 scale = targetWidth / width;
27622 if(x > 0 && y == 0){
27623 scale = targetHeight / height;
27626 if(x > 0 && y > 0){
27627 scale = targetWidth / width;
27629 if(width < height){
27630 scale = targetHeight / height;
27634 context.scale(scale, scale);
27636 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27637 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27639 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27640 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27642 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27644 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27649 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27650 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27652 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27653 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27655 var targetWidth = this.minWidth - 2 * x;
27656 var targetHeight = this.minHeight - 2 * y;
27660 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27661 scale = targetWidth / width;
27664 if(x > 0 && y == 0){
27665 scale = targetHeight / height;
27668 if(x > 0 && y > 0){
27669 scale = targetWidth / width;
27671 if(width < height){
27672 scale = targetHeight / height;
27676 context.scale(scale, scale);
27678 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27679 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27681 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27682 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27684 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27685 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27687 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27692 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27693 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27695 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27696 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27698 var targetWidth = this.minWidth - 2 * x;
27699 var targetHeight = this.minHeight - 2 * y;
27703 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27704 scale = targetWidth / width;
27707 if(x > 0 && y == 0){
27708 scale = targetHeight / height;
27711 if(x > 0 && y > 0){
27712 scale = targetWidth / width;
27714 if(width < height){
27715 scale = targetHeight / height;
27719 context.scale(scale, scale);
27721 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27722 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27724 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27725 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27727 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27729 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27736 this.cropData = canvas.toDataURL(this.cropType);
27738 if(this.fireEvent('crop', this, this.cropData) !== false){
27739 this.process(this.file, this.cropData);
27746 setThumbBoxSize : function()
27750 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27751 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27752 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27754 this.minWidth = width;
27755 this.minHeight = height;
27757 if(this.rotate == 90 || this.rotate == 270){
27758 this.minWidth = height;
27759 this.minHeight = width;
27764 width = Math.ceil(this.minWidth * height / this.minHeight);
27766 if(this.minWidth > this.minHeight){
27768 height = Math.ceil(this.minHeight * width / this.minWidth);
27771 this.thumbEl.setStyle({
27772 width : width + 'px',
27773 height : height + 'px'
27780 setThumbBoxPosition : function()
27782 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27783 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27785 this.thumbEl.setLeft(x);
27786 this.thumbEl.setTop(y);
27790 baseRotateLevel : function()
27792 this.baseRotate = 1;
27795 typeof(this.exif) != 'undefined' &&
27796 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27797 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27799 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27802 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27806 baseScaleLevel : function()
27810 if(this.isDocument){
27812 if(this.baseRotate == 6 || this.baseRotate == 8){
27814 height = this.thumbEl.getHeight();
27815 this.baseScale = height / this.imageEl.OriginWidth;
27817 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27818 width = this.thumbEl.getWidth();
27819 this.baseScale = width / this.imageEl.OriginHeight;
27825 height = this.thumbEl.getHeight();
27826 this.baseScale = height / this.imageEl.OriginHeight;
27828 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27829 width = this.thumbEl.getWidth();
27830 this.baseScale = width / this.imageEl.OriginWidth;
27836 if(this.baseRotate == 6 || this.baseRotate == 8){
27838 width = this.thumbEl.getHeight();
27839 this.baseScale = width / this.imageEl.OriginHeight;
27841 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27842 height = this.thumbEl.getWidth();
27843 this.baseScale = height / this.imageEl.OriginHeight;
27846 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27847 height = this.thumbEl.getWidth();
27848 this.baseScale = height / this.imageEl.OriginHeight;
27850 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27851 width = this.thumbEl.getHeight();
27852 this.baseScale = width / this.imageEl.OriginWidth;
27859 width = this.thumbEl.getWidth();
27860 this.baseScale = width / this.imageEl.OriginWidth;
27862 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27863 height = this.thumbEl.getHeight();
27864 this.baseScale = height / this.imageEl.OriginHeight;
27867 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27869 height = this.thumbEl.getHeight();
27870 this.baseScale = height / this.imageEl.OriginHeight;
27872 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27873 width = this.thumbEl.getWidth();
27874 this.baseScale = width / this.imageEl.OriginWidth;
27882 getScaleLevel : function()
27884 return this.baseScale * Math.pow(1.1, this.scale);
27887 onTouchStart : function(e)
27889 if(!this.canvasLoaded){
27890 this.beforeSelectFile(e);
27894 var touches = e.browserEvent.touches;
27900 if(touches.length == 1){
27901 this.onMouseDown(e);
27905 if(touches.length != 2){
27911 for(var i = 0, finger; finger = touches[i]; i++){
27912 coords.push(finger.pageX, finger.pageY);
27915 var x = Math.pow(coords[0] - coords[2], 2);
27916 var y = Math.pow(coords[1] - coords[3], 2);
27918 this.startDistance = Math.sqrt(x + y);
27920 this.startScale = this.scale;
27922 this.pinching = true;
27923 this.dragable = false;
27927 onTouchMove : function(e)
27929 if(!this.pinching && !this.dragable){
27933 var touches = e.browserEvent.touches;
27940 this.onMouseMove(e);
27946 for(var i = 0, finger; finger = touches[i]; i++){
27947 coords.push(finger.pageX, finger.pageY);
27950 var x = Math.pow(coords[0] - coords[2], 2);
27951 var y = Math.pow(coords[1] - coords[3], 2);
27953 this.endDistance = Math.sqrt(x + y);
27955 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27957 if(!this.zoomable()){
27958 this.scale = this.startScale;
27966 onTouchEnd : function(e)
27968 this.pinching = false;
27969 this.dragable = false;
27973 process : function(file, crop)
27976 this.maskEl.mask(this.loadingText);
27979 this.xhr = new XMLHttpRequest();
27981 file.xhr = this.xhr;
27983 this.xhr.open(this.method, this.url, true);
27986 "Accept": "application/json",
27987 "Cache-Control": "no-cache",
27988 "X-Requested-With": "XMLHttpRequest"
27991 for (var headerName in headers) {
27992 var headerValue = headers[headerName];
27994 this.xhr.setRequestHeader(headerName, headerValue);
28000 this.xhr.onload = function()
28002 _this.xhrOnLoad(_this.xhr);
28005 this.xhr.onerror = function()
28007 _this.xhrOnError(_this.xhr);
28010 var formData = new FormData();
28012 formData.append('returnHTML', 'NO');
28015 formData.append('crop', crop);
28018 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28019 formData.append(this.paramName, file, file.name);
28022 if(typeof(file.filename) != 'undefined'){
28023 formData.append('filename', file.filename);
28026 if(typeof(file.mimetype) != 'undefined'){
28027 formData.append('mimetype', file.mimetype);
28030 if(this.fireEvent('arrange', this, formData) != false){
28031 this.xhr.send(formData);
28035 xhrOnLoad : function(xhr)
28038 this.maskEl.unmask();
28041 if (xhr.readyState !== 4) {
28042 this.fireEvent('exception', this, xhr);
28046 var response = Roo.decode(xhr.responseText);
28048 if(!response.success){
28049 this.fireEvent('exception', this, xhr);
28053 var response = Roo.decode(xhr.responseText);
28055 this.fireEvent('upload', this, response);
28059 xhrOnError : function()
28062 this.maskEl.unmask();
28065 Roo.log('xhr on error');
28067 var response = Roo.decode(xhr.responseText);
28073 prepare : function(file)
28076 this.maskEl.mask(this.loadingText);
28082 if(typeof(file) === 'string'){
28083 this.loadCanvas(file);
28087 if(!file || !this.urlAPI){
28092 this.cropType = file.type;
28096 if(this.fireEvent('prepare', this, this.file) != false){
28098 var reader = new FileReader();
28100 reader.onload = function (e) {
28101 if (e.target.error) {
28102 Roo.log(e.target.error);
28106 var buffer = e.target.result,
28107 dataView = new DataView(buffer),
28109 maxOffset = dataView.byteLength - 4,
28113 if (dataView.getUint16(0) === 0xffd8) {
28114 while (offset < maxOffset) {
28115 markerBytes = dataView.getUint16(offset);
28117 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28118 markerLength = dataView.getUint16(offset + 2) + 2;
28119 if (offset + markerLength > dataView.byteLength) {
28120 Roo.log('Invalid meta data: Invalid segment size.');
28124 if(markerBytes == 0xffe1){
28125 _this.parseExifData(
28132 offset += markerLength;
28142 var url = _this.urlAPI.createObjectURL(_this.file);
28144 _this.loadCanvas(url);
28149 reader.readAsArrayBuffer(this.file);
28155 parseExifData : function(dataView, offset, length)
28157 var tiffOffset = offset + 10,
28161 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28162 // No Exif data, might be XMP data instead
28166 // Check for the ASCII code for "Exif" (0x45786966):
28167 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28168 // No Exif data, might be XMP data instead
28171 if (tiffOffset + 8 > dataView.byteLength) {
28172 Roo.log('Invalid Exif data: Invalid segment size.');
28175 // Check for the two null bytes:
28176 if (dataView.getUint16(offset + 8) !== 0x0000) {
28177 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28180 // Check the byte alignment:
28181 switch (dataView.getUint16(tiffOffset)) {
28183 littleEndian = true;
28186 littleEndian = false;
28189 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28192 // Check for the TIFF tag marker (0x002A):
28193 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28194 Roo.log('Invalid Exif data: Missing TIFF marker.');
28197 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28198 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28200 this.parseExifTags(
28203 tiffOffset + dirOffset,
28208 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28213 if (dirOffset + 6 > dataView.byteLength) {
28214 Roo.log('Invalid Exif data: Invalid directory offset.');
28217 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28218 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28219 if (dirEndOffset + 4 > dataView.byteLength) {
28220 Roo.log('Invalid Exif data: Invalid directory size.');
28223 for (i = 0; i < tagsNumber; i += 1) {
28227 dirOffset + 2 + 12 * i, // tag offset
28231 // Return the offset to the next directory:
28232 return dataView.getUint32(dirEndOffset, littleEndian);
28235 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28237 var tag = dataView.getUint16(offset, littleEndian);
28239 this.exif[tag] = this.getExifValue(
28243 dataView.getUint16(offset + 2, littleEndian), // tag type
28244 dataView.getUint32(offset + 4, littleEndian), // tag length
28249 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28251 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28260 Roo.log('Invalid Exif data: Invalid tag type.');
28264 tagSize = tagType.size * length;
28265 // Determine if the value is contained in the dataOffset bytes,
28266 // or if the value at the dataOffset is a pointer to the actual data:
28267 dataOffset = tagSize > 4 ?
28268 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28269 if (dataOffset + tagSize > dataView.byteLength) {
28270 Roo.log('Invalid Exif data: Invalid data offset.');
28273 if (length === 1) {
28274 return tagType.getValue(dataView, dataOffset, littleEndian);
28277 for (i = 0; i < length; i += 1) {
28278 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28281 if (tagType.ascii) {
28283 // Concatenate the chars:
28284 for (i = 0; i < values.length; i += 1) {
28286 // Ignore the terminating NULL byte(s):
28287 if (c === '\u0000') {
28299 Roo.apply(Roo.bootstrap.UploadCropbox, {
28301 'Orientation': 0x0112
28305 1: 0, //'top-left',
28307 3: 180, //'bottom-right',
28308 // 4: 'bottom-left',
28310 6: 90, //'right-top',
28311 // 7: 'right-bottom',
28312 8: 270 //'left-bottom'
28316 // byte, 8-bit unsigned int:
28318 getValue: function (dataView, dataOffset) {
28319 return dataView.getUint8(dataOffset);
28323 // ascii, 8-bit byte:
28325 getValue: function (dataView, dataOffset) {
28326 return String.fromCharCode(dataView.getUint8(dataOffset));
28331 // short, 16 bit int:
28333 getValue: function (dataView, dataOffset, littleEndian) {
28334 return dataView.getUint16(dataOffset, littleEndian);
28338 // long, 32 bit int:
28340 getValue: function (dataView, dataOffset, littleEndian) {
28341 return dataView.getUint32(dataOffset, littleEndian);
28345 // rational = two long values, first is numerator, second is denominator:
28347 getValue: function (dataView, dataOffset, littleEndian) {
28348 return dataView.getUint32(dataOffset, littleEndian) /
28349 dataView.getUint32(dataOffset + 4, littleEndian);
28353 // slong, 32 bit signed int:
28355 getValue: function (dataView, dataOffset, littleEndian) {
28356 return dataView.getInt32(dataOffset, littleEndian);
28360 // srational, two slongs, first is numerator, second is denominator:
28362 getValue: function (dataView, dataOffset, littleEndian) {
28363 return dataView.getInt32(dataOffset, littleEndian) /
28364 dataView.getInt32(dataOffset + 4, littleEndian);
28374 cls : 'btn-group roo-upload-cropbox-rotate-left',
28375 action : 'rotate-left',
28379 cls : 'btn btn-default',
28380 html : '<i class="fa fa-undo"></i>'
28386 cls : 'btn-group roo-upload-cropbox-picture',
28387 action : 'picture',
28391 cls : 'btn btn-default',
28392 html : '<i class="fa fa-picture-o"></i>'
28398 cls : 'btn-group roo-upload-cropbox-rotate-right',
28399 action : 'rotate-right',
28403 cls : 'btn btn-default',
28404 html : '<i class="fa fa-repeat"></i>'
28412 cls : 'btn-group roo-upload-cropbox-rotate-left',
28413 action : 'rotate-left',
28417 cls : 'btn btn-default',
28418 html : '<i class="fa fa-undo"></i>'
28424 cls : 'btn-group roo-upload-cropbox-download',
28425 action : 'download',
28429 cls : 'btn btn-default',
28430 html : '<i class="fa fa-download"></i>'
28436 cls : 'btn-group roo-upload-cropbox-crop',
28441 cls : 'btn btn-default',
28442 html : '<i class="fa fa-crop"></i>'
28448 cls : 'btn-group roo-upload-cropbox-trash',
28453 cls : 'btn btn-default',
28454 html : '<i class="fa fa-trash"></i>'
28460 cls : 'btn-group roo-upload-cropbox-rotate-right',
28461 action : 'rotate-right',
28465 cls : 'btn btn-default',
28466 html : '<i class="fa fa-repeat"></i>'
28474 cls : 'btn-group roo-upload-cropbox-rotate-left',
28475 action : 'rotate-left',
28479 cls : 'btn btn-default',
28480 html : '<i class="fa fa-undo"></i>'
28486 cls : 'btn-group roo-upload-cropbox-rotate-right',
28487 action : 'rotate-right',
28491 cls : 'btn btn-default',
28492 html : '<i class="fa fa-repeat"></i>'
28505 * @class Roo.bootstrap.DocumentManager
28506 * @extends Roo.bootstrap.Component
28507 * Bootstrap DocumentManager class
28508 * @cfg {String} paramName default 'imageUpload'
28509 * @cfg {String} toolTipName default 'filename'
28510 * @cfg {String} method default POST
28511 * @cfg {String} url action url
28512 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28513 * @cfg {Boolean} multiple multiple upload default true
28514 * @cfg {Number} thumbSize default 300
28515 * @cfg {String} fieldLabel
28516 * @cfg {Number} labelWidth default 4
28517 * @cfg {String} labelAlign (left|top) default left
28518 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28519 * @cfg {Number} labellg set the width of label (1-12)
28520 * @cfg {Number} labelmd set the width of label (1-12)
28521 * @cfg {Number} labelsm set the width of label (1-12)
28522 * @cfg {Number} labelxs set the width of label (1-12)
28525 * Create a new DocumentManager
28526 * @param {Object} config The config object
28529 Roo.bootstrap.DocumentManager = function(config){
28530 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28533 this.delegates = [];
28538 * Fire when initial the DocumentManager
28539 * @param {Roo.bootstrap.DocumentManager} this
28544 * inspect selected file
28545 * @param {Roo.bootstrap.DocumentManager} this
28546 * @param {File} file
28551 * Fire when xhr load exception
28552 * @param {Roo.bootstrap.DocumentManager} this
28553 * @param {XMLHttpRequest} xhr
28555 "exception" : true,
28557 * @event afterupload
28558 * Fire when xhr load exception
28559 * @param {Roo.bootstrap.DocumentManager} this
28560 * @param {XMLHttpRequest} xhr
28562 "afterupload" : true,
28565 * prepare the form data
28566 * @param {Roo.bootstrap.DocumentManager} this
28567 * @param {Object} formData
28572 * Fire when remove the file
28573 * @param {Roo.bootstrap.DocumentManager} this
28574 * @param {Object} file
28579 * Fire after refresh the file
28580 * @param {Roo.bootstrap.DocumentManager} this
28585 * Fire after click the image
28586 * @param {Roo.bootstrap.DocumentManager} this
28587 * @param {Object} file
28592 * Fire when upload a image and editable set to true
28593 * @param {Roo.bootstrap.DocumentManager} this
28594 * @param {Object} file
28598 * @event beforeselectfile
28599 * Fire before select file
28600 * @param {Roo.bootstrap.DocumentManager} this
28602 "beforeselectfile" : true,
28605 * Fire before process file
28606 * @param {Roo.bootstrap.DocumentManager} this
28607 * @param {Object} file
28611 * @event previewrendered
28612 * Fire when preview rendered
28613 * @param {Roo.bootstrap.DocumentManager} this
28614 * @param {Object} file
28616 "previewrendered" : true
28621 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28630 paramName : 'imageUpload',
28631 toolTipName : 'filename',
28634 labelAlign : 'left',
28644 getAutoCreate : function()
28646 var managerWidget = {
28648 cls : 'roo-document-manager',
28652 cls : 'roo-document-manager-selector',
28657 cls : 'roo-document-manager-uploader',
28661 cls : 'roo-document-manager-upload-btn',
28662 html : '<i class="fa fa-plus"></i>'
28673 cls : 'column col-md-12',
28678 if(this.fieldLabel.length){
28683 cls : 'column col-md-12',
28684 html : this.fieldLabel
28688 cls : 'column col-md-12',
28693 if(this.labelAlign == 'left'){
28698 html : this.fieldLabel
28707 if(this.labelWidth > 12){
28708 content[0].style = "width: " + this.labelWidth + 'px';
28711 if(this.labelWidth < 13 && this.labelmd == 0){
28712 this.labelmd = this.labelWidth;
28715 if(this.labellg > 0){
28716 content[0].cls += ' col-lg-' + this.labellg;
28717 content[1].cls += ' col-lg-' + (12 - this.labellg);
28720 if(this.labelmd > 0){
28721 content[0].cls += ' col-md-' + this.labelmd;
28722 content[1].cls += ' col-md-' + (12 - this.labelmd);
28725 if(this.labelsm > 0){
28726 content[0].cls += ' col-sm-' + this.labelsm;
28727 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28730 if(this.labelxs > 0){
28731 content[0].cls += ' col-xs-' + this.labelxs;
28732 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28740 cls : 'row clearfix',
28748 initEvents : function()
28750 this.managerEl = this.el.select('.roo-document-manager', true).first();
28751 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28753 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28754 this.selectorEl.hide();
28757 this.selectorEl.attr('multiple', 'multiple');
28760 this.selectorEl.on('change', this.onFileSelected, this);
28762 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28763 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28765 this.uploader.on('click', this.onUploaderClick, this);
28767 this.renderProgressDialog();
28771 window.addEventListener("resize", function() { _this.refresh(); } );
28773 this.fireEvent('initial', this);
28776 renderProgressDialog : function()
28780 this.progressDialog = new Roo.bootstrap.Modal({
28781 cls : 'roo-document-manager-progress-dialog',
28782 allow_close : false,
28792 btnclick : function() {
28793 _this.uploadCancel();
28799 this.progressDialog.render(Roo.get(document.body));
28801 this.progress = new Roo.bootstrap.Progress({
28802 cls : 'roo-document-manager-progress',
28807 this.progress.render(this.progressDialog.getChildContainer());
28809 this.progressBar = new Roo.bootstrap.ProgressBar({
28810 cls : 'roo-document-manager-progress-bar',
28813 aria_valuemax : 12,
28817 this.progressBar.render(this.progress.getChildContainer());
28820 onUploaderClick : function(e)
28822 e.preventDefault();
28824 if(this.fireEvent('beforeselectfile', this) != false){
28825 this.selectorEl.dom.click();
28830 onFileSelected : function(e)
28832 e.preventDefault();
28834 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28838 Roo.each(this.selectorEl.dom.files, function(file){
28839 if(this.fireEvent('inspect', this, file) != false){
28840 this.files.push(file);
28850 this.selectorEl.dom.value = '';
28852 if(!this.files || !this.files.length){
28856 if(this.boxes > 0 && this.files.length > this.boxes){
28857 this.files = this.files.slice(0, this.boxes);
28860 this.uploader.show();
28862 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28863 this.uploader.hide();
28872 Roo.each(this.files, function(file){
28874 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28875 var f = this.renderPreview(file);
28880 if(file.type.indexOf('image') != -1){
28881 this.delegates.push(
28883 _this.process(file);
28884 }).createDelegate(this)
28892 _this.process(file);
28893 }).createDelegate(this)
28898 this.files = files;
28900 this.delegates = this.delegates.concat(docs);
28902 if(!this.delegates.length){
28907 this.progressBar.aria_valuemax = this.delegates.length;
28914 arrange : function()
28916 if(!this.delegates.length){
28917 this.progressDialog.hide();
28922 var delegate = this.delegates.shift();
28924 this.progressDialog.show();
28926 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28928 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28933 refresh : function()
28935 this.uploader.show();
28937 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28938 this.uploader.hide();
28941 Roo.isTouch ? this.closable(false) : this.closable(true);
28943 this.fireEvent('refresh', this);
28946 onRemove : function(e, el, o)
28948 e.preventDefault();
28950 this.fireEvent('remove', this, o);
28954 remove : function(o)
28958 Roo.each(this.files, function(file){
28959 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28968 this.files = files;
28975 Roo.each(this.files, function(file){
28980 file.target.remove();
28989 onClick : function(e, el, o)
28991 e.preventDefault();
28993 this.fireEvent('click', this, o);
28997 closable : function(closable)
28999 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29001 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29013 xhrOnLoad : function(xhr)
29015 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29019 if (xhr.readyState !== 4) {
29021 this.fireEvent('exception', this, xhr);
29025 var response = Roo.decode(xhr.responseText);
29027 if(!response.success){
29029 this.fireEvent('exception', this, xhr);
29033 var file = this.renderPreview(response.data);
29035 this.files.push(file);
29039 this.fireEvent('afterupload', this, xhr);
29043 xhrOnError : function(xhr)
29045 Roo.log('xhr on error');
29047 var response = Roo.decode(xhr.responseText);
29054 process : function(file)
29056 if(this.fireEvent('process', this, file) !== false){
29057 if(this.editable && file.type.indexOf('image') != -1){
29058 this.fireEvent('edit', this, file);
29062 this.uploadStart(file, false);
29069 uploadStart : function(file, crop)
29071 this.xhr = new XMLHttpRequest();
29073 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29078 file.xhr = this.xhr;
29080 this.managerEl.createChild({
29082 cls : 'roo-document-manager-loading',
29086 tooltip : file.name,
29087 cls : 'roo-document-manager-thumb',
29088 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29094 this.xhr.open(this.method, this.url, true);
29097 "Accept": "application/json",
29098 "Cache-Control": "no-cache",
29099 "X-Requested-With": "XMLHttpRequest"
29102 for (var headerName in headers) {
29103 var headerValue = headers[headerName];
29105 this.xhr.setRequestHeader(headerName, headerValue);
29111 this.xhr.onload = function()
29113 _this.xhrOnLoad(_this.xhr);
29116 this.xhr.onerror = function()
29118 _this.xhrOnError(_this.xhr);
29121 var formData = new FormData();
29123 formData.append('returnHTML', 'NO');
29126 formData.append('crop', crop);
29129 formData.append(this.paramName, file, file.name);
29136 if(this.fireEvent('prepare', this, formData, options) != false){
29138 if(options.manually){
29142 this.xhr.send(formData);
29146 this.uploadCancel();
29149 uploadCancel : function()
29155 this.delegates = [];
29157 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29164 renderPreview : function(file)
29166 if(typeof(file.target) != 'undefined' && file.target){
29170 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29172 var previewEl = this.managerEl.createChild({
29174 cls : 'roo-document-manager-preview',
29178 tooltip : file[this.toolTipName],
29179 cls : 'roo-document-manager-thumb',
29180 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29185 html : '<i class="fa fa-times-circle"></i>'
29190 var close = previewEl.select('button.close', true).first();
29192 close.on('click', this.onRemove, this, file);
29194 file.target = previewEl;
29196 var image = previewEl.select('img', true).first();
29200 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29202 image.on('click', this.onClick, this, file);
29204 this.fireEvent('previewrendered', this, file);
29210 onPreviewLoad : function(file, image)
29212 if(typeof(file.target) == 'undefined' || !file.target){
29216 var width = image.dom.naturalWidth || image.dom.width;
29217 var height = image.dom.naturalHeight || image.dom.height;
29219 if(width > height){
29220 file.target.addClass('wide');
29224 file.target.addClass('tall');
29229 uploadFromSource : function(file, crop)
29231 this.xhr = new XMLHttpRequest();
29233 this.managerEl.createChild({
29235 cls : 'roo-document-manager-loading',
29239 tooltip : file.name,
29240 cls : 'roo-document-manager-thumb',
29241 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29247 this.xhr.open(this.method, this.url, true);
29250 "Accept": "application/json",
29251 "Cache-Control": "no-cache",
29252 "X-Requested-With": "XMLHttpRequest"
29255 for (var headerName in headers) {
29256 var headerValue = headers[headerName];
29258 this.xhr.setRequestHeader(headerName, headerValue);
29264 this.xhr.onload = function()
29266 _this.xhrOnLoad(_this.xhr);
29269 this.xhr.onerror = function()
29271 _this.xhrOnError(_this.xhr);
29274 var formData = new FormData();
29276 formData.append('returnHTML', 'NO');
29278 formData.append('crop', crop);
29280 if(typeof(file.filename) != 'undefined'){
29281 formData.append('filename', file.filename);
29284 if(typeof(file.mimetype) != 'undefined'){
29285 formData.append('mimetype', file.mimetype);
29290 if(this.fireEvent('prepare', this, formData) != false){
29291 this.xhr.send(formData);
29301 * @class Roo.bootstrap.DocumentViewer
29302 * @extends Roo.bootstrap.Component
29303 * Bootstrap DocumentViewer class
29304 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29305 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29308 * Create a new DocumentViewer
29309 * @param {Object} config The config object
29312 Roo.bootstrap.DocumentViewer = function(config){
29313 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29318 * Fire after initEvent
29319 * @param {Roo.bootstrap.DocumentViewer} this
29325 * @param {Roo.bootstrap.DocumentViewer} this
29330 * Fire after download button
29331 * @param {Roo.bootstrap.DocumentViewer} this
29336 * Fire after trash button
29337 * @param {Roo.bootstrap.DocumentViewer} this
29344 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29346 showDownload : true,
29350 getAutoCreate : function()
29354 cls : 'roo-document-viewer',
29358 cls : 'roo-document-viewer-body',
29362 cls : 'roo-document-viewer-thumb',
29366 cls : 'roo-document-viewer-image'
29374 cls : 'roo-document-viewer-footer',
29377 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29381 cls : 'btn-group roo-document-viewer-download',
29385 cls : 'btn btn-default',
29386 html : '<i class="fa fa-download"></i>'
29392 cls : 'btn-group roo-document-viewer-trash',
29396 cls : 'btn btn-default',
29397 html : '<i class="fa fa-trash"></i>'
29410 initEvents : function()
29412 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29413 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29415 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29416 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29418 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29419 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29421 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29422 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29424 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29425 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29427 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29428 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29430 this.bodyEl.on('click', this.onClick, this);
29431 this.downloadBtn.on('click', this.onDownload, this);
29432 this.trashBtn.on('click', this.onTrash, this);
29434 this.downloadBtn.hide();
29435 this.trashBtn.hide();
29437 if(this.showDownload){
29438 this.downloadBtn.show();
29441 if(this.showTrash){
29442 this.trashBtn.show();
29445 if(!this.showDownload && !this.showTrash) {
29446 this.footerEl.hide();
29451 initial : function()
29453 this.fireEvent('initial', this);
29457 onClick : function(e)
29459 e.preventDefault();
29461 this.fireEvent('click', this);
29464 onDownload : function(e)
29466 e.preventDefault();
29468 this.fireEvent('download', this);
29471 onTrash : function(e)
29473 e.preventDefault();
29475 this.fireEvent('trash', this);
29487 * @class Roo.bootstrap.NavProgressBar
29488 * @extends Roo.bootstrap.Component
29489 * Bootstrap NavProgressBar class
29492 * Create a new nav progress bar
29493 * @param {Object} config The config object
29496 Roo.bootstrap.NavProgressBar = function(config){
29497 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29499 this.bullets = this.bullets || [];
29501 // Roo.bootstrap.NavProgressBar.register(this);
29505 * Fires when the active item changes
29506 * @param {Roo.bootstrap.NavProgressBar} this
29507 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29508 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29515 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29520 getAutoCreate : function()
29522 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29526 cls : 'roo-navigation-bar-group',
29530 cls : 'roo-navigation-top-bar'
29534 cls : 'roo-navigation-bullets-bar',
29538 cls : 'roo-navigation-bar'
29545 cls : 'roo-navigation-bottom-bar'
29555 initEvents: function()
29560 onRender : function(ct, position)
29562 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29564 if(this.bullets.length){
29565 Roo.each(this.bullets, function(b){
29574 addItem : function(cfg)
29576 var item = new Roo.bootstrap.NavProgressItem(cfg);
29578 item.parentId = this.id;
29579 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29582 var top = new Roo.bootstrap.Element({
29584 cls : 'roo-navigation-bar-text'
29587 var bottom = new Roo.bootstrap.Element({
29589 cls : 'roo-navigation-bar-text'
29592 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29593 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29595 var topText = new Roo.bootstrap.Element({
29597 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29600 var bottomText = new Roo.bootstrap.Element({
29602 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29605 topText.onRender(top.el, null);
29606 bottomText.onRender(bottom.el, null);
29609 item.bottomEl = bottom;
29612 this.barItems.push(item);
29617 getActive : function()
29619 var active = false;
29621 Roo.each(this.barItems, function(v){
29623 if (!v.isActive()) {
29635 setActiveItem : function(item)
29639 Roo.each(this.barItems, function(v){
29640 if (v.rid == item.rid) {
29644 if (v.isActive()) {
29645 v.setActive(false);
29650 item.setActive(true);
29652 this.fireEvent('changed', this, item, prev);
29655 getBarItem: function(rid)
29659 Roo.each(this.barItems, function(e) {
29660 if (e.rid != rid) {
29671 indexOfItem : function(item)
29675 Roo.each(this.barItems, function(v, i){
29677 if (v.rid != item.rid) {
29688 setActiveNext : function()
29690 var i = this.indexOfItem(this.getActive());
29692 if (i > this.barItems.length) {
29696 this.setActiveItem(this.barItems[i+1]);
29699 setActivePrev : function()
29701 var i = this.indexOfItem(this.getActive());
29707 this.setActiveItem(this.barItems[i-1]);
29710 format : function()
29712 if(!this.barItems.length){
29716 var width = 100 / this.barItems.length;
29718 Roo.each(this.barItems, function(i){
29719 i.el.setStyle('width', width + '%');
29720 i.topEl.el.setStyle('width', width + '%');
29721 i.bottomEl.el.setStyle('width', width + '%');
29730 * Nav Progress Item
29735 * @class Roo.bootstrap.NavProgressItem
29736 * @extends Roo.bootstrap.Component
29737 * Bootstrap NavProgressItem class
29738 * @cfg {String} rid the reference id
29739 * @cfg {Boolean} active (true|false) Is item active default false
29740 * @cfg {Boolean} disabled (true|false) Is item active default false
29741 * @cfg {String} html
29742 * @cfg {String} position (top|bottom) text position default bottom
29743 * @cfg {String} icon show icon instead of number
29746 * Create a new NavProgressItem
29747 * @param {Object} config The config object
29749 Roo.bootstrap.NavProgressItem = function(config){
29750 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29755 * The raw click event for the entire grid.
29756 * @param {Roo.bootstrap.NavProgressItem} this
29757 * @param {Roo.EventObject} e
29764 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29770 position : 'bottom',
29773 getAutoCreate : function()
29775 var iconCls = 'roo-navigation-bar-item-icon';
29777 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29781 cls: 'roo-navigation-bar-item',
29791 cfg.cls += ' active';
29794 cfg.cls += ' disabled';
29800 disable : function()
29802 this.setDisabled(true);
29805 enable : function()
29807 this.setDisabled(false);
29810 initEvents: function()
29812 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29814 this.iconEl.on('click', this.onClick, this);
29817 onClick : function(e)
29819 e.preventDefault();
29825 if(this.fireEvent('click', this, e) === false){
29829 this.parent().setActiveItem(this);
29832 isActive: function ()
29834 return this.active;
29837 setActive : function(state)
29839 if(this.active == state){
29843 this.active = state;
29846 this.el.addClass('active');
29850 this.el.removeClass('active');
29855 setDisabled : function(state)
29857 if(this.disabled == state){
29861 this.disabled = state;
29864 this.el.addClass('disabled');
29868 this.el.removeClass('disabled');
29871 tooltipEl : function()
29873 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29886 * @class Roo.bootstrap.FieldLabel
29887 * @extends Roo.bootstrap.Component
29888 * Bootstrap FieldLabel class
29889 * @cfg {String} html contents of the element
29890 * @cfg {String} tag tag of the element default label
29891 * @cfg {String} cls class of the element
29892 * @cfg {String} target label target
29893 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29894 * @cfg {String} invalidClass default "text-warning"
29895 * @cfg {String} validClass default "text-success"
29896 * @cfg {String} iconTooltip default "This field is required"
29897 * @cfg {String} indicatorpos (left|right) default left
29900 * Create a new FieldLabel
29901 * @param {Object} config The config object
29904 Roo.bootstrap.FieldLabel = function(config){
29905 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29910 * Fires after the field has been marked as invalid.
29911 * @param {Roo.form.FieldLabel} this
29912 * @param {String} msg The validation message
29917 * Fires after the field has been validated with no errors.
29918 * @param {Roo.form.FieldLabel} this
29924 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29931 invalidClass : 'has-warning',
29932 validClass : 'has-success',
29933 iconTooltip : 'This field is required',
29934 indicatorpos : 'left',
29936 getAutoCreate : function(){
29940 cls : 'roo-bootstrap-field-label ' + this.cls,
29945 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29946 tooltip : this.iconTooltip
29955 if(this.indicatorpos == 'right'){
29958 cls : 'roo-bootstrap-field-label ' + this.cls,
29967 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29968 tooltip : this.iconTooltip
29977 initEvents: function()
29979 Roo.bootstrap.Element.superclass.initEvents.call(this);
29981 this.indicator = this.indicatorEl();
29983 if(this.indicator){
29984 this.indicator.removeClass('visible');
29985 this.indicator.addClass('invisible');
29988 Roo.bootstrap.FieldLabel.register(this);
29991 indicatorEl : function()
29993 var indicator = this.el.select('i.roo-required-indicator',true).first();
30004 * Mark this field as valid
30006 markValid : function()
30008 if(this.indicator){
30009 this.indicator.removeClass('visible');
30010 this.indicator.addClass('invisible');
30013 this.el.removeClass(this.invalidClass);
30015 this.el.addClass(this.validClass);
30017 this.fireEvent('valid', this);
30021 * Mark this field as invalid
30022 * @param {String} msg The validation message
30024 markInvalid : function(msg)
30026 if(this.indicator){
30027 this.indicator.removeClass('invisible');
30028 this.indicator.addClass('visible');
30031 this.el.removeClass(this.validClass);
30033 this.el.addClass(this.invalidClass);
30035 this.fireEvent('invalid', this, msg);
30041 Roo.apply(Roo.bootstrap.FieldLabel, {
30046 * register a FieldLabel Group
30047 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30049 register : function(label)
30051 if(this.groups.hasOwnProperty(label.target)){
30055 this.groups[label.target] = label;
30059 * fetch a FieldLabel Group based on the target
30060 * @param {string} target
30061 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30063 get: function(target) {
30064 if (typeof(this.groups[target]) == 'undefined') {
30068 return this.groups[target] ;
30077 * page DateSplitField.
30083 * @class Roo.bootstrap.DateSplitField
30084 * @extends Roo.bootstrap.Component
30085 * Bootstrap DateSplitField class
30086 * @cfg {string} fieldLabel - the label associated
30087 * @cfg {Number} labelWidth set the width of label (0-12)
30088 * @cfg {String} labelAlign (top|left)
30089 * @cfg {Boolean} dayAllowBlank (true|false) default false
30090 * @cfg {Boolean} monthAllowBlank (true|false) default false
30091 * @cfg {Boolean} yearAllowBlank (true|false) default false
30092 * @cfg {string} dayPlaceholder
30093 * @cfg {string} monthPlaceholder
30094 * @cfg {string} yearPlaceholder
30095 * @cfg {string} dayFormat default 'd'
30096 * @cfg {string} monthFormat default 'm'
30097 * @cfg {string} yearFormat default 'Y'
30098 * @cfg {Number} labellg set the width of label (1-12)
30099 * @cfg {Number} labelmd set the width of label (1-12)
30100 * @cfg {Number} labelsm set the width of label (1-12)
30101 * @cfg {Number} labelxs set the width of label (1-12)
30105 * Create a new DateSplitField
30106 * @param {Object} config The config object
30109 Roo.bootstrap.DateSplitField = function(config){
30110 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30116 * getting the data of years
30117 * @param {Roo.bootstrap.DateSplitField} this
30118 * @param {Object} years
30123 * getting the data of days
30124 * @param {Roo.bootstrap.DateSplitField} this
30125 * @param {Object} days
30130 * Fires after the field has been marked as invalid.
30131 * @param {Roo.form.Field} this
30132 * @param {String} msg The validation message
30137 * Fires after the field has been validated with no errors.
30138 * @param {Roo.form.Field} this
30144 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30147 labelAlign : 'top',
30149 dayAllowBlank : false,
30150 monthAllowBlank : false,
30151 yearAllowBlank : false,
30152 dayPlaceholder : '',
30153 monthPlaceholder : '',
30154 yearPlaceholder : '',
30158 isFormField : true,
30164 getAutoCreate : function()
30168 cls : 'row roo-date-split-field-group',
30173 cls : 'form-hidden-field roo-date-split-field-group-value',
30179 var labelCls = 'col-md-12';
30180 var contentCls = 'col-md-4';
30182 if(this.fieldLabel){
30186 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30190 html : this.fieldLabel
30195 if(this.labelAlign == 'left'){
30197 if(this.labelWidth > 12){
30198 label.style = "width: " + this.labelWidth + 'px';
30201 if(this.labelWidth < 13 && this.labelmd == 0){
30202 this.labelmd = this.labelWidth;
30205 if(this.labellg > 0){
30206 labelCls = ' col-lg-' + this.labellg;
30207 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30210 if(this.labelmd > 0){
30211 labelCls = ' col-md-' + this.labelmd;
30212 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30215 if(this.labelsm > 0){
30216 labelCls = ' col-sm-' + this.labelsm;
30217 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30220 if(this.labelxs > 0){
30221 labelCls = ' col-xs-' + this.labelxs;
30222 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30226 label.cls += ' ' + labelCls;
30228 cfg.cn.push(label);
30231 Roo.each(['day', 'month', 'year'], function(t){
30234 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30241 inputEl: function ()
30243 return this.el.select('.roo-date-split-field-group-value', true).first();
30246 onRender : function(ct, position)
30250 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30252 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30254 this.dayField = new Roo.bootstrap.ComboBox({
30255 allowBlank : this.dayAllowBlank,
30256 alwaysQuery : true,
30257 displayField : 'value',
30260 forceSelection : true,
30262 placeholder : this.dayPlaceholder,
30263 selectOnFocus : true,
30264 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30265 triggerAction : 'all',
30267 valueField : 'value',
30268 store : new Roo.data.SimpleStore({
30269 data : (function() {
30271 _this.fireEvent('days', _this, days);
30274 fields : [ 'value' ]
30277 select : function (_self, record, index)
30279 _this.setValue(_this.getValue());
30284 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30286 this.monthField = new Roo.bootstrap.MonthField({
30287 after : '<i class=\"fa fa-calendar\"></i>',
30288 allowBlank : this.monthAllowBlank,
30289 placeholder : this.monthPlaceholder,
30292 render : function (_self)
30294 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30295 e.preventDefault();
30299 select : function (_self, oldvalue, newvalue)
30301 _this.setValue(_this.getValue());
30306 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30308 this.yearField = new Roo.bootstrap.ComboBox({
30309 allowBlank : this.yearAllowBlank,
30310 alwaysQuery : true,
30311 displayField : 'value',
30314 forceSelection : true,
30316 placeholder : this.yearPlaceholder,
30317 selectOnFocus : true,
30318 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30319 triggerAction : 'all',
30321 valueField : 'value',
30322 store : new Roo.data.SimpleStore({
30323 data : (function() {
30325 _this.fireEvent('years', _this, years);
30328 fields : [ 'value' ]
30331 select : function (_self, record, index)
30333 _this.setValue(_this.getValue());
30338 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30341 setValue : function(v, format)
30343 this.inputEl.dom.value = v;
30345 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30347 var d = Date.parseDate(v, f);
30354 this.setDay(d.format(this.dayFormat));
30355 this.setMonth(d.format(this.monthFormat));
30356 this.setYear(d.format(this.yearFormat));
30363 setDay : function(v)
30365 this.dayField.setValue(v);
30366 this.inputEl.dom.value = this.getValue();
30371 setMonth : function(v)
30373 this.monthField.setValue(v, true);
30374 this.inputEl.dom.value = this.getValue();
30379 setYear : function(v)
30381 this.yearField.setValue(v);
30382 this.inputEl.dom.value = this.getValue();
30387 getDay : function()
30389 return this.dayField.getValue();
30392 getMonth : function()
30394 return this.monthField.getValue();
30397 getYear : function()
30399 return this.yearField.getValue();
30402 getValue : function()
30404 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30406 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30416 this.inputEl.dom.value = '';
30421 validate : function()
30423 var d = this.dayField.validate();
30424 var m = this.monthField.validate();
30425 var y = this.yearField.validate();
30430 (!this.dayAllowBlank && !d) ||
30431 (!this.monthAllowBlank && !m) ||
30432 (!this.yearAllowBlank && !y)
30437 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30446 this.markInvalid();
30451 markValid : function()
30454 var label = this.el.select('label', true).first();
30455 var icon = this.el.select('i.fa-star', true).first();
30461 this.fireEvent('valid', this);
30465 * Mark this field as invalid
30466 * @param {String} msg The validation message
30468 markInvalid : function(msg)
30471 var label = this.el.select('label', true).first();
30472 var icon = this.el.select('i.fa-star', true).first();
30474 if(label && !icon){
30475 this.el.select('.roo-date-split-field-label', true).createChild({
30477 cls : 'text-danger fa fa-lg fa-star',
30478 tooltip : 'This field is required',
30479 style : 'margin-right:5px;'
30483 this.fireEvent('invalid', this, msg);
30486 clearInvalid : function()
30488 var label = this.el.select('label', true).first();
30489 var icon = this.el.select('i.fa-star', true).first();
30495 this.fireEvent('valid', this);
30498 getName: function()
30508 * http://masonry.desandro.com
30510 * The idea is to render all the bricks based on vertical width...
30512 * The original code extends 'outlayer' - we might need to use that....
30518 * @class Roo.bootstrap.LayoutMasonry
30519 * @extends Roo.bootstrap.Component
30520 * Bootstrap Layout Masonry class
30523 * Create a new Element
30524 * @param {Object} config The config object
30527 Roo.bootstrap.LayoutMasonry = function(config){
30529 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30533 Roo.bootstrap.LayoutMasonry.register(this);
30539 * Fire after layout the items
30540 * @param {Roo.bootstrap.LayoutMasonry} this
30541 * @param {Roo.EventObject} e
30548 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30551 * @cfg {Boolean} isLayoutInstant = no animation?
30553 isLayoutInstant : false, // needed?
30556 * @cfg {Number} boxWidth width of the columns
30561 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30566 * @cfg {Number} padWidth padding below box..
30571 * @cfg {Number} gutter gutter width..
30576 * @cfg {Number} maxCols maximum number of columns
30582 * @cfg {Boolean} isAutoInitial defalut true
30584 isAutoInitial : true,
30589 * @cfg {Boolean} isHorizontal defalut false
30591 isHorizontal : false,
30593 currentSize : null,
30599 bricks: null, //CompositeElement
30603 _isLayoutInited : false,
30605 // isAlternative : false, // only use for vertical layout...
30608 * @cfg {Number} alternativePadWidth padding below box..
30610 alternativePadWidth : 50,
30612 selectedBrick : [],
30614 getAutoCreate : function(){
30616 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30620 cls: 'blog-masonary-wrapper ' + this.cls,
30622 cls : 'mas-boxes masonary'
30629 getChildContainer: function( )
30631 if (this.boxesEl) {
30632 return this.boxesEl;
30635 this.boxesEl = this.el.select('.mas-boxes').first();
30637 return this.boxesEl;
30641 initEvents : function()
30645 if(this.isAutoInitial){
30646 Roo.log('hook children rendered');
30647 this.on('childrenrendered', function() {
30648 Roo.log('children rendered');
30654 initial : function()
30656 this.selectedBrick = [];
30658 this.currentSize = this.el.getBox(true);
30660 Roo.EventManager.onWindowResize(this.resize, this);
30662 if(!this.isAutoInitial){
30670 //this.layout.defer(500,this);
30674 resize : function()
30676 var cs = this.el.getBox(true);
30679 this.currentSize.width == cs.width &&
30680 this.currentSize.x == cs.x &&
30681 this.currentSize.height == cs.height &&
30682 this.currentSize.y == cs.y
30684 Roo.log("no change in with or X or Y");
30688 this.currentSize = cs;
30694 layout : function()
30696 this._resetLayout();
30698 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30700 this.layoutItems( isInstant );
30702 this._isLayoutInited = true;
30704 this.fireEvent('layout', this);
30708 _resetLayout : function()
30710 if(this.isHorizontal){
30711 this.horizontalMeasureColumns();
30715 this.verticalMeasureColumns();
30719 verticalMeasureColumns : function()
30721 this.getContainerWidth();
30723 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30724 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30728 var boxWidth = this.boxWidth + this.padWidth;
30730 if(this.containerWidth < this.boxWidth){
30731 boxWidth = this.containerWidth
30734 var containerWidth = this.containerWidth;
30736 var cols = Math.floor(containerWidth / boxWidth);
30738 this.cols = Math.max( cols, 1 );
30740 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30742 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30744 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30746 this.colWidth = boxWidth + avail - this.padWidth;
30748 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30749 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30752 horizontalMeasureColumns : function()
30754 this.getContainerWidth();
30756 var boxWidth = this.boxWidth;
30758 if(this.containerWidth < boxWidth){
30759 boxWidth = this.containerWidth;
30762 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30764 this.el.setHeight(boxWidth);
30768 getContainerWidth : function()
30770 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30773 layoutItems : function( isInstant )
30775 Roo.log(this.bricks);
30777 var items = Roo.apply([], this.bricks);
30779 if(this.isHorizontal){
30780 this._horizontalLayoutItems( items , isInstant );
30784 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30785 // this._verticalAlternativeLayoutItems( items , isInstant );
30789 this._verticalLayoutItems( items , isInstant );
30793 _verticalLayoutItems : function ( items , isInstant)
30795 if ( !items || !items.length ) {
30800 ['xs', 'xs', 'xs', 'tall'],
30801 ['xs', 'xs', 'tall'],
30802 ['xs', 'xs', 'sm'],
30803 ['xs', 'xs', 'xs'],
30809 ['sm', 'xs', 'xs'],
30813 ['tall', 'xs', 'xs', 'xs'],
30814 ['tall', 'xs', 'xs'],
30826 Roo.each(items, function(item, k){
30828 switch (item.size) {
30829 // these layouts take up a full box,
30840 boxes.push([item]);
30863 var filterPattern = function(box, length)
30871 var pattern = box.slice(0, length);
30875 Roo.each(pattern, function(i){
30876 format.push(i.size);
30879 Roo.each(standard, function(s){
30881 if(String(s) != String(format)){
30890 if(!match && length == 1){
30895 filterPattern(box, length - 1);
30899 queue.push(pattern);
30901 box = box.slice(length, box.length);
30903 filterPattern(box, 4);
30909 Roo.each(boxes, function(box, k){
30915 if(box.length == 1){
30920 filterPattern(box, 4);
30924 this._processVerticalLayoutQueue( queue, isInstant );
30928 // _verticalAlternativeLayoutItems : function( items , isInstant )
30930 // if ( !items || !items.length ) {
30934 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30938 _horizontalLayoutItems : function ( items , isInstant)
30940 if ( !items || !items.length || items.length < 3) {
30946 var eItems = items.slice(0, 3);
30948 items = items.slice(3, items.length);
30951 ['xs', 'xs', 'xs', 'wide'],
30952 ['xs', 'xs', 'wide'],
30953 ['xs', 'xs', 'sm'],
30954 ['xs', 'xs', 'xs'],
30960 ['sm', 'xs', 'xs'],
30964 ['wide', 'xs', 'xs', 'xs'],
30965 ['wide', 'xs', 'xs'],
30978 Roo.each(items, function(item, k){
30980 switch (item.size) {
30991 boxes.push([item]);
31015 var filterPattern = function(box, length)
31023 var pattern = box.slice(0, length);
31027 Roo.each(pattern, function(i){
31028 format.push(i.size);
31031 Roo.each(standard, function(s){
31033 if(String(s) != String(format)){
31042 if(!match && length == 1){
31047 filterPattern(box, length - 1);
31051 queue.push(pattern);
31053 box = box.slice(length, box.length);
31055 filterPattern(box, 4);
31061 Roo.each(boxes, function(box, k){
31067 if(box.length == 1){
31072 filterPattern(box, 4);
31079 var pos = this.el.getBox(true);
31083 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31085 var hit_end = false;
31087 Roo.each(queue, function(box){
31091 Roo.each(box, function(b){
31093 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31103 Roo.each(box, function(b){
31105 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31108 mx = Math.max(mx, b.x);
31112 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31116 Roo.each(box, function(b){
31118 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31132 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31135 /** Sets position of item in DOM
31136 * @param {Element} item
31137 * @param {Number} x - horizontal position
31138 * @param {Number} y - vertical position
31139 * @param {Boolean} isInstant - disables transitions
31141 _processVerticalLayoutQueue : function( queue, isInstant )
31143 var pos = this.el.getBox(true);
31148 for (var i = 0; i < this.cols; i++){
31152 Roo.each(queue, function(box, k){
31154 var col = k % this.cols;
31156 Roo.each(box, function(b,kk){
31158 b.el.position('absolute');
31160 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31161 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31163 if(b.size == 'md-left' || b.size == 'md-right'){
31164 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31165 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31168 b.el.setWidth(width);
31169 b.el.setHeight(height);
31171 b.el.select('iframe',true).setSize(width,height);
31175 for (var i = 0; i < this.cols; i++){
31177 if(maxY[i] < maxY[col]){
31182 col = Math.min(col, i);
31186 x = pos.x + col * (this.colWidth + this.padWidth);
31190 var positions = [];
31192 switch (box.length){
31194 positions = this.getVerticalOneBoxColPositions(x, y, box);
31197 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31200 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31203 positions = this.getVerticalFourBoxColPositions(x, y, box);
31209 Roo.each(box, function(b,kk){
31211 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31213 var sz = b.el.getSize();
31215 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31223 for (var i = 0; i < this.cols; i++){
31224 mY = Math.max(mY, maxY[i]);
31227 this.el.setHeight(mY - pos.y);
31231 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31233 // var pos = this.el.getBox(true);
31236 // var maxX = pos.right;
31238 // var maxHeight = 0;
31240 // Roo.each(items, function(item, k){
31244 // item.el.position('absolute');
31246 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31248 // item.el.setWidth(width);
31250 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31252 // item.el.setHeight(height);
31255 // item.el.setXY([x, y], isInstant ? false : true);
31257 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31260 // y = y + height + this.alternativePadWidth;
31262 // maxHeight = maxHeight + height + this.alternativePadWidth;
31266 // this.el.setHeight(maxHeight);
31270 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31272 var pos = this.el.getBox(true);
31277 var maxX = pos.right;
31279 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31281 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31283 Roo.each(queue, function(box, k){
31285 Roo.each(box, function(b, kk){
31287 b.el.position('absolute');
31289 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31290 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31292 if(b.size == 'md-left' || b.size == 'md-right'){
31293 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31294 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31297 b.el.setWidth(width);
31298 b.el.setHeight(height);
31306 var positions = [];
31308 switch (box.length){
31310 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31313 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31316 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31319 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31325 Roo.each(box, function(b,kk){
31327 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31329 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31337 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31339 Roo.each(eItems, function(b,k){
31341 b.size = (k == 0) ? 'sm' : 'xs';
31342 b.x = (k == 0) ? 2 : 1;
31343 b.y = (k == 0) ? 2 : 1;
31345 b.el.position('absolute');
31347 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31349 b.el.setWidth(width);
31351 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31353 b.el.setHeight(height);
31357 var positions = [];
31360 x : maxX - this.unitWidth * 2 - this.gutter,
31365 x : maxX - this.unitWidth,
31366 y : minY + (this.unitWidth + this.gutter) * 2
31370 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31374 Roo.each(eItems, function(b,k){
31376 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31382 getVerticalOneBoxColPositions : function(x, y, box)
31386 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31388 if(box[0].size == 'md-left'){
31392 if(box[0].size == 'md-right'){
31397 x : x + (this.unitWidth + this.gutter) * rand,
31404 getVerticalTwoBoxColPositions : function(x, y, box)
31408 if(box[0].size == 'xs'){
31412 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31416 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31430 x : x + (this.unitWidth + this.gutter) * 2,
31431 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31438 getVerticalThreeBoxColPositions : function(x, y, box)
31442 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31450 x : x + (this.unitWidth + this.gutter) * 1,
31455 x : x + (this.unitWidth + this.gutter) * 2,
31463 if(box[0].size == 'xs' && box[1].size == 'xs'){
31472 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31476 x : x + (this.unitWidth + this.gutter) * 1,
31490 x : x + (this.unitWidth + this.gutter) * 2,
31495 x : x + (this.unitWidth + this.gutter) * 2,
31496 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31503 getVerticalFourBoxColPositions : function(x, y, box)
31507 if(box[0].size == 'xs'){
31516 y : y + (this.unitHeight + this.gutter) * 1
31521 y : y + (this.unitHeight + this.gutter) * 2
31525 x : x + (this.unitWidth + this.gutter) * 1,
31539 x : x + (this.unitWidth + this.gutter) * 2,
31544 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31545 y : y + (this.unitHeight + this.gutter) * 1
31549 x : x + (this.unitWidth + this.gutter) * 2,
31550 y : y + (this.unitWidth + this.gutter) * 2
31557 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31561 if(box[0].size == 'md-left'){
31563 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31570 if(box[0].size == 'md-right'){
31572 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31573 y : minY + (this.unitWidth + this.gutter) * 1
31579 var rand = Math.floor(Math.random() * (4 - box[0].y));
31582 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31583 y : minY + (this.unitWidth + this.gutter) * rand
31590 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31594 if(box[0].size == 'xs'){
31597 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31602 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31603 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31611 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31616 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31617 y : minY + (this.unitWidth + this.gutter) * 2
31624 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31628 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31631 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31636 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31637 y : minY + (this.unitWidth + this.gutter) * 1
31641 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31642 y : minY + (this.unitWidth + this.gutter) * 2
31649 if(box[0].size == 'xs' && box[1].size == 'xs'){
31652 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31657 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31662 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31663 y : minY + (this.unitWidth + this.gutter) * 1
31671 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31676 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31677 y : minY + (this.unitWidth + this.gutter) * 2
31681 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31682 y : minY + (this.unitWidth + this.gutter) * 2
31689 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31693 if(box[0].size == 'xs'){
31696 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31701 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31706 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),
31711 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31712 y : minY + (this.unitWidth + this.gutter) * 1
31720 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31725 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31726 y : minY + (this.unitWidth + this.gutter) * 2
31730 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31731 y : minY + (this.unitWidth + this.gutter) * 2
31735 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),
31736 y : minY + (this.unitWidth + this.gutter) * 2
31744 * remove a Masonry Brick
31745 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31747 removeBrick : function(brick_id)
31753 for (var i = 0; i<this.bricks.length; i++) {
31754 if (this.bricks[i].id == brick_id) {
31755 this.bricks.splice(i,1);
31756 this.el.dom.removeChild(Roo.get(brick_id).dom);
31763 * adds a Masonry Brick
31764 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31766 addBrick : function(cfg)
31768 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31769 //this.register(cn);
31770 cn.parentId = this.id;
31771 cn.onRender(this.el, null);
31776 * register a Masonry Brick
31777 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31780 register : function(brick)
31782 this.bricks.push(brick);
31783 brick.masonryId = this.id;
31787 * clear all the Masonry Brick
31789 clearAll : function()
31792 //this.getChildContainer().dom.innerHTML = "";
31793 this.el.dom.innerHTML = '';
31796 getSelected : function()
31798 if (!this.selectedBrick) {
31802 return this.selectedBrick;
31806 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31810 * register a Masonry Layout
31811 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31814 register : function(layout)
31816 this.groups[layout.id] = layout;
31819 * fetch a Masonry Layout based on the masonry layout ID
31820 * @param {string} the masonry layout to add
31821 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31824 get: function(layout_id) {
31825 if (typeof(this.groups[layout_id]) == 'undefined') {
31828 return this.groups[layout_id] ;
31840 * http://masonry.desandro.com
31842 * The idea is to render all the bricks based on vertical width...
31844 * The original code extends 'outlayer' - we might need to use that....
31850 * @class Roo.bootstrap.LayoutMasonryAuto
31851 * @extends Roo.bootstrap.Component
31852 * Bootstrap Layout Masonry class
31855 * Create a new Element
31856 * @param {Object} config The config object
31859 Roo.bootstrap.LayoutMasonryAuto = function(config){
31860 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31863 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31866 * @cfg {Boolean} isFitWidth - resize the width..
31868 isFitWidth : false, // options..
31870 * @cfg {Boolean} isOriginLeft = left align?
31872 isOriginLeft : true,
31874 * @cfg {Boolean} isOriginTop = top align?
31876 isOriginTop : false,
31878 * @cfg {Boolean} isLayoutInstant = no animation?
31880 isLayoutInstant : false, // needed?
31882 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31884 isResizingContainer : true,
31886 * @cfg {Number} columnWidth width of the columns
31892 * @cfg {Number} maxCols maximum number of columns
31897 * @cfg {Number} padHeight padding below box..
31903 * @cfg {Boolean} isAutoInitial defalut true
31906 isAutoInitial : true,
31912 initialColumnWidth : 0,
31913 currentSize : null,
31915 colYs : null, // array.
31922 bricks: null, //CompositeElement
31923 cols : 0, // array?
31924 // element : null, // wrapped now this.el
31925 _isLayoutInited : null,
31928 getAutoCreate : function(){
31932 cls: 'blog-masonary-wrapper ' + this.cls,
31934 cls : 'mas-boxes masonary'
31941 getChildContainer: function( )
31943 if (this.boxesEl) {
31944 return this.boxesEl;
31947 this.boxesEl = this.el.select('.mas-boxes').first();
31949 return this.boxesEl;
31953 initEvents : function()
31957 if(this.isAutoInitial){
31958 Roo.log('hook children rendered');
31959 this.on('childrenrendered', function() {
31960 Roo.log('children rendered');
31967 initial : function()
31969 this.reloadItems();
31971 this.currentSize = this.el.getBox(true);
31973 /// was window resize... - let's see if this works..
31974 Roo.EventManager.onWindowResize(this.resize, this);
31976 if(!this.isAutoInitial){
31981 this.layout.defer(500,this);
31984 reloadItems: function()
31986 this.bricks = this.el.select('.masonry-brick', true);
31988 this.bricks.each(function(b) {
31989 //Roo.log(b.getSize());
31990 if (!b.attr('originalwidth')) {
31991 b.attr('originalwidth', b.getSize().width);
31996 Roo.log(this.bricks.elements.length);
31999 resize : function()
32002 var cs = this.el.getBox(true);
32004 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32005 Roo.log("no change in with or X");
32008 this.currentSize = cs;
32012 layout : function()
32015 this._resetLayout();
32016 //this._manageStamps();
32018 // don't animate first layout
32019 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32020 this.layoutItems( isInstant );
32022 // flag for initalized
32023 this._isLayoutInited = true;
32026 layoutItems : function( isInstant )
32028 //var items = this._getItemsForLayout( this.items );
32029 // original code supports filtering layout items.. we just ignore it..
32031 this._layoutItems( this.bricks , isInstant );
32033 this._postLayout();
32035 _layoutItems : function ( items , isInstant)
32037 //this.fireEvent( 'layout', this, items );
32040 if ( !items || !items.elements.length ) {
32041 // no items, emit event with empty array
32046 items.each(function(item) {
32047 Roo.log("layout item");
32049 // get x/y object from method
32050 var position = this._getItemLayoutPosition( item );
32052 position.item = item;
32053 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32054 queue.push( position );
32057 this._processLayoutQueue( queue );
32059 /** Sets position of item in DOM
32060 * @param {Element} item
32061 * @param {Number} x - horizontal position
32062 * @param {Number} y - vertical position
32063 * @param {Boolean} isInstant - disables transitions
32065 _processLayoutQueue : function( queue )
32067 for ( var i=0, len = queue.length; i < len; i++ ) {
32068 var obj = queue[i];
32069 obj.item.position('absolute');
32070 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32076 * Any logic you want to do after each layout,
32077 * i.e. size the container
32079 _postLayout : function()
32081 this.resizeContainer();
32084 resizeContainer : function()
32086 if ( !this.isResizingContainer ) {
32089 var size = this._getContainerSize();
32091 this.el.setSize(size.width,size.height);
32092 this.boxesEl.setSize(size.width,size.height);
32098 _resetLayout : function()
32100 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32101 this.colWidth = this.el.getWidth();
32102 //this.gutter = this.el.getWidth();
32104 this.measureColumns();
32110 this.colYs.push( 0 );
32116 measureColumns : function()
32118 this.getContainerWidth();
32119 // if columnWidth is 0, default to outerWidth of first item
32120 if ( !this.columnWidth ) {
32121 var firstItem = this.bricks.first();
32122 Roo.log(firstItem);
32123 this.columnWidth = this.containerWidth;
32124 if (firstItem && firstItem.attr('originalwidth') ) {
32125 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32127 // columnWidth fall back to item of first element
32128 Roo.log("set column width?");
32129 this.initialColumnWidth = this.columnWidth ;
32131 // if first elem has no width, default to size of container
32136 if (this.initialColumnWidth) {
32137 this.columnWidth = this.initialColumnWidth;
32142 // column width is fixed at the top - however if container width get's smaller we should
32145 // this bit calcs how man columns..
32147 var columnWidth = this.columnWidth += this.gutter;
32149 // calculate columns
32150 var containerWidth = this.containerWidth + this.gutter;
32152 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32153 // fix rounding errors, typically with gutters
32154 var excess = columnWidth - containerWidth % columnWidth;
32157 // if overshoot is less than a pixel, round up, otherwise floor it
32158 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32159 cols = Math[ mathMethod ]( cols );
32160 this.cols = Math.max( cols, 1 );
32161 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32163 // padding positioning..
32164 var totalColWidth = this.cols * this.columnWidth;
32165 var padavail = this.containerWidth - totalColWidth;
32166 // so for 2 columns - we need 3 'pads'
32168 var padNeeded = (1+this.cols) * this.padWidth;
32170 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32172 this.columnWidth += padExtra
32173 //this.padWidth = Math.floor(padavail / ( this.cols));
32175 // adjust colum width so that padding is fixed??
32177 // we have 3 columns ... total = width * 3
32178 // we have X left over... that should be used by
32180 //if (this.expandC) {
32188 getContainerWidth : function()
32190 /* // container is parent if fit width
32191 var container = this.isFitWidth ? this.element.parentNode : this.element;
32192 // check that this.size and size are there
32193 // IE8 triggers resize on body size change, so they might not be
32195 var size = getSize( container ); //FIXME
32196 this.containerWidth = size && size.innerWidth; //FIXME
32199 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32203 _getItemLayoutPosition : function( item ) // what is item?
32205 // we resize the item to our columnWidth..
32207 item.setWidth(this.columnWidth);
32208 item.autoBoxAdjust = false;
32210 var sz = item.getSize();
32212 // how many columns does this brick span
32213 var remainder = this.containerWidth % this.columnWidth;
32215 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32216 // round if off by 1 pixel, otherwise use ceil
32217 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32218 colSpan = Math.min( colSpan, this.cols );
32220 // normally this should be '1' as we dont' currently allow multi width columns..
32222 var colGroup = this._getColGroup( colSpan );
32223 // get the minimum Y value from the columns
32224 var minimumY = Math.min.apply( Math, colGroup );
32225 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32227 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32229 // position the brick
32231 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32232 y: this.currentSize.y + minimumY + this.padHeight
32236 // apply setHeight to necessary columns
32237 var setHeight = minimumY + sz.height + this.padHeight;
32238 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32240 var setSpan = this.cols + 1 - colGroup.length;
32241 for ( var i = 0; i < setSpan; i++ ) {
32242 this.colYs[ shortColIndex + i ] = setHeight ;
32249 * @param {Number} colSpan - number of columns the element spans
32250 * @returns {Array} colGroup
32252 _getColGroup : function( colSpan )
32254 if ( colSpan < 2 ) {
32255 // if brick spans only one column, use all the column Ys
32260 // how many different places could this brick fit horizontally
32261 var groupCount = this.cols + 1 - colSpan;
32262 // for each group potential horizontal position
32263 for ( var i = 0; i < groupCount; i++ ) {
32264 // make an array of colY values for that one group
32265 var groupColYs = this.colYs.slice( i, i + colSpan );
32266 // and get the max value of the array
32267 colGroup[i] = Math.max.apply( Math, groupColYs );
32272 _manageStamp : function( stamp )
32274 var stampSize = stamp.getSize();
32275 var offset = stamp.getBox();
32276 // get the columns that this stamp affects
32277 var firstX = this.isOriginLeft ? offset.x : offset.right;
32278 var lastX = firstX + stampSize.width;
32279 var firstCol = Math.floor( firstX / this.columnWidth );
32280 firstCol = Math.max( 0, firstCol );
32282 var lastCol = Math.floor( lastX / this.columnWidth );
32283 // lastCol should not go over if multiple of columnWidth #425
32284 lastCol -= lastX % this.columnWidth ? 0 : 1;
32285 lastCol = Math.min( this.cols - 1, lastCol );
32287 // set colYs to bottom of the stamp
32288 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32291 for ( var i = firstCol; i <= lastCol; i++ ) {
32292 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32297 _getContainerSize : function()
32299 this.maxY = Math.max.apply( Math, this.colYs );
32304 if ( this.isFitWidth ) {
32305 size.width = this._getContainerFitWidth();
32311 _getContainerFitWidth : function()
32313 var unusedCols = 0;
32314 // count unused columns
32317 if ( this.colYs[i] !== 0 ) {
32322 // fit container to columns that have been used
32323 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32326 needsResizeLayout : function()
32328 var previousWidth = this.containerWidth;
32329 this.getContainerWidth();
32330 return previousWidth !== this.containerWidth;
32345 * @class Roo.bootstrap.MasonryBrick
32346 * @extends Roo.bootstrap.Component
32347 * Bootstrap MasonryBrick class
32350 * Create a new MasonryBrick
32351 * @param {Object} config The config object
32354 Roo.bootstrap.MasonryBrick = function(config){
32356 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32358 Roo.bootstrap.MasonryBrick.register(this);
32364 * When a MasonryBrick is clcik
32365 * @param {Roo.bootstrap.MasonryBrick} this
32366 * @param {Roo.EventObject} e
32372 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32375 * @cfg {String} title
32379 * @cfg {String} html
32383 * @cfg {String} bgimage
32387 * @cfg {String} videourl
32391 * @cfg {String} cls
32395 * @cfg {String} href
32399 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32404 * @cfg {String} placetitle (center|bottom)
32409 * @cfg {Boolean} isFitContainer defalut true
32411 isFitContainer : true,
32414 * @cfg {Boolean} preventDefault defalut false
32416 preventDefault : false,
32419 * @cfg {Boolean} inverse defalut false
32421 maskInverse : false,
32423 getAutoCreate : function()
32425 if(!this.isFitContainer){
32426 return this.getSplitAutoCreate();
32429 var cls = 'masonry-brick masonry-brick-full';
32431 if(this.href.length){
32432 cls += ' masonry-brick-link';
32435 if(this.bgimage.length){
32436 cls += ' masonry-brick-image';
32439 if(this.maskInverse){
32440 cls += ' mask-inverse';
32443 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32444 cls += ' enable-mask';
32448 cls += ' masonry-' + this.size + '-brick';
32451 if(this.placetitle.length){
32453 switch (this.placetitle) {
32455 cls += ' masonry-center-title';
32458 cls += ' masonry-bottom-title';
32465 if(!this.html.length && !this.bgimage.length){
32466 cls += ' masonry-center-title';
32469 if(!this.html.length && this.bgimage.length){
32470 cls += ' masonry-bottom-title';
32475 cls += ' ' + this.cls;
32479 tag: (this.href.length) ? 'a' : 'div',
32484 cls: 'masonry-brick-mask'
32488 cls: 'masonry-brick-paragraph',
32494 if(this.href.length){
32495 cfg.href = this.href;
32498 var cn = cfg.cn[1].cn;
32500 if(this.title.length){
32503 cls: 'masonry-brick-title',
32508 if(this.html.length){
32511 cls: 'masonry-brick-text',
32516 if (!this.title.length && !this.html.length) {
32517 cfg.cn[1].cls += ' hide';
32520 if(this.bgimage.length){
32523 cls: 'masonry-brick-image-view',
32528 if(this.videourl.length){
32529 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32530 // youtube support only?
32533 cls: 'masonry-brick-image-view',
32536 allowfullscreen : true
32544 getSplitAutoCreate : function()
32546 var cls = 'masonry-brick masonry-brick-split';
32548 if(this.href.length){
32549 cls += ' masonry-brick-link';
32552 if(this.bgimage.length){
32553 cls += ' masonry-brick-image';
32557 cls += ' masonry-' + this.size + '-brick';
32560 switch (this.placetitle) {
32562 cls += ' masonry-center-title';
32565 cls += ' masonry-bottom-title';
32568 if(!this.bgimage.length){
32569 cls += ' masonry-center-title';
32572 if(this.bgimage.length){
32573 cls += ' masonry-bottom-title';
32579 cls += ' ' + this.cls;
32583 tag: (this.href.length) ? 'a' : 'div',
32588 cls: 'masonry-brick-split-head',
32592 cls: 'masonry-brick-paragraph',
32599 cls: 'masonry-brick-split-body',
32605 if(this.href.length){
32606 cfg.href = this.href;
32609 if(this.title.length){
32610 cfg.cn[0].cn[0].cn.push({
32612 cls: 'masonry-brick-title',
32617 if(this.html.length){
32618 cfg.cn[1].cn.push({
32620 cls: 'masonry-brick-text',
32625 if(this.bgimage.length){
32626 cfg.cn[0].cn.push({
32628 cls: 'masonry-brick-image-view',
32633 if(this.videourl.length){
32634 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32635 // youtube support only?
32636 cfg.cn[0].cn.cn.push({
32638 cls: 'masonry-brick-image-view',
32641 allowfullscreen : true
32648 initEvents: function()
32650 switch (this.size) {
32683 this.el.on('touchstart', this.onTouchStart, this);
32684 this.el.on('touchmove', this.onTouchMove, this);
32685 this.el.on('touchend', this.onTouchEnd, this);
32686 this.el.on('contextmenu', this.onContextMenu, this);
32688 this.el.on('mouseenter' ,this.enter, this);
32689 this.el.on('mouseleave', this.leave, this);
32690 this.el.on('click', this.onClick, this);
32693 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32694 this.parent().bricks.push(this);
32699 onClick: function(e, el)
32701 var time = this.endTimer - this.startTimer;
32702 // Roo.log(e.preventDefault());
32705 e.preventDefault();
32710 if(!this.preventDefault){
32714 e.preventDefault();
32716 if (this.activcClass != '') {
32717 this.selectBrick();
32720 this.fireEvent('click', this);
32723 enter: function(e, el)
32725 e.preventDefault();
32727 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32731 if(this.bgimage.length && this.html.length){
32732 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32736 leave: function(e, el)
32738 e.preventDefault();
32740 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32744 if(this.bgimage.length && this.html.length){
32745 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32749 onTouchStart: function(e, el)
32751 // e.preventDefault();
32753 this.touchmoved = false;
32755 if(!this.isFitContainer){
32759 if(!this.bgimage.length || !this.html.length){
32763 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32765 this.timer = new Date().getTime();
32769 onTouchMove: function(e, el)
32771 this.touchmoved = true;
32774 onContextMenu : function(e,el)
32776 e.preventDefault();
32777 e.stopPropagation();
32781 onTouchEnd: function(e, el)
32783 // e.preventDefault();
32785 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32792 if(!this.bgimage.length || !this.html.length){
32794 if(this.href.length){
32795 window.location.href = this.href;
32801 if(!this.isFitContainer){
32805 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32807 window.location.href = this.href;
32810 //selection on single brick only
32811 selectBrick : function() {
32813 if (!this.parentId) {
32817 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32818 var index = m.selectedBrick.indexOf(this.id);
32821 m.selectedBrick.splice(index,1);
32822 this.el.removeClass(this.activeClass);
32826 for(var i = 0; i < m.selectedBrick.length; i++) {
32827 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32828 b.el.removeClass(b.activeClass);
32831 m.selectedBrick = [];
32833 m.selectedBrick.push(this.id);
32834 this.el.addClass(this.activeClass);
32840 Roo.apply(Roo.bootstrap.MasonryBrick, {
32843 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32845 * register a Masonry Brick
32846 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32849 register : function(brick)
32851 //this.groups[brick.id] = brick;
32852 this.groups.add(brick.id, brick);
32855 * fetch a masonry brick based on the masonry brick ID
32856 * @param {string} the masonry brick to add
32857 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32860 get: function(brick_id)
32862 // if (typeof(this.groups[brick_id]) == 'undefined') {
32865 // return this.groups[brick_id] ;
32867 if(this.groups.key(brick_id)) {
32868 return this.groups.key(brick_id);
32886 * @class Roo.bootstrap.Brick
32887 * @extends Roo.bootstrap.Component
32888 * Bootstrap Brick class
32891 * Create a new Brick
32892 * @param {Object} config The config object
32895 Roo.bootstrap.Brick = function(config){
32896 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32902 * When a Brick is click
32903 * @param {Roo.bootstrap.Brick} this
32904 * @param {Roo.EventObject} e
32910 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32913 * @cfg {String} title
32917 * @cfg {String} html
32921 * @cfg {String} bgimage
32925 * @cfg {String} cls
32929 * @cfg {String} href
32933 * @cfg {String} video
32937 * @cfg {Boolean} square
32941 getAutoCreate : function()
32943 var cls = 'roo-brick';
32945 if(this.href.length){
32946 cls += ' roo-brick-link';
32949 if(this.bgimage.length){
32950 cls += ' roo-brick-image';
32953 if(!this.html.length && !this.bgimage.length){
32954 cls += ' roo-brick-center-title';
32957 if(!this.html.length && this.bgimage.length){
32958 cls += ' roo-brick-bottom-title';
32962 cls += ' ' + this.cls;
32966 tag: (this.href.length) ? 'a' : 'div',
32971 cls: 'roo-brick-paragraph',
32977 if(this.href.length){
32978 cfg.href = this.href;
32981 var cn = cfg.cn[0].cn;
32983 if(this.title.length){
32986 cls: 'roo-brick-title',
32991 if(this.html.length){
32994 cls: 'roo-brick-text',
33001 if(this.bgimage.length){
33004 cls: 'roo-brick-image-view',
33012 initEvents: function()
33014 if(this.title.length || this.html.length){
33015 this.el.on('mouseenter' ,this.enter, this);
33016 this.el.on('mouseleave', this.leave, this);
33019 Roo.EventManager.onWindowResize(this.resize, this);
33021 if(this.bgimage.length){
33022 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33023 this.imageEl.on('load', this.onImageLoad, this);
33030 onImageLoad : function()
33035 resize : function()
33037 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33039 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33041 if(this.bgimage.length){
33042 var image = this.el.select('.roo-brick-image-view', true).first();
33044 image.setWidth(paragraph.getWidth());
33047 image.setHeight(paragraph.getWidth());
33050 this.el.setHeight(image.getHeight());
33051 paragraph.setHeight(image.getHeight());
33057 enter: function(e, el)
33059 e.preventDefault();
33061 if(this.bgimage.length){
33062 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33063 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33067 leave: function(e, el)
33069 e.preventDefault();
33071 if(this.bgimage.length){
33072 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33073 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33088 * @class Roo.bootstrap.NumberField
33089 * @extends Roo.bootstrap.Input
33090 * Bootstrap NumberField class
33096 * Create a new NumberField
33097 * @param {Object} config The config object
33100 Roo.bootstrap.NumberField = function(config){
33101 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33104 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33107 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33109 allowDecimals : true,
33111 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33113 decimalSeparator : ".",
33115 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33117 decimalPrecision : 2,
33119 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33121 allowNegative : true,
33124 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33128 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33130 minValue : Number.NEGATIVE_INFINITY,
33132 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33134 maxValue : Number.MAX_VALUE,
33136 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33138 minText : "The minimum value for this field is {0}",
33140 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33142 maxText : "The maximum value for this field is {0}",
33144 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33145 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33147 nanText : "{0} is not a valid number",
33149 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33153 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33155 thousandsDelimiter : false,
33157 * @cfg {String} valueAlign alignment of value
33159 valueAlign : "left",
33161 getAutoCreate : function()
33163 var hiddenInput = {
33167 cls: 'hidden-number-input'
33171 hiddenInput.name = this.name;
33176 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33178 this.name = hiddenInput.name;
33180 if(cfg.cn.length > 0) {
33181 cfg.cn.push(hiddenInput);
33188 initEvents : function()
33190 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33192 var allowed = "0123456789";
33194 if(this.allowDecimals){
33195 allowed += this.decimalSeparator;
33198 if(this.allowNegative){
33202 if(this.thousandsDelimiter) {
33206 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33208 var keyPress = function(e){
33210 var k = e.getKey();
33212 var c = e.getCharCode();
33215 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33216 allowed.indexOf(String.fromCharCode(c)) === -1
33222 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33226 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33231 this.el.on("keypress", keyPress, this);
33234 validateValue : function(value)
33237 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33241 var num = this.parseValue(value);
33244 this.markInvalid(String.format(this.nanText, value));
33248 if(num < this.minValue){
33249 this.markInvalid(String.format(this.minText, this.minValue));
33253 if(num > this.maxValue){
33254 this.markInvalid(String.format(this.maxText, this.maxValue));
33261 getValue : function()
33263 var v = this.hiddenEl().getValue();
33265 return this.fixPrecision(this.parseValue(v));
33268 parseValue : function(value)
33270 if(this.thousandsDelimiter) {
33272 r = new RegExp(",", "g");
33273 value = value.replace(r, "");
33276 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33277 return isNaN(value) ? '' : value;
33280 fixPrecision : function(value)
33282 if(this.thousandsDelimiter) {
33284 r = new RegExp(",", "g");
33285 value = value.replace(r, "");
33288 var nan = isNaN(value);
33290 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33291 return nan ? '' : value;
33293 return parseFloat(value).toFixed(this.decimalPrecision);
33296 setValue : function(v)
33298 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33304 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33306 this.inputEl().dom.value = (v == '') ? '' :
33307 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33309 if(!this.allowZero && v === '0') {
33310 this.hiddenEl().dom.value = '';
33311 this.inputEl().dom.value = '';
33318 decimalPrecisionFcn : function(v)
33320 return Math.floor(v);
33323 beforeBlur : function()
33329 var v = this.parseValue(this.getRawValue());
33336 hiddenEl : function()
33338 return this.el.select('input.hidden-number-input',true).first();
33350 * @class Roo.bootstrap.DocumentSlider
33351 * @extends Roo.bootstrap.Component
33352 * Bootstrap DocumentSlider class
33355 * Create a new DocumentViewer
33356 * @param {Object} config The config object
33359 Roo.bootstrap.DocumentSlider = function(config){
33360 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33367 * Fire after initEvent
33368 * @param {Roo.bootstrap.DocumentSlider} this
33373 * Fire after update
33374 * @param {Roo.bootstrap.DocumentSlider} this
33380 * @param {Roo.bootstrap.DocumentSlider} this
33386 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33392 getAutoCreate : function()
33396 cls : 'roo-document-slider',
33400 cls : 'roo-document-slider-header',
33404 cls : 'roo-document-slider-header-title'
33410 cls : 'roo-document-slider-body',
33414 cls : 'roo-document-slider-prev',
33418 cls : 'fa fa-chevron-left'
33424 cls : 'roo-document-slider-thumb',
33428 cls : 'roo-document-slider-image'
33434 cls : 'roo-document-slider-next',
33438 cls : 'fa fa-chevron-right'
33450 initEvents : function()
33452 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33453 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33455 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33456 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33458 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33459 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33461 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33462 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33464 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33465 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33467 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33468 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33470 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33471 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33473 this.thumbEl.on('click', this.onClick, this);
33475 this.prevIndicator.on('click', this.prev, this);
33477 this.nextIndicator.on('click', this.next, this);
33481 initial : function()
33483 if(this.files.length){
33484 this.indicator = 1;
33488 this.fireEvent('initial', this);
33491 update : function()
33493 this.imageEl.attr('src', this.files[this.indicator - 1]);
33495 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33497 this.prevIndicator.show();
33499 if(this.indicator == 1){
33500 this.prevIndicator.hide();
33503 this.nextIndicator.show();
33505 if(this.indicator == this.files.length){
33506 this.nextIndicator.hide();
33509 this.thumbEl.scrollTo('top');
33511 this.fireEvent('update', this);
33514 onClick : function(e)
33516 e.preventDefault();
33518 this.fireEvent('click', this);
33523 e.preventDefault();
33525 this.indicator = Math.max(1, this.indicator - 1);
33532 e.preventDefault();
33534 this.indicator = Math.min(this.files.length, this.indicator + 1);
33548 * @class Roo.bootstrap.RadioSet
33549 * @extends Roo.bootstrap.Input
33550 * Bootstrap RadioSet class
33551 * @cfg {String} indicatorpos (left|right) default left
33552 * @cfg {Boolean} inline (true|false) inline the element (default true)
33553 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33555 * Create a new RadioSet
33556 * @param {Object} config The config object
33559 Roo.bootstrap.RadioSet = function(config){
33561 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33565 Roo.bootstrap.RadioSet.register(this);
33570 * Fires when the element is checked or unchecked.
33571 * @param {Roo.bootstrap.RadioSet} this This radio
33572 * @param {Roo.bootstrap.Radio} item The checked item
33577 * Fires when the element is click.
33578 * @param {Roo.bootstrap.RadioSet} this This radio set
33579 * @param {Roo.bootstrap.Radio} item The checked item
33580 * @param {Roo.EventObject} e The event object
33587 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33595 indicatorpos : 'left',
33597 getAutoCreate : function()
33601 cls : 'roo-radio-set-label',
33605 html : this.fieldLabel
33610 if(this.indicatorpos == 'left'){
33613 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33614 tooltip : 'This field is required'
33619 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33620 tooltip : 'This field is required'
33626 cls : 'roo-radio-set-items'
33629 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33631 if (align === 'left' && this.fieldLabel.length) {
33634 cls : "roo-radio-set-right",
33640 if(this.labelWidth > 12){
33641 label.style = "width: " + this.labelWidth + 'px';
33644 if(this.labelWidth < 13 && this.labelmd == 0){
33645 this.labelmd = this.labelWidth;
33648 if(this.labellg > 0){
33649 label.cls += ' col-lg-' + this.labellg;
33650 items.cls += ' col-lg-' + (12 - this.labellg);
33653 if(this.labelmd > 0){
33654 label.cls += ' col-md-' + this.labelmd;
33655 items.cls += ' col-md-' + (12 - this.labelmd);
33658 if(this.labelsm > 0){
33659 label.cls += ' col-sm-' + this.labelsm;
33660 items.cls += ' col-sm-' + (12 - this.labelsm);
33663 if(this.labelxs > 0){
33664 label.cls += ' col-xs-' + this.labelxs;
33665 items.cls += ' col-xs-' + (12 - this.labelxs);
33671 cls : 'roo-radio-set',
33675 cls : 'roo-radio-set-input',
33678 value : this.value ? this.value : ''
33685 if(this.weight.length){
33686 cfg.cls += ' roo-radio-' + this.weight;
33690 cfg.cls += ' roo-radio-set-inline';
33694 ['xs','sm','md','lg'].map(function(size){
33695 if (settings[size]) {
33696 cfg.cls += ' col-' + size + '-' + settings[size];
33704 initEvents : function()
33706 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33707 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33709 if(!this.fieldLabel.length){
33710 this.labelEl.hide();
33713 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33714 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33716 this.indicatorEl().addClass('invisible');
33718 this.originalValue = this.getValue();
33722 inputEl: function ()
33724 return this.el.select('.roo-radio-set-input', true).first();
33727 getChildContainer : function()
33729 return this.itemsEl;
33732 register : function(item)
33734 this.radioes.push(item);
33738 validate : function()
33740 if(this.getVisibilityEl().hasClass('hidden')){
33746 Roo.each(this.radioes, function(i){
33755 if(this.allowBlank) {
33759 if(this.disabled || valid){
33764 this.markInvalid();
33769 markValid : function()
33771 if(this.labelEl.isVisible(true)){
33772 this.indicatorEl().removeClass('visible');
33773 this.indicatorEl().addClass('invisible');
33776 this.el.removeClass([this.invalidClass, this.validClass]);
33777 this.el.addClass(this.validClass);
33779 this.fireEvent('valid', this);
33782 markInvalid : function(msg)
33784 if(this.allowBlank || this.disabled){
33788 if(this.labelEl.isVisible(true)){
33789 this.indicatorEl().removeClass('invisible');
33790 this.indicatorEl().addClass('visible');
33793 this.el.removeClass([this.invalidClass, this.validClass]);
33794 this.el.addClass(this.invalidClass);
33796 this.fireEvent('invalid', this, msg);
33800 setValue : function(v, suppressEvent)
33802 if(this.value === v){
33809 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33812 Roo.each(this.radioes, function(i){
33814 i.el.removeClass('checked');
33817 Roo.each(this.radioes, function(i){
33819 if(i.value === v || i.value.toString() === v.toString()){
33821 i.el.addClass('checked');
33823 if(suppressEvent !== true){
33824 this.fireEvent('check', this, i);
33835 clearInvalid : function(){
33837 if(!this.el || this.preventMark){
33841 this.el.removeClass([this.invalidClass]);
33843 this.fireEvent('valid', this);
33848 Roo.apply(Roo.bootstrap.RadioSet, {
33852 register : function(set)
33854 this.groups[set.name] = set;
33857 get: function(name)
33859 if (typeof(this.groups[name]) == 'undefined') {
33863 return this.groups[name] ;
33869 * Ext JS Library 1.1.1
33870 * Copyright(c) 2006-2007, Ext JS, LLC.
33872 * Originally Released Under LGPL - original licence link has changed is not relivant.
33875 * <script type="text/javascript">
33880 * @class Roo.bootstrap.SplitBar
33881 * @extends Roo.util.Observable
33882 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33886 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33887 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33888 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33889 split.minSize = 100;
33890 split.maxSize = 600;
33891 split.animate = true;
33892 split.on('moved', splitterMoved);
33895 * Create a new SplitBar
33896 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33897 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33898 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33899 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33900 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33901 position of the SplitBar).
33903 Roo.bootstrap.SplitBar = function(cfg){
33908 // dragElement : elm
33909 // resizingElement: el,
33911 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33912 // placement : Roo.bootstrap.SplitBar.LEFT ,
33913 // existingProxy ???
33916 this.el = Roo.get(cfg.dragElement, true);
33917 this.el.dom.unselectable = "on";
33919 this.resizingEl = Roo.get(cfg.resizingElement, true);
33923 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33924 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33927 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33930 * The minimum size of the resizing element. (Defaults to 0)
33936 * The maximum size of the resizing element. (Defaults to 2000)
33939 this.maxSize = 2000;
33942 * Whether to animate the transition to the new size
33945 this.animate = false;
33948 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33951 this.useShim = false;
33956 if(!cfg.existingProxy){
33958 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33960 this.proxy = Roo.get(cfg.existingProxy).dom;
33963 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33966 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33969 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33972 this.dragSpecs = {};
33975 * @private The adapter to use to positon and resize elements
33977 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33978 this.adapter.init(this);
33980 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33982 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
33983 this.el.addClass("roo-splitbar-h");
33986 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
33987 this.el.addClass("roo-splitbar-v");
33993 * Fires when the splitter is moved (alias for {@link #event-moved})
33994 * @param {Roo.bootstrap.SplitBar} this
33995 * @param {Number} newSize the new width or height
34000 * Fires when the splitter is moved
34001 * @param {Roo.bootstrap.SplitBar} this
34002 * @param {Number} newSize the new width or height
34006 * @event beforeresize
34007 * Fires before the splitter is dragged
34008 * @param {Roo.bootstrap.SplitBar} this
34010 "beforeresize" : true,
34012 "beforeapply" : true
34015 Roo.util.Observable.call(this);
34018 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34019 onStartProxyDrag : function(x, y){
34020 this.fireEvent("beforeresize", this);
34022 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34024 o.enableDisplayMode("block");
34025 // all splitbars share the same overlay
34026 Roo.bootstrap.SplitBar.prototype.overlay = o;
34028 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34029 this.overlay.show();
34030 Roo.get(this.proxy).setDisplayed("block");
34031 var size = this.adapter.getElementSize(this);
34032 this.activeMinSize = this.getMinimumSize();;
34033 this.activeMaxSize = this.getMaximumSize();;
34034 var c1 = size - this.activeMinSize;
34035 var c2 = Math.max(this.activeMaxSize - size, 0);
34036 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34037 this.dd.resetConstraints();
34038 this.dd.setXConstraint(
34039 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34040 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34042 this.dd.setYConstraint(0, 0);
34044 this.dd.resetConstraints();
34045 this.dd.setXConstraint(0, 0);
34046 this.dd.setYConstraint(
34047 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34048 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34051 this.dragSpecs.startSize = size;
34052 this.dragSpecs.startPoint = [x, y];
34053 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34057 * @private Called after the drag operation by the DDProxy
34059 onEndProxyDrag : function(e){
34060 Roo.get(this.proxy).setDisplayed(false);
34061 var endPoint = Roo.lib.Event.getXY(e);
34063 this.overlay.hide();
34066 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34067 newSize = this.dragSpecs.startSize +
34068 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34069 endPoint[0] - this.dragSpecs.startPoint[0] :
34070 this.dragSpecs.startPoint[0] - endPoint[0]
34073 newSize = this.dragSpecs.startSize +
34074 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34075 endPoint[1] - this.dragSpecs.startPoint[1] :
34076 this.dragSpecs.startPoint[1] - endPoint[1]
34079 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34080 if(newSize != this.dragSpecs.startSize){
34081 if(this.fireEvent('beforeapply', this, newSize) !== false){
34082 this.adapter.setElementSize(this, newSize);
34083 this.fireEvent("moved", this, newSize);
34084 this.fireEvent("resize", this, newSize);
34090 * Get the adapter this SplitBar uses
34091 * @return The adapter object
34093 getAdapter : function(){
34094 return this.adapter;
34098 * Set the adapter this SplitBar uses
34099 * @param {Object} adapter A SplitBar adapter object
34101 setAdapter : function(adapter){
34102 this.adapter = adapter;
34103 this.adapter.init(this);
34107 * Gets the minimum size for the resizing element
34108 * @return {Number} The minimum size
34110 getMinimumSize : function(){
34111 return this.minSize;
34115 * Sets the minimum size for the resizing element
34116 * @param {Number} minSize The minimum size
34118 setMinimumSize : function(minSize){
34119 this.minSize = minSize;
34123 * Gets the maximum size for the resizing element
34124 * @return {Number} The maximum size
34126 getMaximumSize : function(){
34127 return this.maxSize;
34131 * Sets the maximum size for the resizing element
34132 * @param {Number} maxSize The maximum size
34134 setMaximumSize : function(maxSize){
34135 this.maxSize = maxSize;
34139 * Sets the initialize size for the resizing element
34140 * @param {Number} size The initial size
34142 setCurrentSize : function(size){
34143 var oldAnimate = this.animate;
34144 this.animate = false;
34145 this.adapter.setElementSize(this, size);
34146 this.animate = oldAnimate;
34150 * Destroy this splitbar.
34151 * @param {Boolean} removeEl True to remove the element
34153 destroy : function(removeEl){
34155 this.shim.remove();
34158 this.proxy.parentNode.removeChild(this.proxy);
34166 * @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.
34168 Roo.bootstrap.SplitBar.createProxy = function(dir){
34169 var proxy = new Roo.Element(document.createElement("div"));
34170 proxy.unselectable();
34171 var cls = 'roo-splitbar-proxy';
34172 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34173 document.body.appendChild(proxy.dom);
34178 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34179 * Default Adapter. It assumes the splitter and resizing element are not positioned
34180 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34182 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34185 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34186 // do nothing for now
34187 init : function(s){
34191 * Called before drag operations to get the current size of the resizing element.
34192 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34194 getElementSize : function(s){
34195 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34196 return s.resizingEl.getWidth();
34198 return s.resizingEl.getHeight();
34203 * Called after drag operations to set the size of the resizing element.
34204 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34205 * @param {Number} newSize The new size to set
34206 * @param {Function} onComplete A function to be invoked when resizing is complete
34208 setElementSize : function(s, newSize, onComplete){
34209 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34211 s.resizingEl.setWidth(newSize);
34213 onComplete(s, newSize);
34216 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34221 s.resizingEl.setHeight(newSize);
34223 onComplete(s, newSize);
34226 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34233 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34234 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34235 * Adapter that moves the splitter element to align with the resized sizing element.
34236 * Used with an absolute positioned SplitBar.
34237 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34238 * document.body, make sure you assign an id to the body element.
34240 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34241 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34242 this.container = Roo.get(container);
34245 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34246 init : function(s){
34247 this.basic.init(s);
34250 getElementSize : function(s){
34251 return this.basic.getElementSize(s);
34254 setElementSize : function(s, newSize, onComplete){
34255 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34258 moveSplitter : function(s){
34259 var yes = Roo.bootstrap.SplitBar;
34260 switch(s.placement){
34262 s.el.setX(s.resizingEl.getRight());
34265 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34268 s.el.setY(s.resizingEl.getBottom());
34271 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34278 * Orientation constant - Create a vertical SplitBar
34282 Roo.bootstrap.SplitBar.VERTICAL = 1;
34285 * Orientation constant - Create a horizontal SplitBar
34289 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34292 * Placement constant - The resizing element is to the left of the splitter element
34296 Roo.bootstrap.SplitBar.LEFT = 1;
34299 * Placement constant - The resizing element is to the right of the splitter element
34303 Roo.bootstrap.SplitBar.RIGHT = 2;
34306 * Placement constant - The resizing element is positioned above the splitter element
34310 Roo.bootstrap.SplitBar.TOP = 3;
34313 * Placement constant - The resizing element is positioned under splitter element
34317 Roo.bootstrap.SplitBar.BOTTOM = 4;
34318 Roo.namespace("Roo.bootstrap.layout");/*
34320 * Ext JS Library 1.1.1
34321 * Copyright(c) 2006-2007, Ext JS, LLC.
34323 * Originally Released Under LGPL - original licence link has changed is not relivant.
34326 * <script type="text/javascript">
34330 * @class Roo.bootstrap.layout.Manager
34331 * @extends Roo.bootstrap.Component
34332 * Base class for layout managers.
34334 Roo.bootstrap.layout.Manager = function(config)
34336 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34342 /** false to disable window resize monitoring @type Boolean */
34343 this.monitorWindowResize = true;
34348 * Fires when a layout is performed.
34349 * @param {Roo.LayoutManager} this
34353 * @event regionresized
34354 * Fires when the user resizes a region.
34355 * @param {Roo.LayoutRegion} region The resized region
34356 * @param {Number} newSize The new size (width for east/west, height for north/south)
34358 "regionresized" : true,
34360 * @event regioncollapsed
34361 * Fires when a region is collapsed.
34362 * @param {Roo.LayoutRegion} region The collapsed region
34364 "regioncollapsed" : true,
34366 * @event regionexpanded
34367 * Fires when a region is expanded.
34368 * @param {Roo.LayoutRegion} region The expanded region
34370 "regionexpanded" : true
34372 this.updating = false;
34375 this.el = Roo.get(config.el);
34381 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34386 monitorWindowResize : true,
34392 onRender : function(ct, position)
34395 this.el = Roo.get(ct);
34398 //this.fireEvent('render',this);
34402 initEvents: function()
34406 // ie scrollbar fix
34407 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34408 document.body.scroll = "no";
34409 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34410 this.el.position('relative');
34412 this.id = this.el.id;
34413 this.el.addClass("roo-layout-container");
34414 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34415 if(this.el.dom != document.body ) {
34416 this.el.on('resize', this.layout,this);
34417 this.el.on('show', this.layout,this);
34423 * Returns true if this layout is currently being updated
34424 * @return {Boolean}
34426 isUpdating : function(){
34427 return this.updating;
34431 * Suspend the LayoutManager from doing auto-layouts while
34432 * making multiple add or remove calls
34434 beginUpdate : function(){
34435 this.updating = true;
34439 * Restore auto-layouts and optionally disable the manager from performing a layout
34440 * @param {Boolean} noLayout true to disable a layout update
34442 endUpdate : function(noLayout){
34443 this.updating = false;
34449 layout: function(){
34453 onRegionResized : function(region, newSize){
34454 this.fireEvent("regionresized", region, newSize);
34458 onRegionCollapsed : function(region){
34459 this.fireEvent("regioncollapsed", region);
34462 onRegionExpanded : function(region){
34463 this.fireEvent("regionexpanded", region);
34467 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34468 * performs box-model adjustments.
34469 * @return {Object} The size as an object {width: (the width), height: (the height)}
34471 getViewSize : function()
34474 if(this.el.dom != document.body){
34475 size = this.el.getSize();
34477 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34479 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34480 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34485 * Returns the Element this layout is bound to.
34486 * @return {Roo.Element}
34488 getEl : function(){
34493 * Returns the specified region.
34494 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34495 * @return {Roo.LayoutRegion}
34497 getRegion : function(target){
34498 return this.regions[target.toLowerCase()];
34501 onWindowResize : function(){
34502 if(this.monitorWindowResize){
34509 * Ext JS Library 1.1.1
34510 * Copyright(c) 2006-2007, Ext JS, LLC.
34512 * Originally Released Under LGPL - original licence link has changed is not relivant.
34515 * <script type="text/javascript">
34518 * @class Roo.bootstrap.layout.Border
34519 * @extends Roo.bootstrap.layout.Manager
34520 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34521 * please see: examples/bootstrap/nested.html<br><br>
34523 <b>The container the layout is rendered into can be either the body element or any other element.
34524 If it is not the body element, the container needs to either be an absolute positioned element,
34525 or you will need to add "position:relative" to the css of the container. You will also need to specify
34526 the container size if it is not the body element.</b>
34529 * Create a new Border
34530 * @param {Object} config Configuration options
34532 Roo.bootstrap.layout.Border = function(config){
34533 config = config || {};
34534 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34538 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34539 if(config[region]){
34540 config[region].region = region;
34541 this.addRegion(config[region]);
34547 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34549 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34551 * Creates and adds a new region if it doesn't already exist.
34552 * @param {String} target The target region key (north, south, east, west or center).
34553 * @param {Object} config The regions config object
34554 * @return {BorderLayoutRegion} The new region
34556 addRegion : function(config)
34558 if(!this.regions[config.region]){
34559 var r = this.factory(config);
34560 this.bindRegion(r);
34562 return this.regions[config.region];
34566 bindRegion : function(r){
34567 this.regions[r.config.region] = r;
34569 r.on("visibilitychange", this.layout, this);
34570 r.on("paneladded", this.layout, this);
34571 r.on("panelremoved", this.layout, this);
34572 r.on("invalidated", this.layout, this);
34573 r.on("resized", this.onRegionResized, this);
34574 r.on("collapsed", this.onRegionCollapsed, this);
34575 r.on("expanded", this.onRegionExpanded, this);
34579 * Performs a layout update.
34581 layout : function()
34583 if(this.updating) {
34587 // render all the rebions if they have not been done alreayd?
34588 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34589 if(this.regions[region] && !this.regions[region].bodyEl){
34590 this.regions[region].onRender(this.el)
34594 var size = this.getViewSize();
34595 var w = size.width;
34596 var h = size.height;
34601 //var x = 0, y = 0;
34603 var rs = this.regions;
34604 var north = rs["north"];
34605 var south = rs["south"];
34606 var west = rs["west"];
34607 var east = rs["east"];
34608 var center = rs["center"];
34609 //if(this.hideOnLayout){ // not supported anymore
34610 //c.el.setStyle("display", "none");
34612 if(north && north.isVisible()){
34613 var b = north.getBox();
34614 var m = north.getMargins();
34615 b.width = w - (m.left+m.right);
34618 centerY = b.height + b.y + m.bottom;
34619 centerH -= centerY;
34620 north.updateBox(this.safeBox(b));
34622 if(south && south.isVisible()){
34623 var b = south.getBox();
34624 var m = south.getMargins();
34625 b.width = w - (m.left+m.right);
34627 var totalHeight = (b.height + m.top + m.bottom);
34628 b.y = h - totalHeight + m.top;
34629 centerH -= totalHeight;
34630 south.updateBox(this.safeBox(b));
34632 if(west && west.isVisible()){
34633 var b = west.getBox();
34634 var m = west.getMargins();
34635 b.height = centerH - (m.top+m.bottom);
34637 b.y = centerY + m.top;
34638 var totalWidth = (b.width + m.left + m.right);
34639 centerX += totalWidth;
34640 centerW -= totalWidth;
34641 west.updateBox(this.safeBox(b));
34643 if(east && east.isVisible()){
34644 var b = east.getBox();
34645 var m = east.getMargins();
34646 b.height = centerH - (m.top+m.bottom);
34647 var totalWidth = (b.width + m.left + m.right);
34648 b.x = w - totalWidth + m.left;
34649 b.y = centerY + m.top;
34650 centerW -= totalWidth;
34651 east.updateBox(this.safeBox(b));
34654 var m = center.getMargins();
34656 x: centerX + m.left,
34657 y: centerY + m.top,
34658 width: centerW - (m.left+m.right),
34659 height: centerH - (m.top+m.bottom)
34661 //if(this.hideOnLayout){
34662 //center.el.setStyle("display", "block");
34664 center.updateBox(this.safeBox(centerBox));
34667 this.fireEvent("layout", this);
34671 safeBox : function(box){
34672 box.width = Math.max(0, box.width);
34673 box.height = Math.max(0, box.height);
34678 * Adds a ContentPanel (or subclass) to this layout.
34679 * @param {String} target The target region key (north, south, east, west or center).
34680 * @param {Roo.ContentPanel} panel The panel to add
34681 * @return {Roo.ContentPanel} The added panel
34683 add : function(target, panel){
34685 target = target.toLowerCase();
34686 return this.regions[target].add(panel);
34690 * Remove a ContentPanel (or subclass) to this layout.
34691 * @param {String} target The target region key (north, south, east, west or center).
34692 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34693 * @return {Roo.ContentPanel} The removed panel
34695 remove : function(target, panel){
34696 target = target.toLowerCase();
34697 return this.regions[target].remove(panel);
34701 * Searches all regions for a panel with the specified id
34702 * @param {String} panelId
34703 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34705 findPanel : function(panelId){
34706 var rs = this.regions;
34707 for(var target in rs){
34708 if(typeof rs[target] != "function"){
34709 var p = rs[target].getPanel(panelId);
34719 * Searches all regions for a panel with the specified id and activates (shows) it.
34720 * @param {String/ContentPanel} panelId The panels id or the panel itself
34721 * @return {Roo.ContentPanel} The shown panel or null
34723 showPanel : function(panelId) {
34724 var rs = this.regions;
34725 for(var target in rs){
34726 var r = rs[target];
34727 if(typeof r != "function"){
34728 if(r.hasPanel(panelId)){
34729 return r.showPanel(panelId);
34737 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34738 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34741 restoreState : function(provider){
34743 provider = Roo.state.Manager;
34745 var sm = new Roo.LayoutStateManager();
34746 sm.init(this, provider);
34752 * Adds a xtype elements to the layout.
34756 xtype : 'ContentPanel',
34763 xtype : 'NestedLayoutPanel',
34769 items : [ ... list of content panels or nested layout panels.. ]
34773 * @param {Object} cfg Xtype definition of item to add.
34775 addxtype : function(cfg)
34777 // basically accepts a pannel...
34778 // can accept a layout region..!?!?
34779 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34782 // theory? children can only be panels??
34784 //if (!cfg.xtype.match(/Panel$/)) {
34789 if (typeof(cfg.region) == 'undefined') {
34790 Roo.log("Failed to add Panel, region was not set");
34794 var region = cfg.region;
34800 xitems = cfg.items;
34807 case 'Content': // ContentPanel (el, cfg)
34808 case 'Scroll': // ContentPanel (el, cfg)
34810 cfg.autoCreate = true;
34811 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34813 // var el = this.el.createChild();
34814 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34817 this.add(region, ret);
34821 case 'TreePanel': // our new panel!
34822 cfg.el = this.el.createChild();
34823 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34824 this.add(region, ret);
34829 // create a new Layout (which is a Border Layout...
34831 var clayout = cfg.layout;
34832 clayout.el = this.el.createChild();
34833 clayout.items = clayout.items || [];
34837 // replace this exitems with the clayout ones..
34838 xitems = clayout.items;
34840 // force background off if it's in center...
34841 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34842 cfg.background = false;
34844 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34847 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34848 //console.log('adding nested layout panel ' + cfg.toSource());
34849 this.add(region, ret);
34850 nb = {}; /// find first...
34855 // needs grid and region
34857 //var el = this.getRegion(region).el.createChild();
34859 *var el = this.el.createChild();
34860 // create the grid first...
34861 cfg.grid.container = el;
34862 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34865 if (region == 'center' && this.active ) {
34866 cfg.background = false;
34869 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34871 this.add(region, ret);
34873 if (cfg.background) {
34874 // render grid on panel activation (if panel background)
34875 ret.on('activate', function(gp) {
34876 if (!gp.grid.rendered) {
34877 // gp.grid.render(el);
34881 // cfg.grid.render(el);
34887 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34888 // it was the old xcomponent building that caused this before.
34889 // espeically if border is the top element in the tree.
34899 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34901 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34902 this.add(region, ret);
34906 throw "Can not add '" + cfg.xtype + "' to Border";
34912 this.beginUpdate();
34916 Roo.each(xitems, function(i) {
34917 region = nb && i.region ? i.region : false;
34919 var add = ret.addxtype(i);
34922 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34923 if (!i.background) {
34924 abn[region] = nb[region] ;
34931 // make the last non-background panel active..
34932 //if (nb) { Roo.log(abn); }
34935 for(var r in abn) {
34936 region = this.getRegion(r);
34938 // tried using nb[r], but it does not work..
34940 region.showPanel(abn[r]);
34951 factory : function(cfg)
34954 var validRegions = Roo.bootstrap.layout.Border.regions;
34956 var target = cfg.region;
34959 var r = Roo.bootstrap.layout;
34963 return new r.North(cfg);
34965 return new r.South(cfg);
34967 return new r.East(cfg);
34969 return new r.West(cfg);
34971 return new r.Center(cfg);
34973 throw 'Layout region "'+target+'" not supported.';
34980 * Ext JS Library 1.1.1
34981 * Copyright(c) 2006-2007, Ext JS, LLC.
34983 * Originally Released Under LGPL - original licence link has changed is not relivant.
34986 * <script type="text/javascript">
34990 * @class Roo.bootstrap.layout.Basic
34991 * @extends Roo.util.Observable
34992 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
34993 * and does not have a titlebar, tabs or any other features. All it does is size and position
34994 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
34995 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34996 * @cfg {string} region the region that it inhabits..
34997 * @cfg {bool} skipConfig skip config?
35001 Roo.bootstrap.layout.Basic = function(config){
35003 this.mgr = config.mgr;
35005 this.position = config.region;
35007 var skipConfig = config.skipConfig;
35011 * @scope Roo.BasicLayoutRegion
35015 * @event beforeremove
35016 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35017 * @param {Roo.LayoutRegion} this
35018 * @param {Roo.ContentPanel} panel The panel
35019 * @param {Object} e The cancel event object
35021 "beforeremove" : true,
35023 * @event invalidated
35024 * Fires when the layout for this region is changed.
35025 * @param {Roo.LayoutRegion} this
35027 "invalidated" : true,
35029 * @event visibilitychange
35030 * Fires when this region is shown or hidden
35031 * @param {Roo.LayoutRegion} this
35032 * @param {Boolean} visibility true or false
35034 "visibilitychange" : true,
35036 * @event paneladded
35037 * Fires when a panel is added.
35038 * @param {Roo.LayoutRegion} this
35039 * @param {Roo.ContentPanel} panel The panel
35041 "paneladded" : true,
35043 * @event panelremoved
35044 * Fires when a panel is removed.
35045 * @param {Roo.LayoutRegion} this
35046 * @param {Roo.ContentPanel} panel The panel
35048 "panelremoved" : true,
35050 * @event beforecollapse
35051 * Fires when this region before collapse.
35052 * @param {Roo.LayoutRegion} this
35054 "beforecollapse" : true,
35057 * Fires when this region is collapsed.
35058 * @param {Roo.LayoutRegion} this
35060 "collapsed" : true,
35063 * Fires when this region is expanded.
35064 * @param {Roo.LayoutRegion} this
35069 * Fires when this region is slid into view.
35070 * @param {Roo.LayoutRegion} this
35072 "slideshow" : true,
35075 * Fires when this region slides out of view.
35076 * @param {Roo.LayoutRegion} this
35078 "slidehide" : true,
35080 * @event panelactivated
35081 * Fires when a panel is activated.
35082 * @param {Roo.LayoutRegion} this
35083 * @param {Roo.ContentPanel} panel The activated panel
35085 "panelactivated" : true,
35088 * Fires when the user resizes this region.
35089 * @param {Roo.LayoutRegion} this
35090 * @param {Number} newSize The new size (width for east/west, height for north/south)
35094 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35095 this.panels = new Roo.util.MixedCollection();
35096 this.panels.getKey = this.getPanelId.createDelegate(this);
35098 this.activePanel = null;
35099 // ensure listeners are added...
35101 if (config.listeners || config.events) {
35102 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35103 listeners : config.listeners || {},
35104 events : config.events || {}
35108 if(skipConfig !== true){
35109 this.applyConfig(config);
35113 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35115 getPanelId : function(p){
35119 applyConfig : function(config){
35120 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35121 this.config = config;
35126 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35127 * the width, for horizontal (north, south) the height.
35128 * @param {Number} newSize The new width or height
35130 resizeTo : function(newSize){
35131 var el = this.el ? this.el :
35132 (this.activePanel ? this.activePanel.getEl() : null);
35134 switch(this.position){
35137 el.setWidth(newSize);
35138 this.fireEvent("resized", this, newSize);
35142 el.setHeight(newSize);
35143 this.fireEvent("resized", this, newSize);
35149 getBox : function(){
35150 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35153 getMargins : function(){
35154 return this.margins;
35157 updateBox : function(box){
35159 var el = this.activePanel.getEl();
35160 el.dom.style.left = box.x + "px";
35161 el.dom.style.top = box.y + "px";
35162 this.activePanel.setSize(box.width, box.height);
35166 * Returns the container element for this region.
35167 * @return {Roo.Element}
35169 getEl : function(){
35170 return this.activePanel;
35174 * Returns true if this region is currently visible.
35175 * @return {Boolean}
35177 isVisible : function(){
35178 return this.activePanel ? true : false;
35181 setActivePanel : function(panel){
35182 panel = this.getPanel(panel);
35183 if(this.activePanel && this.activePanel != panel){
35184 this.activePanel.setActiveState(false);
35185 this.activePanel.getEl().setLeftTop(-10000,-10000);
35187 this.activePanel = panel;
35188 panel.setActiveState(true);
35190 panel.setSize(this.box.width, this.box.height);
35192 this.fireEvent("panelactivated", this, panel);
35193 this.fireEvent("invalidated");
35197 * Show the specified panel.
35198 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35199 * @return {Roo.ContentPanel} The shown panel or null
35201 showPanel : function(panel){
35202 panel = this.getPanel(panel);
35204 this.setActivePanel(panel);
35210 * Get the active panel for this region.
35211 * @return {Roo.ContentPanel} The active panel or null
35213 getActivePanel : function(){
35214 return this.activePanel;
35218 * Add the passed ContentPanel(s)
35219 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35220 * @return {Roo.ContentPanel} The panel added (if only one was added)
35222 add : function(panel){
35223 if(arguments.length > 1){
35224 for(var i = 0, len = arguments.length; i < len; i++) {
35225 this.add(arguments[i]);
35229 if(this.hasPanel(panel)){
35230 this.showPanel(panel);
35233 var el = panel.getEl();
35234 if(el.dom.parentNode != this.mgr.el.dom){
35235 this.mgr.el.dom.appendChild(el.dom);
35237 if(panel.setRegion){
35238 panel.setRegion(this);
35240 this.panels.add(panel);
35241 el.setStyle("position", "absolute");
35242 if(!panel.background){
35243 this.setActivePanel(panel);
35244 if(this.config.initialSize && this.panels.getCount()==1){
35245 this.resizeTo(this.config.initialSize);
35248 this.fireEvent("paneladded", this, panel);
35253 * Returns true if the panel is in this region.
35254 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35255 * @return {Boolean}
35257 hasPanel : function(panel){
35258 if(typeof panel == "object"){ // must be panel obj
35259 panel = panel.getId();
35261 return this.getPanel(panel) ? true : false;
35265 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35266 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35267 * @param {Boolean} preservePanel Overrides the config preservePanel option
35268 * @return {Roo.ContentPanel} The panel that was removed
35270 remove : function(panel, preservePanel){
35271 panel = this.getPanel(panel);
35276 this.fireEvent("beforeremove", this, panel, e);
35277 if(e.cancel === true){
35280 var panelId = panel.getId();
35281 this.panels.removeKey(panelId);
35286 * Returns the panel specified or null if it's not in this region.
35287 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35288 * @return {Roo.ContentPanel}
35290 getPanel : function(id){
35291 if(typeof id == "object"){ // must be panel obj
35294 return this.panels.get(id);
35298 * Returns this regions position (north/south/east/west/center).
35301 getPosition: function(){
35302 return this.position;
35306 * Ext JS Library 1.1.1
35307 * Copyright(c) 2006-2007, Ext JS, LLC.
35309 * Originally Released Under LGPL - original licence link has changed is not relivant.
35312 * <script type="text/javascript">
35316 * @class Roo.bootstrap.layout.Region
35317 * @extends Roo.bootstrap.layout.Basic
35318 * This class represents a region in a layout manager.
35320 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35321 * @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})
35322 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35323 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35324 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35325 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35326 * @cfg {String} title The title for the region (overrides panel titles)
35327 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35328 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35329 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35330 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35331 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35332 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35333 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35334 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35335 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35336 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35338 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35339 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35340 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35341 * @cfg {Number} width For East/West panels
35342 * @cfg {Number} height For North/South panels
35343 * @cfg {Boolean} split To show the splitter
35344 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35346 * @cfg {string} cls Extra CSS classes to add to region
35348 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35349 * @cfg {string} region the region that it inhabits..
35352 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35353 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35355 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35356 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35357 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35359 Roo.bootstrap.layout.Region = function(config)
35361 this.applyConfig(config);
35363 var mgr = config.mgr;
35364 var pos = config.region;
35365 config.skipConfig = true;
35366 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35369 this.onRender(mgr.el);
35372 this.visible = true;
35373 this.collapsed = false;
35374 this.unrendered_panels = [];
35377 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35379 position: '', // set by wrapper (eg. north/south etc..)
35380 unrendered_panels : null, // unrendered panels.
35381 createBody : function(){
35382 /** This region's body element
35383 * @type Roo.Element */
35384 this.bodyEl = this.el.createChild({
35386 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35390 onRender: function(ctr, pos)
35392 var dh = Roo.DomHelper;
35393 /** This region's container element
35394 * @type Roo.Element */
35395 this.el = dh.append(ctr.dom, {
35397 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35399 /** This region's title element
35400 * @type Roo.Element */
35402 this.titleEl = dh.append(this.el.dom,
35405 unselectable: "on",
35406 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35408 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35409 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35412 this.titleEl.enableDisplayMode();
35413 /** This region's title text element
35414 * @type HTMLElement */
35415 this.titleTextEl = this.titleEl.dom.firstChild;
35416 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35418 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35419 this.closeBtn.enableDisplayMode();
35420 this.closeBtn.on("click", this.closeClicked, this);
35421 this.closeBtn.hide();
35423 this.createBody(this.config);
35424 if(this.config.hideWhenEmpty){
35426 this.on("paneladded", this.validateVisibility, this);
35427 this.on("panelremoved", this.validateVisibility, this);
35429 if(this.autoScroll){
35430 this.bodyEl.setStyle("overflow", "auto");
35432 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35434 //if(c.titlebar !== false){
35435 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35436 this.titleEl.hide();
35438 this.titleEl.show();
35439 if(this.config.title){
35440 this.titleTextEl.innerHTML = this.config.title;
35444 if(this.config.collapsed){
35445 this.collapse(true);
35447 if(this.config.hidden){
35451 if (this.unrendered_panels && this.unrendered_panels.length) {
35452 for (var i =0;i< this.unrendered_panels.length; i++) {
35453 this.add(this.unrendered_panels[i]);
35455 this.unrendered_panels = null;
35461 applyConfig : function(c)
35464 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35465 var dh = Roo.DomHelper;
35466 if(c.titlebar !== false){
35467 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35468 this.collapseBtn.on("click", this.collapse, this);
35469 this.collapseBtn.enableDisplayMode();
35471 if(c.showPin === true || this.showPin){
35472 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35473 this.stickBtn.enableDisplayMode();
35474 this.stickBtn.on("click", this.expand, this);
35475 this.stickBtn.hide();
35480 /** This region's collapsed element
35481 * @type Roo.Element */
35484 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35485 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35488 if(c.floatable !== false){
35489 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35490 this.collapsedEl.on("click", this.collapseClick, this);
35493 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35494 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35495 id: "message", unselectable: "on", style:{"float":"left"}});
35496 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35498 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35499 this.expandBtn.on("click", this.expand, this);
35503 if(this.collapseBtn){
35504 this.collapseBtn.setVisible(c.collapsible == true);
35507 this.cmargins = c.cmargins || this.cmargins ||
35508 (this.position == "west" || this.position == "east" ?
35509 {top: 0, left: 2, right:2, bottom: 0} :
35510 {top: 2, left: 0, right:0, bottom: 2});
35512 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35515 this.bottomTabs = c.tabPosition != "top";
35517 this.autoScroll = c.autoScroll || false;
35522 this.duration = c.duration || .30;
35523 this.slideDuration = c.slideDuration || .45;
35528 * Returns true if this region is currently visible.
35529 * @return {Boolean}
35531 isVisible : function(){
35532 return this.visible;
35536 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35537 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35539 //setCollapsedTitle : function(title){
35540 // title = title || " ";
35541 // if(this.collapsedTitleTextEl){
35542 // this.collapsedTitleTextEl.innerHTML = title;
35546 getBox : function(){
35548 // if(!this.collapsed){
35549 b = this.el.getBox(false, true);
35551 // b = this.collapsedEl.getBox(false, true);
35556 getMargins : function(){
35557 return this.margins;
35558 //return this.collapsed ? this.cmargins : this.margins;
35561 highlight : function(){
35562 this.el.addClass("x-layout-panel-dragover");
35565 unhighlight : function(){
35566 this.el.removeClass("x-layout-panel-dragover");
35569 updateBox : function(box)
35571 if (!this.bodyEl) {
35572 return; // not rendered yet..
35576 if(!this.collapsed){
35577 this.el.dom.style.left = box.x + "px";
35578 this.el.dom.style.top = box.y + "px";
35579 this.updateBody(box.width, box.height);
35581 this.collapsedEl.dom.style.left = box.x + "px";
35582 this.collapsedEl.dom.style.top = box.y + "px";
35583 this.collapsedEl.setSize(box.width, box.height);
35586 this.tabs.autoSizeTabs();
35590 updateBody : function(w, h)
35593 this.el.setWidth(w);
35594 w -= this.el.getBorderWidth("rl");
35595 if(this.config.adjustments){
35596 w += this.config.adjustments[0];
35599 if(h !== null && h > 0){
35600 this.el.setHeight(h);
35601 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35602 h -= this.el.getBorderWidth("tb");
35603 if(this.config.adjustments){
35604 h += this.config.adjustments[1];
35606 this.bodyEl.setHeight(h);
35608 h = this.tabs.syncHeight(h);
35611 if(this.panelSize){
35612 w = w !== null ? w : this.panelSize.width;
35613 h = h !== null ? h : this.panelSize.height;
35615 if(this.activePanel){
35616 var el = this.activePanel.getEl();
35617 w = w !== null ? w : el.getWidth();
35618 h = h !== null ? h : el.getHeight();
35619 this.panelSize = {width: w, height: h};
35620 this.activePanel.setSize(w, h);
35622 if(Roo.isIE && this.tabs){
35623 this.tabs.el.repaint();
35628 * Returns the container element for this region.
35629 * @return {Roo.Element}
35631 getEl : function(){
35636 * Hides this region.
35639 //if(!this.collapsed){
35640 this.el.dom.style.left = "-2000px";
35643 // this.collapsedEl.dom.style.left = "-2000px";
35644 // this.collapsedEl.hide();
35646 this.visible = false;
35647 this.fireEvent("visibilitychange", this, false);
35651 * Shows this region if it was previously hidden.
35654 //if(!this.collapsed){
35657 // this.collapsedEl.show();
35659 this.visible = true;
35660 this.fireEvent("visibilitychange", this, true);
35663 closeClicked : function(){
35664 if(this.activePanel){
35665 this.remove(this.activePanel);
35669 collapseClick : function(e){
35671 e.stopPropagation();
35674 e.stopPropagation();
35680 * Collapses this region.
35681 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35684 collapse : function(skipAnim, skipCheck = false){
35685 if(this.collapsed) {
35689 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35691 this.collapsed = true;
35693 this.split.el.hide();
35695 if(this.config.animate && skipAnim !== true){
35696 this.fireEvent("invalidated", this);
35697 this.animateCollapse();
35699 this.el.setLocation(-20000,-20000);
35701 this.collapsedEl.show();
35702 this.fireEvent("collapsed", this);
35703 this.fireEvent("invalidated", this);
35709 animateCollapse : function(){
35714 * Expands this region if it was previously collapsed.
35715 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35716 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35719 expand : function(e, skipAnim){
35721 e.stopPropagation();
35723 if(!this.collapsed || this.el.hasActiveFx()) {
35727 this.afterSlideIn();
35730 this.collapsed = false;
35731 if(this.config.animate && skipAnim !== true){
35732 this.animateExpand();
35736 this.split.el.show();
35738 this.collapsedEl.setLocation(-2000,-2000);
35739 this.collapsedEl.hide();
35740 this.fireEvent("invalidated", this);
35741 this.fireEvent("expanded", this);
35745 animateExpand : function(){
35749 initTabs : function()
35751 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35753 var ts = new Roo.bootstrap.panel.Tabs({
35754 el: this.bodyEl.dom,
35755 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35756 disableTooltips: this.config.disableTabTips,
35757 toolbar : this.config.toolbar
35760 if(this.config.hideTabs){
35761 ts.stripWrap.setDisplayed(false);
35764 ts.resizeTabs = this.config.resizeTabs === true;
35765 ts.minTabWidth = this.config.minTabWidth || 40;
35766 ts.maxTabWidth = this.config.maxTabWidth || 250;
35767 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35768 ts.monitorResize = false;
35769 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35770 ts.bodyEl.addClass('roo-layout-tabs-body');
35771 this.panels.each(this.initPanelAsTab, this);
35774 initPanelAsTab : function(panel){
35775 var ti = this.tabs.addTab(
35779 this.config.closeOnTab && panel.isClosable(),
35782 if(panel.tabTip !== undefined){
35783 ti.setTooltip(panel.tabTip);
35785 ti.on("activate", function(){
35786 this.setActivePanel(panel);
35789 if(this.config.closeOnTab){
35790 ti.on("beforeclose", function(t, e){
35792 this.remove(panel);
35796 panel.tabItem = ti;
35801 updatePanelTitle : function(panel, title)
35803 if(this.activePanel == panel){
35804 this.updateTitle(title);
35807 var ti = this.tabs.getTab(panel.getEl().id);
35809 if(panel.tabTip !== undefined){
35810 ti.setTooltip(panel.tabTip);
35815 updateTitle : function(title){
35816 if(this.titleTextEl && !this.config.title){
35817 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35821 setActivePanel : function(panel)
35823 panel = this.getPanel(panel);
35824 if(this.activePanel && this.activePanel != panel){
35825 if(this.activePanel.setActiveState(false) === false){
35829 this.activePanel = panel;
35830 panel.setActiveState(true);
35831 if(this.panelSize){
35832 panel.setSize(this.panelSize.width, this.panelSize.height);
35835 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35837 this.updateTitle(panel.getTitle());
35839 this.fireEvent("invalidated", this);
35841 this.fireEvent("panelactivated", this, panel);
35845 * Shows the specified panel.
35846 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35847 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35849 showPanel : function(panel)
35851 panel = this.getPanel(panel);
35854 var tab = this.tabs.getTab(panel.getEl().id);
35855 if(tab.isHidden()){
35856 this.tabs.unhideTab(tab.id);
35860 this.setActivePanel(panel);
35867 * Get the active panel for this region.
35868 * @return {Roo.ContentPanel} The active panel or null
35870 getActivePanel : function(){
35871 return this.activePanel;
35874 validateVisibility : function(){
35875 if(this.panels.getCount() < 1){
35876 this.updateTitle(" ");
35877 this.closeBtn.hide();
35880 if(!this.isVisible()){
35887 * Adds the passed ContentPanel(s) to this region.
35888 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35889 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35891 add : function(panel)
35893 if(arguments.length > 1){
35894 for(var i = 0, len = arguments.length; i < len; i++) {
35895 this.add(arguments[i]);
35900 // if we have not been rendered yet, then we can not really do much of this..
35901 if (!this.bodyEl) {
35902 this.unrendered_panels.push(panel);
35909 if(this.hasPanel(panel)){
35910 this.showPanel(panel);
35913 panel.setRegion(this);
35914 this.panels.add(panel);
35915 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35916 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35917 // and hide them... ???
35918 this.bodyEl.dom.appendChild(panel.getEl().dom);
35919 if(panel.background !== true){
35920 this.setActivePanel(panel);
35922 this.fireEvent("paneladded", this, panel);
35929 this.initPanelAsTab(panel);
35933 if(panel.background !== true){
35934 this.tabs.activate(panel.getEl().id);
35936 this.fireEvent("paneladded", this, panel);
35941 * Hides the tab for the specified panel.
35942 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35944 hidePanel : function(panel){
35945 if(this.tabs && (panel = this.getPanel(panel))){
35946 this.tabs.hideTab(panel.getEl().id);
35951 * Unhides the tab for a previously hidden panel.
35952 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35954 unhidePanel : function(panel){
35955 if(this.tabs && (panel = this.getPanel(panel))){
35956 this.tabs.unhideTab(panel.getEl().id);
35960 clearPanels : function(){
35961 while(this.panels.getCount() > 0){
35962 this.remove(this.panels.first());
35967 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35968 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35969 * @param {Boolean} preservePanel Overrides the config preservePanel option
35970 * @return {Roo.ContentPanel} The panel that was removed
35972 remove : function(panel, preservePanel)
35974 panel = this.getPanel(panel);
35979 this.fireEvent("beforeremove", this, panel, e);
35980 if(e.cancel === true){
35983 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
35984 var panelId = panel.getId();
35985 this.panels.removeKey(panelId);
35987 document.body.appendChild(panel.getEl().dom);
35990 this.tabs.removeTab(panel.getEl().id);
35991 }else if (!preservePanel){
35992 this.bodyEl.dom.removeChild(panel.getEl().dom);
35994 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
35995 var p = this.panels.first();
35996 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
35997 tempEl.appendChild(p.getEl().dom);
35998 this.bodyEl.update("");
35999 this.bodyEl.dom.appendChild(p.getEl().dom);
36001 this.updateTitle(p.getTitle());
36003 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36004 this.setActivePanel(p);
36006 panel.setRegion(null);
36007 if(this.activePanel == panel){
36008 this.activePanel = null;
36010 if(this.config.autoDestroy !== false && preservePanel !== true){
36011 try{panel.destroy();}catch(e){}
36013 this.fireEvent("panelremoved", this, panel);
36018 * Returns the TabPanel component used by this region
36019 * @return {Roo.TabPanel}
36021 getTabs : function(){
36025 createTool : function(parentEl, className){
36026 var btn = Roo.DomHelper.append(parentEl, {
36028 cls: "x-layout-tools-button",
36031 cls: "roo-layout-tools-button-inner " + className,
36035 btn.addClassOnOver("roo-layout-tools-button-over");
36040 * Ext JS Library 1.1.1
36041 * Copyright(c) 2006-2007, Ext JS, LLC.
36043 * Originally Released Under LGPL - original licence link has changed is not relivant.
36046 * <script type="text/javascript">
36052 * @class Roo.SplitLayoutRegion
36053 * @extends Roo.LayoutRegion
36054 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36056 Roo.bootstrap.layout.Split = function(config){
36057 this.cursor = config.cursor;
36058 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36061 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36063 splitTip : "Drag to resize.",
36064 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36065 useSplitTips : false,
36067 applyConfig : function(config){
36068 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36071 onRender : function(ctr,pos) {
36073 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36074 if(!this.config.split){
36079 var splitEl = Roo.DomHelper.append(ctr.dom, {
36081 id: this.el.id + "-split",
36082 cls: "roo-layout-split roo-layout-split-"+this.position,
36085 /** The SplitBar for this region
36086 * @type Roo.SplitBar */
36087 // does not exist yet...
36088 Roo.log([this.position, this.orientation]);
36090 this.split = new Roo.bootstrap.SplitBar({
36091 dragElement : splitEl,
36092 resizingElement: this.el,
36093 orientation : this.orientation
36096 this.split.on("moved", this.onSplitMove, this);
36097 this.split.useShim = this.config.useShim === true;
36098 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36099 if(this.useSplitTips){
36100 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36102 //if(config.collapsible){
36103 // this.split.el.on("dblclick", this.collapse, this);
36106 if(typeof this.config.minSize != "undefined"){
36107 this.split.minSize = this.config.minSize;
36109 if(typeof this.config.maxSize != "undefined"){
36110 this.split.maxSize = this.config.maxSize;
36112 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36113 this.hideSplitter();
36118 getHMaxSize : function(){
36119 var cmax = this.config.maxSize || 10000;
36120 var center = this.mgr.getRegion("center");
36121 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36124 getVMaxSize : function(){
36125 var cmax = this.config.maxSize || 10000;
36126 var center = this.mgr.getRegion("center");
36127 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36130 onSplitMove : function(split, newSize){
36131 this.fireEvent("resized", this, newSize);
36135 * Returns the {@link Roo.SplitBar} for this region.
36136 * @return {Roo.SplitBar}
36138 getSplitBar : function(){
36143 this.hideSplitter();
36144 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36147 hideSplitter : function(){
36149 this.split.el.setLocation(-2000,-2000);
36150 this.split.el.hide();
36156 this.split.el.show();
36158 Roo.bootstrap.layout.Split.superclass.show.call(this);
36161 beforeSlide: function(){
36162 if(Roo.isGecko){// firefox overflow auto bug workaround
36163 this.bodyEl.clip();
36165 this.tabs.bodyEl.clip();
36167 if(this.activePanel){
36168 this.activePanel.getEl().clip();
36170 if(this.activePanel.beforeSlide){
36171 this.activePanel.beforeSlide();
36177 afterSlide : function(){
36178 if(Roo.isGecko){// firefox overflow auto bug workaround
36179 this.bodyEl.unclip();
36181 this.tabs.bodyEl.unclip();
36183 if(this.activePanel){
36184 this.activePanel.getEl().unclip();
36185 if(this.activePanel.afterSlide){
36186 this.activePanel.afterSlide();
36192 initAutoHide : function(){
36193 if(this.autoHide !== false){
36194 if(!this.autoHideHd){
36195 var st = new Roo.util.DelayedTask(this.slideIn, this);
36196 this.autoHideHd = {
36197 "mouseout": function(e){
36198 if(!e.within(this.el, true)){
36202 "mouseover" : function(e){
36208 this.el.on(this.autoHideHd);
36212 clearAutoHide : function(){
36213 if(this.autoHide !== false){
36214 this.el.un("mouseout", this.autoHideHd.mouseout);
36215 this.el.un("mouseover", this.autoHideHd.mouseover);
36219 clearMonitor : function(){
36220 Roo.get(document).un("click", this.slideInIf, this);
36223 // these names are backwards but not changed for compat
36224 slideOut : function(){
36225 if(this.isSlid || this.el.hasActiveFx()){
36228 this.isSlid = true;
36229 if(this.collapseBtn){
36230 this.collapseBtn.hide();
36232 this.closeBtnState = this.closeBtn.getStyle('display');
36233 this.closeBtn.hide();
36235 this.stickBtn.show();
36238 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36239 this.beforeSlide();
36240 this.el.setStyle("z-index", 10001);
36241 this.el.slideIn(this.getSlideAnchor(), {
36242 callback: function(){
36244 this.initAutoHide();
36245 Roo.get(document).on("click", this.slideInIf, this);
36246 this.fireEvent("slideshow", this);
36253 afterSlideIn : function(){
36254 this.clearAutoHide();
36255 this.isSlid = false;
36256 this.clearMonitor();
36257 this.el.setStyle("z-index", "");
36258 if(this.collapseBtn){
36259 this.collapseBtn.show();
36261 this.closeBtn.setStyle('display', this.closeBtnState);
36263 this.stickBtn.hide();
36265 this.fireEvent("slidehide", this);
36268 slideIn : function(cb){
36269 if(!this.isSlid || this.el.hasActiveFx()){
36273 this.isSlid = false;
36274 this.beforeSlide();
36275 this.el.slideOut(this.getSlideAnchor(), {
36276 callback: function(){
36277 this.el.setLeftTop(-10000, -10000);
36279 this.afterSlideIn();
36287 slideInIf : function(e){
36288 if(!e.within(this.el)){
36293 animateCollapse : function(){
36294 this.beforeSlide();
36295 this.el.setStyle("z-index", 20000);
36296 var anchor = this.getSlideAnchor();
36297 this.el.slideOut(anchor, {
36298 callback : function(){
36299 this.el.setStyle("z-index", "");
36300 this.collapsedEl.slideIn(anchor, {duration:.3});
36302 this.el.setLocation(-10000,-10000);
36304 this.fireEvent("collapsed", this);
36311 animateExpand : function(){
36312 this.beforeSlide();
36313 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36314 this.el.setStyle("z-index", 20000);
36315 this.collapsedEl.hide({
36318 this.el.slideIn(this.getSlideAnchor(), {
36319 callback : function(){
36320 this.el.setStyle("z-index", "");
36323 this.split.el.show();
36325 this.fireEvent("invalidated", this);
36326 this.fireEvent("expanded", this);
36354 getAnchor : function(){
36355 return this.anchors[this.position];
36358 getCollapseAnchor : function(){
36359 return this.canchors[this.position];
36362 getSlideAnchor : function(){
36363 return this.sanchors[this.position];
36366 getAlignAdj : function(){
36367 var cm = this.cmargins;
36368 switch(this.position){
36384 getExpandAdj : function(){
36385 var c = this.collapsedEl, cm = this.cmargins;
36386 switch(this.position){
36388 return [-(cm.right+c.getWidth()+cm.left), 0];
36391 return [cm.right+c.getWidth()+cm.left, 0];
36394 return [0, -(cm.top+cm.bottom+c.getHeight())];
36397 return [0, cm.top+cm.bottom+c.getHeight()];
36403 * Ext JS Library 1.1.1
36404 * Copyright(c) 2006-2007, Ext JS, LLC.
36406 * Originally Released Under LGPL - original licence link has changed is not relivant.
36409 * <script type="text/javascript">
36412 * These classes are private internal classes
36414 Roo.bootstrap.layout.Center = function(config){
36415 config.region = "center";
36416 Roo.bootstrap.layout.Region.call(this, config);
36417 this.visible = true;
36418 this.minWidth = config.minWidth || 20;
36419 this.minHeight = config.minHeight || 20;
36422 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36424 // center panel can't be hidden
36428 // center panel can't be hidden
36431 getMinWidth: function(){
36432 return this.minWidth;
36435 getMinHeight: function(){
36436 return this.minHeight;
36449 Roo.bootstrap.layout.North = function(config)
36451 config.region = 'north';
36452 config.cursor = 'n-resize';
36454 Roo.bootstrap.layout.Split.call(this, config);
36458 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36459 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36460 this.split.el.addClass("roo-layout-split-v");
36462 var size = config.initialSize || config.height;
36463 if(typeof size != "undefined"){
36464 this.el.setHeight(size);
36467 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36469 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36473 getBox : function(){
36474 if(this.collapsed){
36475 return this.collapsedEl.getBox();
36477 var box = this.el.getBox();
36479 box.height += this.split.el.getHeight();
36484 updateBox : function(box){
36485 if(this.split && !this.collapsed){
36486 box.height -= this.split.el.getHeight();
36487 this.split.el.setLeft(box.x);
36488 this.split.el.setTop(box.y+box.height);
36489 this.split.el.setWidth(box.width);
36491 if(this.collapsed){
36492 this.updateBody(box.width, null);
36494 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36502 Roo.bootstrap.layout.South = function(config){
36503 config.region = 'south';
36504 config.cursor = 's-resize';
36505 Roo.bootstrap.layout.Split.call(this, config);
36507 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36508 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36509 this.split.el.addClass("roo-layout-split-v");
36511 var size = config.initialSize || config.height;
36512 if(typeof size != "undefined"){
36513 this.el.setHeight(size);
36517 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36518 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36519 getBox : function(){
36520 if(this.collapsed){
36521 return this.collapsedEl.getBox();
36523 var box = this.el.getBox();
36525 var sh = this.split.el.getHeight();
36532 updateBox : function(box){
36533 if(this.split && !this.collapsed){
36534 var sh = this.split.el.getHeight();
36537 this.split.el.setLeft(box.x);
36538 this.split.el.setTop(box.y-sh);
36539 this.split.el.setWidth(box.width);
36541 if(this.collapsed){
36542 this.updateBody(box.width, null);
36544 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36548 Roo.bootstrap.layout.East = function(config){
36549 config.region = "east";
36550 config.cursor = "e-resize";
36551 Roo.bootstrap.layout.Split.call(this, config);
36553 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36554 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36555 this.split.el.addClass("roo-layout-split-h");
36557 var size = config.initialSize || config.width;
36558 if(typeof size != "undefined"){
36559 this.el.setWidth(size);
36562 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36563 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36564 getBox : function(){
36565 if(this.collapsed){
36566 return this.collapsedEl.getBox();
36568 var box = this.el.getBox();
36570 var sw = this.split.el.getWidth();
36577 updateBox : function(box){
36578 if(this.split && !this.collapsed){
36579 var sw = this.split.el.getWidth();
36581 this.split.el.setLeft(box.x);
36582 this.split.el.setTop(box.y);
36583 this.split.el.setHeight(box.height);
36586 if(this.collapsed){
36587 this.updateBody(null, box.height);
36589 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36593 Roo.bootstrap.layout.West = function(config){
36594 config.region = "west";
36595 config.cursor = "w-resize";
36597 Roo.bootstrap.layout.Split.call(this, config);
36599 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36600 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36601 this.split.el.addClass("roo-layout-split-h");
36605 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36606 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36608 onRender: function(ctr, pos)
36610 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36611 var size = this.config.initialSize || this.config.width;
36612 if(typeof size != "undefined"){
36613 this.el.setWidth(size);
36617 getBox : function(){
36618 if(this.collapsed){
36619 return this.collapsedEl.getBox();
36621 var box = this.el.getBox();
36623 box.width += this.split.el.getWidth();
36628 updateBox : function(box){
36629 if(this.split && !this.collapsed){
36630 var sw = this.split.el.getWidth();
36632 this.split.el.setLeft(box.x+box.width);
36633 this.split.el.setTop(box.y);
36634 this.split.el.setHeight(box.height);
36636 if(this.collapsed){
36637 this.updateBody(null, box.height);
36639 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36642 Roo.namespace("Roo.bootstrap.panel");/*
36644 * Ext JS Library 1.1.1
36645 * Copyright(c) 2006-2007, Ext JS, LLC.
36647 * Originally Released Under LGPL - original licence link has changed is not relivant.
36650 * <script type="text/javascript">
36653 * @class Roo.ContentPanel
36654 * @extends Roo.util.Observable
36655 * A basic ContentPanel element.
36656 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36657 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36658 * @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
36659 * @cfg {Boolean} closable True if the panel can be closed/removed
36660 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36661 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36662 * @cfg {Toolbar} toolbar A toolbar for this panel
36663 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36664 * @cfg {String} title The title for this panel
36665 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36666 * @cfg {String} url Calls {@link #setUrl} with this value
36667 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36668 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36669 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36670 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36671 * @cfg {Boolean} badges render the badges
36674 * Create a new ContentPanel.
36675 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36676 * @param {String/Object} config A string to set only the title or a config object
36677 * @param {String} content (optional) Set the HTML content for this panel
36678 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36680 Roo.bootstrap.panel.Content = function( config){
36682 this.tpl = config.tpl || false;
36684 var el = config.el;
36685 var content = config.content;
36687 if(config.autoCreate){ // xtype is available if this is called from factory
36690 this.el = Roo.get(el);
36691 if(!this.el && config && config.autoCreate){
36692 if(typeof config.autoCreate == "object"){
36693 if(!config.autoCreate.id){
36694 config.autoCreate.id = config.id||el;
36696 this.el = Roo.DomHelper.append(document.body,
36697 config.autoCreate, true);
36699 var elcfg = { tag: "div",
36700 cls: "roo-layout-inactive-content",
36704 elcfg.html = config.html;
36708 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36711 this.closable = false;
36712 this.loaded = false;
36713 this.active = false;
36716 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36718 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36720 this.wrapEl = this.el; //this.el.wrap();
36722 if (config.toolbar.items) {
36723 ti = config.toolbar.items ;
36724 delete config.toolbar.items ;
36728 this.toolbar.render(this.wrapEl, 'before');
36729 for(var i =0;i < ti.length;i++) {
36730 // Roo.log(['add child', items[i]]);
36731 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36733 this.toolbar.items = nitems;
36734 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36735 delete config.toolbar;
36739 // xtype created footer. - not sure if will work as we normally have to render first..
36740 if (this.footer && !this.footer.el && this.footer.xtype) {
36741 if (!this.wrapEl) {
36742 this.wrapEl = this.el.wrap();
36745 this.footer.container = this.wrapEl.createChild();
36747 this.footer = Roo.factory(this.footer, Roo);
36752 if(typeof config == "string"){
36753 this.title = config;
36755 Roo.apply(this, config);
36759 this.resizeEl = Roo.get(this.resizeEl, true);
36761 this.resizeEl = this.el;
36763 // handle view.xtype
36771 * Fires when this panel is activated.
36772 * @param {Roo.ContentPanel} this
36776 * @event deactivate
36777 * Fires when this panel is activated.
36778 * @param {Roo.ContentPanel} this
36780 "deactivate" : true,
36784 * Fires when this panel is resized if fitToFrame is true.
36785 * @param {Roo.ContentPanel} this
36786 * @param {Number} width The width after any component adjustments
36787 * @param {Number} height The height after any component adjustments
36793 * Fires when this tab is created
36794 * @param {Roo.ContentPanel} this
36805 if(this.autoScroll){
36806 this.resizeEl.setStyle("overflow", "auto");
36808 // fix randome scrolling
36809 //this.el.on('scroll', function() {
36810 // Roo.log('fix random scolling');
36811 // this.scrollTo('top',0);
36814 content = content || this.content;
36816 this.setContent(content);
36818 if(config && config.url){
36819 this.setUrl(this.url, this.params, this.loadOnce);
36824 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36826 if (this.view && typeof(this.view.xtype) != 'undefined') {
36827 this.view.el = this.el.appendChild(document.createElement("div"));
36828 this.view = Roo.factory(this.view);
36829 this.view.render && this.view.render(false, '');
36833 this.fireEvent('render', this);
36836 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36840 setRegion : function(region){
36841 this.region = region;
36842 this.setActiveClass(region && !this.background);
36846 setActiveClass: function(state)
36849 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36850 this.el.setStyle('position','relative');
36852 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36853 this.el.setStyle('position', 'absolute');
36858 * Returns the toolbar for this Panel if one was configured.
36859 * @return {Roo.Toolbar}
36861 getToolbar : function(){
36862 return this.toolbar;
36865 setActiveState : function(active)
36867 this.active = active;
36868 this.setActiveClass(active);
36870 if(this.fireEvent("deactivate", this) === false){
36875 this.fireEvent("activate", this);
36879 * Updates this panel's element
36880 * @param {String} content The new content
36881 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36883 setContent : function(content, loadScripts){
36884 this.el.update(content, loadScripts);
36887 ignoreResize : function(w, h){
36888 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36891 this.lastSize = {width: w, height: h};
36896 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36897 * @return {Roo.UpdateManager} The UpdateManager
36899 getUpdateManager : function(){
36900 return this.el.getUpdateManager();
36903 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36904 * @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:
36907 url: "your-url.php",
36908 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36909 callback: yourFunction,
36910 scope: yourObject, //(optional scope)
36913 text: "Loading...",
36918 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36919 * 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.
36920 * @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}
36921 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36922 * @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.
36923 * @return {Roo.ContentPanel} this
36926 var um = this.el.getUpdateManager();
36927 um.update.apply(um, arguments);
36933 * 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.
36934 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36935 * @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)
36936 * @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)
36937 * @return {Roo.UpdateManager} The UpdateManager
36939 setUrl : function(url, params, loadOnce){
36940 if(this.refreshDelegate){
36941 this.removeListener("activate", this.refreshDelegate);
36943 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36944 this.on("activate", this.refreshDelegate);
36945 return this.el.getUpdateManager();
36948 _handleRefresh : function(url, params, loadOnce){
36949 if(!loadOnce || !this.loaded){
36950 var updater = this.el.getUpdateManager();
36951 updater.update(url, params, this._setLoaded.createDelegate(this));
36955 _setLoaded : function(){
36956 this.loaded = true;
36960 * Returns this panel's id
36963 getId : function(){
36968 * Returns this panel's element - used by regiosn to add.
36969 * @return {Roo.Element}
36971 getEl : function(){
36972 return this.wrapEl || this.el;
36977 adjustForComponents : function(width, height)
36979 //Roo.log('adjustForComponents ');
36980 if(this.resizeEl != this.el){
36981 width -= this.el.getFrameWidth('lr');
36982 height -= this.el.getFrameWidth('tb');
36985 var te = this.toolbar.getEl();
36986 te.setWidth(width);
36987 height -= te.getHeight();
36990 var te = this.footer.getEl();
36991 te.setWidth(width);
36992 height -= te.getHeight();
36996 if(this.adjustments){
36997 width += this.adjustments[0];
36998 height += this.adjustments[1];
37000 return {"width": width, "height": height};
37003 setSize : function(width, height){
37004 if(this.fitToFrame && !this.ignoreResize(width, height)){
37005 if(this.fitContainer && this.resizeEl != this.el){
37006 this.el.setSize(width, height);
37008 var size = this.adjustForComponents(width, height);
37009 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37010 this.fireEvent('resize', this, size.width, size.height);
37015 * Returns this panel's title
37018 getTitle : function(){
37020 if (typeof(this.title) != 'object') {
37025 for (var k in this.title) {
37026 if (!this.title.hasOwnProperty(k)) {
37030 if (k.indexOf('-') >= 0) {
37031 var s = k.split('-');
37032 for (var i = 0; i<s.length; i++) {
37033 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37036 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37043 * Set this panel's title
37044 * @param {String} title
37046 setTitle : function(title){
37047 this.title = title;
37049 this.region.updatePanelTitle(this, title);
37054 * Returns true is this panel was configured to be closable
37055 * @return {Boolean}
37057 isClosable : function(){
37058 return this.closable;
37061 beforeSlide : function(){
37063 this.resizeEl.clip();
37066 afterSlide : function(){
37068 this.resizeEl.unclip();
37072 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37073 * Will fail silently if the {@link #setUrl} method has not been called.
37074 * This does not activate the panel, just updates its content.
37076 refresh : function(){
37077 if(this.refreshDelegate){
37078 this.loaded = false;
37079 this.refreshDelegate();
37084 * Destroys this panel
37086 destroy : function(){
37087 this.el.removeAllListeners();
37088 var tempEl = document.createElement("span");
37089 tempEl.appendChild(this.el.dom);
37090 tempEl.innerHTML = "";
37096 * form - if the content panel contains a form - this is a reference to it.
37097 * @type {Roo.form.Form}
37101 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37102 * This contains a reference to it.
37108 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37118 * @param {Object} cfg Xtype definition of item to add.
37122 getChildContainer: function () {
37123 return this.getEl();
37128 var ret = new Roo.factory(cfg);
37133 if (cfg.xtype.match(/^Form$/)) {
37136 //if (this.footer) {
37137 // el = this.footer.container.insertSibling(false, 'before');
37139 el = this.el.createChild();
37142 this.form = new Roo.form.Form(cfg);
37145 if ( this.form.allItems.length) {
37146 this.form.render(el.dom);
37150 // should only have one of theses..
37151 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37152 // views.. should not be just added - used named prop 'view''
37154 cfg.el = this.el.appendChild(document.createElement("div"));
37157 var ret = new Roo.factory(cfg);
37159 ret.render && ret.render(false, ''); // render blank..
37169 * @class Roo.bootstrap.panel.Grid
37170 * @extends Roo.bootstrap.panel.Content
37172 * Create a new GridPanel.
37173 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37174 * @param {Object} config A the config object
37180 Roo.bootstrap.panel.Grid = function(config)
37184 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37185 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37187 config.el = this.wrapper;
37188 //this.el = this.wrapper;
37190 if (config.container) {
37191 // ctor'ed from a Border/panel.grid
37194 this.wrapper.setStyle("overflow", "hidden");
37195 this.wrapper.addClass('roo-grid-container');
37200 if(config.toolbar){
37201 var tool_el = this.wrapper.createChild();
37202 this.toolbar = Roo.factory(config.toolbar);
37204 if (config.toolbar.items) {
37205 ti = config.toolbar.items ;
37206 delete config.toolbar.items ;
37210 this.toolbar.render(tool_el);
37211 for(var i =0;i < ti.length;i++) {
37212 // Roo.log(['add child', items[i]]);
37213 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37215 this.toolbar.items = nitems;
37217 delete config.toolbar;
37220 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37221 config.grid.scrollBody = true;;
37222 config.grid.monitorWindowResize = false; // turn off autosizing
37223 config.grid.autoHeight = false;
37224 config.grid.autoWidth = false;
37226 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37228 if (config.background) {
37229 // render grid on panel activation (if panel background)
37230 this.on('activate', function(gp) {
37231 if (!gp.grid.rendered) {
37232 gp.grid.render(this.wrapper);
37233 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37238 this.grid.render(this.wrapper);
37239 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37242 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37243 // ??? needed ??? config.el = this.wrapper;
37248 // xtype created footer. - not sure if will work as we normally have to render first..
37249 if (this.footer && !this.footer.el && this.footer.xtype) {
37251 var ctr = this.grid.getView().getFooterPanel(true);
37252 this.footer.dataSource = this.grid.dataSource;
37253 this.footer = Roo.factory(this.footer, Roo);
37254 this.footer.render(ctr);
37264 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37265 getId : function(){
37266 return this.grid.id;
37270 * Returns the grid for this panel
37271 * @return {Roo.bootstrap.Table}
37273 getGrid : function(){
37277 setSize : function(width, height){
37278 if(!this.ignoreResize(width, height)){
37279 var grid = this.grid;
37280 var size = this.adjustForComponents(width, height);
37281 var gridel = grid.getGridEl();
37282 gridel.setSize(size.width, size.height);
37284 var thd = grid.getGridEl().select('thead',true).first();
37285 var tbd = grid.getGridEl().select('tbody', true).first();
37287 tbd.setSize(width, height - thd.getHeight());
37296 beforeSlide : function(){
37297 this.grid.getView().scroller.clip();
37300 afterSlide : function(){
37301 this.grid.getView().scroller.unclip();
37304 destroy : function(){
37305 this.grid.destroy();
37307 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37312 * @class Roo.bootstrap.panel.Nest
37313 * @extends Roo.bootstrap.panel.Content
37315 * Create a new Panel, that can contain a layout.Border.
37318 * @param {Roo.BorderLayout} layout The layout for this panel
37319 * @param {String/Object} config A string to set only the title or a config object
37321 Roo.bootstrap.panel.Nest = function(config)
37323 // construct with only one argument..
37324 /* FIXME - implement nicer consturctors
37325 if (layout.layout) {
37327 layout = config.layout;
37328 delete config.layout;
37330 if (layout.xtype && !layout.getEl) {
37331 // then layout needs constructing..
37332 layout = Roo.factory(layout, Roo);
37336 config.el = config.layout.getEl();
37338 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37340 config.layout.monitorWindowResize = false; // turn off autosizing
37341 this.layout = config.layout;
37342 this.layout.getEl().addClass("roo-layout-nested-layout");
37349 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37351 setSize : function(width, height){
37352 if(!this.ignoreResize(width, height)){
37353 var size = this.adjustForComponents(width, height);
37354 var el = this.layout.getEl();
37355 if (size.height < 1) {
37356 el.setWidth(size.width);
37358 el.setSize(size.width, size.height);
37360 var touch = el.dom.offsetWidth;
37361 this.layout.layout();
37362 // ie requires a double layout on the first pass
37363 if(Roo.isIE && !this.initialized){
37364 this.initialized = true;
37365 this.layout.layout();
37370 // activate all subpanels if not currently active..
37372 setActiveState : function(active){
37373 this.active = active;
37374 this.setActiveClass(active);
37377 this.fireEvent("deactivate", this);
37381 this.fireEvent("activate", this);
37382 // not sure if this should happen before or after..
37383 if (!this.layout) {
37384 return; // should not happen..
37387 for (var r in this.layout.regions) {
37388 reg = this.layout.getRegion(r);
37389 if (reg.getActivePanel()) {
37390 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37391 reg.setActivePanel(reg.getActivePanel());
37394 if (!reg.panels.length) {
37397 reg.showPanel(reg.getPanel(0));
37406 * Returns the nested BorderLayout for this panel
37407 * @return {Roo.BorderLayout}
37409 getLayout : function(){
37410 return this.layout;
37414 * Adds a xtype elements to the layout of the nested panel
37418 xtype : 'ContentPanel',
37425 xtype : 'NestedLayoutPanel',
37431 items : [ ... list of content panels or nested layout panels.. ]
37435 * @param {Object} cfg Xtype definition of item to add.
37437 addxtype : function(cfg) {
37438 return this.layout.addxtype(cfg);
37443 * Ext JS Library 1.1.1
37444 * Copyright(c) 2006-2007, Ext JS, LLC.
37446 * Originally Released Under LGPL - original licence link has changed is not relivant.
37449 * <script type="text/javascript">
37452 * @class Roo.TabPanel
37453 * @extends Roo.util.Observable
37454 * A lightweight tab container.
37458 // basic tabs 1, built from existing content
37459 var tabs = new Roo.TabPanel("tabs1");
37460 tabs.addTab("script", "View Script");
37461 tabs.addTab("markup", "View Markup");
37462 tabs.activate("script");
37464 // more advanced tabs, built from javascript
37465 var jtabs = new Roo.TabPanel("jtabs");
37466 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37468 // set up the UpdateManager
37469 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37470 var updater = tab2.getUpdateManager();
37471 updater.setDefaultUrl("ajax1.htm");
37472 tab2.on('activate', updater.refresh, updater, true);
37474 // Use setUrl for Ajax loading
37475 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37476 tab3.setUrl("ajax2.htm", null, true);
37479 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37482 jtabs.activate("jtabs-1");
37485 * Create a new TabPanel.
37486 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37487 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37489 Roo.bootstrap.panel.Tabs = function(config){
37491 * The container element for this TabPanel.
37492 * @type Roo.Element
37494 this.el = Roo.get(config.el);
37497 if(typeof config == "boolean"){
37498 this.tabPosition = config ? "bottom" : "top";
37500 Roo.apply(this, config);
37504 if(this.tabPosition == "bottom"){
37505 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37506 this.el.addClass("roo-tabs-bottom");
37508 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37509 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37510 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37512 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37514 if(this.tabPosition != "bottom"){
37515 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37516 * @type Roo.Element
37518 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37519 this.el.addClass("roo-tabs-top");
37523 this.bodyEl.setStyle("position", "relative");
37525 this.active = null;
37526 this.activateDelegate = this.activate.createDelegate(this);
37531 * Fires when the active tab changes
37532 * @param {Roo.TabPanel} this
37533 * @param {Roo.TabPanelItem} activePanel The new active tab
37537 * @event beforetabchange
37538 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37539 * @param {Roo.TabPanel} this
37540 * @param {Object} e Set cancel to true on this object to cancel the tab change
37541 * @param {Roo.TabPanelItem} tab The tab being changed to
37543 "beforetabchange" : true
37546 Roo.EventManager.onWindowResize(this.onResize, this);
37547 this.cpad = this.el.getPadding("lr");
37548 this.hiddenCount = 0;
37551 // toolbar on the tabbar support...
37552 if (this.toolbar) {
37553 alert("no toolbar support yet");
37554 this.toolbar = false;
37556 var tcfg = this.toolbar;
37557 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37558 this.toolbar = new Roo.Toolbar(tcfg);
37559 if (Roo.isSafari) {
37560 var tbl = tcfg.container.child('table', true);
37561 tbl.setAttribute('width', '100%');
37569 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37572 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37574 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37576 tabPosition : "top",
37578 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37580 currentTabWidth : 0,
37582 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37586 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37590 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37592 preferredTabWidth : 175,
37594 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37596 resizeTabs : false,
37598 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37600 monitorResize : true,
37602 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37607 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37608 * @param {String} id The id of the div to use <b>or create</b>
37609 * @param {String} text The text for the tab
37610 * @param {String} content (optional) Content to put in the TabPanelItem body
37611 * @param {Boolean} closable (optional) True to create a close icon on the tab
37612 * @return {Roo.TabPanelItem} The created TabPanelItem
37614 addTab : function(id, text, content, closable, tpl)
37616 var item = new Roo.bootstrap.panel.TabItem({
37620 closable : closable,
37623 this.addTabItem(item);
37625 item.setContent(content);
37631 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37632 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37633 * @return {Roo.TabPanelItem}
37635 getTab : function(id){
37636 return this.items[id];
37640 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37641 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37643 hideTab : function(id){
37644 var t = this.items[id];
37647 this.hiddenCount++;
37648 this.autoSizeTabs();
37653 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37654 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37656 unhideTab : function(id){
37657 var t = this.items[id];
37659 t.setHidden(false);
37660 this.hiddenCount--;
37661 this.autoSizeTabs();
37666 * Adds an existing {@link Roo.TabPanelItem}.
37667 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37669 addTabItem : function(item){
37670 this.items[item.id] = item;
37671 this.items.push(item);
37672 // if(this.resizeTabs){
37673 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37674 // this.autoSizeTabs();
37676 // item.autoSize();
37681 * Removes a {@link Roo.TabPanelItem}.
37682 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37684 removeTab : function(id){
37685 var items = this.items;
37686 var tab = items[id];
37687 if(!tab) { return; }
37688 var index = items.indexOf(tab);
37689 if(this.active == tab && items.length > 1){
37690 var newTab = this.getNextAvailable(index);
37695 this.stripEl.dom.removeChild(tab.pnode.dom);
37696 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37697 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37699 items.splice(index, 1);
37700 delete this.items[tab.id];
37701 tab.fireEvent("close", tab);
37702 tab.purgeListeners();
37703 this.autoSizeTabs();
37706 getNextAvailable : function(start){
37707 var items = this.items;
37709 // look for a next tab that will slide over to
37710 // replace the one being removed
37711 while(index < items.length){
37712 var item = items[++index];
37713 if(item && !item.isHidden()){
37717 // if one isn't found select the previous tab (on the left)
37720 var item = items[--index];
37721 if(item && !item.isHidden()){
37729 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37730 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37732 disableTab : function(id){
37733 var tab = this.items[id];
37734 if(tab && this.active != tab){
37740 * Enables a {@link Roo.TabPanelItem} that is disabled.
37741 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37743 enableTab : function(id){
37744 var tab = this.items[id];
37749 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37750 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37751 * @return {Roo.TabPanelItem} The TabPanelItem.
37753 activate : function(id){
37754 var tab = this.items[id];
37758 if(tab == this.active || tab.disabled){
37762 this.fireEvent("beforetabchange", this, e, tab);
37763 if(e.cancel !== true && !tab.disabled){
37765 this.active.hide();
37767 this.active = this.items[id];
37768 this.active.show();
37769 this.fireEvent("tabchange", this, this.active);
37775 * Gets the active {@link Roo.TabPanelItem}.
37776 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37778 getActiveTab : function(){
37779 return this.active;
37783 * Updates the tab body element to fit the height of the container element
37784 * for overflow scrolling
37785 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37787 syncHeight : function(targetHeight){
37788 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37789 var bm = this.bodyEl.getMargins();
37790 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37791 this.bodyEl.setHeight(newHeight);
37795 onResize : function(){
37796 if(this.monitorResize){
37797 this.autoSizeTabs();
37802 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37804 beginUpdate : function(){
37805 this.updating = true;
37809 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37811 endUpdate : function(){
37812 this.updating = false;
37813 this.autoSizeTabs();
37817 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37819 autoSizeTabs : function(){
37820 var count = this.items.length;
37821 var vcount = count - this.hiddenCount;
37822 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37825 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37826 var availWidth = Math.floor(w / vcount);
37827 var b = this.stripBody;
37828 if(b.getWidth() > w){
37829 var tabs = this.items;
37830 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37831 if(availWidth < this.minTabWidth){
37832 /*if(!this.sleft){ // incomplete scrolling code
37833 this.createScrollButtons();
37836 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37839 if(this.currentTabWidth < this.preferredTabWidth){
37840 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37846 * Returns the number of tabs in this TabPanel.
37849 getCount : function(){
37850 return this.items.length;
37854 * Resizes all the tabs to the passed width
37855 * @param {Number} The new width
37857 setTabWidth : function(width){
37858 this.currentTabWidth = width;
37859 for(var i = 0, len = this.items.length; i < len; i++) {
37860 if(!this.items[i].isHidden()) {
37861 this.items[i].setWidth(width);
37867 * Destroys this TabPanel
37868 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37870 destroy : function(removeEl){
37871 Roo.EventManager.removeResizeListener(this.onResize, this);
37872 for(var i = 0, len = this.items.length; i < len; i++){
37873 this.items[i].purgeListeners();
37875 if(removeEl === true){
37876 this.el.update("");
37881 createStrip : function(container)
37883 var strip = document.createElement("nav");
37884 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37885 container.appendChild(strip);
37889 createStripList : function(strip)
37891 // div wrapper for retard IE
37892 // returns the "tr" element.
37893 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37894 //'<div class="x-tabs-strip-wrap">'+
37895 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37896 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37897 return strip.firstChild; //.firstChild.firstChild.firstChild;
37899 createBody : function(container)
37901 var body = document.createElement("div");
37902 Roo.id(body, "tab-body");
37903 //Roo.fly(body).addClass("x-tabs-body");
37904 Roo.fly(body).addClass("tab-content");
37905 container.appendChild(body);
37908 createItemBody :function(bodyEl, id){
37909 var body = Roo.getDom(id);
37911 body = document.createElement("div");
37914 //Roo.fly(body).addClass("x-tabs-item-body");
37915 Roo.fly(body).addClass("tab-pane");
37916 bodyEl.insertBefore(body, bodyEl.firstChild);
37920 createStripElements : function(stripEl, text, closable, tpl)
37922 var td = document.createElement("li"); // was td..
37925 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37928 stripEl.appendChild(td);
37930 td.className = "x-tabs-closable";
37931 if(!this.closeTpl){
37932 this.closeTpl = new Roo.Template(
37933 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37934 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37935 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37938 var el = this.closeTpl.overwrite(td, {"text": text});
37939 var close = el.getElementsByTagName("div")[0];
37940 var inner = el.getElementsByTagName("em")[0];
37941 return {"el": el, "close": close, "inner": inner};
37944 // not sure what this is..
37945 // if(!this.tabTpl){
37946 //this.tabTpl = new Roo.Template(
37947 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37948 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37950 // this.tabTpl = new Roo.Template(
37951 // '<a href="#">' +
37952 // '<span unselectable="on"' +
37953 // (this.disableTooltips ? '' : ' title="{text}"') +
37954 // ' >{text}</span></a>'
37960 var template = tpl || this.tabTpl || false;
37964 template = new Roo.Template(
37966 '<span unselectable="on"' +
37967 (this.disableTooltips ? '' : ' title="{text}"') +
37968 ' >{text}</span></a>'
37972 switch (typeof(template)) {
37976 template = new Roo.Template(template);
37982 var el = template.overwrite(td, {"text": text});
37984 var inner = el.getElementsByTagName("span")[0];
37986 return {"el": el, "inner": inner};
37994 * @class Roo.TabPanelItem
37995 * @extends Roo.util.Observable
37996 * Represents an individual item (tab plus body) in a TabPanel.
37997 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
37998 * @param {String} id The id of this TabPanelItem
37999 * @param {String} text The text for the tab of this TabPanelItem
38000 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38002 Roo.bootstrap.panel.TabItem = function(config){
38004 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38005 * @type Roo.TabPanel
38007 this.tabPanel = config.panel;
38009 * The id for this TabPanelItem
38012 this.id = config.id;
38014 this.disabled = false;
38016 this.text = config.text;
38018 this.loaded = false;
38019 this.closable = config.closable;
38022 * The body element for this TabPanelItem.
38023 * @type Roo.Element
38025 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38026 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38027 this.bodyEl.setStyle("display", "block");
38028 this.bodyEl.setStyle("zoom", "1");
38029 //this.hideAction();
38031 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38033 this.el = Roo.get(els.el);
38034 this.inner = Roo.get(els.inner, true);
38035 this.textEl = Roo.get(this.el.dom.firstChild, true);
38036 this.pnode = Roo.get(els.el.parentNode, true);
38037 // this.el.on("mousedown", this.onTabMouseDown, this);
38038 this.el.on("click", this.onTabClick, this);
38040 if(config.closable){
38041 var c = Roo.get(els.close, true);
38042 c.dom.title = this.closeText;
38043 c.addClassOnOver("close-over");
38044 c.on("click", this.closeClick, this);
38050 * Fires when this tab becomes the active tab.
38051 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38052 * @param {Roo.TabPanelItem} this
38056 * @event beforeclose
38057 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38058 * @param {Roo.TabPanelItem} this
38059 * @param {Object} e Set cancel to true on this object to cancel the close.
38061 "beforeclose": true,
38064 * Fires when this tab is closed.
38065 * @param {Roo.TabPanelItem} this
38069 * @event deactivate
38070 * Fires when this tab is no longer the active tab.
38071 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38072 * @param {Roo.TabPanelItem} this
38074 "deactivate" : true
38076 this.hidden = false;
38078 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38081 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38083 purgeListeners : function(){
38084 Roo.util.Observable.prototype.purgeListeners.call(this);
38085 this.el.removeAllListeners();
38088 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38091 this.pnode.addClass("active");
38094 this.tabPanel.stripWrap.repaint();
38096 this.fireEvent("activate", this.tabPanel, this);
38100 * Returns true if this tab is the active tab.
38101 * @return {Boolean}
38103 isActive : function(){
38104 return this.tabPanel.getActiveTab() == this;
38108 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38111 this.pnode.removeClass("active");
38113 this.fireEvent("deactivate", this.tabPanel, this);
38116 hideAction : function(){
38117 this.bodyEl.hide();
38118 this.bodyEl.setStyle("position", "absolute");
38119 this.bodyEl.setLeft("-20000px");
38120 this.bodyEl.setTop("-20000px");
38123 showAction : function(){
38124 this.bodyEl.setStyle("position", "relative");
38125 this.bodyEl.setTop("");
38126 this.bodyEl.setLeft("");
38127 this.bodyEl.show();
38131 * Set the tooltip for the tab.
38132 * @param {String} tooltip The tab's tooltip
38134 setTooltip : function(text){
38135 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38136 this.textEl.dom.qtip = text;
38137 this.textEl.dom.removeAttribute('title');
38139 this.textEl.dom.title = text;
38143 onTabClick : function(e){
38144 e.preventDefault();
38145 this.tabPanel.activate(this.id);
38148 onTabMouseDown : function(e){
38149 e.preventDefault();
38150 this.tabPanel.activate(this.id);
38153 getWidth : function(){
38154 return this.inner.getWidth();
38157 setWidth : function(width){
38158 var iwidth = width - this.pnode.getPadding("lr");
38159 this.inner.setWidth(iwidth);
38160 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38161 this.pnode.setWidth(width);
38165 * Show or hide the tab
38166 * @param {Boolean} hidden True to hide or false to show.
38168 setHidden : function(hidden){
38169 this.hidden = hidden;
38170 this.pnode.setStyle("display", hidden ? "none" : "");
38174 * Returns true if this tab is "hidden"
38175 * @return {Boolean}
38177 isHidden : function(){
38178 return this.hidden;
38182 * Returns the text for this tab
38185 getText : function(){
38189 autoSize : function(){
38190 //this.el.beginMeasure();
38191 this.textEl.setWidth(1);
38193 * #2804 [new] Tabs in Roojs
38194 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38196 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38197 //this.el.endMeasure();
38201 * Sets the text for the tab (Note: this also sets the tooltip text)
38202 * @param {String} text The tab's text and tooltip
38204 setText : function(text){
38206 this.textEl.update(text);
38207 this.setTooltip(text);
38208 //if(!this.tabPanel.resizeTabs){
38209 // this.autoSize();
38213 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38215 activate : function(){
38216 this.tabPanel.activate(this.id);
38220 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38222 disable : function(){
38223 if(this.tabPanel.active != this){
38224 this.disabled = true;
38225 this.pnode.addClass("disabled");
38230 * Enables this TabPanelItem if it was previously disabled.
38232 enable : function(){
38233 this.disabled = false;
38234 this.pnode.removeClass("disabled");
38238 * Sets the content for this TabPanelItem.
38239 * @param {String} content The content
38240 * @param {Boolean} loadScripts true to look for and load scripts
38242 setContent : function(content, loadScripts){
38243 this.bodyEl.update(content, loadScripts);
38247 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38248 * @return {Roo.UpdateManager} The UpdateManager
38250 getUpdateManager : function(){
38251 return this.bodyEl.getUpdateManager();
38255 * Set a URL to be used to load the content for this TabPanelItem.
38256 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38257 * @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)
38258 * @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)
38259 * @return {Roo.UpdateManager} The UpdateManager
38261 setUrl : function(url, params, loadOnce){
38262 if(this.refreshDelegate){
38263 this.un('activate', this.refreshDelegate);
38265 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38266 this.on("activate", this.refreshDelegate);
38267 return this.bodyEl.getUpdateManager();
38271 _handleRefresh : function(url, params, loadOnce){
38272 if(!loadOnce || !this.loaded){
38273 var updater = this.bodyEl.getUpdateManager();
38274 updater.update(url, params, this._setLoaded.createDelegate(this));
38279 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38280 * Will fail silently if the setUrl method has not been called.
38281 * This does not activate the panel, just updates its content.
38283 refresh : function(){
38284 if(this.refreshDelegate){
38285 this.loaded = false;
38286 this.refreshDelegate();
38291 _setLoaded : function(){
38292 this.loaded = true;
38296 closeClick : function(e){
38299 this.fireEvent("beforeclose", this, o);
38300 if(o.cancel !== true){
38301 this.tabPanel.removeTab(this.id);
38305 * The text displayed in the tooltip for the close icon.
38308 closeText : "Close this tab"
38311 * This script refer to:
38312 * Title: International Telephone Input
38313 * Author: Jack O'Connor
38314 * Code version: v12.1.12
38315 * Availability: https://github.com/jackocnr/intl-tel-input.git
38318 Roo.bootstrap.PhoneInputData = function() {
38321 "Afghanistan (افغانستان)",
38326 "Albania (Shqipëri)",
38331 "Algeria (الجزائر)",
38356 "Antigua and Barbuda",
38366 "Armenia (Հայաստան)",
38382 "Austria (Österreich)",
38387 "Azerbaijan (Azərbaycan)",
38397 "Bahrain (البحرين)",
38402 "Bangladesh (বাংলাদেশ)",
38412 "Belarus (Беларусь)",
38417 "Belgium (België)",
38447 "Bosnia and Herzegovina (Босна и Херцеговина)",
38462 "British Indian Ocean Territory",
38467 "British Virgin Islands",
38477 "Bulgaria (България)",
38487 "Burundi (Uburundi)",
38492 "Cambodia (កម្ពុជា)",
38497 "Cameroon (Cameroun)",
38506 ["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"]
38509 "Cape Verde (Kabu Verdi)",
38514 "Caribbean Netherlands",
38525 "Central African Republic (République centrafricaine)",
38545 "Christmas Island",
38551 "Cocos (Keeling) Islands",
38562 "Comoros (جزر القمر)",
38567 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38572 "Congo (Republic) (Congo-Brazzaville)",
38592 "Croatia (Hrvatska)",
38613 "Czech Republic (Česká republika)",
38618 "Denmark (Danmark)",
38633 "Dominican Republic (República Dominicana)",
38637 ["809", "829", "849"]
38655 "Equatorial Guinea (Guinea Ecuatorial)",
38675 "Falkland Islands (Islas Malvinas)",
38680 "Faroe Islands (Føroyar)",
38701 "French Guiana (Guyane française)",
38706 "French Polynesia (Polynésie française)",
38721 "Georgia (საქართველო)",
38726 "Germany (Deutschland)",
38746 "Greenland (Kalaallit Nunaat)",
38783 "Guinea-Bissau (Guiné Bissau)",
38808 "Hungary (Magyarország)",
38813 "Iceland (Ísland)",
38833 "Iraq (العراق)",
38849 "Israel (ישראל)",
38876 "Jordan (الأردن)",
38881 "Kazakhstan (Казахстан)",
38902 "Kuwait (الكويت)",
38907 "Kyrgyzstan (Кыргызстан)",
38917 "Latvia (Latvija)",
38922 "Lebanon (لبنان)",
38937 "Libya (ليبيا)",
38947 "Lithuania (Lietuva)",
38962 "Macedonia (FYROM) (Македонија)",
38967 "Madagascar (Madagasikara)",
38997 "Marshall Islands",
39007 "Mauritania (موريتانيا)",
39012 "Mauritius (Moris)",
39033 "Moldova (Republica Moldova)",
39043 "Mongolia (Монгол)",
39048 "Montenegro (Crna Gora)",
39058 "Morocco (المغرب)",
39064 "Mozambique (Moçambique)",
39069 "Myanmar (Burma) (မြန်မာ)",
39074 "Namibia (Namibië)",
39089 "Netherlands (Nederland)",
39094 "New Caledonia (Nouvelle-Calédonie)",
39129 "North Korea (조선 민주주의 인민 공화국)",
39134 "Northern Mariana Islands",
39150 "Pakistan (پاکستان)",
39160 "Palestine (فلسطين)",
39170 "Papua New Guinea",
39212 "Réunion (La Réunion)",
39218 "Romania (România)",
39234 "Saint Barthélemy",
39245 "Saint Kitts and Nevis",
39255 "Saint Martin (Saint-Martin (partie française))",
39261 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39266 "Saint Vincent and the Grenadines",
39281 "São Tomé and Príncipe (São Tomé e Príncipe)",
39286 "Saudi Arabia (المملكة العربية السعودية)",
39291 "Senegal (Sénégal)",
39321 "Slovakia (Slovensko)",
39326 "Slovenia (Slovenija)",
39336 "Somalia (Soomaaliya)",
39346 "South Korea (대한민국)",
39351 "South Sudan (جنوب السودان)",
39361 "Sri Lanka (ශ්රී ලංකාව)",
39366 "Sudan (السودان)",
39376 "Svalbard and Jan Mayen",
39387 "Sweden (Sverige)",
39392 "Switzerland (Schweiz)",
39397 "Syria (سوريا)",
39442 "Trinidad and Tobago",
39447 "Tunisia (تونس)",
39452 "Turkey (Türkiye)",
39462 "Turks and Caicos Islands",
39472 "U.S. Virgin Islands",
39482 "Ukraine (Україна)",
39487 "United Arab Emirates (الإمارات العربية المتحدة)",
39509 "Uzbekistan (Oʻzbekiston)",
39519 "Vatican City (Città del Vaticano)",
39530 "Vietnam (Việt Nam)",
39535 "Wallis and Futuna (Wallis-et-Futuna)",
39540 "Western Sahara (الصحراء الغربية)",
39546 "Yemen (اليمن)",
39570 * This script refer to:
39571 * Title: International Telephone Input
39572 * Author: Jack O'Connor
39573 * Code version: v12.1.12
39574 * Availability: https://github.com/jackocnr/intl-tel-input.git
39578 * @class Roo.bootstrap.PhoneInput
39579 * @extends Roo.bootstrap.TriggerField
39580 * An input with International dial-code selection
39582 * @cfg {String} defaultDialCode default '+852'
39583 * @cfg {Array} preferedCountries default []
39586 * Create a new PhoneInput.
39587 * @param {Object} config Configuration options
39590 Roo.bootstrap.PhoneInput = function(config) {
39591 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39594 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39596 listWidth: undefined,
39598 selectedClass: 'active',
39600 invalidClass : "has-warning",
39602 validClass: 'has-success',
39604 allowed: '0123456789',
39607 * @cfg {String} defaultDialCode The default dial code when initializing the input
39609 defaultDialCode: '+852',
39612 * @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
39614 preferedCountries: false,
39616 getAutoCreate : function()
39618 var data = Roo.bootstrap.PhoneInputData();
39619 var align = this.labelAlign || this.parentLabelAlign();
39622 this.allCountries = [];
39623 this.dialCodeMapping = [];
39625 for (var i = 0; i < data.length; i++) {
39627 this.allCountries[i] = {
39631 priority: c[3] || 0,
39632 areaCodes: c[4] || null
39634 this.dialCodeMapping[c[2]] = {
39637 priority: c[3] || 0,
39638 areaCodes: c[4] || null
39650 cls : 'form-control tel-input',
39651 autocomplete: 'new-password'
39654 var hiddenInput = {
39657 cls: 'hidden-tel-input'
39661 hiddenInput.name = this.name;
39664 if (this.disabled) {
39665 input.disabled = true;
39668 var flag_container = {
39685 cls: this.hasFeedback ? 'has-feedback' : '',
39691 cls: 'dial-code-holder',
39698 cls: 'roo-select2-container input-group',
39705 if (this.fieldLabel.length) {
39708 tooltip: 'This field is required'
39714 cls: 'control-label',
39720 html: this.fieldLabel
39723 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39729 if(this.indicatorpos == 'right') {
39730 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39737 if(align == 'left') {
39745 if(this.labelWidth > 12){
39746 label.style = "width: " + this.labelWidth + 'px';
39748 if(this.labelWidth < 13 && this.labelmd == 0){
39749 this.labelmd = this.labelWidth;
39751 if(this.labellg > 0){
39752 label.cls += ' col-lg-' + this.labellg;
39753 input.cls += ' col-lg-' + (12 - this.labellg);
39755 if(this.labelmd > 0){
39756 label.cls += ' col-md-' + this.labelmd;
39757 container.cls += ' col-md-' + (12 - this.labelmd);
39759 if(this.labelsm > 0){
39760 label.cls += ' col-sm-' + this.labelsm;
39761 container.cls += ' col-sm-' + (12 - this.labelsm);
39763 if(this.labelxs > 0){
39764 label.cls += ' col-xs-' + this.labelxs;
39765 container.cls += ' col-xs-' + (12 - this.labelxs);
39775 var settings = this;
39777 ['xs','sm','md','lg'].map(function(size){
39778 if (settings[size]) {
39779 cfg.cls += ' col-' + size + '-' + settings[size];
39783 this.store = new Roo.data.Store({
39784 proxy : new Roo.data.MemoryProxy({}),
39785 reader : new Roo.data.JsonReader({
39796 'name' : 'dialCode',
39800 'name' : 'priority',
39804 'name' : 'areaCodes',
39811 if(!this.preferedCountries) {
39812 this.preferedCountries = [
39819 var p = this.preferedCountries.reverse();
39822 for (var i = 0; i < p.length; i++) {
39823 for (var j = 0; j < this.allCountries.length; j++) {
39824 if(this.allCountries[j].iso2 == p[i]) {
39825 var t = this.allCountries[j];
39826 this.allCountries.splice(j,1);
39827 this.allCountries.unshift(t);
39833 this.store.proxy.data = {
39835 data: this.allCountries
39841 initEvents : function()
39844 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39846 this.indicator = this.indicatorEl();
39847 this.flag = this.flagEl();
39848 this.dialCodeHolder = this.dialCodeHolderEl();
39850 this.trigger = this.el.select('div.flag-box',true).first();
39851 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39856 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39857 _this.list.setWidth(lw);
39860 this.list.on('mouseover', this.onViewOver, this);
39861 this.list.on('mousemove', this.onViewMove, this);
39862 this.inputEl().on("keyup", this.onKeyUp, this);
39864 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39866 this.view = new Roo.View(this.list, this.tpl, {
39867 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39870 this.view.on('click', this.onViewClick, this);
39871 this.setValue(this.defaultDialCode);
39874 onTriggerClick : function(e)
39876 Roo.log('trigger click');
39881 if(this.isExpanded()){
39883 this.hasFocus = false;
39885 this.store.load({});
39886 this.hasFocus = true;
39891 isExpanded : function()
39893 return this.list.isVisible();
39896 collapse : function()
39898 if(!this.isExpanded()){
39902 Roo.get(document).un('mousedown', this.collapseIf, this);
39903 Roo.get(document).un('mousewheel', this.collapseIf, this);
39904 this.fireEvent('collapse', this);
39908 expand : function()
39912 if(this.isExpanded() || !this.hasFocus){
39916 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39917 this.list.setWidth(lw);
39920 this.restrictHeight();
39922 Roo.get(document).on('mousedown', this.collapseIf, this);
39923 Roo.get(document).on('mousewheel', this.collapseIf, this);
39925 this.fireEvent('expand', this);
39928 restrictHeight : function()
39930 this.list.alignTo(this.inputEl(), this.listAlign);
39931 this.list.alignTo(this.inputEl(), this.listAlign);
39934 onViewOver : function(e, t)
39936 if(this.inKeyMode){
39939 var item = this.view.findItemFromChild(t);
39942 var index = this.view.indexOf(item);
39943 this.select(index, false);
39948 onViewClick : function(view, doFocus, el, e)
39950 var index = this.view.getSelectedIndexes()[0];
39952 var r = this.store.getAt(index);
39955 this.onSelect(r, index);
39957 if(doFocus !== false && !this.blockFocus){
39958 this.inputEl().focus();
39962 onViewMove : function(e, t)
39964 this.inKeyMode = false;
39967 select : function(index, scrollIntoView)
39969 this.selectedIndex = index;
39970 this.view.select(index);
39971 if(scrollIntoView !== false){
39972 var el = this.view.getNode(index);
39974 this.list.scrollChildIntoView(el, false);
39979 createList : function()
39981 this.list = Roo.get(document.body).createChild({
39983 cls: 'typeahead typeahead-long dropdown-menu tel-list',
39984 style: 'display:none'
39986 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
39989 collapseIf : function(e)
39991 var in_combo = e.within(this.el);
39992 var in_list = e.within(this.list);
39993 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
39995 if (in_combo || in_list || is_list) {
40001 onSelect : function(record, index)
40003 if(this.fireEvent('beforeselect', this, record, index) !== false){
40005 this.setFlagClass(record.data.iso2);
40006 this.setDialCode(record.data.dialCode);
40007 this.hasFocus = false;
40009 this.fireEvent('select', this, record, index);
40013 flagEl : function()
40015 var flag = this.el.select('div.flag',true).first();
40022 dialCodeHolderEl : function()
40024 var d = this.el.select('input.dial-code-holder',true).first();
40031 setDialCode : function(v)
40033 this.dialCodeHolder.dom.value = '+'+v;
40036 setFlagClass : function(n)
40038 this.flag.dom.className = 'flag '+n;
40041 getValue : function()
40043 var v = this.inputEl().getValue();
40044 if(this.dialCodeHolder) {
40045 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40050 setValue : function(v)
40052 var d = this.getDialCode(v);
40054 //invalid dial code
40055 if(v.length == 0 || !d || d.length == 0) {
40057 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40058 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40064 this.setFlagClass(this.dialCodeMapping[d].iso2);
40065 this.setDialCode(d);
40066 this.inputEl().dom.value = v.replace('+'+d,'');
40067 this.hiddenEl().dom.value = this.getValue();
40072 getDialCode : function(v = '')
40074 if (v.length == 0) {
40075 return this.dialCodeHolder.dom.value;
40079 if (v.charAt(0) != "+") {
40082 var numericChars = "";
40083 for (var i = 1; i < v.length; i++) {
40084 var c = v.charAt(i);
40087 if (this.dialCodeMapping[numericChars]) {
40088 dialCode = v.substr(1, i);
40090 if (numericChars.length == 4) {
40100 this.setValue(this.defaultDialCode);
40104 hiddenEl : function()
40106 return this.el.select('input.hidden-tel-input',true).first();
40109 onKeyUp : function(e){
40111 var k = e.getKey();
40112 var c = e.getCharCode();
40115 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40116 this.allowed.indexOf(String.fromCharCode(c)) === -1
40121 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40124 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40128 this.setValue(this.getValue());
40133 * @class Roo.bootstrap.MoneyField
40134 * @extends Roo.bootstrap.ComboBox
40135 * Bootstrap MoneyField class
40138 * Create a new MoneyField.
40139 * @param {Object} config Configuration options
40142 Roo.bootstrap.MoneyField = function(config) {
40144 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40148 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40151 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40153 allowDecimals : true,
40155 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40157 decimalSeparator : ".",
40159 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40161 decimalPrecision : 0,
40163 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40165 allowNegative : true,
40167 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40169 minValue : Number.NEGATIVE_INFINITY,
40171 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40173 maxValue : Number.MAX_VALUE,
40175 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40177 minText : "The minimum value for this field is {0}",
40179 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40181 maxText : "The maximum value for this field is {0}",
40183 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40184 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40186 nanText : "{0} is not a valid number",
40188 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40192 * @cfg {String} defaults currency of the MoneyField
40193 * value should be in lkey
40195 defaultCurrency : false,
40197 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40199 thousandsDelimiter : false,
40209 getAutoCreate : function()
40211 var align = this.labelAlign || this.parentLabelAlign();
40223 cls : 'form-control roo-money-amount-input',
40224 autocomplete: 'new-password'
40227 var hiddenInput = {
40231 cls: 'hidden-number-input'
40235 hiddenInput.name = this.name;
40238 if (this.disabled) {
40239 input.disabled = true;
40242 var clg = 12 - this.inputlg;
40243 var cmd = 12 - this.inputmd;
40244 var csm = 12 - this.inputsm;
40245 var cxs = 12 - this.inputxs;
40249 cls : 'row roo-money-field',
40253 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40257 cls: 'roo-select2-container input-group',
40261 cls : 'form-control roo-money-currency-input',
40262 autocomplete: 'new-password',
40264 name : this.currencyName
40268 cls : 'input-group-addon',
40282 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40286 cls: this.hasFeedback ? 'has-feedback' : '',
40297 if (this.fieldLabel.length) {
40300 tooltip: 'This field is required'
40306 cls: 'control-label',
40312 html: this.fieldLabel
40315 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40321 if(this.indicatorpos == 'right') {
40322 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40329 if(align == 'left') {
40337 if(this.labelWidth > 12){
40338 label.style = "width: " + this.labelWidth + 'px';
40340 if(this.labelWidth < 13 && this.labelmd == 0){
40341 this.labelmd = this.labelWidth;
40343 if(this.labellg > 0){
40344 label.cls += ' col-lg-' + this.labellg;
40345 input.cls += ' col-lg-' + (12 - this.labellg);
40347 if(this.labelmd > 0){
40348 label.cls += ' col-md-' + this.labelmd;
40349 container.cls += ' col-md-' + (12 - this.labelmd);
40351 if(this.labelsm > 0){
40352 label.cls += ' col-sm-' + this.labelsm;
40353 container.cls += ' col-sm-' + (12 - this.labelsm);
40355 if(this.labelxs > 0){
40356 label.cls += ' col-xs-' + this.labelxs;
40357 container.cls += ' col-xs-' + (12 - this.labelxs);
40368 var settings = this;
40370 ['xs','sm','md','lg'].map(function(size){
40371 if (settings[size]) {
40372 cfg.cls += ' col-' + size + '-' + settings[size];
40379 initEvents : function()
40381 this.indicator = this.indicatorEl();
40383 this.initCurrencyEvent();
40385 this.initNumberEvent();
40388 initCurrencyEvent : function()
40391 throw "can not find store for combo";
40394 this.store = Roo.factory(this.store, Roo.data);
40395 this.store.parent = this;
40399 this.triggerEl = this.el.select('.input-group-addon', true).first();
40401 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40406 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40407 _this.list.setWidth(lw);
40410 this.list.on('mouseover', this.onViewOver, this);
40411 this.list.on('mousemove', this.onViewMove, this);
40412 this.list.on('scroll', this.onViewScroll, this);
40415 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40418 this.view = new Roo.View(this.list, this.tpl, {
40419 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40422 this.view.on('click', this.onViewClick, this);
40424 this.store.on('beforeload', this.onBeforeLoad, this);
40425 this.store.on('load', this.onLoad, this);
40426 this.store.on('loadexception', this.onLoadException, this);
40428 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40429 "up" : function(e){
40430 this.inKeyMode = true;
40434 "down" : function(e){
40435 if(!this.isExpanded()){
40436 this.onTriggerClick();
40438 this.inKeyMode = true;
40443 "enter" : function(e){
40446 if(this.fireEvent("specialkey", this, e)){
40447 this.onViewClick(false);
40453 "esc" : function(e){
40457 "tab" : function(e){
40460 if(this.fireEvent("specialkey", this, e)){
40461 this.onViewClick(false);
40469 doRelay : function(foo, bar, hname){
40470 if(hname == 'down' || this.scope.isExpanded()){
40471 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40479 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40483 initNumberEvent : function(e)
40485 this.inputEl().on("keydown" , this.fireKey, this);
40486 this.inputEl().on("focus", this.onFocus, this);
40487 this.inputEl().on("blur", this.onBlur, this);
40489 this.inputEl().relayEvent('keyup', this);
40491 if(this.indicator){
40492 this.indicator.addClass('invisible');
40495 this.originalValue = this.getValue();
40497 if(this.validationEvent == 'keyup'){
40498 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40499 this.inputEl().on('keyup', this.filterValidation, this);
40501 else if(this.validationEvent !== false){
40502 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40505 if(this.selectOnFocus){
40506 this.on("focus", this.preFocus, this);
40509 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40510 this.inputEl().on("keypress", this.filterKeys, this);
40512 this.inputEl().relayEvent('keypress', this);
40515 var allowed = "0123456789";
40517 if(this.allowDecimals){
40518 allowed += this.decimalSeparator;
40521 if(this.allowNegative){
40525 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40527 var keyPress = function(e){
40529 var k = e.getKey();
40531 var c = e.getCharCode();
40534 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40535 allowed.indexOf(String.fromCharCode(c)) === -1
40541 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40545 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40550 this.inputEl().on("keypress", keyPress, this);
40554 onTriggerClick : function(e)
40561 this.loadNext = false;
40563 if(this.isExpanded()){
40568 this.hasFocus = true;
40570 if(this.triggerAction == 'all') {
40571 this.doQuery(this.allQuery, true);
40575 this.doQuery(this.getRawValue());
40578 getCurrency : function()
40580 var v = this.currencyEl().getValue();
40585 restrictHeight : function()
40587 this.list.alignTo(this.currencyEl(), this.listAlign);
40588 this.list.alignTo(this.currencyEl(), this.listAlign);
40591 onViewClick : function(view, doFocus, el, e)
40593 var index = this.view.getSelectedIndexes()[0];
40595 var r = this.store.getAt(index);
40598 this.onSelect(r, index);
40602 onSelect : function(record, index){
40604 if(this.fireEvent('beforeselect', this, record, index) !== false){
40606 this.setFromCurrencyData(index > -1 ? record.data : false);
40610 this.fireEvent('select', this, record, index);
40614 setFromCurrencyData : function(o)
40618 this.lastCurrency = o;
40620 if (this.currencyField) {
40621 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40623 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40626 this.lastSelectionText = currency;
40628 //setting default currency
40629 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40630 this.setCurrency(this.defaultCurrency);
40634 this.setCurrency(currency);
40637 setFromData : function(o)
40641 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40643 this.setFromCurrencyData(c);
40648 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40650 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40653 this.setValue(value);
40657 setCurrency : function(v)
40659 this.currencyValue = v;
40662 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40667 setValue : function(v)
40669 v = this.fixPrecision(v);
40671 v = String(v).replace(".", this.decimalSeparator);
40677 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40679 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40680 this.thousandsDelimiter || ','
40683 if(this.allowBlank && !v) {
40684 this.inputEl().dom.value = '';
40691 getRawValue : function()
40693 var v = this.inputEl().getValue();
40698 getValue : function()
40700 return this.fixPrecision(this.parseValue(this.getRawValue()));
40703 parseValue : function(value)
40705 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40706 return isNaN(value) ? '' : value;
40709 fixPrecision : function(value)
40711 var nan = isNaN(value);
40713 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40714 return nan ? '' : value;
40717 return parseFloat(value).toFixed(this.decimalPrecision);
40720 decimalPrecisionFcn : function(v)
40722 return Math.floor(v);
40725 validateValue : function(value)
40727 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40731 var num = this.parseValue(value);
40734 this.markInvalid(String.format(this.nanText, value));
40738 if(num < this.minValue){
40739 this.markInvalid(String.format(this.minText, this.minValue));
40743 if(num > this.maxValue){
40744 this.markInvalid(String.format(this.maxText, this.maxValue));
40751 validate : function()
40753 if(this.disabled || this.allowBlank){
40758 var currency = this.getCurrency();
40760 if(this.validateValue(this.getRawValue()) && currency.length){
40765 this.markInvalid();
40769 getName: function()
40774 beforeBlur : function()
40780 var v = this.parseValue(this.getRawValue());
40787 onBlur : function()
40791 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40792 //this.el.removeClass(this.focusClass);
40795 this.hasFocus = false;
40797 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40801 var v = this.getValue();
40803 if(String(v) !== String(this.startValue)){
40804 this.fireEvent('change', this, v, this.startValue);
40807 this.fireEvent("blur", this);
40810 inputEl : function()
40812 return this.el.select('.roo-money-amount-input', true).first();
40815 currencyEl : function()
40817 return this.el.select('.roo-money-currency-input', true).first();
40820 hiddenEl : function()
40822 return this.el.select('input.hidden-number-input',true).first();