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 is it a slidy toggle button
566 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567 * @cfg {String} ontext text for on toggle state
568 * @cfg {String} offtext text for off toggle state
569 * @cfg {Boolean} defaulton
570 * @cfg {Boolean} preventDefault default true
571 * @cfg {Boolean} removeClass remove the standard class..
572 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
575 * Create a new button
576 * @param {Object} config The config object
580 Roo.bootstrap.Button = function(config){
581 Roo.bootstrap.Button.superclass.constructor.call(this, config);
582 this.weightClass = ["btn-default",
594 * When a butotn is pressed
595 * @param {Roo.bootstrap.Button} btn
596 * @param {Roo.EventObject} e
601 * After the button has been toggles
602 * @param {Roo.bootstrap.Button} btn
603 * @param {Roo.EventObject} e
604 * @param {boolean} pressed (also available as button.pressed)
610 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
628 preventDefault: true,
637 getAutoCreate : function(){
645 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
646 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
651 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
653 if (this.toggle == true) {
656 cls: 'slider-frame roo-button',
661 'data-off-text':'OFF',
662 cls: 'slider-button',
668 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
669 cfg.cls += ' '+this.weight;
678 cfg["aria-hidden"] = true;
680 cfg.html = "×";
686 if (this.theme==='default') {
687 cfg.cls = 'btn roo-button';
689 //if (this.parentType != 'Navbar') {
690 this.weight = this.weight.length ? this.weight : 'default';
692 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
694 cfg.cls += ' btn-' + this.weight;
696 } else if (this.theme==='glow') {
699 cfg.cls = 'btn-glow roo-button';
701 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
703 cfg.cls += ' ' + this.weight;
709 this.cls += ' inverse';
713 if (this.active || this.pressed === true) {
714 cfg.cls += ' active';
718 cfg.disabled = 'disabled';
722 Roo.log('changing to ul' );
724 this.glyphicon = 'caret';
727 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
729 //gsRoo.log(this.parentType);
730 if (this.parentType === 'Navbar' && !this.parent().bar) {
731 Roo.log('changing to li?');
740 href : this.href || '#'
743 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
744 cfg.cls += ' dropdown';
751 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
753 if (this.glyphicon) {
754 cfg.html = ' ' + cfg.html;
759 cls: 'glyphicon glyphicon-' + this.glyphicon
769 // cfg.cls='btn roo-button';
773 var value = cfg.html;
778 cls: 'glyphicon glyphicon-' + this.glyphicon,
797 cfg.cls += ' dropdown';
798 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
801 if (cfg.tag !== 'a' && this.href !== '') {
802 throw "Tag must be a to set href.";
803 } else if (this.href.length > 0) {
804 cfg.href = this.href;
807 if(this.removeClass){
812 cfg.target = this.target;
817 initEvents: function() {
818 // Roo.log('init events?');
819 // Roo.log(this.el.dom);
822 if (typeof (this.menu) != 'undefined') {
823 this.menu.parentType = this.xtype;
824 this.menu.triggerEl = this.el;
825 this.addxtype(Roo.apply({}, this.menu));
829 if (this.el.hasClass('roo-button')) {
830 this.el.on('click', this.onClick, this);
832 this.el.select('.roo-button').on('click', this.onClick, this);
835 if(this.removeClass){
836 this.el.on('click', this.onClick, this);
839 this.el.enableDisplayMode();
842 onClick : function(e)
849 Roo.log('button on click ');
850 if(this.preventDefault){
854 if (this.pressed === true || this.pressed === false) {
855 this.pressed = !this.pressed;
856 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
857 this.fireEvent('toggle', this, e, this.pressed);
861 this.fireEvent('click', this, e);
865 * Enables this button
869 this.disabled = false;
870 this.el.removeClass('disabled');
874 * Disable this button
878 this.disabled = true;
879 this.el.addClass('disabled');
882 * sets the active state on/off,
883 * @param {Boolean} state (optional) Force a particular state
885 setActive : function(v) {
887 this.el[v ? 'addClass' : 'removeClass']('active');
891 * toggles the current active state
893 toggleActive : function()
895 var active = this.el.hasClass('active');
896 this.setActive(!active);
901 * get the current active state
902 * @return {boolean} true if it's active
904 isActive : function()
906 return this.el.hasClass('active');
909 * set the text of the first selected button
911 setText : function(str)
913 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
916 * get the text of the first selected button
920 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
931 setWeight : function(str)
933 this.el.removeClass(this.weightClass);
934 this.el.addClass('btn-' + str);
948 * @class Roo.bootstrap.Column
949 * @extends Roo.bootstrap.Component
950 * Bootstrap Column class
951 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
952 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
953 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
954 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
955 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
956 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
957 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
958 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
961 * @cfg {Boolean} hidden (true|false) hide the element
962 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
963 * @cfg {String} fa (ban|check|...) font awesome icon
964 * @cfg {Number} fasize (1|2|....) font awsome size
966 * @cfg {String} icon (info-sign|check|...) glyphicon name
968 * @cfg {String} html content of column.
971 * Create a new Column
972 * @param {Object} config The config object
975 Roo.bootstrap.Column = function(config){
976 Roo.bootstrap.Column.superclass.constructor.call(this, config);
979 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
997 getAutoCreate : function(){
998 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1006 ['xs','sm','md','lg'].map(function(size){
1007 //Roo.log( size + ':' + settings[size]);
1009 if (settings[size+'off'] !== false) {
1010 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1013 if (settings[size] === false) {
1017 if (!settings[size]) { // 0 = hidden
1018 cfg.cls += ' hidden-' + size;
1021 cfg.cls += ' col-' + size + '-' + settings[size];
1026 cfg.cls += ' hidden';
1029 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1030 cfg.cls +=' alert alert-' + this.alert;
1034 if (this.html.length) {
1035 cfg.html = this.html;
1039 if (this.fasize > 1) {
1040 fasize = ' fa-' + this.fasize + 'x';
1042 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1047 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1066 * @class Roo.bootstrap.Container
1067 * @extends Roo.bootstrap.Component
1068 * Bootstrap Container class
1069 * @cfg {Boolean} jumbotron is it a jumbotron element
1070 * @cfg {String} html content of element
1071 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1072 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1073 * @cfg {String} header content of header (for panel)
1074 * @cfg {String} footer content of footer (for panel)
1075 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1076 * @cfg {String} tag (header|aside|section) type of HTML tag.
1077 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1078 * @cfg {String} fa font awesome icon
1079 * @cfg {String} icon (info-sign|check|...) glyphicon name
1080 * @cfg {Boolean} hidden (true|false) hide the element
1081 * @cfg {Boolean} expandable (true|false) default false
1082 * @cfg {Boolean} expanded (true|false) default true
1083 * @cfg {String} rheader contet on the right of header
1084 * @cfg {Boolean} clickable (true|false) default false
1088 * Create a new Container
1089 * @param {Object} config The config object
1092 Roo.bootstrap.Container = function(config){
1093 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1099 * After the panel has been expand
1101 * @param {Roo.bootstrap.Container} this
1106 * After the panel has been collapsed
1108 * @param {Roo.bootstrap.Container} this
1113 * When a element is chick
1114 * @param {Roo.bootstrap.Container} this
1115 * @param {Roo.EventObject} e
1121 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1139 getChildContainer : function() {
1145 if (this.panel.length) {
1146 return this.el.select('.panel-body',true).first();
1153 getAutoCreate : function(){
1156 tag : this.tag || 'div',
1160 if (this.jumbotron) {
1161 cfg.cls = 'jumbotron';
1166 // - this is applied by the parent..
1168 // cfg.cls = this.cls + '';
1171 if (this.sticky.length) {
1173 var bd = Roo.get(document.body);
1174 if (!bd.hasClass('bootstrap-sticky')) {
1175 bd.addClass('bootstrap-sticky');
1176 Roo.select('html',true).setStyle('height', '100%');
1179 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1183 if (this.well.length) {
1184 switch (this.well) {
1187 cfg.cls +=' well well-' +this.well;
1196 cfg.cls += ' hidden';
1200 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1201 cfg.cls +=' alert alert-' + this.alert;
1206 if (this.panel.length) {
1207 cfg.cls += ' panel panel-' + this.panel;
1209 if (this.header.length) {
1213 if(this.expandable){
1215 cfg.cls = cfg.cls + ' expandable';
1219 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1227 cls : 'panel-title',
1228 html : (this.expandable ? ' ' : '') + this.header
1232 cls: 'panel-header-right',
1238 cls : 'panel-heading',
1239 style : this.expandable ? 'cursor: pointer' : '',
1247 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1252 if (this.footer.length) {
1254 cls : 'panel-footer',
1263 body.html = this.html || cfg.html;
1264 // prefix with the icons..
1266 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1269 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1274 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1275 cfg.cls = 'container';
1281 initEvents: function()
1283 if(this.expandable){
1284 var headerEl = this.headerEl();
1287 headerEl.on('click', this.onToggleClick, this);
1292 this.el.on('click', this.onClick, this);
1297 onToggleClick : function()
1299 var headerEl = this.headerEl();
1315 if(this.fireEvent('expand', this)) {
1317 this.expanded = true;
1319 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1321 this.el.select('.panel-body',true).first().removeClass('hide');
1323 var toggleEl = this.toggleEl();
1329 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1334 collapse : function()
1336 if(this.fireEvent('collapse', this)) {
1338 this.expanded = false;
1340 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1341 this.el.select('.panel-body',true).first().addClass('hide');
1343 var toggleEl = this.toggleEl();
1349 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1353 toggleEl : function()
1355 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1359 return this.el.select('.panel-heading .fa',true).first();
1362 headerEl : function()
1364 if(!this.el || !this.panel.length || !this.header.length){
1368 return this.el.select('.panel-heading',true).first()
1373 if(!this.el || !this.panel.length){
1377 return this.el.select('.panel-body',true).first()
1380 titleEl : function()
1382 if(!this.el || !this.panel.length || !this.header.length){
1386 return this.el.select('.panel-title',true).first();
1389 setTitle : function(v)
1391 var titleEl = this.titleEl();
1397 titleEl.dom.innerHTML = v;
1400 getTitle : function()
1403 var titleEl = this.titleEl();
1409 return titleEl.dom.innerHTML;
1412 setRightTitle : function(v)
1414 var t = this.el.select('.panel-header-right',true).first();
1420 t.dom.innerHTML = v;
1423 onClick : function(e)
1427 this.fireEvent('click', this, e);
1440 * @class Roo.bootstrap.Img
1441 * @extends Roo.bootstrap.Component
1442 * Bootstrap Img class
1443 * @cfg {Boolean} imgResponsive false | true
1444 * @cfg {String} border rounded | circle | thumbnail
1445 * @cfg {String} src image source
1446 * @cfg {String} alt image alternative text
1447 * @cfg {String} href a tag href
1448 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1449 * @cfg {String} xsUrl xs image source
1450 * @cfg {String} smUrl sm image source
1451 * @cfg {String} mdUrl md image source
1452 * @cfg {String} lgUrl lg image source
1455 * Create a new Input
1456 * @param {Object} config The config object
1459 Roo.bootstrap.Img = function(config){
1460 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1466 * The img click event for the img.
1467 * @param {Roo.EventObject} e
1473 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1475 imgResponsive: true,
1485 getAutoCreate : function()
1487 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1488 return this.createSingleImg();
1493 cls: 'roo-image-responsive-group',
1498 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1500 if(!_this[size + 'Url']){
1506 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1507 html: _this.html || cfg.html,
1508 src: _this[size + 'Url']
1511 img.cls += ' roo-image-responsive-' + size;
1513 var s = ['xs', 'sm', 'md', 'lg'];
1515 s.splice(s.indexOf(size), 1);
1517 Roo.each(s, function(ss){
1518 img.cls += ' hidden-' + ss;
1521 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1522 cfg.cls += ' img-' + _this.border;
1526 cfg.alt = _this.alt;
1539 a.target = _this.target;
1543 cfg.cn.push((_this.href) ? a : img);
1550 createSingleImg : function()
1554 cls: (this.imgResponsive) ? 'img-responsive' : '',
1556 src : 'about:blank' // just incase src get's set to undefined?!?
1559 cfg.html = this.html || cfg.html;
1561 cfg.src = this.src || cfg.src;
1563 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1564 cfg.cls += ' img-' + this.border;
1581 a.target = this.target;
1586 return (this.href) ? a : cfg;
1589 initEvents: function()
1592 this.el.on('click', this.onClick, this);
1597 onClick : function(e)
1599 Roo.log('img onclick');
1600 this.fireEvent('click', this, e);
1603 * Sets the url of the image - used to update it
1604 * @param {String} url the url of the image
1607 setSrc : function(url)
1611 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1612 this.el.dom.src = url;
1616 this.el.select('img', true).first().dom.src = url;
1632 * @class Roo.bootstrap.Link
1633 * @extends Roo.bootstrap.Component
1634 * Bootstrap Link Class
1635 * @cfg {String} alt image alternative text
1636 * @cfg {String} href a tag href
1637 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1638 * @cfg {String} html the content of the link.
1639 * @cfg {String} anchor name for the anchor link
1640 * @cfg {String} fa - favicon
1642 * @cfg {Boolean} preventDefault (true | false) default false
1646 * Create a new Input
1647 * @param {Object} config The config object
1650 Roo.bootstrap.Link = function(config){
1651 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1657 * The img click event for the img.
1658 * @param {Roo.EventObject} e
1664 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1668 preventDefault: false,
1674 getAutoCreate : function()
1676 var html = this.html || '';
1678 if (this.fa !== false) {
1679 html = '<i class="fa fa-' + this.fa + '"></i>';
1684 // anchor's do not require html/href...
1685 if (this.anchor === false) {
1687 cfg.href = this.href || '#';
1689 cfg.name = this.anchor;
1690 if (this.html !== false || this.fa !== false) {
1693 if (this.href !== false) {
1694 cfg.href = this.href;
1698 if(this.alt !== false){
1703 if(this.target !== false) {
1704 cfg.target = this.target;
1710 initEvents: function() {
1712 if(!this.href || this.preventDefault){
1713 this.el.on('click', this.onClick, this);
1717 onClick : function(e)
1719 if(this.preventDefault){
1722 //Roo.log('img onclick');
1723 this.fireEvent('click', this, e);
1736 * @class Roo.bootstrap.Header
1737 * @extends Roo.bootstrap.Component
1738 * Bootstrap Header class
1739 * @cfg {String} html content of header
1740 * @cfg {Number} level (1|2|3|4|5|6) default 1
1743 * Create a new Header
1744 * @param {Object} config The config object
1748 Roo.bootstrap.Header = function(config){
1749 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1752 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1760 getAutoCreate : function(){
1765 tag: 'h' + (1 *this.level),
1766 html: this.html || ''
1778 * Ext JS Library 1.1.1
1779 * Copyright(c) 2006-2007, Ext JS, LLC.
1781 * Originally Released Under LGPL - original licence link has changed is not relivant.
1784 * <script type="text/javascript">
1788 * @class Roo.bootstrap.MenuMgr
1789 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1792 Roo.bootstrap.MenuMgr = function(){
1793 var menus, active, groups = {}, attached = false, lastShow = new Date();
1795 // private - called when first menu is created
1798 active = new Roo.util.MixedCollection();
1799 Roo.get(document).addKeyListener(27, function(){
1800 if(active.length > 0){
1808 if(active && active.length > 0){
1809 var c = active.clone();
1819 if(active.length < 1){
1820 Roo.get(document).un("mouseup", onMouseDown);
1828 var last = active.last();
1829 lastShow = new Date();
1832 Roo.get(document).on("mouseup", onMouseDown);
1837 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1838 m.parentMenu.activeChild = m;
1839 }else if(last && last.isVisible()){
1840 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1845 function onBeforeHide(m){
1847 m.activeChild.hide();
1849 if(m.autoHideTimer){
1850 clearTimeout(m.autoHideTimer);
1851 delete m.autoHideTimer;
1856 function onBeforeShow(m){
1857 var pm = m.parentMenu;
1858 if(!pm && !m.allowOtherMenus){
1860 }else if(pm && pm.activeChild && active != m){
1861 pm.activeChild.hide();
1865 // private this should really trigger on mouseup..
1866 function onMouseDown(e){
1867 Roo.log("on Mouse Up");
1869 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1870 Roo.log("MenuManager hideAll");
1879 function onBeforeCheck(mi, state){
1881 var g = groups[mi.group];
1882 for(var i = 0, l = g.length; i < l; i++){
1884 g[i].setChecked(false);
1893 * Hides all menus that are currently visible
1895 hideAll : function(){
1900 register : function(menu){
1904 menus[menu.id] = menu;
1905 menu.on("beforehide", onBeforeHide);
1906 menu.on("hide", onHide);
1907 menu.on("beforeshow", onBeforeShow);
1908 menu.on("show", onShow);
1910 if(g && menu.events["checkchange"]){
1914 groups[g].push(menu);
1915 menu.on("checkchange", onCheck);
1920 * Returns a {@link Roo.menu.Menu} object
1921 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1922 * be used to generate and return a new Menu instance.
1924 get : function(menu){
1925 if(typeof menu == "string"){ // menu id
1927 }else if(menu.events){ // menu instance
1930 /*else if(typeof menu.length == 'number'){ // array of menu items?
1931 return new Roo.bootstrap.Menu({items:menu});
1932 }else{ // otherwise, must be a config
1933 return new Roo.bootstrap.Menu(menu);
1940 unregister : function(menu){
1941 delete menus[menu.id];
1942 menu.un("beforehide", onBeforeHide);
1943 menu.un("hide", onHide);
1944 menu.un("beforeshow", onBeforeShow);
1945 menu.un("show", onShow);
1947 if(g && menu.events["checkchange"]){
1948 groups[g].remove(menu);
1949 menu.un("checkchange", onCheck);
1954 registerCheckable : function(menuItem){
1955 var g = menuItem.group;
1960 groups[g].push(menuItem);
1961 menuItem.on("beforecheckchange", onBeforeCheck);
1966 unregisterCheckable : function(menuItem){
1967 var g = menuItem.group;
1969 groups[g].remove(menuItem);
1970 menuItem.un("beforecheckchange", onBeforeCheck);
1982 * @class Roo.bootstrap.Menu
1983 * @extends Roo.bootstrap.Component
1984 * Bootstrap Menu class - container for MenuItems
1985 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1986 * @cfg {bool} hidden if the menu should be hidden when rendered.
1987 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1988 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1992 * @param {Object} config The config object
1996 Roo.bootstrap.Menu = function(config){
1997 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1998 if (this.registerMenu && this.type != 'treeview') {
1999 Roo.bootstrap.MenuMgr.register(this);
2004 * Fires before this menu is displayed
2005 * @param {Roo.menu.Menu} this
2010 * Fires before this menu is hidden
2011 * @param {Roo.menu.Menu} this
2016 * Fires after this menu is displayed
2017 * @param {Roo.menu.Menu} this
2022 * Fires after this menu is hidden
2023 * @param {Roo.menu.Menu} this
2028 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2029 * @param {Roo.menu.Menu} this
2030 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2031 * @param {Roo.EventObject} e
2036 * Fires when the mouse is hovering over this menu
2037 * @param {Roo.menu.Menu} this
2038 * @param {Roo.EventObject} e
2039 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2044 * Fires when the mouse exits this menu
2045 * @param {Roo.menu.Menu} this
2046 * @param {Roo.EventObject} e
2047 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2052 * Fires when a menu item contained in this menu is clicked
2053 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2054 * @param {Roo.EventObject} e
2058 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2061 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2065 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2068 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2070 registerMenu : true,
2072 menuItems :false, // stores the menu items..
2082 getChildContainer : function() {
2086 getAutoCreate : function(){
2088 //if (['right'].indexOf(this.align)!==-1) {
2089 // cfg.cn[1].cls += ' pull-right'
2095 cls : 'dropdown-menu' ,
2096 style : 'z-index:1000'
2100 if (this.type === 'submenu') {
2101 cfg.cls = 'submenu active';
2103 if (this.type === 'treeview') {
2104 cfg.cls = 'treeview-menu';
2109 initEvents : function() {
2111 // Roo.log("ADD event");
2112 // Roo.log(this.triggerEl.dom);
2114 this.triggerEl.on('click', this.onTriggerClick, this);
2116 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2118 this.triggerEl.addClass('dropdown-toggle');
2121 this.el.on('touchstart' , this.onTouch, this);
2123 this.el.on('click' , this.onClick, this);
2125 this.el.on("mouseover", this.onMouseOver, this);
2126 this.el.on("mouseout", this.onMouseOut, this);
2130 findTargetItem : function(e)
2132 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2136 //Roo.log(t); Roo.log(t.id);
2138 //Roo.log(this.menuitems);
2139 return this.menuitems.get(t.id);
2141 //return this.items.get(t.menuItemId);
2147 onTouch : function(e)
2149 Roo.log("menu.onTouch");
2150 //e.stopEvent(); this make the user popdown broken
2154 onClick : function(e)
2156 Roo.log("menu.onClick");
2158 var t = this.findTargetItem(e);
2159 if(!t || t.isContainer){
2164 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2165 if(t == this.activeItem && t.shouldDeactivate(e)){
2166 this.activeItem.deactivate();
2167 delete this.activeItem;
2171 this.setActiveItem(t, true);
2179 Roo.log('pass click event');
2183 this.fireEvent("click", this, t, e);
2187 if(!t.href.length || t.href == '#'){
2188 (function() { _this.hide(); }).defer(100);
2193 onMouseOver : function(e){
2194 var t = this.findTargetItem(e);
2197 // if(t.canActivate && !t.disabled){
2198 // this.setActiveItem(t, true);
2202 this.fireEvent("mouseover", this, e, t);
2204 isVisible : function(){
2205 return !this.hidden;
2207 onMouseOut : function(e){
2208 var t = this.findTargetItem(e);
2211 // if(t == this.activeItem && t.shouldDeactivate(e)){
2212 // this.activeItem.deactivate();
2213 // delete this.activeItem;
2216 this.fireEvent("mouseout", this, e, t);
2221 * Displays this menu relative to another element
2222 * @param {String/HTMLElement/Roo.Element} element The element to align to
2223 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2224 * the element (defaults to this.defaultAlign)
2225 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2227 show : function(el, pos, parentMenu){
2228 this.parentMenu = parentMenu;
2232 this.fireEvent("beforeshow", this);
2233 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2236 * Displays this menu at a specific xy position
2237 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2238 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2240 showAt : function(xy, parentMenu, /* private: */_e){
2241 this.parentMenu = parentMenu;
2246 this.fireEvent("beforeshow", this);
2247 //xy = this.el.adjustForConstraints(xy);
2251 this.hideMenuItems();
2252 this.hidden = false;
2253 this.triggerEl.addClass('open');
2255 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2256 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2259 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2264 this.fireEvent("show", this);
2270 this.doFocus.defer(50, this);
2274 doFocus : function(){
2276 this.focusEl.focus();
2281 * Hides this menu and optionally all parent menus
2282 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2284 hide : function(deep)
2287 this.hideMenuItems();
2288 if(this.el && this.isVisible()){
2289 this.fireEvent("beforehide", this);
2290 if(this.activeItem){
2291 this.activeItem.deactivate();
2292 this.activeItem = null;
2294 this.triggerEl.removeClass('open');;
2296 this.fireEvent("hide", this);
2298 if(deep === true && this.parentMenu){
2299 this.parentMenu.hide(true);
2303 onTriggerClick : function(e)
2305 Roo.log('trigger click');
2307 var target = e.getTarget();
2309 Roo.log(target.nodeName.toLowerCase());
2311 if(target.nodeName.toLowerCase() === 'i'){
2317 onTriggerPress : function(e)
2319 Roo.log('trigger press');
2320 //Roo.log(e.getTarget());
2321 // Roo.log(this.triggerEl.dom);
2323 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2324 var pel = Roo.get(e.getTarget());
2325 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2326 Roo.log('is treeview or dropdown?');
2330 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2334 if (this.isVisible()) {
2339 this.show(this.triggerEl, false, false);
2342 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2349 hideMenuItems : function()
2351 Roo.log("hide Menu Items");
2355 //$(backdrop).remove()
2356 this.el.select('.open',true).each(function(aa) {
2358 aa.removeClass('open');
2359 //var parent = getParent($(this))
2360 //var relatedTarget = { relatedTarget: this }
2362 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2363 //if (e.isDefaultPrevented()) return
2364 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2367 addxtypeChild : function (tree, cntr) {
2368 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2370 this.menuitems.add(comp);
2382 this.getEl().dom.innerHTML = '';
2383 this.menuitems.clear();
2397 * @class Roo.bootstrap.MenuItem
2398 * @extends Roo.bootstrap.Component
2399 * Bootstrap MenuItem class
2400 * @cfg {String} html the menu label
2401 * @cfg {String} href the link
2402 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2403 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2404 * @cfg {Boolean} active used on sidebars to highlight active itesm
2405 * @cfg {String} fa favicon to show on left of menu item.
2406 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2410 * Create a new MenuItem
2411 * @param {Object} config The config object
2415 Roo.bootstrap.MenuItem = function(config){
2416 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2421 * The raw click event for the entire grid.
2422 * @param {Roo.bootstrap.MenuItem} this
2423 * @param {Roo.EventObject} e
2429 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2433 preventDefault: false,
2434 isContainer : false,
2438 getAutoCreate : function(){
2440 if(this.isContainer){
2443 cls: 'dropdown-menu-item'
2457 if (this.fa !== false) {
2460 cls : 'fa fa-' + this.fa
2469 cls: 'dropdown-menu-item',
2472 if (this.parent().type == 'treeview') {
2473 cfg.cls = 'treeview-menu';
2476 cfg.cls += ' active';
2481 anc.href = this.href || cfg.cn[0].href ;
2482 ctag.html = this.html || cfg.cn[0].html ;
2486 initEvents: function()
2488 if (this.parent().type == 'treeview') {
2489 this.el.select('a').on('click', this.onClick, this);
2493 this.menu.parentType = this.xtype;
2494 this.menu.triggerEl = this.el;
2495 this.menu = this.addxtype(Roo.apply({}, this.menu));
2499 onClick : function(e)
2501 Roo.log('item on click ');
2503 if(this.preventDefault){
2506 //this.parent().hideMenuItems();
2508 this.fireEvent('click', this, e);
2527 * @class Roo.bootstrap.MenuSeparator
2528 * @extends Roo.bootstrap.Component
2529 * Bootstrap MenuSeparator class
2532 * Create a new MenuItem
2533 * @param {Object} config The config object
2537 Roo.bootstrap.MenuSeparator = function(config){
2538 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2541 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2543 getAutoCreate : function(){
2562 * @class Roo.bootstrap.Modal
2563 * @extends Roo.bootstrap.Component
2564 * Bootstrap Modal class
2565 * @cfg {String} title Title of dialog
2566 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2567 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2568 * @cfg {Boolean} specificTitle default false
2569 * @cfg {Array} buttons Array of buttons or standard button set..
2570 * @cfg {String} buttonPosition (left|right|center) default right
2571 * @cfg {Boolean} animate default true
2572 * @cfg {Boolean} allow_close default true
2573 * @cfg {Boolean} fitwindow default false
2574 * @cfg {String} size (sm|lg) default empty
2578 * Create a new Modal Dialog
2579 * @param {Object} config The config object
2582 Roo.bootstrap.Modal = function(config){
2583 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2588 * The raw btnclick event for the button
2589 * @param {Roo.EventObject} e
2594 * Fire when dialog resize
2595 * @param {Roo.bootstrap.Modal} this
2596 * @param {Roo.EventObject} e
2600 this.buttons = this.buttons || [];
2603 this.tmpl = Roo.factory(this.tmpl);
2608 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2610 title : 'test dialog',
2620 specificTitle: false,
2622 buttonPosition: 'right',
2641 onRender : function(ct, position)
2643 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2646 var cfg = Roo.apply({}, this.getAutoCreate());
2649 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2651 //if (!cfg.name.length) {
2655 cfg.cls += ' ' + this.cls;
2658 cfg.style = this.style;
2660 this.el = Roo.get(document.body).createChild(cfg, position);
2662 //var type = this.el.dom.type;
2665 if(this.tabIndex !== undefined){
2666 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2669 this.dialogEl = this.el.select('.modal-dialog',true).first();
2670 this.bodyEl = this.el.select('.modal-body',true).first();
2671 this.closeEl = this.el.select('.modal-header .close', true).first();
2672 this.headerEl = this.el.select('.modal-header',true).first();
2673 this.titleEl = this.el.select('.modal-title',true).first();
2674 this.footerEl = this.el.select('.modal-footer',true).first();
2676 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2677 this.maskEl.enableDisplayMode("block");
2679 //this.el.addClass("x-dlg-modal");
2681 if (this.buttons.length) {
2682 Roo.each(this.buttons, function(bb) {
2683 var b = Roo.apply({}, bb);
2684 b.xns = b.xns || Roo.bootstrap;
2685 b.xtype = b.xtype || 'Button';
2686 if (typeof(b.listeners) == 'undefined') {
2687 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2690 var btn = Roo.factory(b);
2692 btn.render(this.el.select('.modal-footer div').first());
2696 // render the children.
2699 if(typeof(this.items) != 'undefined'){
2700 var items = this.items;
2703 for(var i =0;i < items.length;i++) {
2704 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2708 this.items = nitems;
2710 // where are these used - they used to be body/close/footer
2714 //this.el.addClass([this.fieldClass, this.cls]);
2718 getAutoCreate : function(){
2723 html : this.html || ''
2728 cls : 'modal-title',
2732 if(this.specificTitle){
2738 if (this.allow_close) {
2750 if(this.size.length){
2751 size = 'modal-' + this.size;
2756 style : 'display: none',
2759 cls: "modal-dialog " + size,
2762 cls : "modal-content",
2765 cls : 'modal-header',
2770 cls : 'modal-footer',
2774 cls: 'btn-' + this.buttonPosition
2791 modal.cls += ' fade';
2797 getChildContainer : function() {
2802 getButtonContainer : function() {
2803 return this.el.select('.modal-footer div',true).first();
2806 initEvents : function()
2808 if (this.allow_close) {
2809 this.closeEl.on('click', this.hide, this);
2811 Roo.EventManager.onWindowResize(this.resize, this, true);
2818 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2819 if (this.fitwindow) {
2820 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2821 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2826 setSize : function(w,h)
2836 if (!this.rendered) {
2840 this.el.setStyle('display', 'block');
2842 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2845 this.el.addClass('in');
2848 this.el.addClass('in');
2852 // not sure how we can show data in here..
2854 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2857 Roo.get(document.body).addClass("x-body-masked");
2859 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2860 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2865 this.fireEvent('show', this);
2867 // set zindex here - otherwise it appears to be ignored...
2868 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2871 this.items.forEach( function(e) {
2872 e.layout ? e.layout() : false;
2880 if(this.fireEvent("beforehide", this) !== false){
2882 Roo.get(document.body).removeClass("x-body-masked");
2883 this.el.removeClass('in');
2884 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2886 if(this.animate){ // why
2888 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2890 this.el.setStyle('display', 'none');
2892 this.fireEvent('hide', this);
2896 addButton : function(str, cb)
2900 var b = Roo.apply({}, { html : str } );
2901 b.xns = b.xns || Roo.bootstrap;
2902 b.xtype = b.xtype || 'Button';
2903 if (typeof(b.listeners) == 'undefined') {
2904 b.listeners = { click : cb.createDelegate(this) };
2907 var btn = Roo.factory(b);
2909 btn.render(this.el.select('.modal-footer div').first());
2915 setDefaultButton : function(btn)
2917 //this.el.select('.modal-footer').()
2921 resizeTo: function(w,h)
2925 this.dialogEl.setWidth(w);
2926 if (this.diff === false) {
2927 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2930 this.bodyEl.setHeight(h-this.diff);
2932 this.fireEvent('resize', this);
2935 setContentSize : function(w, h)
2939 onButtonClick: function(btn,e)
2942 this.fireEvent('btnclick', btn.name, e);
2945 * Set the title of the Dialog
2946 * @param {String} str new Title
2948 setTitle: function(str) {
2949 this.titleEl.dom.innerHTML = str;
2952 * Set the body of the Dialog
2953 * @param {String} str new Title
2955 setBody: function(str) {
2956 this.bodyEl.dom.innerHTML = str;
2959 * Set the body of the Dialog using the template
2960 * @param {Obj} data - apply this data to the template and replace the body contents.
2962 applyBody: function(obj)
2965 Roo.log("Error - using apply Body without a template");
2968 this.tmpl.overwrite(this.bodyEl, obj);
2974 Roo.apply(Roo.bootstrap.Modal, {
2976 * Button config that displays a single OK button
2985 * Button config that displays Yes and No buttons
3001 * Button config that displays OK and Cancel buttons
3016 * Button config that displays Yes, No and Cancel buttons
3040 * messagebox - can be used as a replace
3044 * @class Roo.MessageBox
3045 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3049 Roo.Msg.alert('Status', 'Changes saved successfully.');
3051 // Prompt for user data:
3052 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3054 // process text value...
3058 // Show a dialog using config options:
3060 title:'Save Changes?',
3061 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3062 buttons: Roo.Msg.YESNOCANCEL,
3069 Roo.bootstrap.MessageBox = function(){
3070 var dlg, opt, mask, waitTimer;
3071 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3072 var buttons, activeTextEl, bwidth;
3076 var handleButton = function(button){
3078 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3082 var handleHide = function(){
3084 dlg.el.removeClass(opt.cls);
3087 // Roo.TaskMgr.stop(waitTimer);
3088 // waitTimer = null;
3093 var updateButtons = function(b){
3096 buttons["ok"].hide();
3097 buttons["cancel"].hide();
3098 buttons["yes"].hide();
3099 buttons["no"].hide();
3100 //dlg.footer.dom.style.display = 'none';
3103 dlg.footerEl.dom.style.display = '';
3104 for(var k in buttons){
3105 if(typeof buttons[k] != "function"){
3108 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3109 width += buttons[k].el.getWidth()+15;
3119 var handleEsc = function(d, k, e){
3120 if(opt && opt.closable !== false){
3130 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3131 * @return {Roo.BasicDialog} The BasicDialog element
3133 getDialog : function(){
3135 dlg = new Roo.bootstrap.Modal( {
3138 //constraintoviewport:false,
3140 //collapsible : false,
3145 //buttonAlign:"center",
3146 closeClick : function(){
3147 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3150 handleButton("cancel");
3155 dlg.on("hide", handleHide);
3157 //dlg.addKeyListener(27, handleEsc);
3159 this.buttons = buttons;
3160 var bt = this.buttonText;
3161 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3162 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3163 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3164 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3166 bodyEl = dlg.bodyEl.createChild({
3168 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3169 '<textarea class="roo-mb-textarea"></textarea>' +
3170 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3172 msgEl = bodyEl.dom.firstChild;
3173 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3174 textboxEl.enableDisplayMode();
3175 textboxEl.addKeyListener([10,13], function(){
3176 if(dlg.isVisible() && opt && opt.buttons){
3179 }else if(opt.buttons.yes){
3180 handleButton("yes");
3184 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3185 textareaEl.enableDisplayMode();
3186 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3187 progressEl.enableDisplayMode();
3189 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3190 var pf = progressEl.dom.firstChild;
3192 pp = Roo.get(pf.firstChild);
3193 pp.setHeight(pf.offsetHeight);
3201 * Updates the message box body text
3202 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3203 * the XHTML-compliant non-breaking space character '&#160;')
3204 * @return {Roo.MessageBox} This message box
3206 updateText : function(text)
3208 if(!dlg.isVisible() && !opt.width){
3209 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3210 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3212 msgEl.innerHTML = text || ' ';
3214 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3215 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3217 Math.min(opt.width || cw , this.maxWidth),
3218 Math.max(opt.minWidth || this.minWidth, bwidth)
3221 activeTextEl.setWidth(w);
3223 if(dlg.isVisible()){
3224 dlg.fixedcenter = false;
3226 // to big, make it scroll. = But as usual stupid IE does not support
3229 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3230 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3231 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3233 bodyEl.dom.style.height = '';
3234 bodyEl.dom.style.overflowY = '';
3237 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3239 bodyEl.dom.style.overflowX = '';
3242 dlg.setContentSize(w, bodyEl.getHeight());
3243 if(dlg.isVisible()){
3244 dlg.fixedcenter = true;
3250 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3251 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3252 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3253 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3254 * @return {Roo.MessageBox} This message box
3256 updateProgress : function(value, text){
3258 this.updateText(text);
3261 if (pp) { // weird bug on my firefox - for some reason this is not defined
3262 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3263 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3269 * Returns true if the message box is currently displayed
3270 * @return {Boolean} True if the message box is visible, else false
3272 isVisible : function(){
3273 return dlg && dlg.isVisible();
3277 * Hides the message box if it is displayed
3280 if(this.isVisible()){
3286 * Displays a new message box, or reinitializes an existing message box, based on the config options
3287 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3288 * The following config object properties are supported:
3290 Property Type Description
3291 ---------- --------------- ------------------------------------------------------------------------------------
3292 animEl String/Element An id or Element from which the message box should animate as it opens and
3293 closes (defaults to undefined)
3294 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3295 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3296 closable Boolean False to hide the top-right close button (defaults to true). Note that
3297 progress and wait dialogs will ignore this property and always hide the
3298 close button as they can only be closed programmatically.
3299 cls String A custom CSS class to apply to the message box element
3300 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3301 displayed (defaults to 75)
3302 fn Function A callback function to execute after closing the dialog. The arguments to the
3303 function will be btn (the name of the button that was clicked, if applicable,
3304 e.g. "ok"), and text (the value of the active text field, if applicable).
3305 Progress and wait dialogs will ignore this option since they do not respond to
3306 user actions and can only be closed programmatically, so any required function
3307 should be called by the same code after it closes the dialog.
3308 icon String A CSS class that provides a background image to be used as an icon for
3309 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3310 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3311 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3312 modal Boolean False to allow user interaction with the page while the message box is
3313 displayed (defaults to true)
3314 msg String A string that will replace the existing message box body text (defaults
3315 to the XHTML-compliant non-breaking space character ' ')
3316 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3317 progress Boolean True to display a progress bar (defaults to false)
3318 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3319 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3320 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3321 title String The title text
3322 value String The string value to set into the active textbox element if displayed
3323 wait Boolean True to display a progress bar (defaults to false)
3324 width Number The width of the dialog in pixels
3331 msg: 'Please enter your address:',
3333 buttons: Roo.MessageBox.OKCANCEL,
3336 animEl: 'addAddressBtn'
3339 * @param {Object} config Configuration options
3340 * @return {Roo.MessageBox} This message box
3342 show : function(options)
3345 // this causes nightmares if you show one dialog after another
3346 // especially on callbacks..
3348 if(this.isVisible()){
3351 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3352 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3353 Roo.log("New Dialog Message:" + options.msg )
3354 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3355 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3358 var d = this.getDialog();
3360 d.setTitle(opt.title || " ");
3361 d.closeEl.setDisplayed(opt.closable !== false);
3362 activeTextEl = textboxEl;
3363 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3368 textareaEl.setHeight(typeof opt.multiline == "number" ?
3369 opt.multiline : this.defaultTextHeight);
3370 activeTextEl = textareaEl;
3379 progressEl.setDisplayed(opt.progress === true);
3380 this.updateProgress(0);
3381 activeTextEl.dom.value = opt.value || "";
3383 dlg.setDefaultButton(activeTextEl);
3385 var bs = opt.buttons;
3389 }else if(bs && bs.yes){
3390 db = buttons["yes"];
3392 dlg.setDefaultButton(db);
3394 bwidth = updateButtons(opt.buttons);
3395 this.updateText(opt.msg);
3397 d.el.addClass(opt.cls);
3399 d.proxyDrag = opt.proxyDrag === true;
3400 d.modal = opt.modal !== false;
3401 d.mask = opt.modal !== false ? mask : false;
3403 // force it to the end of the z-index stack so it gets a cursor in FF
3404 document.body.appendChild(dlg.el.dom);
3405 d.animateTarget = null;
3406 d.show(options.animEl);
3412 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3413 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3414 * and closing the message box when the process is complete.
3415 * @param {String} title The title bar text
3416 * @param {String} msg The message box body text
3417 * @return {Roo.MessageBox} This message box
3419 progress : function(title, msg){
3426 minWidth: this.minProgressWidth,
3433 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3434 * If a callback function is passed it will be called after the user clicks the button, and the
3435 * id of the button that was clicked will be passed as the only parameter to the callback
3436 * (could also be the top-right close button).
3437 * @param {String} title The title bar text
3438 * @param {String} msg The message box body text
3439 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3440 * @param {Object} scope (optional) The scope of the callback function
3441 * @return {Roo.MessageBox} This message box
3443 alert : function(title, msg, fn, scope)
3458 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3459 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3460 * You are responsible for closing the message box when the process is complete.
3461 * @param {String} msg The message box body text
3462 * @param {String} title (optional) The title bar text
3463 * @return {Roo.MessageBox} This message box
3465 wait : function(msg, title){
3476 waitTimer = Roo.TaskMgr.start({
3478 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3486 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3487 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3488 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3489 * @param {String} title The title bar text
3490 * @param {String} msg The message box body text
3491 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3492 * @param {Object} scope (optional) The scope of the callback function
3493 * @return {Roo.MessageBox} This message box
3495 confirm : function(title, msg, fn, scope){
3499 buttons: this.YESNO,
3508 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3509 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3510 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3511 * (could also be the top-right close button) and the text that was entered will be passed as the two
3512 * parameters to the callback.
3513 * @param {String} title The title bar text
3514 * @param {String} msg The message box body text
3515 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3516 * @param {Object} scope (optional) The scope of the callback function
3517 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3518 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3519 * @return {Roo.MessageBox} This message box
3521 prompt : function(title, msg, fn, scope, multiline){
3525 buttons: this.OKCANCEL,
3530 multiline: multiline,
3537 * Button config that displays a single OK button
3542 * Button config that displays Yes and No buttons
3545 YESNO : {yes:true, no:true},
3547 * Button config that displays OK and Cancel buttons
3550 OKCANCEL : {ok:true, cancel:true},
3552 * Button config that displays Yes, No and Cancel buttons
3555 YESNOCANCEL : {yes:true, no:true, cancel:true},
3558 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3561 defaultTextHeight : 75,
3563 * The maximum width in pixels of the message box (defaults to 600)
3568 * The minimum width in pixels of the message box (defaults to 100)
3573 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3574 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3577 minProgressWidth : 250,
3579 * An object containing the default button text strings that can be overriden for localized language support.
3580 * Supported properties are: ok, cancel, yes and no.
3581 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3594 * Shorthand for {@link Roo.MessageBox}
3596 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3597 Roo.Msg = Roo.Msg || Roo.MessageBox;
3606 * @class Roo.bootstrap.Navbar
3607 * @extends Roo.bootstrap.Component
3608 * Bootstrap Navbar class
3611 * Create a new Navbar
3612 * @param {Object} config The config object
3616 Roo.bootstrap.Navbar = function(config){
3617 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3621 * @event beforetoggle
3622 * Fire before toggle the menu
3623 * @param {Roo.EventObject} e
3625 "beforetoggle" : true
3629 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3638 getAutoCreate : function(){
3641 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3645 initEvents :function ()
3647 //Roo.log(this.el.select('.navbar-toggle',true));
3648 this.el.select('.navbar-toggle',true).on('click', function() {
3649 if(this.fireEvent('beforetoggle', this) !== false){
3650 this.el.select('.navbar-collapse',true).toggleClass('in');
3660 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3662 var size = this.el.getSize();
3663 this.maskEl.setSize(size.width, size.height);
3664 this.maskEl.enableDisplayMode("block");
3673 getChildContainer : function()
3675 if (this.el.select('.collapse').getCount()) {
3676 return this.el.select('.collapse',true).first();
3709 * @class Roo.bootstrap.NavSimplebar
3710 * @extends Roo.bootstrap.Navbar
3711 * Bootstrap Sidebar class
3713 * @cfg {Boolean} inverse is inverted color
3715 * @cfg {String} type (nav | pills | tabs)
3716 * @cfg {Boolean} arrangement stacked | justified
3717 * @cfg {String} align (left | right) alignment
3719 * @cfg {Boolean} main (true|false) main nav bar? default false
3720 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3722 * @cfg {String} tag (header|footer|nav|div) default is nav
3728 * Create a new Sidebar
3729 * @param {Object} config The config object
3733 Roo.bootstrap.NavSimplebar = function(config){
3734 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3737 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3753 getAutoCreate : function(){
3757 tag : this.tag || 'div',
3770 this.type = this.type || 'nav';
3771 if (['tabs','pills'].indexOf(this.type)!==-1) {
3772 cfg.cn[0].cls += ' nav-' + this.type
3776 if (this.type!=='nav') {
3777 Roo.log('nav type must be nav/tabs/pills')
3779 cfg.cn[0].cls += ' navbar-nav'
3785 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3786 cfg.cn[0].cls += ' nav-' + this.arrangement;
3790 if (this.align === 'right') {
3791 cfg.cn[0].cls += ' navbar-right';
3795 cfg.cls += ' navbar-inverse';
3822 * @class Roo.bootstrap.NavHeaderbar
3823 * @extends Roo.bootstrap.NavSimplebar
3824 * Bootstrap Sidebar class
3826 * @cfg {String} brand what is brand
3827 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3828 * @cfg {String} brand_href href of the brand
3829 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3830 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3831 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3832 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3835 * Create a new Sidebar
3836 * @param {Object} config The config object
3840 Roo.bootstrap.NavHeaderbar = function(config){
3841 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3845 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3852 desktopCenter : false,
3855 getAutoCreate : function(){
3858 tag: this.nav || 'nav',
3865 if (this.desktopCenter) {
3866 cn.push({cls : 'container', cn : []});
3873 cls: 'navbar-header',
3878 cls: 'navbar-toggle',
3879 'data-toggle': 'collapse',
3884 html: 'Toggle navigation'
3906 cls: 'collapse navbar-collapse',
3910 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3912 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3913 cfg.cls += ' navbar-' + this.position;
3915 // tag can override this..
3917 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3920 if (this.brand !== '') {
3923 href: this.brand_href ? this.brand_href : '#',
3924 cls: 'navbar-brand',
3932 cfg.cls += ' main-nav';
3940 getHeaderChildContainer : function()
3942 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3943 return this.el.select('.navbar-header',true).first();
3946 return this.getChildContainer();
3950 initEvents : function()
3952 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3954 if (this.autohide) {
3959 Roo.get(document).on('scroll',function(e) {
3960 var ns = Roo.get(document).getScroll().top;
3961 var os = prevScroll;
3965 ft.removeClass('slideDown');
3966 ft.addClass('slideUp');
3969 ft.removeClass('slideUp');
3970 ft.addClass('slideDown');
3991 * @class Roo.bootstrap.NavSidebar
3992 * @extends Roo.bootstrap.Navbar
3993 * Bootstrap Sidebar class
3996 * Create a new Sidebar
3997 * @param {Object} config The config object
4001 Roo.bootstrap.NavSidebar = function(config){
4002 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4005 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4007 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4009 getAutoCreate : function(){
4014 cls: 'sidebar sidebar-nav'
4036 * @class Roo.bootstrap.NavGroup
4037 * @extends Roo.bootstrap.Component
4038 * Bootstrap NavGroup class
4039 * @cfg {String} align (left|right)
4040 * @cfg {Boolean} inverse
4041 * @cfg {String} type (nav|pills|tab) default nav
4042 * @cfg {String} navId - reference Id for navbar.
4046 * Create a new nav group
4047 * @param {Object} config The config object
4050 Roo.bootstrap.NavGroup = function(config){
4051 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4054 Roo.bootstrap.NavGroup.register(this);
4058 * Fires when the active item changes
4059 * @param {Roo.bootstrap.NavGroup} this
4060 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4061 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4068 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4079 getAutoCreate : function()
4081 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4088 if (['tabs','pills'].indexOf(this.type)!==-1) {
4089 cfg.cls += ' nav-' + this.type
4091 if (this.type!=='nav') {
4092 Roo.log('nav type must be nav/tabs/pills')
4094 cfg.cls += ' navbar-nav'
4097 if (this.parent() && this.parent().sidebar) {
4100 cls: 'dashboard-menu sidebar-menu'
4106 if (this.form === true) {
4112 if (this.align === 'right') {
4113 cfg.cls += ' navbar-right';
4115 cfg.cls += ' navbar-left';
4119 if (this.align === 'right') {
4120 cfg.cls += ' navbar-right';
4124 cfg.cls += ' navbar-inverse';
4132 * sets the active Navigation item
4133 * @param {Roo.bootstrap.NavItem} the new current navitem
4135 setActiveItem : function(item)
4138 Roo.each(this.navItems, function(v){
4143 v.setActive(false, true);
4150 item.setActive(true, true);
4151 this.fireEvent('changed', this, item, prev);
4156 * gets the active Navigation item
4157 * @return {Roo.bootstrap.NavItem} the current navitem
4159 getActive : function()
4163 Roo.each(this.navItems, function(v){
4174 indexOfNav : function()
4178 Roo.each(this.navItems, function(v,i){
4189 * adds a Navigation item
4190 * @param {Roo.bootstrap.NavItem} the navitem to add
4192 addItem : function(cfg)
4194 var cn = new Roo.bootstrap.NavItem(cfg);
4196 cn.parentId = this.id;
4197 cn.onRender(this.el, null);
4201 * register a Navigation item
4202 * @param {Roo.bootstrap.NavItem} the navitem to add
4204 register : function(item)
4206 this.navItems.push( item);
4207 item.navId = this.navId;
4212 * clear all the Navigation item
4215 clearAll : function()
4218 this.el.dom.innerHTML = '';
4221 getNavItem: function(tabId)
4224 Roo.each(this.navItems, function(e) {
4225 if (e.tabId == tabId) {
4235 setActiveNext : function()
4237 var i = this.indexOfNav(this.getActive());
4238 if (i > this.navItems.length) {
4241 this.setActiveItem(this.navItems[i+1]);
4243 setActivePrev : function()
4245 var i = this.indexOfNav(this.getActive());
4249 this.setActiveItem(this.navItems[i-1]);
4251 clearWasActive : function(except) {
4252 Roo.each(this.navItems, function(e) {
4253 if (e.tabId != except.tabId && e.was_active) {
4254 e.was_active = false;
4261 getWasActive : function ()
4264 Roo.each(this.navItems, function(e) {
4279 Roo.apply(Roo.bootstrap.NavGroup, {
4283 * register a Navigation Group
4284 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4286 register : function(navgrp)
4288 this.groups[navgrp.navId] = navgrp;
4292 * fetch a Navigation Group based on the navigation ID
4293 * @param {string} the navgroup to add
4294 * @returns {Roo.bootstrap.NavGroup} the navgroup
4296 get: function(navId) {
4297 if (typeof(this.groups[navId]) == 'undefined') {
4299 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4301 return this.groups[navId] ;
4316 * @class Roo.bootstrap.NavItem
4317 * @extends Roo.bootstrap.Component
4318 * Bootstrap Navbar.NavItem class
4319 * @cfg {String} href link to
4320 * @cfg {String} html content of button
4321 * @cfg {String} badge text inside badge
4322 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4323 * @cfg {String} glyphicon name of glyphicon
4324 * @cfg {String} icon name of font awesome icon
4325 * @cfg {Boolean} active Is item active
4326 * @cfg {Boolean} disabled Is item disabled
4328 * @cfg {Boolean} preventDefault (true | false) default false
4329 * @cfg {String} tabId the tab that this item activates.
4330 * @cfg {String} tagtype (a|span) render as a href or span?
4331 * @cfg {Boolean} animateRef (true|false) link to element default false
4334 * Create a new Navbar Item
4335 * @param {Object} config The config object
4337 Roo.bootstrap.NavItem = function(config){
4338 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4343 * The raw click event for the entire grid.
4344 * @param {Roo.EventObject} e
4349 * Fires when the active item active state changes
4350 * @param {Roo.bootstrap.NavItem} this
4351 * @param {boolean} state the new state
4357 * Fires when scroll to element
4358 * @param {Roo.bootstrap.NavItem} this
4359 * @param {Object} options
4360 * @param {Roo.EventObject} e
4368 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4376 preventDefault : false,
4383 getAutoCreate : function(){
4392 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4394 if (this.disabled) {
4395 cfg.cls += ' disabled';
4398 if (this.href || this.html || this.glyphicon || this.icon) {
4402 href : this.href || "#",
4403 html: this.html || ''
4408 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4411 if(this.glyphicon) {
4412 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4417 cfg.cn[0].html += " <span class='caret'></span>";
4421 if (this.badge !== '') {
4423 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4431 initEvents: function()
4433 if (typeof (this.menu) != 'undefined') {
4434 this.menu.parentType = this.xtype;
4435 this.menu.triggerEl = this.el;
4436 this.menu = this.addxtype(Roo.apply({}, this.menu));
4439 this.el.select('a',true).on('click', this.onClick, this);
4441 if(this.tagtype == 'span'){
4442 this.el.select('span',true).on('click', this.onClick, this);
4445 // at this point parent should be available..
4446 this.parent().register(this);
4449 onClick : function(e)
4451 if (e.getTarget('.dropdown-menu-item')) {
4452 // did you click on a menu itemm.... - then don't trigger onclick..
4457 this.preventDefault ||
4460 Roo.log("NavItem - prevent Default?");
4464 if (this.disabled) {
4468 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4469 if (tg && tg.transition) {
4470 Roo.log("waiting for the transitionend");
4476 //Roo.log("fire event clicked");
4477 if(this.fireEvent('click', this, e) === false){
4481 if(this.tagtype == 'span'){
4485 //Roo.log(this.href);
4486 var ael = this.el.select('a',true).first();
4489 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4490 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4491 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4492 return; // ignore... - it's a 'hash' to another page.
4494 Roo.log("NavItem - prevent Default?");
4496 this.scrollToElement(e);
4500 var p = this.parent();
4502 if (['tabs','pills'].indexOf(p.type)!==-1) {
4503 if (typeof(p.setActiveItem) !== 'undefined') {
4504 p.setActiveItem(this);
4508 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4509 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4510 // remove the collapsed menu expand...
4511 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4515 isActive: function () {
4518 setActive : function(state, fire, is_was_active)
4520 if (this.active && !state && this.navId) {
4521 this.was_active = true;
4522 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4524 nv.clearWasActive(this);
4528 this.active = state;
4531 this.el.removeClass('active');
4532 } else if (!this.el.hasClass('active')) {
4533 this.el.addClass('active');
4536 this.fireEvent('changed', this, state);
4539 // show a panel if it's registered and related..
4541 if (!this.navId || !this.tabId || !state || is_was_active) {
4545 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4549 var pan = tg.getPanelByName(this.tabId);
4553 // if we can not flip to new panel - go back to old nav highlight..
4554 if (false == tg.showPanel(pan)) {
4555 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4557 var onav = nv.getWasActive();
4559 onav.setActive(true, false, true);
4568 // this should not be here...
4569 setDisabled : function(state)
4571 this.disabled = state;
4573 this.el.removeClass('disabled');
4574 } else if (!this.el.hasClass('disabled')) {
4575 this.el.addClass('disabled');
4581 * Fetch the element to display the tooltip on.
4582 * @return {Roo.Element} defaults to this.el
4584 tooltipEl : function()
4586 return this.el.select('' + this.tagtype + '', true).first();
4589 scrollToElement : function(e)
4591 var c = document.body;
4594 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4596 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4597 c = document.documentElement;
4600 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4606 var o = target.calcOffsetsTo(c);
4613 this.fireEvent('scrollto', this, options, e);
4615 Roo.get(c).scrollTo('top', options.value, true);
4628 * <span> icon </span>
4629 * <span> text </span>
4630 * <span>badge </span>
4634 * @class Roo.bootstrap.NavSidebarItem
4635 * @extends Roo.bootstrap.NavItem
4636 * Bootstrap Navbar.NavSidebarItem class
4637 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4638 * {Boolean} open is the menu open
4639 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4640 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4641 * {String} buttonSize (sm|md|lg)the extra classes for the button
4642 * {Boolean} showArrow show arrow next to the text (default true)
4644 * Create a new Navbar Button
4645 * @param {Object} config The config object
4647 Roo.bootstrap.NavSidebarItem = function(config){
4648 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4653 * The raw click event for the entire grid.
4654 * @param {Roo.EventObject} e
4659 * Fires when the active item active state changes
4660 * @param {Roo.bootstrap.NavSidebarItem} this
4661 * @param {boolean} state the new state
4669 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4671 badgeWeight : 'default',
4677 buttonWeight : 'default',
4683 getAutoCreate : function(){
4688 href : this.href || '#',
4694 if(this.buttonView){
4697 href : this.href || '#',
4698 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4711 cfg.cls += ' active';
4714 if (this.disabled) {
4715 cfg.cls += ' disabled';
4718 cfg.cls += ' open x-open';
4721 if (this.glyphicon || this.icon) {
4722 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4723 a.cn.push({ tag : 'i', cls : c }) ;
4726 if(!this.buttonView){
4729 html : this.html || ''
4736 if (this.badge !== '') {
4737 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4743 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4746 a.cls += ' dropdown-toggle treeview' ;
4752 initEvents : function()
4754 if (typeof (this.menu) != 'undefined') {
4755 this.menu.parentType = this.xtype;
4756 this.menu.triggerEl = this.el;
4757 this.menu = this.addxtype(Roo.apply({}, this.menu));
4760 this.el.on('click', this.onClick, this);
4762 if(this.badge !== ''){
4763 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4768 onClick : function(e)
4775 if(this.preventDefault){
4779 this.fireEvent('click', this);
4782 disable : function()
4784 this.setDisabled(true);
4789 this.setDisabled(false);
4792 setDisabled : function(state)
4794 if(this.disabled == state){
4798 this.disabled = state;
4801 this.el.addClass('disabled');
4805 this.el.removeClass('disabled');
4810 setActive : function(state)
4812 if(this.active == state){
4816 this.active = state;
4819 this.el.addClass('active');
4823 this.el.removeClass('active');
4828 isActive: function ()
4833 setBadge : function(str)
4839 this.badgeEl.dom.innerHTML = str;
4856 * @class Roo.bootstrap.Row
4857 * @extends Roo.bootstrap.Component
4858 * Bootstrap Row class (contains columns...)
4862 * @param {Object} config The config object
4865 Roo.bootstrap.Row = function(config){
4866 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4869 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4871 getAutoCreate : function(){
4890 * @class Roo.bootstrap.Element
4891 * @extends Roo.bootstrap.Component
4892 * Bootstrap Element class
4893 * @cfg {String} html contents of the element
4894 * @cfg {String} tag tag of the element
4895 * @cfg {String} cls class of the element
4896 * @cfg {Boolean} preventDefault (true|false) default false
4897 * @cfg {Boolean} clickable (true|false) default false
4900 * Create a new Element
4901 * @param {Object} config The config object
4904 Roo.bootstrap.Element = function(config){
4905 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4911 * When a element is chick
4912 * @param {Roo.bootstrap.Element} this
4913 * @param {Roo.EventObject} e
4919 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4924 preventDefault: false,
4927 getAutoCreate : function(){
4931 // cls: this.cls, double assign in parent class Component.js :: onRender
4938 initEvents: function()
4940 Roo.bootstrap.Element.superclass.initEvents.call(this);
4943 this.el.on('click', this.onClick, this);
4948 onClick : function(e)
4950 if(this.preventDefault){
4954 this.fireEvent('click', this, e);
4957 getValue : function()
4959 return this.el.dom.innerHTML;
4962 setValue : function(value)
4964 this.el.dom.innerHTML = value;
4979 * @class Roo.bootstrap.Pagination
4980 * @extends Roo.bootstrap.Component
4981 * Bootstrap Pagination class
4982 * @cfg {String} size xs | sm | md | lg
4983 * @cfg {Boolean} inverse false | true
4986 * Create a new Pagination
4987 * @param {Object} config The config object
4990 Roo.bootstrap.Pagination = function(config){
4991 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4994 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5000 getAutoCreate : function(){
5006 cfg.cls += ' inverse';
5012 cfg.cls += " " + this.cls;
5030 * @class Roo.bootstrap.PaginationItem
5031 * @extends Roo.bootstrap.Component
5032 * Bootstrap PaginationItem class
5033 * @cfg {String} html text
5034 * @cfg {String} href the link
5035 * @cfg {Boolean} preventDefault (true | false) default true
5036 * @cfg {Boolean} active (true | false) default false
5037 * @cfg {Boolean} disabled default false
5041 * Create a new PaginationItem
5042 * @param {Object} config The config object
5046 Roo.bootstrap.PaginationItem = function(config){
5047 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5052 * The raw click event for the entire grid.
5053 * @param {Roo.EventObject} e
5059 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5063 preventDefault: true,
5068 getAutoCreate : function(){
5074 href : this.href ? this.href : '#',
5075 html : this.html ? this.html : ''
5085 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5089 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5095 initEvents: function() {
5097 this.el.on('click', this.onClick, this);
5100 onClick : function(e)
5102 Roo.log('PaginationItem on click ');
5103 if(this.preventDefault){
5111 this.fireEvent('click', this, e);
5127 * @class Roo.bootstrap.Slider
5128 * @extends Roo.bootstrap.Component
5129 * Bootstrap Slider class
5132 * Create a new Slider
5133 * @param {Object} config The config object
5136 Roo.bootstrap.Slider = function(config){
5137 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5140 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5142 getAutoCreate : function(){
5146 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5150 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5162 * Ext JS Library 1.1.1
5163 * Copyright(c) 2006-2007, Ext JS, LLC.
5165 * Originally Released Under LGPL - original licence link has changed is not relivant.
5168 * <script type="text/javascript">
5173 * @class Roo.grid.ColumnModel
5174 * @extends Roo.util.Observable
5175 * This is the default implementation of a ColumnModel used by the Grid. It defines
5176 * the columns in the grid.
5179 var colModel = new Roo.grid.ColumnModel([
5180 {header: "Ticker", width: 60, sortable: true, locked: true},
5181 {header: "Company Name", width: 150, sortable: true},
5182 {header: "Market Cap.", width: 100, sortable: true},
5183 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5184 {header: "Employees", width: 100, sortable: true, resizable: false}
5189 * The config options listed for this class are options which may appear in each
5190 * individual column definition.
5191 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5193 * @param {Object} config An Array of column config objects. See this class's
5194 * config objects for details.
5196 Roo.grid.ColumnModel = function(config){
5198 * The config passed into the constructor
5200 this.config = config;
5203 // if no id, create one
5204 // if the column does not have a dataIndex mapping,
5205 // map it to the order it is in the config
5206 for(var i = 0, len = config.length; i < len; i++){
5208 if(typeof c.dataIndex == "undefined"){
5211 if(typeof c.renderer == "string"){
5212 c.renderer = Roo.util.Format[c.renderer];
5214 if(typeof c.id == "undefined"){
5217 if(c.editor && c.editor.xtype){
5218 c.editor = Roo.factory(c.editor, Roo.grid);
5220 if(c.editor && c.editor.isFormField){
5221 c.editor = new Roo.grid.GridEditor(c.editor);
5223 this.lookup[c.id] = c;
5227 * The width of columns which have no width specified (defaults to 100)
5230 this.defaultWidth = 100;
5233 * Default sortable of columns which have no sortable specified (defaults to false)
5236 this.defaultSortable = false;
5240 * @event widthchange
5241 * Fires when the width of a column changes.
5242 * @param {ColumnModel} this
5243 * @param {Number} columnIndex The column index
5244 * @param {Number} newWidth The new width
5246 "widthchange": true,
5248 * @event headerchange
5249 * Fires when the text of a header changes.
5250 * @param {ColumnModel} this
5251 * @param {Number} columnIndex The column index
5252 * @param {Number} newText The new header text
5254 "headerchange": true,
5256 * @event hiddenchange
5257 * Fires when a column is hidden or "unhidden".
5258 * @param {ColumnModel} this
5259 * @param {Number} columnIndex The column index
5260 * @param {Boolean} hidden true if hidden, false otherwise
5262 "hiddenchange": true,
5264 * @event columnmoved
5265 * Fires when a column is moved.
5266 * @param {ColumnModel} this
5267 * @param {Number} oldIndex
5268 * @param {Number} newIndex
5270 "columnmoved" : true,
5272 * @event columlockchange
5273 * Fires when a column's locked state is changed
5274 * @param {ColumnModel} this
5275 * @param {Number} colIndex
5276 * @param {Boolean} locked true if locked
5278 "columnlockchange" : true
5280 Roo.grid.ColumnModel.superclass.constructor.call(this);
5282 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5284 * @cfg {String} header The header text to display in the Grid view.
5287 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5288 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5289 * specified, the column's index is used as an index into the Record's data Array.
5292 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5293 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5296 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5297 * Defaults to the value of the {@link #defaultSortable} property.
5298 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5301 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5304 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5307 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5310 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5313 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5314 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5315 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5316 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5319 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5322 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5325 * @cfg {String} cursor (Optional)
5328 * @cfg {String} tooltip (Optional)
5331 * @cfg {Number} xs (Optional)
5334 * @cfg {Number} sm (Optional)
5337 * @cfg {Number} md (Optional)
5340 * @cfg {Number} lg (Optional)
5343 * Returns the id of the column at the specified index.
5344 * @param {Number} index The column index
5345 * @return {String} the id
5347 getColumnId : function(index){
5348 return this.config[index].id;
5352 * Returns the column for a specified id.
5353 * @param {String} id The column id
5354 * @return {Object} the column
5356 getColumnById : function(id){
5357 return this.lookup[id];
5362 * Returns the column for a specified dataIndex.
5363 * @param {String} dataIndex The column dataIndex
5364 * @return {Object|Boolean} the column or false if not found
5366 getColumnByDataIndex: function(dataIndex){
5367 var index = this.findColumnIndex(dataIndex);
5368 return index > -1 ? this.config[index] : false;
5372 * Returns the index for a specified column id.
5373 * @param {String} id The column id
5374 * @return {Number} the index, or -1 if not found
5376 getIndexById : function(id){
5377 for(var i = 0, len = this.config.length; i < len; i++){
5378 if(this.config[i].id == id){
5386 * Returns the index for a specified column dataIndex.
5387 * @param {String} dataIndex The column dataIndex
5388 * @return {Number} the index, or -1 if not found
5391 findColumnIndex : function(dataIndex){
5392 for(var i = 0, len = this.config.length; i < len; i++){
5393 if(this.config[i].dataIndex == dataIndex){
5401 moveColumn : function(oldIndex, newIndex){
5402 var c = this.config[oldIndex];
5403 this.config.splice(oldIndex, 1);
5404 this.config.splice(newIndex, 0, c);
5405 this.dataMap = null;
5406 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5409 isLocked : function(colIndex){
5410 return this.config[colIndex].locked === true;
5413 setLocked : function(colIndex, value, suppressEvent){
5414 if(this.isLocked(colIndex) == value){
5417 this.config[colIndex].locked = value;
5419 this.fireEvent("columnlockchange", this, colIndex, value);
5423 getTotalLockedWidth : function(){
5425 for(var i = 0; i < this.config.length; i++){
5426 if(this.isLocked(i) && !this.isHidden(i)){
5427 this.totalWidth += this.getColumnWidth(i);
5433 getLockedCount : function(){
5434 for(var i = 0, len = this.config.length; i < len; i++){
5435 if(!this.isLocked(i)){
5440 return this.config.length;
5444 * Returns the number of columns.
5447 getColumnCount : function(visibleOnly){
5448 if(visibleOnly === true){
5450 for(var i = 0, len = this.config.length; i < len; i++){
5451 if(!this.isHidden(i)){
5457 return this.config.length;
5461 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5462 * @param {Function} fn
5463 * @param {Object} scope (optional)
5464 * @return {Array} result
5466 getColumnsBy : function(fn, scope){
5468 for(var i = 0, len = this.config.length; i < len; i++){
5469 var c = this.config[i];
5470 if(fn.call(scope||this, c, i) === true){
5478 * Returns true if the specified column is sortable.
5479 * @param {Number} col The column index
5482 isSortable : function(col){
5483 if(typeof this.config[col].sortable == "undefined"){
5484 return this.defaultSortable;
5486 return this.config[col].sortable;
5490 * Returns the rendering (formatting) function defined for the column.
5491 * @param {Number} col The column index.
5492 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5494 getRenderer : function(col){
5495 if(!this.config[col].renderer){
5496 return Roo.grid.ColumnModel.defaultRenderer;
5498 return this.config[col].renderer;
5502 * Sets the rendering (formatting) function for a column.
5503 * @param {Number} col The column index
5504 * @param {Function} fn The function to use to process the cell's raw data
5505 * to return HTML markup for the grid view. The render function is called with
5506 * the following parameters:<ul>
5507 * <li>Data value.</li>
5508 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5509 * <li>css A CSS style string to apply to the table cell.</li>
5510 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5511 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5512 * <li>Row index</li>
5513 * <li>Column index</li>
5514 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5516 setRenderer : function(col, fn){
5517 this.config[col].renderer = fn;
5521 * Returns the width for the specified column.
5522 * @param {Number} col The column index
5525 getColumnWidth : function(col){
5526 return this.config[col].width * 1 || this.defaultWidth;
5530 * Sets the width for a column.
5531 * @param {Number} col The column index
5532 * @param {Number} width The new width
5534 setColumnWidth : function(col, width, suppressEvent){
5535 this.config[col].width = width;
5536 this.totalWidth = null;
5538 this.fireEvent("widthchange", this, col, width);
5543 * Returns the total width of all columns.
5544 * @param {Boolean} includeHidden True to include hidden column widths
5547 getTotalWidth : function(includeHidden){
5548 if(!this.totalWidth){
5549 this.totalWidth = 0;
5550 for(var i = 0, len = this.config.length; i < len; i++){
5551 if(includeHidden || !this.isHidden(i)){
5552 this.totalWidth += this.getColumnWidth(i);
5556 return this.totalWidth;
5560 * Returns the header for the specified column.
5561 * @param {Number} col The column index
5564 getColumnHeader : function(col){
5565 return this.config[col].header;
5569 * Sets the header for a column.
5570 * @param {Number} col The column index
5571 * @param {String} header The new header
5573 setColumnHeader : function(col, header){
5574 this.config[col].header = header;
5575 this.fireEvent("headerchange", this, col, header);
5579 * Returns the tooltip for the specified column.
5580 * @param {Number} col The column index
5583 getColumnTooltip : function(col){
5584 return this.config[col].tooltip;
5587 * Sets the tooltip for a column.
5588 * @param {Number} col The column index
5589 * @param {String} tooltip The new tooltip
5591 setColumnTooltip : function(col, tooltip){
5592 this.config[col].tooltip = tooltip;
5596 * Returns the dataIndex for the specified column.
5597 * @param {Number} col The column index
5600 getDataIndex : function(col){
5601 return this.config[col].dataIndex;
5605 * Sets the dataIndex for a column.
5606 * @param {Number} col The column index
5607 * @param {Number} dataIndex The new dataIndex
5609 setDataIndex : function(col, dataIndex){
5610 this.config[col].dataIndex = dataIndex;
5616 * Returns true if the cell is editable.
5617 * @param {Number} colIndex The column index
5618 * @param {Number} rowIndex The row index - this is nto actually used..?
5621 isCellEditable : function(colIndex, rowIndex){
5622 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5626 * Returns the editor defined for the cell/column.
5627 * return false or null to disable editing.
5628 * @param {Number} colIndex The column index
5629 * @param {Number} rowIndex The row index
5632 getCellEditor : function(colIndex, rowIndex){
5633 return this.config[colIndex].editor;
5637 * Sets if a column is editable.
5638 * @param {Number} col The column index
5639 * @param {Boolean} editable True if the column is editable
5641 setEditable : function(col, editable){
5642 this.config[col].editable = editable;
5647 * Returns true if the column is hidden.
5648 * @param {Number} colIndex The column index
5651 isHidden : function(colIndex){
5652 return this.config[colIndex].hidden;
5657 * Returns true if the column width cannot be changed
5659 isFixed : function(colIndex){
5660 return this.config[colIndex].fixed;
5664 * Returns true if the column can be resized
5667 isResizable : function(colIndex){
5668 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5671 * Sets if a column is hidden.
5672 * @param {Number} colIndex The column index
5673 * @param {Boolean} hidden True if the column is hidden
5675 setHidden : function(colIndex, hidden){
5676 this.config[colIndex].hidden = hidden;
5677 this.totalWidth = null;
5678 this.fireEvent("hiddenchange", this, colIndex, hidden);
5682 * Sets the editor for a column.
5683 * @param {Number} col The column index
5684 * @param {Object} editor The editor object
5686 setEditor : function(col, editor){
5687 this.config[col].editor = editor;
5691 Roo.grid.ColumnModel.defaultRenderer = function(value)
5693 if(typeof value == "object") {
5696 if(typeof value == "string" && value.length < 1){
5700 return String.format("{0}", value);
5703 // Alias for backwards compatibility
5704 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5707 * Ext JS Library 1.1.1
5708 * Copyright(c) 2006-2007, Ext JS, LLC.
5710 * Originally Released Under LGPL - original licence link has changed is not relivant.
5713 * <script type="text/javascript">
5717 * @class Roo.LoadMask
5718 * A simple utility class for generically masking elements while loading data. If the element being masked has
5719 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5720 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5721 * element's UpdateManager load indicator and will be destroyed after the initial load.
5723 * Create a new LoadMask
5724 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5725 * @param {Object} config The config object
5727 Roo.LoadMask = function(el, config){
5728 this.el = Roo.get(el);
5729 Roo.apply(this, config);
5731 this.store.on('beforeload', this.onBeforeLoad, this);
5732 this.store.on('load', this.onLoad, this);
5733 this.store.on('loadexception', this.onLoadException, this);
5734 this.removeMask = false;
5736 var um = this.el.getUpdateManager();
5737 um.showLoadIndicator = false; // disable the default indicator
5738 um.on('beforeupdate', this.onBeforeLoad, this);
5739 um.on('update', this.onLoad, this);
5740 um.on('failure', this.onLoad, this);
5741 this.removeMask = true;
5745 Roo.LoadMask.prototype = {
5747 * @cfg {Boolean} removeMask
5748 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5749 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5753 * The text to display in a centered loading message box (defaults to 'Loading...')
5757 * @cfg {String} msgCls
5758 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5760 msgCls : 'x-mask-loading',
5763 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5769 * Disables the mask to prevent it from being displayed
5771 disable : function(){
5772 this.disabled = true;
5776 * Enables the mask so that it can be displayed
5778 enable : function(){
5779 this.disabled = false;
5782 onLoadException : function()
5786 if (typeof(arguments[3]) != 'undefined') {
5787 Roo.MessageBox.alert("Error loading",arguments[3]);
5791 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5792 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5799 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5804 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5808 onBeforeLoad : function(){
5810 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5815 destroy : function(){
5817 this.store.un('beforeload', this.onBeforeLoad, this);
5818 this.store.un('load', this.onLoad, this);
5819 this.store.un('loadexception', this.onLoadException, this);
5821 var um = this.el.getUpdateManager();
5822 um.un('beforeupdate', this.onBeforeLoad, this);
5823 um.un('update', this.onLoad, this);
5824 um.un('failure', this.onLoad, this);
5835 * @class Roo.bootstrap.Table
5836 * @extends Roo.bootstrap.Component
5837 * Bootstrap Table class
5838 * @cfg {String} cls table class
5839 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5840 * @cfg {String} bgcolor Specifies the background color for a table
5841 * @cfg {Number} border Specifies whether the table cells should have borders or not
5842 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5843 * @cfg {Number} cellspacing Specifies the space between cells
5844 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5845 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5846 * @cfg {String} sortable Specifies that the table should be sortable
5847 * @cfg {String} summary Specifies a summary of the content of a table
5848 * @cfg {Number} width Specifies the width of a table
5849 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5851 * @cfg {boolean} striped Should the rows be alternative striped
5852 * @cfg {boolean} bordered Add borders to the table
5853 * @cfg {boolean} hover Add hover highlighting
5854 * @cfg {boolean} condensed Format condensed
5855 * @cfg {boolean} responsive Format condensed
5856 * @cfg {Boolean} loadMask (true|false) default false
5857 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5858 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5859 * @cfg {Boolean} rowSelection (true|false) default false
5860 * @cfg {Boolean} cellSelection (true|false) default false
5861 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5862 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5863 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5867 * Create a new Table
5868 * @param {Object} config The config object
5871 Roo.bootstrap.Table = function(config){
5872 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5877 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5878 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5879 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5880 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5882 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5884 this.sm.grid = this;
5885 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5886 this.sm = this.selModel;
5887 this.sm.xmodule = this.xmodule || false;
5890 if (this.cm && typeof(this.cm.config) == 'undefined') {
5891 this.colModel = new Roo.grid.ColumnModel(this.cm);
5892 this.cm = this.colModel;
5893 this.cm.xmodule = this.xmodule || false;
5896 this.store= Roo.factory(this.store, Roo.data);
5897 this.ds = this.store;
5898 this.ds.xmodule = this.xmodule || false;
5901 if (this.footer && this.store) {
5902 this.footer.dataSource = this.ds;
5903 this.footer = Roo.factory(this.footer);
5910 * Fires when a cell is clicked
5911 * @param {Roo.bootstrap.Table} this
5912 * @param {Roo.Element} el
5913 * @param {Number} rowIndex
5914 * @param {Number} columnIndex
5915 * @param {Roo.EventObject} e
5919 * @event celldblclick
5920 * Fires when a cell is double clicked
5921 * @param {Roo.bootstrap.Table} this
5922 * @param {Roo.Element} el
5923 * @param {Number} rowIndex
5924 * @param {Number} columnIndex
5925 * @param {Roo.EventObject} e
5927 "celldblclick" : true,
5930 * Fires when a row is clicked
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Roo.EventObject} e
5938 * @event rowdblclick
5939 * Fires when a row is double clicked
5940 * @param {Roo.bootstrap.Table} this
5941 * @param {Roo.Element} el
5942 * @param {Number} rowIndex
5943 * @param {Roo.EventObject} e
5945 "rowdblclick" : true,
5948 * Fires when a mouseover occur
5949 * @param {Roo.bootstrap.Table} this
5950 * @param {Roo.Element} el
5951 * @param {Number} rowIndex
5952 * @param {Number} columnIndex
5953 * @param {Roo.EventObject} e
5958 * Fires when a mouseout occur
5959 * @param {Roo.bootstrap.Table} this
5960 * @param {Roo.Element} el
5961 * @param {Number} rowIndex
5962 * @param {Number} columnIndex
5963 * @param {Roo.EventObject} e
5968 * Fires when a row is rendered, so you can change add a style to it.
5969 * @param {Roo.bootstrap.Table} this
5970 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5974 * @event rowsrendered
5975 * Fires when all the rows have been rendered
5976 * @param {Roo.bootstrap.Table} this
5978 'rowsrendered' : true,
5980 * @event contextmenu
5981 * The raw contextmenu event for the entire grid.
5982 * @param {Roo.EventObject} e
5984 "contextmenu" : true,
5986 * @event rowcontextmenu
5987 * Fires when a row is right clicked
5988 * @param {Roo.bootstrap.Table} this
5989 * @param {Number} rowIndex
5990 * @param {Roo.EventObject} e
5992 "rowcontextmenu" : true,
5994 * @event cellcontextmenu
5995 * Fires when a cell is right clicked
5996 * @param {Roo.bootstrap.Table} this
5997 * @param {Number} rowIndex
5998 * @param {Number} cellIndex
5999 * @param {Roo.EventObject} e
6001 "cellcontextmenu" : true,
6003 * @event headercontextmenu
6004 * Fires when a header is right clicked
6005 * @param {Roo.bootstrap.Table} this
6006 * @param {Number} columnIndex
6007 * @param {Roo.EventObject} e
6009 "headercontextmenu" : true
6013 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6039 rowSelection : false,
6040 cellSelection : false,
6043 // Roo.Element - the tbody
6045 // Roo.Element - thead element
6048 container: false, // used by gridpanel...
6054 getAutoCreate : function()
6056 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6063 if (this.scrollBody) {
6064 cfg.cls += ' table-body-fixed';
6067 cfg.cls += ' table-striped';
6071 cfg.cls += ' table-hover';
6073 if (this.bordered) {
6074 cfg.cls += ' table-bordered';
6076 if (this.condensed) {
6077 cfg.cls += ' table-condensed';
6079 if (this.responsive) {
6080 cfg.cls += ' table-responsive';
6084 cfg.cls+= ' ' +this.cls;
6087 // this lot should be simplifed...
6090 cfg.align=this.align;
6093 cfg.bgcolor=this.bgcolor;
6096 cfg.border=this.border;
6098 if (this.cellpadding) {
6099 cfg.cellpadding=this.cellpadding;
6101 if (this.cellspacing) {
6102 cfg.cellspacing=this.cellspacing;
6105 cfg.frame=this.frame;
6108 cfg.rules=this.rules;
6110 if (this.sortable) {
6111 cfg.sortable=this.sortable;
6114 cfg.summary=this.summary;
6117 cfg.width=this.width;
6120 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6123 if(this.store || this.cm){
6124 if(this.headerShow){
6125 cfg.cn.push(this.renderHeader());
6128 cfg.cn.push(this.renderBody());
6130 if(this.footerShow){
6131 cfg.cn.push(this.renderFooter());
6133 // where does this come from?
6134 //cfg.cls+= ' TableGrid';
6137 return { cn : [ cfg ] };
6140 initEvents : function()
6142 if(!this.store || !this.cm){
6145 if (this.selModel) {
6146 this.selModel.initEvents();
6150 //Roo.log('initEvents with ds!!!!');
6152 this.mainBody = this.el.select('tbody', true).first();
6153 this.mainHead = this.el.select('thead', true).first();
6160 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6161 e.on('click', _this.sort, _this);
6164 this.mainBody.on("click", this.onClick, this);
6165 this.mainBody.on("dblclick", this.onDblClick, this);
6167 // why is this done????? = it breaks dialogs??
6168 //this.parent().el.setStyle('position', 'relative');
6172 this.footer.parentId = this.id;
6173 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6176 this.el.select('tfoot tr td').first().addClass('hide');
6180 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6182 this.store.on('load', this.onLoad, this);
6183 this.store.on('beforeload', this.onBeforeLoad, this);
6184 this.store.on('update', this.onUpdate, this);
6185 this.store.on('add', this.onAdd, this);
6186 this.store.on("clear", this.clear, this);
6188 this.el.on("contextmenu", this.onContextMenu, this);
6190 this.mainBody.on('scroll', this.onBodyScroll, this);
6192 this.cm.on("headerchange", this.onHeaderChange, this);
6194 this.cm.on("hiddenchange", this.onHiddenChange, this);
6198 onContextMenu : function(e, t)
6200 this.processEvent("contextmenu", e);
6203 processEvent : function(name, e)
6205 if (name != 'touchstart' ) {
6206 this.fireEvent(name, e);
6209 var t = e.getTarget();
6211 var cell = Roo.get(t);
6217 if(cell.findParent('tfoot', false, true)){
6221 if(cell.findParent('thead', false, true)){
6223 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6224 cell = Roo.get(t).findParent('th', false, true);
6226 Roo.log("failed to find th in thead?");
6227 Roo.log(e.getTarget());
6232 var cellIndex = cell.dom.cellIndex;
6234 var ename = name == 'touchstart' ? 'click' : name;
6235 this.fireEvent("header" + ename, this, cellIndex, e);
6240 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6241 cell = Roo.get(t).findParent('td', false, true);
6243 Roo.log("failed to find th in tbody?");
6244 Roo.log(e.getTarget());
6249 var row = cell.findParent('tr', false, true);
6250 var cellIndex = cell.dom.cellIndex;
6251 var rowIndex = row.dom.rowIndex - 1;
6255 this.fireEvent("row" + name, this, rowIndex, e);
6259 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6265 onMouseover : function(e, el)
6267 var cell = Roo.get(el);
6273 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6274 cell = cell.findParent('td', false, true);
6277 var row = cell.findParent('tr', false, true);
6278 var cellIndex = cell.dom.cellIndex;
6279 var rowIndex = row.dom.rowIndex - 1; // start from 0
6281 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6285 onMouseout : function(e, el)
6287 var cell = Roo.get(el);
6293 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6294 cell = cell.findParent('td', false, true);
6297 var row = cell.findParent('tr', false, true);
6298 var cellIndex = cell.dom.cellIndex;
6299 var rowIndex = row.dom.rowIndex - 1; // start from 0
6301 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6305 onClick : function(e, el)
6307 var cell = Roo.get(el);
6309 if(!cell || (!this.cellSelection && !this.rowSelection)){
6313 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6314 cell = cell.findParent('td', false, true);
6317 if(!cell || typeof(cell) == 'undefined'){
6321 var row = cell.findParent('tr', false, true);
6323 if(!row || typeof(row) == 'undefined'){
6327 var cellIndex = cell.dom.cellIndex;
6328 var rowIndex = this.getRowIndex(row);
6330 // why??? - should these not be based on SelectionModel?
6331 if(this.cellSelection){
6332 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6335 if(this.rowSelection){
6336 this.fireEvent('rowclick', this, row, rowIndex, e);
6342 onDblClick : function(e,el)
6344 var cell = Roo.get(el);
6346 if(!cell || (!this.cellSelection && !this.rowSelection)){
6350 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6351 cell = cell.findParent('td', false, true);
6354 if(!cell || typeof(cell) == 'undefined'){
6358 var row = cell.findParent('tr', false, true);
6360 if(!row || typeof(row) == 'undefined'){
6364 var cellIndex = cell.dom.cellIndex;
6365 var rowIndex = this.getRowIndex(row);
6367 if(this.cellSelection){
6368 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6371 if(this.rowSelection){
6372 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6376 sort : function(e,el)
6378 var col = Roo.get(el);
6380 if(!col.hasClass('sortable')){
6384 var sort = col.attr('sort');
6387 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6391 this.store.sortInfo = {field : sort, direction : dir};
6394 Roo.log("calling footer first");
6395 this.footer.onClick('first');
6398 this.store.load({ params : { start : 0 } });
6402 renderHeader : function()
6410 this.totalWidth = 0;
6412 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6414 var config = cm.config[i];
6418 cls : 'roo-bootstrap-thead-col-' + i,
6420 html: cm.getColumnHeader(i)
6425 if(typeof(config.sortable) != 'undefined' && config.sortable){
6427 c.html = '<i class="glyphicon"></i>' + c.html;
6430 if(typeof(config.lgHeader) != 'undefined'){
6431 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6434 if(typeof(config.mdHeader) != 'undefined'){
6435 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6438 if(typeof(config.smHeader) != 'undefined'){
6439 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6442 if(typeof(config.xsHeader) != 'undefined'){
6443 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6450 if(typeof(config.tooltip) != 'undefined'){
6451 c.tooltip = config.tooltip;
6454 if(typeof(config.colspan) != 'undefined'){
6455 c.colspan = config.colspan;
6458 if(typeof(config.hidden) != 'undefined' && config.hidden){
6459 c.style += ' display:none;';
6462 if(typeof(config.dataIndex) != 'undefined'){
6463 c.sort = config.dataIndex;
6468 if(typeof(config.align) != 'undefined' && config.align.length){
6469 c.style += ' text-align:' + config.align + ';';
6472 if(typeof(config.width) != 'undefined'){
6473 c.style += ' width:' + config.width + 'px;';
6474 this.totalWidth += config.width;
6476 this.totalWidth += 100; // assume minimum of 100 per column?
6479 if(typeof(config.cls) != 'undefined'){
6480 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6483 ['xs','sm','md','lg'].map(function(size){
6485 if(typeof(config[size]) == 'undefined'){
6489 if (!config[size]) { // 0 = hidden
6490 c.cls += ' hidden-' + size;
6494 c.cls += ' col-' + size + '-' + config[size];
6508 renderBody : function()
6518 colspan : this.cm.getColumnCount()
6528 renderFooter : function()
6538 colspan : this.cm.getColumnCount()
6552 // Roo.log('ds onload');
6557 var ds = this.store;
6559 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6560 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6561 if (_this.store.sortInfo) {
6563 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6564 e.select('i', true).addClass(['glyphicon-arrow-up']);
6567 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6568 e.select('i', true).addClass(['glyphicon-arrow-down']);
6573 var tbody = this.mainBody;
6575 if(ds.getCount() > 0){
6576 ds.data.each(function(d,rowIndex){
6577 var row = this.renderRow(cm, ds, rowIndex);
6579 tbody.createChild(row);
6583 if(row.cellObjects.length){
6584 Roo.each(row.cellObjects, function(r){
6585 _this.renderCellObject(r);
6592 Roo.each(this.el.select('tbody td', true).elements, function(e){
6593 e.on('mouseover', _this.onMouseover, _this);
6596 Roo.each(this.el.select('tbody td', true).elements, function(e){
6597 e.on('mouseout', _this.onMouseout, _this);
6599 this.fireEvent('rowsrendered', this);
6600 //if(this.loadMask){
6601 // this.maskEl.hide();
6608 onUpdate : function(ds,record)
6610 this.refreshRow(record);
6614 onRemove : function(ds, record, index, isUpdate){
6615 if(isUpdate !== true){
6616 this.fireEvent("beforerowremoved", this, index, record);
6618 var bt = this.mainBody.dom;
6620 var rows = this.el.select('tbody > tr', true).elements;
6622 if(typeof(rows[index]) != 'undefined'){
6623 bt.removeChild(rows[index].dom);
6626 // if(bt.rows[index]){
6627 // bt.removeChild(bt.rows[index]);
6630 if(isUpdate !== true){
6631 //this.stripeRows(index);
6632 //this.syncRowHeights(index, index);
6634 this.fireEvent("rowremoved", this, index, record);
6638 onAdd : function(ds, records, rowIndex)
6640 //Roo.log('on Add called');
6641 // - note this does not handle multiple adding very well..
6642 var bt = this.mainBody.dom;
6643 for (var i =0 ; i < records.length;i++) {
6644 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6645 //Roo.log(records[i]);
6646 //Roo.log(this.store.getAt(rowIndex+i));
6647 this.insertRow(this.store, rowIndex + i, false);
6654 refreshRow : function(record){
6655 var ds = this.store, index;
6656 if(typeof record == 'number'){
6658 record = ds.getAt(index);
6660 index = ds.indexOf(record);
6662 this.insertRow(ds, index, true);
6664 this.onRemove(ds, record, index+1, true);
6666 //this.syncRowHeights(index, index);
6668 this.fireEvent("rowupdated", this, index, record);
6671 insertRow : function(dm, rowIndex, isUpdate){
6674 this.fireEvent("beforerowsinserted", this, rowIndex);
6676 //var s = this.getScrollState();
6677 var row = this.renderRow(this.cm, this.store, rowIndex);
6678 // insert before rowIndex..
6679 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6683 if(row.cellObjects.length){
6684 Roo.each(row.cellObjects, function(r){
6685 _this.renderCellObject(r);
6690 this.fireEvent("rowsinserted", this, rowIndex);
6691 //this.syncRowHeights(firstRow, lastRow);
6692 //this.stripeRows(firstRow);
6699 getRowDom : function(rowIndex)
6701 var rows = this.el.select('tbody > tr', true).elements;
6703 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6706 // returns the object tree for a tr..
6709 renderRow : function(cm, ds, rowIndex)
6711 var d = ds.getAt(rowIndex);
6715 cls : 'roo-bootstrap-tbody-row-' + rowIndex,
6719 var cellObjects = [];
6721 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6722 var config = cm.config[i];
6724 var renderer = cm.getRenderer(i);
6728 if(typeof(renderer) !== 'undefined'){
6729 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6731 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6732 // and are rendered into the cells after the row is rendered - using the id for the element.
6734 if(typeof(value) === 'object'){
6744 rowIndex : rowIndex,
6749 this.fireEvent('rowclass', this, rowcfg);
6753 cls : rowcfg.rowClass + ' roo-bootstrap-tbody-col-' + i,
6755 html: (typeof(value) === 'object') ? '' : value
6762 if(typeof(config.colspan) != 'undefined'){
6763 td.colspan = config.colspan;
6766 if(typeof(config.hidden) != 'undefined' && config.hidden){
6767 td.style += ' display:none;';
6770 if(typeof(config.align) != 'undefined' && config.align.length){
6771 td.style += ' text-align:' + config.align + ';';
6774 if(typeof(config.width) != 'undefined'){
6775 td.style += ' width:' + config.width + 'px;';
6778 if(typeof(config.cursor) != 'undefined'){
6779 td.style += ' cursor:' + config.cursor + ';';
6782 if(typeof(config.cls) != 'undefined'){
6783 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6786 ['xs','sm','md','lg'].map(function(size){
6788 if(typeof(config[size]) == 'undefined'){
6792 if (!config[size]) { // 0 = hidden
6793 td.cls += ' hidden-' + size;
6797 td.cls += ' col-' + size + '-' + config[size];
6802 td.cls += ' hidden';
6809 row.cellObjects = cellObjects;
6817 onBeforeLoad : function()
6819 //Roo.log('ds onBeforeLoad');
6823 //if(this.loadMask){
6824 // this.maskEl.show();
6832 this.el.select('tbody', true).first().dom.innerHTML = '';
6835 * Show or hide a row.
6836 * @param {Number} rowIndex to show or hide
6837 * @param {Boolean} state hide
6839 setRowVisibility : function(rowIndex, state)
6841 var bt = this.mainBody.dom;
6843 var rows = this.el.select('tbody > tr', true).elements;
6845 if(typeof(rows[rowIndex]) == 'undefined'){
6848 rows[rowIndex].dom.style.display = state ? '' : 'none';
6852 getSelectionModel : function(){
6854 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6856 return this.selModel;
6859 * Render the Roo.bootstrap object from renderder
6861 renderCellObject : function(r)
6865 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6867 var t = r.cfg.render(r.container);
6870 Roo.each(r.cfg.cn, function(c){
6872 container: t.getChildContainer(),
6875 _this.renderCellObject(child);
6880 getRowIndex : function(row)
6884 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6895 * Returns the grid's underlying element = used by panel.Grid
6896 * @return {Element} The element
6898 getGridEl : function(){
6902 * Forces a resize - used by panel.Grid
6903 * @return {Element} The element
6905 autoSize : function()
6907 //var ctr = Roo.get(this.container.dom.parentElement);
6908 var ctr = Roo.get(this.el.dom);
6910 var thd = this.getGridEl().select('thead',true).first();
6911 var tbd = this.getGridEl().select('tbody', true).first();
6912 var tfd = this.getGridEl().select('tfoot', true).first();
6914 var cw = ctr.getWidth();
6918 tbd.setSize(ctr.getWidth(),
6919 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6921 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6924 cw = Math.max(cw, this.totalWidth);
6925 this.getGridEl().select('tr',true).setWidth(cw);
6926 // resize 'expandable coloumn?
6928 return; // we doe not have a view in this design..
6931 onBodyScroll: function()
6933 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6935 this.mainHead.setStyle({
6936 'position' : 'relative',
6937 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6943 var scrollHeight = this.mainBody.dom.scrollHeight;
6945 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6947 var height = this.mainBody.getHeight();
6949 if(scrollHeight - height == scrollTop) {
6951 var total = this.ds.getTotalCount();
6953 if(this.footer.cursor + this.footer.pageSize < total){
6955 this.footer.ds.load({
6957 start : this.footer.cursor + this.footer.pageSize,
6958 limit : this.footer.pageSize
6968 onHeaderChange : function()
6971 var header = this.renderHeader();
6972 var table = this.el.select('table', true).first();
6974 this.mainHead.remove();
6975 this.mainHead = table.createChild(header, this.mainBody, false);
6978 onHiddenChange : function()
6981 this.onHeaderChange();
6998 * @class Roo.bootstrap.TableCell
6999 * @extends Roo.bootstrap.Component
7000 * Bootstrap TableCell class
7001 * @cfg {String} html cell contain text
7002 * @cfg {String} cls cell class
7003 * @cfg {String} tag cell tag (td|th) default td
7004 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7005 * @cfg {String} align Aligns the content in a cell
7006 * @cfg {String} axis Categorizes cells
7007 * @cfg {String} bgcolor Specifies the background color of a cell
7008 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7009 * @cfg {Number} colspan Specifies the number of columns a cell should span
7010 * @cfg {String} headers Specifies one or more header cells a cell is related to
7011 * @cfg {Number} height Sets the height of a cell
7012 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7013 * @cfg {Number} rowspan Sets the number of rows a cell should span
7014 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7015 * @cfg {String} valign Vertical aligns the content in a cell
7016 * @cfg {Number} width Specifies the width of a cell
7019 * Create a new TableCell
7020 * @param {Object} config The config object
7023 Roo.bootstrap.TableCell = function(config){
7024 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7027 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7047 getAutoCreate : function(){
7048 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7068 cfg.align=this.align
7074 cfg.bgcolor=this.bgcolor
7077 cfg.charoff=this.charoff
7080 cfg.colspan=this.colspan
7083 cfg.headers=this.headers
7086 cfg.height=this.height
7089 cfg.nowrap=this.nowrap
7092 cfg.rowspan=this.rowspan
7095 cfg.scope=this.scope
7098 cfg.valign=this.valign
7101 cfg.width=this.width
7120 * @class Roo.bootstrap.TableRow
7121 * @extends Roo.bootstrap.Component
7122 * Bootstrap TableRow class
7123 * @cfg {String} cls row class
7124 * @cfg {String} align Aligns the content in a table row
7125 * @cfg {String} bgcolor Specifies a background color for a table row
7126 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7127 * @cfg {String} valign Vertical aligns the content in a table row
7130 * Create a new TableRow
7131 * @param {Object} config The config object
7134 Roo.bootstrap.TableRow = function(config){
7135 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7138 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7146 getAutoCreate : function(){
7147 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7157 cfg.align = this.align;
7160 cfg.bgcolor = this.bgcolor;
7163 cfg.charoff = this.charoff;
7166 cfg.valign = this.valign;
7184 * @class Roo.bootstrap.TableBody
7185 * @extends Roo.bootstrap.Component
7186 * Bootstrap TableBody class
7187 * @cfg {String} cls element class
7188 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7189 * @cfg {String} align Aligns the content inside the element
7190 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7191 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7194 * Create a new TableBody
7195 * @param {Object} config The config object
7198 Roo.bootstrap.TableBody = function(config){
7199 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7202 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7210 getAutoCreate : function(){
7211 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7225 cfg.align = this.align;
7228 cfg.charoff = this.charoff;
7231 cfg.valign = this.valign;
7238 // initEvents : function()
7245 // this.store = Roo.factory(this.store, Roo.data);
7246 // this.store.on('load', this.onLoad, this);
7248 // this.store.load();
7252 // onLoad: function ()
7254 // this.fireEvent('load', this);
7264 * Ext JS Library 1.1.1
7265 * Copyright(c) 2006-2007, Ext JS, LLC.
7267 * Originally Released Under LGPL - original licence link has changed is not relivant.
7270 * <script type="text/javascript">
7273 // as we use this in bootstrap.
7274 Roo.namespace('Roo.form');
7276 * @class Roo.form.Action
7277 * Internal Class used to handle form actions
7279 * @param {Roo.form.BasicForm} el The form element or its id
7280 * @param {Object} config Configuration options
7285 // define the action interface
7286 Roo.form.Action = function(form, options){
7288 this.options = options || {};
7291 * Client Validation Failed
7294 Roo.form.Action.CLIENT_INVALID = 'client';
7296 * Server Validation Failed
7299 Roo.form.Action.SERVER_INVALID = 'server';
7301 * Connect to Server Failed
7304 Roo.form.Action.CONNECT_FAILURE = 'connect';
7306 * Reading Data from Server Failed
7309 Roo.form.Action.LOAD_FAILURE = 'load';
7311 Roo.form.Action.prototype = {
7313 failureType : undefined,
7314 response : undefined,
7318 run : function(options){
7323 success : function(response){
7328 handleResponse : function(response){
7332 // default connection failure
7333 failure : function(response){
7335 this.response = response;
7336 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7337 this.form.afterAction(this, false);
7340 processResponse : function(response){
7341 this.response = response;
7342 if(!response.responseText){
7345 this.result = this.handleResponse(response);
7349 // utility functions used internally
7350 getUrl : function(appendParams){
7351 var url = this.options.url || this.form.url || this.form.el.dom.action;
7353 var p = this.getParams();
7355 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7361 getMethod : function(){
7362 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7365 getParams : function(){
7366 var bp = this.form.baseParams;
7367 var p = this.options.params;
7369 if(typeof p == "object"){
7370 p = Roo.urlEncode(Roo.applyIf(p, bp));
7371 }else if(typeof p == 'string' && bp){
7372 p += '&' + Roo.urlEncode(bp);
7375 p = Roo.urlEncode(bp);
7380 createCallback : function(){
7382 success: this.success,
7383 failure: this.failure,
7385 timeout: (this.form.timeout*1000),
7386 upload: this.form.fileUpload ? this.success : undefined
7391 Roo.form.Action.Submit = function(form, options){
7392 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7395 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7398 haveProgress : false,
7399 uploadComplete : false,
7401 // uploadProgress indicator.
7402 uploadProgress : function()
7404 if (!this.form.progressUrl) {
7408 if (!this.haveProgress) {
7409 Roo.MessageBox.progress("Uploading", "Uploading");
7411 if (this.uploadComplete) {
7412 Roo.MessageBox.hide();
7416 this.haveProgress = true;
7418 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7420 var c = new Roo.data.Connection();
7422 url : this.form.progressUrl,
7427 success : function(req){
7428 //console.log(data);
7432 rdata = Roo.decode(req.responseText)
7434 Roo.log("Invalid data from server..");
7438 if (!rdata || !rdata.success) {
7440 Roo.MessageBox.alert(Roo.encode(rdata));
7443 var data = rdata.data;
7445 if (this.uploadComplete) {
7446 Roo.MessageBox.hide();
7451 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7452 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7455 this.uploadProgress.defer(2000,this);
7458 failure: function(data) {
7459 Roo.log('progress url failed ');
7470 // run get Values on the form, so it syncs any secondary forms.
7471 this.form.getValues();
7473 var o = this.options;
7474 var method = this.getMethod();
7475 var isPost = method == 'POST';
7476 if(o.clientValidation === false || this.form.isValid()){
7478 if (this.form.progressUrl) {
7479 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7480 (new Date() * 1) + '' + Math.random());
7485 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7486 form:this.form.el.dom,
7487 url:this.getUrl(!isPost),
7489 params:isPost ? this.getParams() : null,
7490 isUpload: this.form.fileUpload
7493 this.uploadProgress();
7495 }else if (o.clientValidation !== false){ // client validation failed
7496 this.failureType = Roo.form.Action.CLIENT_INVALID;
7497 this.form.afterAction(this, false);
7501 success : function(response)
7503 this.uploadComplete= true;
7504 if (this.haveProgress) {
7505 Roo.MessageBox.hide();
7509 var result = this.processResponse(response);
7510 if(result === true || result.success){
7511 this.form.afterAction(this, true);
7515 this.form.markInvalid(result.errors);
7516 this.failureType = Roo.form.Action.SERVER_INVALID;
7518 this.form.afterAction(this, false);
7520 failure : function(response)
7522 this.uploadComplete= true;
7523 if (this.haveProgress) {
7524 Roo.MessageBox.hide();
7527 this.response = response;
7528 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7529 this.form.afterAction(this, false);
7532 handleResponse : function(response){
7533 if(this.form.errorReader){
7534 var rs = this.form.errorReader.read(response);
7537 for(var i = 0, len = rs.records.length; i < len; i++) {
7538 var r = rs.records[i];
7542 if(errors.length < 1){
7546 success : rs.success,
7552 ret = Roo.decode(response.responseText);
7556 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7566 Roo.form.Action.Load = function(form, options){
7567 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7568 this.reader = this.form.reader;
7571 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7576 Roo.Ajax.request(Roo.apply(
7577 this.createCallback(), {
7578 method:this.getMethod(),
7579 url:this.getUrl(false),
7580 params:this.getParams()
7584 success : function(response){
7586 var result = this.processResponse(response);
7587 if(result === true || !result.success || !result.data){
7588 this.failureType = Roo.form.Action.LOAD_FAILURE;
7589 this.form.afterAction(this, false);
7592 this.form.clearInvalid();
7593 this.form.setValues(result.data);
7594 this.form.afterAction(this, true);
7597 handleResponse : function(response){
7598 if(this.form.reader){
7599 var rs = this.form.reader.read(response);
7600 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7602 success : rs.success,
7606 return Roo.decode(response.responseText);
7610 Roo.form.Action.ACTION_TYPES = {
7611 'load' : Roo.form.Action.Load,
7612 'submit' : Roo.form.Action.Submit
7621 * @class Roo.bootstrap.Form
7622 * @extends Roo.bootstrap.Component
7623 * Bootstrap Form class
7624 * @cfg {String} method GET | POST (default POST)
7625 * @cfg {String} labelAlign top | left (default top)
7626 * @cfg {String} align left | right - for navbars
7627 * @cfg {Boolean} loadMask load mask when submit (default true)
7632 * @param {Object} config The config object
7636 Roo.bootstrap.Form = function(config){
7638 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7640 Roo.bootstrap.Form.popover.apply();
7644 * @event clientvalidation
7645 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7646 * @param {Form} this
7647 * @param {Boolean} valid true if the form has passed client-side validation
7649 clientvalidation: true,
7651 * @event beforeaction
7652 * Fires before any action is performed. Return false to cancel the action.
7653 * @param {Form} this
7654 * @param {Action} action The action to be performed
7658 * @event actionfailed
7659 * Fires when an action fails.
7660 * @param {Form} this
7661 * @param {Action} action The action that failed
7663 actionfailed : true,
7665 * @event actioncomplete
7666 * Fires when an action is completed.
7667 * @param {Form} this
7668 * @param {Action} action The action that completed
7670 actioncomplete : true
7674 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7677 * @cfg {String} method
7678 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7683 * The URL to use for form actions if one isn't supplied in the action options.
7686 * @cfg {Boolean} fileUpload
7687 * Set to true if this form is a file upload.
7691 * @cfg {Object} baseParams
7692 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7696 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7700 * @cfg {Sting} align (left|right) for navbar forms
7705 activeAction : null,
7708 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7709 * element by passing it or its id or mask the form itself by passing in true.
7712 waitMsgTarget : false,
7717 * @cfg {Boolean} errorMask (true|false) default false
7722 * @cfg {Number} maskOffset Default 100
7727 * @cfg {Boolean} maskBody
7731 getAutoCreate : function(){
7735 method : this.method || 'POST',
7736 id : this.id || Roo.id(),
7739 if (this.parent().xtype.match(/^Nav/)) {
7740 cfg.cls = 'navbar-form navbar-' + this.align;
7744 if (this.labelAlign == 'left' ) {
7745 cfg.cls += ' form-horizontal';
7751 initEvents : function()
7753 this.el.on('submit', this.onSubmit, this);
7754 // this was added as random key presses on the form where triggering form submit.
7755 this.el.on('keypress', function(e) {
7756 if (e.getCharCode() != 13) {
7759 // we might need to allow it for textareas.. and some other items.
7760 // check e.getTarget().
7762 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7766 Roo.log("keypress blocked");
7774 onSubmit : function(e){
7779 * Returns true if client-side validation on the form is successful.
7782 isValid : function(){
7783 var items = this.getItems();
7787 items.each(function(f){
7793 if(!target && f.el.isVisible(true)){
7799 if(this.errorMask && !valid){
7800 Roo.bootstrap.Form.popover.mask(this, target);
7807 * Returns true if any fields in this form have changed since their original load.
7810 isDirty : function(){
7812 var items = this.getItems();
7813 items.each(function(f){
7823 * Performs a predefined action (submit or load) or custom actions you define on this form.
7824 * @param {String} actionName The name of the action type
7825 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7826 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7827 * accept other config options):
7829 Property Type Description
7830 ---------------- --------------- ----------------------------------------------------------------------------------
7831 url String The url for the action (defaults to the form's url)
7832 method String The form method to use (defaults to the form's method, or POST if not defined)
7833 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7834 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7835 validate the form on the client (defaults to false)
7837 * @return {BasicForm} this
7839 doAction : function(action, options){
7840 if(typeof action == 'string'){
7841 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7843 if(this.fireEvent('beforeaction', this, action) !== false){
7844 this.beforeAction(action);
7845 action.run.defer(100, action);
7851 beforeAction : function(action){
7852 var o = action.options;
7857 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7859 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7862 // not really supported yet.. ??
7864 //if(this.waitMsgTarget === true){
7865 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7866 //}else if(this.waitMsgTarget){
7867 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7868 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7870 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7876 afterAction : function(action, success){
7877 this.activeAction = null;
7878 var o = action.options;
7883 Roo.get(document.body).unmask();
7889 //if(this.waitMsgTarget === true){
7890 // this.el.unmask();
7891 //}else if(this.waitMsgTarget){
7892 // this.waitMsgTarget.unmask();
7894 // Roo.MessageBox.updateProgress(1);
7895 // Roo.MessageBox.hide();
7902 Roo.callback(o.success, o.scope, [this, action]);
7903 this.fireEvent('actioncomplete', this, action);
7907 // failure condition..
7908 // we have a scenario where updates need confirming.
7909 // eg. if a locking scenario exists..
7910 // we look for { errors : { needs_confirm : true }} in the response.
7912 (typeof(action.result) != 'undefined') &&
7913 (typeof(action.result.errors) != 'undefined') &&
7914 (typeof(action.result.errors.needs_confirm) != 'undefined')
7917 Roo.log("not supported yet");
7920 Roo.MessageBox.confirm(
7921 "Change requires confirmation",
7922 action.result.errorMsg,
7927 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7937 Roo.callback(o.failure, o.scope, [this, action]);
7938 // show an error message if no failed handler is set..
7939 if (!this.hasListener('actionfailed')) {
7940 Roo.log("need to add dialog support");
7942 Roo.MessageBox.alert("Error",
7943 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7944 action.result.errorMsg :
7945 "Saving Failed, please check your entries or try again"
7950 this.fireEvent('actionfailed', this, action);
7955 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7956 * @param {String} id The value to search for
7959 findField : function(id){
7960 var items = this.getItems();
7961 var field = items.get(id);
7963 items.each(function(f){
7964 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7971 return field || null;
7974 * Mark fields in this form invalid in bulk.
7975 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7976 * @return {BasicForm} this
7978 markInvalid : function(errors){
7979 if(errors instanceof Array){
7980 for(var i = 0, len = errors.length; i < len; i++){
7981 var fieldError = errors[i];
7982 var f = this.findField(fieldError.id);
7984 f.markInvalid(fieldError.msg);
7990 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7991 field.markInvalid(errors[id]);
7995 //Roo.each(this.childForms || [], function (f) {
7996 // f.markInvalid(errors);
8003 * Set values for fields in this form in bulk.
8004 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8005 * @return {BasicForm} this
8007 setValues : function(values){
8008 if(values instanceof Array){ // array of objects
8009 for(var i = 0, len = values.length; i < len; i++){
8011 var f = this.findField(v.id);
8013 f.setValue(v.value);
8014 if(this.trackResetOnLoad){
8015 f.originalValue = f.getValue();
8019 }else{ // object hash
8022 if(typeof values[id] != 'function' && (field = this.findField(id))){
8024 if (field.setFromData &&
8026 field.displayField &&
8027 // combos' with local stores can
8028 // be queried via setValue()
8029 // to set their value..
8030 (field.store && !field.store.isLocal)
8034 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8035 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8036 field.setFromData(sd);
8038 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8040 field.setFromData(values);
8043 field.setValue(values[id]);
8047 if(this.trackResetOnLoad){
8048 field.originalValue = field.getValue();
8054 //Roo.each(this.childForms || [], function (f) {
8055 // f.setValues(values);
8062 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8063 * they are returned as an array.
8064 * @param {Boolean} asString
8067 getValues : function(asString){
8068 //if (this.childForms) {
8069 // copy values from the child forms
8070 // Roo.each(this.childForms, function (f) {
8071 // this.setValues(f.getValues());
8077 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8078 if(asString === true){
8081 return Roo.urlDecode(fs);
8085 * Returns the fields in this form as an object with key/value pairs.
8086 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8089 getFieldValues : function(with_hidden)
8091 var items = this.getItems();
8093 items.each(function(f){
8099 var v = f.getValue();
8101 if (f.inputType =='radio') {
8102 if (typeof(ret[f.getName()]) == 'undefined') {
8103 ret[f.getName()] = ''; // empty..
8106 if (!f.el.dom.checked) {
8114 if(f.xtype == 'MoneyField'){
8115 ret[f.currencyName] = f.getCurrency();
8118 // not sure if this supported any more..
8119 if ((typeof(v) == 'object') && f.getRawValue) {
8120 v = f.getRawValue() ; // dates..
8122 // combo boxes where name != hiddenName...
8123 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8124 ret[f.name] = f.getRawValue();
8126 ret[f.getName()] = v;
8133 * Clears all invalid messages in this form.
8134 * @return {BasicForm} this
8136 clearInvalid : function(){
8137 var items = this.getItems();
8139 items.each(function(f){
8148 * @return {BasicForm} this
8151 var items = this.getItems();
8152 items.each(function(f){
8156 Roo.each(this.childForms || [], function (f) {
8164 getItems : function()
8166 var r=new Roo.util.MixedCollection(false, function(o){
8167 return o.id || (o.id = Roo.id());
8169 var iter = function(el) {
8176 Roo.each(el.items,function(e) {
8185 hideFields : function(items)
8187 Roo.each(items, function(i){
8189 var f = this.findField(i);
8195 if(f.xtype == 'DateField'){
8196 f.setVisible(false);
8205 showFields : function(items)
8207 Roo.each(items, function(i){
8209 var f = this.findField(i);
8215 if(f.xtype == 'DateField'){
8227 Roo.apply(Roo.bootstrap.Form, {
8254 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8255 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8256 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8257 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8260 this.maskEl.top.enableDisplayMode("block");
8261 this.maskEl.left.enableDisplayMode("block");
8262 this.maskEl.bottom.enableDisplayMode("block");
8263 this.maskEl.right.enableDisplayMode("block");
8265 this.toolTip = new Roo.bootstrap.Tooltip({
8266 cls : 'roo-form-error-popover',
8268 'left' : ['r-l', [-2,0], 'right'],
8269 'right' : ['l-r', [2,0], 'left'],
8270 'bottom' : ['tl-bl', [0,2], 'top'],
8271 'top' : [ 'bl-tl', [0,-2], 'bottom']
8275 this.toolTip.render(Roo.get(document.body));
8277 this.toolTip.el.enableDisplayMode("block");
8279 Roo.get(document.body).on('click', function(){
8283 Roo.get(document.body).on('touchstart', function(){
8287 this.isApplied = true
8290 mask : function(form, target)
8294 this.target = target;
8296 if(!this.form.errorMask || !target.el){
8300 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8302 Roo.log(scrollable);
8304 var ot = this.target.el.calcOffsetsTo(scrollable);
8306 var scrollTo = ot[1] - this.form.maskOffset;
8308 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8310 scrollable.scrollTo('top', scrollTo);
8312 var box = this.target.el.getBox();
8314 var zIndex = Roo.bootstrap.Modal.zIndex++;
8317 this.maskEl.top.setStyle('position', 'absolute');
8318 this.maskEl.top.setStyle('z-index', zIndex);
8319 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8320 this.maskEl.top.setLeft(0);
8321 this.maskEl.top.setTop(0);
8322 this.maskEl.top.show();
8324 this.maskEl.left.setStyle('position', 'absolute');
8325 this.maskEl.left.setStyle('z-index', zIndex);
8326 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8327 this.maskEl.left.setLeft(0);
8328 this.maskEl.left.setTop(box.y - this.padding);
8329 this.maskEl.left.show();
8331 this.maskEl.bottom.setStyle('position', 'absolute');
8332 this.maskEl.bottom.setStyle('z-index', zIndex);
8333 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8334 this.maskEl.bottom.setLeft(0);
8335 this.maskEl.bottom.setTop(box.bottom + this.padding);
8336 this.maskEl.bottom.show();
8338 this.maskEl.right.setStyle('position', 'absolute');
8339 this.maskEl.right.setStyle('z-index', zIndex);
8340 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8341 this.maskEl.right.setLeft(box.right + this.padding);
8342 this.maskEl.right.setTop(box.y - this.padding);
8343 this.maskEl.right.show();
8345 this.toolTip.bindEl = this.target.el;
8347 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8349 var tip = this.target.blankText;
8351 if(this.target.getValue() !== '' ) {
8353 if (this.target.invalidText.length) {
8354 tip = this.target.invalidText;
8355 } else if (this.target.regexText.length){
8356 tip = this.target.regexText;
8360 this.toolTip.show(tip);
8362 this.intervalID = window.setInterval(function() {
8363 Roo.bootstrap.Form.popover.unmask();
8366 window.onwheel = function(){ return false;};
8368 (function(){ this.isMasked = true; }).defer(500, this);
8374 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8378 this.maskEl.top.setStyle('position', 'absolute');
8379 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8380 this.maskEl.top.hide();
8382 this.maskEl.left.setStyle('position', 'absolute');
8383 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8384 this.maskEl.left.hide();
8386 this.maskEl.bottom.setStyle('position', 'absolute');
8387 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8388 this.maskEl.bottom.hide();
8390 this.maskEl.right.setStyle('position', 'absolute');
8391 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8392 this.maskEl.right.hide();
8394 this.toolTip.hide();
8396 this.toolTip.el.hide();
8398 window.onwheel = function(){ return true;};
8400 if(this.intervalID){
8401 window.clearInterval(this.intervalID);
8402 this.intervalID = false;
8405 this.isMasked = false;
8415 * Ext JS Library 1.1.1
8416 * Copyright(c) 2006-2007, Ext JS, LLC.
8418 * Originally Released Under LGPL - original licence link has changed is not relivant.
8421 * <script type="text/javascript">
8424 * @class Roo.form.VTypes
8425 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8428 Roo.form.VTypes = function(){
8429 // closure these in so they are only created once.
8430 var alpha = /^[a-zA-Z_]+$/;
8431 var alphanum = /^[a-zA-Z0-9_]+$/;
8432 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8433 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8435 // All these messages and functions are configurable
8438 * The function used to validate email addresses
8439 * @param {String} value The email address
8441 'email' : function(v){
8442 return email.test(v);
8445 * The error text to display when the email validation function returns false
8448 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8450 * The keystroke filter mask to be applied on email input
8453 'emailMask' : /[a-z0-9_\.\-@]/i,
8456 * The function used to validate URLs
8457 * @param {String} value The URL
8459 'url' : function(v){
8463 * The error text to display when the url validation function returns false
8466 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8469 * The function used to validate alpha values
8470 * @param {String} value The value
8472 'alpha' : function(v){
8473 return alpha.test(v);
8476 * The error text to display when the alpha validation function returns false
8479 'alphaText' : 'This field should only contain letters and _',
8481 * The keystroke filter mask to be applied on alpha input
8484 'alphaMask' : /[a-z_]/i,
8487 * The function used to validate alphanumeric values
8488 * @param {String} value The value
8490 'alphanum' : function(v){
8491 return alphanum.test(v);
8494 * The error text to display when the alphanumeric validation function returns false
8497 'alphanumText' : 'This field should only contain letters, numbers and _',
8499 * The keystroke filter mask to be applied on alphanumeric input
8502 'alphanumMask' : /[a-z0-9_]/i
8512 * @class Roo.bootstrap.Input
8513 * @extends Roo.bootstrap.Component
8514 * Bootstrap Input class
8515 * @cfg {Boolean} disabled is it disabled
8516 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8517 * @cfg {String} name name of the input
8518 * @cfg {string} fieldLabel - the label associated
8519 * @cfg {string} placeholder - placeholder to put in text.
8520 * @cfg {string} before - input group add on before
8521 * @cfg {string} after - input group add on after
8522 * @cfg {string} size - (lg|sm) or leave empty..
8523 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8524 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8525 * @cfg {Number} md colspan out of 12 for computer-sized screens
8526 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8527 * @cfg {string} value default value of the input
8528 * @cfg {Number} labelWidth set the width of label
8529 * @cfg {Number} labellg set the width of label (1-12)
8530 * @cfg {Number} labelmd set the width of label (1-12)
8531 * @cfg {Number} labelsm set the width of label (1-12)
8532 * @cfg {Number} labelxs set the width of label (1-12)
8533 * @cfg {String} labelAlign (top|left)
8534 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8535 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8536 * @cfg {String} indicatorpos (left|right) default left
8538 * @cfg {String} align (left|center|right) Default left
8539 * @cfg {Boolean} forceFeedback (true|false) Default false
8542 * Create a new Input
8543 * @param {Object} config The config object
8546 Roo.bootstrap.Input = function(config){
8548 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8553 * Fires when this field receives input focus.
8554 * @param {Roo.form.Field} this
8559 * Fires when this field loses input focus.
8560 * @param {Roo.form.Field} this
8565 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8566 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8567 * @param {Roo.form.Field} this
8568 * @param {Roo.EventObject} e The event object
8573 * Fires just before the field blurs if the field value has changed.
8574 * @param {Roo.form.Field} this
8575 * @param {Mixed} newValue The new value
8576 * @param {Mixed} oldValue The original value
8581 * Fires after the field has been marked as invalid.
8582 * @param {Roo.form.Field} this
8583 * @param {String} msg The validation message
8588 * Fires after the field has been validated with no errors.
8589 * @param {Roo.form.Field} this
8594 * Fires after the key up
8595 * @param {Roo.form.Field} this
8596 * @param {Roo.EventObject} e The event Object
8602 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8604 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8605 automatic validation (defaults to "keyup").
8607 validationEvent : "keyup",
8609 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8611 validateOnBlur : true,
8613 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8615 validationDelay : 250,
8617 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8619 focusClass : "x-form-focus", // not needed???
8623 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8625 invalidClass : "has-warning",
8628 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8630 validClass : "has-success",
8633 * @cfg {Boolean} hasFeedback (true|false) default true
8638 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8640 invalidFeedbackClass : "glyphicon-warning-sign",
8643 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8645 validFeedbackClass : "glyphicon-ok",
8648 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8650 selectOnFocus : false,
8653 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8657 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8662 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8664 disableKeyFilter : false,
8667 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8671 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8675 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8677 blankText : "Please complete this mandatory field",
8680 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8684 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8686 maxLength : Number.MAX_VALUE,
8688 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8690 minLengthText : "The minimum length for this field is {0}",
8692 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8694 maxLengthText : "The maximum length for this field is {0}",
8698 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8699 * If available, this function will be called only after the basic validators all return true, and will be passed the
8700 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8704 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8705 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8706 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8710 * @cfg {String} regexText -- Depricated - use Invalid Text
8715 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8721 autocomplete: false,
8740 formatedValue : false,
8741 forceFeedback : false,
8743 indicatorpos : 'left',
8750 parentLabelAlign : function()
8753 while (parent.parent()) {
8754 parent = parent.parent();
8755 if (typeof(parent.labelAlign) !='undefined') {
8756 return parent.labelAlign;
8763 getAutoCreate : function()
8765 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8771 if(this.inputType != 'hidden'){
8772 cfg.cls = 'form-group' //input-group
8778 type : this.inputType,
8780 cls : 'form-control',
8781 placeholder : this.placeholder || '',
8782 autocomplete : this.autocomplete || 'new-password'
8786 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8789 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8790 input.maxLength = this.maxLength;
8793 if (this.disabled) {
8794 input.disabled=true;
8797 if (this.readOnly) {
8798 input.readonly=true;
8802 input.name = this.name;
8806 input.cls += ' input-' + this.size;
8810 ['xs','sm','md','lg'].map(function(size){
8811 if (settings[size]) {
8812 cfg.cls += ' col-' + size + '-' + settings[size];
8816 var inputblock = input;
8820 cls: 'glyphicon form-control-feedback'
8823 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8826 cls : 'has-feedback',
8834 if (this.before || this.after) {
8837 cls : 'input-group',
8841 if (this.before && typeof(this.before) == 'string') {
8843 inputblock.cn.push({
8845 cls : 'roo-input-before input-group-addon',
8849 if (this.before && typeof(this.before) == 'object') {
8850 this.before = Roo.factory(this.before);
8852 inputblock.cn.push({
8854 cls : 'roo-input-before input-group-' +
8855 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8859 inputblock.cn.push(input);
8861 if (this.after && typeof(this.after) == 'string') {
8862 inputblock.cn.push({
8864 cls : 'roo-input-after input-group-addon',
8868 if (this.after && typeof(this.after) == 'object') {
8869 this.after = Roo.factory(this.after);
8871 inputblock.cn.push({
8873 cls : 'roo-input-after input-group-' +
8874 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8878 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8879 inputblock.cls += ' has-feedback';
8880 inputblock.cn.push(feedback);
8884 if (align ==='left' && this.fieldLabel.length) {
8886 cfg.cls += ' roo-form-group-label-left';
8891 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8892 tooltip : 'This field is required'
8897 cls : 'control-label',
8898 html : this.fieldLabel
8909 var labelCfg = cfg.cn[1];
8910 var contentCfg = cfg.cn[2];
8912 if(this.indicatorpos == 'right'){
8917 cls : 'control-label',
8921 html : this.fieldLabel
8925 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8926 tooltip : 'This field is required'
8939 labelCfg = cfg.cn[0];
8940 contentCfg = cfg.cn[1];
8944 if(this.labelWidth > 12){
8945 labelCfg.style = "width: " + this.labelWidth + 'px';
8948 if(this.labelWidth < 13 && this.labelmd == 0){
8949 this.labelmd = this.labelWidth;
8952 if(this.labellg > 0){
8953 labelCfg.cls += ' col-lg-' + this.labellg;
8954 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8957 if(this.labelmd > 0){
8958 labelCfg.cls += ' col-md-' + this.labelmd;
8959 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8962 if(this.labelsm > 0){
8963 labelCfg.cls += ' col-sm-' + this.labelsm;
8964 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8967 if(this.labelxs > 0){
8968 labelCfg.cls += ' col-xs-' + this.labelxs;
8969 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8973 } else if ( this.fieldLabel.length) {
8978 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8979 tooltip : 'This field is required'
8983 //cls : 'input-group-addon',
8984 html : this.fieldLabel
8992 if(this.indicatorpos == 'right'){
8997 //cls : 'input-group-addon',
8998 html : this.fieldLabel
9003 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9004 tooltip : 'This field is required'
9024 if (this.parentType === 'Navbar' && this.parent().bar) {
9025 cfg.cls += ' navbar-form';
9028 if (this.parentType === 'NavGroup') {
9029 cfg.cls += ' navbar-form';
9037 * return the real input element.
9039 inputEl: function ()
9041 return this.el.select('input.form-control',true).first();
9044 tooltipEl : function()
9046 return this.inputEl();
9049 indicatorEl : function()
9051 var indicator = this.el.select('i.roo-required-indicator',true).first();
9061 setDisabled : function(v)
9063 var i = this.inputEl().dom;
9065 i.removeAttribute('disabled');
9069 i.setAttribute('disabled','true');
9071 initEvents : function()
9074 this.inputEl().on("keydown" , this.fireKey, this);
9075 this.inputEl().on("focus", this.onFocus, this);
9076 this.inputEl().on("blur", this.onBlur, this);
9078 this.inputEl().relayEvent('keyup', this);
9080 this.indicator = this.indicatorEl();
9083 this.indicator.addClass('invisible');
9086 // reference to original value for reset
9087 this.originalValue = this.getValue();
9088 //Roo.form.TextField.superclass.initEvents.call(this);
9089 if(this.validationEvent == 'keyup'){
9090 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9091 this.inputEl().on('keyup', this.filterValidation, this);
9093 else if(this.validationEvent !== false){
9094 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9097 if(this.selectOnFocus){
9098 this.on("focus", this.preFocus, this);
9101 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9102 this.inputEl().on("keypress", this.filterKeys, this);
9104 this.inputEl().relayEvent('keypress', this);
9107 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9108 this.el.on("click", this.autoSize, this);
9111 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9112 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9115 if (typeof(this.before) == 'object') {
9116 this.before.render(this.el.select('.roo-input-before',true).first());
9118 if (typeof(this.after) == 'object') {
9119 this.after.render(this.el.select('.roo-input-after',true).first());
9124 filterValidation : function(e){
9125 if(!e.isNavKeyPress()){
9126 this.validationTask.delay(this.validationDelay);
9130 * Validates the field value
9131 * @return {Boolean} True if the value is valid, else false
9133 validate : function(){
9134 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9135 if(this.disabled || this.validateValue(this.getRawValue())){
9146 * Validates a value according to the field's validation rules and marks the field as invalid
9147 * if the validation fails
9148 * @param {Mixed} value The value to validate
9149 * @return {Boolean} True if the value is valid, else false
9151 validateValue : function(value)
9153 if(this.getVisibilityEl().hasClass('hidden')){
9157 if(value.length < 1) { // if it's blank
9158 if(this.allowBlank){
9164 if(value.length < this.minLength){
9167 if(value.length > this.maxLength){
9171 var vt = Roo.form.VTypes;
9172 if(!vt[this.vtype](value, this)){
9176 if(typeof this.validator == "function"){
9177 var msg = this.validator(value);
9181 if (typeof(msg) == 'string') {
9182 this.invalidText = msg;
9186 if(this.regex && !this.regex.test(value)){
9194 fireKey : function(e){
9195 //Roo.log('field ' + e.getKey());
9196 if(e.isNavKeyPress()){
9197 this.fireEvent("specialkey", this, e);
9200 focus : function (selectText){
9202 this.inputEl().focus();
9203 if(selectText === true){
9204 this.inputEl().dom.select();
9210 onFocus : function(){
9211 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9212 // this.el.addClass(this.focusClass);
9215 this.hasFocus = true;
9216 this.startValue = this.getValue();
9217 this.fireEvent("focus", this);
9221 beforeBlur : Roo.emptyFn,
9225 onBlur : function(){
9227 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9228 //this.el.removeClass(this.focusClass);
9230 this.hasFocus = false;
9231 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9234 var v = this.getValue();
9235 if(String(v) !== String(this.startValue)){
9236 this.fireEvent('change', this, v, this.startValue);
9238 this.fireEvent("blur", this);
9242 * Resets the current field value to the originally loaded value and clears any validation messages
9245 this.setValue(this.originalValue);
9249 * Returns the name of the field
9250 * @return {Mixed} name The name field
9252 getName: function(){
9256 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9257 * @return {Mixed} value The field value
9259 getValue : function(){
9261 var v = this.inputEl().getValue();
9266 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9267 * @return {Mixed} value The field value
9269 getRawValue : function(){
9270 var v = this.inputEl().getValue();
9276 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9277 * @param {Mixed} value The value to set
9279 setRawValue : function(v){
9280 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9283 selectText : function(start, end){
9284 var v = this.getRawValue();
9286 start = start === undefined ? 0 : start;
9287 end = end === undefined ? v.length : end;
9288 var d = this.inputEl().dom;
9289 if(d.setSelectionRange){
9290 d.setSelectionRange(start, end);
9291 }else if(d.createTextRange){
9292 var range = d.createTextRange();
9293 range.moveStart("character", start);
9294 range.moveEnd("character", v.length-end);
9301 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9302 * @param {Mixed} value The value to set
9304 setValue : function(v){
9307 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9313 processValue : function(value){
9314 if(this.stripCharsRe){
9315 var newValue = value.replace(this.stripCharsRe, '');
9316 if(newValue !== value){
9317 this.setRawValue(newValue);
9324 preFocus : function(){
9326 if(this.selectOnFocus){
9327 this.inputEl().dom.select();
9330 filterKeys : function(e){
9332 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9335 var c = e.getCharCode(), cc = String.fromCharCode(c);
9336 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9339 if(!this.maskRe.test(cc)){
9344 * Clear any invalid styles/messages for this field
9346 clearInvalid : function(){
9348 if(!this.el || this.preventMark){ // not rendered
9353 this.el.removeClass(this.invalidClass);
9355 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9357 var feedback = this.el.select('.form-control-feedback', true).first();
9360 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9365 this.fireEvent('valid', this);
9369 * Mark this field as valid
9371 markValid : function()
9373 if(!this.el || this.preventMark){ // not rendered...
9377 this.el.removeClass([this.invalidClass, this.validClass]);
9379 var feedback = this.el.select('.form-control-feedback', true).first();
9382 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9386 this.indicator.removeClass('visible');
9387 this.indicator.addClass('invisible');
9394 if(this.allowBlank && !this.getRawValue().length){
9398 this.el.addClass(this.validClass);
9400 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9402 var feedback = this.el.select('.form-control-feedback', true).first();
9405 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9406 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9411 this.fireEvent('valid', this);
9415 * Mark this field as invalid
9416 * @param {String} msg The validation message
9418 markInvalid : function(msg)
9420 if(!this.el || this.preventMark){ // not rendered
9424 this.el.removeClass([this.invalidClass, this.validClass]);
9426 var feedback = this.el.select('.form-control-feedback', true).first();
9429 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9436 if(this.allowBlank && !this.getRawValue().length){
9441 this.indicator.removeClass('invisible');
9442 this.indicator.addClass('visible');
9445 this.el.addClass(this.invalidClass);
9447 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9449 var feedback = this.el.select('.form-control-feedback', true).first();
9452 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9454 if(this.getValue().length || this.forceFeedback){
9455 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9462 this.fireEvent('invalid', this, msg);
9465 SafariOnKeyDown : function(event)
9467 // this is a workaround for a password hang bug on chrome/ webkit.
9468 if (this.inputEl().dom.type != 'password') {
9472 var isSelectAll = false;
9474 if(this.inputEl().dom.selectionEnd > 0){
9475 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9477 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9478 event.preventDefault();
9483 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9485 event.preventDefault();
9486 // this is very hacky as keydown always get's upper case.
9488 var cc = String.fromCharCode(event.getCharCode());
9489 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9493 adjustWidth : function(tag, w){
9494 tag = tag.toLowerCase();
9495 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9496 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9500 if(tag == 'textarea'){
9503 }else if(Roo.isOpera){
9507 if(tag == 'textarea'){
9515 setFieldLabel : function(v)
9522 var ar = this.el.select('label > span',true);
9524 if (ar.elements.length) {
9525 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9526 this.fieldLabel = v;
9530 var br = this.el.select('label',true);
9532 if(br.elements.length) {
9533 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9534 this.fieldLabel = v;
9538 Roo.log('Cannot Found any of label > span || label in input');
9542 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9543 this.fieldLabel = v;
9558 * @class Roo.bootstrap.TextArea
9559 * @extends Roo.bootstrap.Input
9560 * Bootstrap TextArea class
9561 * @cfg {Number} cols Specifies the visible width of a text area
9562 * @cfg {Number} rows Specifies the visible number of lines in a text area
9563 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9564 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9565 * @cfg {string} html text
9568 * Create a new TextArea
9569 * @param {Object} config The config object
9572 Roo.bootstrap.TextArea = function(config){
9573 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9577 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9587 getAutoCreate : function(){
9589 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9595 if(this.inputType != 'hidden'){
9596 cfg.cls = 'form-group' //input-group
9604 value : this.value || '',
9605 html: this.html || '',
9606 cls : 'form-control',
9607 placeholder : this.placeholder || ''
9611 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9612 input.maxLength = this.maxLength;
9616 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9620 input.cols = this.cols;
9623 if (this.readOnly) {
9624 input.readonly = true;
9628 input.name = this.name;
9632 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9636 ['xs','sm','md','lg'].map(function(size){
9637 if (settings[size]) {
9638 cfg.cls += ' col-' + size + '-' + settings[size];
9642 var inputblock = input;
9644 if(this.hasFeedback && !this.allowBlank){
9648 cls: 'glyphicon form-control-feedback'
9652 cls : 'has-feedback',
9661 if (this.before || this.after) {
9664 cls : 'input-group',
9668 inputblock.cn.push({
9670 cls : 'input-group-addon',
9675 inputblock.cn.push(input);
9677 if(this.hasFeedback && !this.allowBlank){
9678 inputblock.cls += ' has-feedback';
9679 inputblock.cn.push(feedback);
9683 inputblock.cn.push({
9685 cls : 'input-group-addon',
9692 if (align ==='left' && this.fieldLabel.length) {
9697 cls : 'control-label',
9698 html : this.fieldLabel
9709 if(this.labelWidth > 12){
9710 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9713 if(this.labelWidth < 13 && this.labelmd == 0){
9714 this.labelmd = this.labelWidth;
9717 if(this.labellg > 0){
9718 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9719 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9722 if(this.labelmd > 0){
9723 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9724 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9727 if(this.labelsm > 0){
9728 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9729 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9732 if(this.labelxs > 0){
9733 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9734 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9737 } else if ( this.fieldLabel.length) {
9742 //cls : 'input-group-addon',
9743 html : this.fieldLabel
9761 if (this.disabled) {
9762 input.disabled=true;
9769 * return the real textarea element.
9771 inputEl: function ()
9773 return this.el.select('textarea.form-control',true).first();
9777 * Clear any invalid styles/messages for this field
9779 clearInvalid : function()
9782 if(!this.el || this.preventMark){ // not rendered
9786 var label = this.el.select('label', true).first();
9787 var icon = this.el.select('i.fa-star', true).first();
9793 this.el.removeClass(this.invalidClass);
9795 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9797 var feedback = this.el.select('.form-control-feedback', true).first();
9800 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9805 this.fireEvent('valid', this);
9809 * Mark this field as valid
9811 markValid : function()
9813 if(!this.el || this.preventMark){ // not rendered
9817 this.el.removeClass([this.invalidClass, this.validClass]);
9819 var feedback = this.el.select('.form-control-feedback', true).first();
9822 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9825 if(this.disabled || this.allowBlank){
9829 var label = this.el.select('label', true).first();
9830 var icon = this.el.select('i.fa-star', true).first();
9836 this.el.addClass(this.validClass);
9838 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9840 var feedback = this.el.select('.form-control-feedback', true).first();
9843 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9844 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9849 this.fireEvent('valid', this);
9853 * Mark this field as invalid
9854 * @param {String} msg The validation message
9856 markInvalid : function(msg)
9858 if(!this.el || this.preventMark){ // not rendered
9862 this.el.removeClass([this.invalidClass, this.validClass]);
9864 var feedback = this.el.select('.form-control-feedback', true).first();
9867 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9870 if(this.disabled || this.allowBlank){
9874 var label = this.el.select('label', true).first();
9875 var icon = this.el.select('i.fa-star', true).first();
9877 if(!this.getValue().length && label && !icon){
9878 this.el.createChild({
9880 cls : 'text-danger fa fa-lg fa-star',
9881 tooltip : 'This field is required',
9882 style : 'margin-right:5px;'
9886 this.el.addClass(this.invalidClass);
9888 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9890 var feedback = this.el.select('.form-control-feedback', true).first();
9893 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9895 if(this.getValue().length || this.forceFeedback){
9896 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9903 this.fireEvent('invalid', this, msg);
9911 * trigger field - base class for combo..
9916 * @class Roo.bootstrap.TriggerField
9917 * @extends Roo.bootstrap.Input
9918 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9919 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9920 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9921 * for which you can provide a custom implementation. For example:
9923 var trigger = new Roo.bootstrap.TriggerField();
9924 trigger.onTriggerClick = myTriggerFn;
9925 trigger.applyTo('my-field');
9928 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9929 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9930 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9931 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9932 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9935 * Create a new TriggerField.
9936 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9937 * to the base TextField)
9939 Roo.bootstrap.TriggerField = function(config){
9940 this.mimicing = false;
9941 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9944 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9946 * @cfg {String} triggerClass A CSS class to apply to the trigger
9949 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9954 * @cfg {Boolean} removable (true|false) special filter default false
9958 /** @cfg {Boolean} grow @hide */
9959 /** @cfg {Number} growMin @hide */
9960 /** @cfg {Number} growMax @hide */
9966 autoSize: Roo.emptyFn,
9973 actionMode : 'wrap',
9978 getAutoCreate : function(){
9980 var align = this.labelAlign || this.parentLabelAlign();
9985 cls: 'form-group' //input-group
9992 type : this.inputType,
9993 cls : 'form-control',
9994 autocomplete: 'new-password',
9995 placeholder : this.placeholder || ''
9999 input.name = this.name;
10002 input.cls += ' input-' + this.size;
10005 if (this.disabled) {
10006 input.disabled=true;
10009 var inputblock = input;
10011 if(this.hasFeedback && !this.allowBlank){
10015 cls: 'glyphicon form-control-feedback'
10018 if(this.removable && !this.editable && !this.tickable){
10020 cls : 'has-feedback',
10026 cls : 'roo-combo-removable-btn close'
10033 cls : 'has-feedback',
10042 if(this.removable && !this.editable && !this.tickable){
10044 cls : 'roo-removable',
10050 cls : 'roo-combo-removable-btn close'
10057 if (this.before || this.after) {
10060 cls : 'input-group',
10064 inputblock.cn.push({
10066 cls : 'input-group-addon',
10071 inputblock.cn.push(input);
10073 if(this.hasFeedback && !this.allowBlank){
10074 inputblock.cls += ' has-feedback';
10075 inputblock.cn.push(feedback);
10079 inputblock.cn.push({
10081 cls : 'input-group-addon',
10094 cls: 'form-hidden-field'
10108 cls: 'form-hidden-field'
10112 cls: 'roo-select2-choices',
10116 cls: 'roo-select2-search-field',
10129 cls: 'roo-select2-container input-group',
10134 // cls: 'typeahead typeahead-long dropdown-menu',
10135 // style: 'display:none'
10140 if(!this.multiple && this.showToggleBtn){
10146 if (this.caret != false) {
10149 cls: 'fa fa-' + this.caret
10156 cls : 'input-group-addon btn dropdown-toggle',
10161 cls: 'combobox-clear',
10175 combobox.cls += ' roo-select2-container-multi';
10178 if (align ==='left' && this.fieldLabel.length) {
10180 cfg.cls += ' roo-form-group-label-left';
10185 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10186 tooltip : 'This field is required'
10191 cls : 'control-label',
10192 html : this.fieldLabel
10204 var labelCfg = cfg.cn[1];
10205 var contentCfg = cfg.cn[2];
10207 if(this.indicatorpos == 'right'){
10212 cls : 'control-label',
10216 html : this.fieldLabel
10220 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10221 tooltip : 'This field is required'
10234 labelCfg = cfg.cn[0];
10235 contentCfg = cfg.cn[1];
10238 if(this.labelWidth > 12){
10239 labelCfg.style = "width: " + this.labelWidth + 'px';
10242 if(this.labelWidth < 13 && this.labelmd == 0){
10243 this.labelmd = this.labelWidth;
10246 if(this.labellg > 0){
10247 labelCfg.cls += ' col-lg-' + this.labellg;
10248 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10251 if(this.labelmd > 0){
10252 labelCfg.cls += ' col-md-' + this.labelmd;
10253 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10256 if(this.labelsm > 0){
10257 labelCfg.cls += ' col-sm-' + this.labelsm;
10258 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10261 if(this.labelxs > 0){
10262 labelCfg.cls += ' col-xs-' + this.labelxs;
10263 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10266 } else if ( this.fieldLabel.length) {
10267 // Roo.log(" label");
10271 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10272 tooltip : 'This field is required'
10276 //cls : 'input-group-addon',
10277 html : this.fieldLabel
10285 if(this.indicatorpos == 'right'){
10293 html : this.fieldLabel
10297 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10298 tooltip : 'This field is required'
10311 // Roo.log(" no label && no align");
10318 ['xs','sm','md','lg'].map(function(size){
10319 if (settings[size]) {
10320 cfg.cls += ' col-' + size + '-' + settings[size];
10331 onResize : function(w, h){
10332 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10333 // if(typeof w == 'number'){
10334 // var x = w - this.trigger.getWidth();
10335 // this.inputEl().setWidth(this.adjustWidth('input', x));
10336 // this.trigger.setStyle('left', x+'px');
10341 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10344 getResizeEl : function(){
10345 return this.inputEl();
10349 getPositionEl : function(){
10350 return this.inputEl();
10354 alignErrorIcon : function(){
10355 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10359 initEvents : function(){
10363 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10364 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10365 if(!this.multiple && this.showToggleBtn){
10366 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10367 if(this.hideTrigger){
10368 this.trigger.setDisplayed(false);
10370 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10374 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10377 if(this.removable && !this.editable && !this.tickable){
10378 var close = this.closeTriggerEl();
10381 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10382 close.on('click', this.removeBtnClick, this, close);
10386 //this.trigger.addClassOnOver('x-form-trigger-over');
10387 //this.trigger.addClassOnClick('x-form-trigger-click');
10390 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10394 closeTriggerEl : function()
10396 var close = this.el.select('.roo-combo-removable-btn', true).first();
10397 return close ? close : false;
10400 removeBtnClick : function(e, h, el)
10402 e.preventDefault();
10404 if(this.fireEvent("remove", this) !== false){
10406 this.fireEvent("afterremove", this)
10410 createList : function()
10412 this.list = Roo.get(document.body).createChild({
10414 cls: 'typeahead typeahead-long dropdown-menu',
10415 style: 'display:none'
10418 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10423 initTrigger : function(){
10428 onDestroy : function(){
10430 this.trigger.removeAllListeners();
10431 // this.trigger.remove();
10434 // this.wrap.remove();
10436 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10440 onFocus : function(){
10441 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10443 if(!this.mimicing){
10444 this.wrap.addClass('x-trigger-wrap-focus');
10445 this.mimicing = true;
10446 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10447 if(this.monitorTab){
10448 this.el.on("keydown", this.checkTab, this);
10455 checkTab : function(e){
10456 if(e.getKey() == e.TAB){
10457 this.triggerBlur();
10462 onBlur : function(){
10467 mimicBlur : function(e, t){
10469 if(!this.wrap.contains(t) && this.validateBlur()){
10470 this.triggerBlur();
10476 triggerBlur : function(){
10477 this.mimicing = false;
10478 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10479 if(this.monitorTab){
10480 this.el.un("keydown", this.checkTab, this);
10482 //this.wrap.removeClass('x-trigger-wrap-focus');
10483 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10487 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10488 validateBlur : function(e, t){
10493 onDisable : function(){
10494 this.inputEl().dom.disabled = true;
10495 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10497 // this.wrap.addClass('x-item-disabled');
10502 onEnable : function(){
10503 this.inputEl().dom.disabled = false;
10504 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10506 // this.el.removeClass('x-item-disabled');
10511 onShow : function(){
10512 var ae = this.getActionEl();
10515 ae.dom.style.display = '';
10516 ae.dom.style.visibility = 'visible';
10522 onHide : function(){
10523 var ae = this.getActionEl();
10524 ae.dom.style.display = 'none';
10528 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10529 * by an implementing function.
10531 * @param {EventObject} e
10533 onTriggerClick : Roo.emptyFn
10537 * Ext JS Library 1.1.1
10538 * Copyright(c) 2006-2007, Ext JS, LLC.
10540 * Originally Released Under LGPL - original licence link has changed is not relivant.
10543 * <script type="text/javascript">
10548 * @class Roo.data.SortTypes
10550 * Defines the default sorting (casting?) comparison functions used when sorting data.
10552 Roo.data.SortTypes = {
10554 * Default sort that does nothing
10555 * @param {Mixed} s The value being converted
10556 * @return {Mixed} The comparison value
10558 none : function(s){
10563 * The regular expression used to strip tags
10567 stripTagsRE : /<\/?[^>]+>/gi,
10570 * Strips all HTML tags to sort on text only
10571 * @param {Mixed} s The value being converted
10572 * @return {String} The comparison value
10574 asText : function(s){
10575 return String(s).replace(this.stripTagsRE, "");
10579 * Strips all HTML tags to sort on text only - Case insensitive
10580 * @param {Mixed} s The value being converted
10581 * @return {String} The comparison value
10583 asUCText : function(s){
10584 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10588 * Case insensitive string
10589 * @param {Mixed} s The value being converted
10590 * @return {String} The comparison value
10592 asUCString : function(s) {
10593 return String(s).toUpperCase();
10598 * @param {Mixed} s The value being converted
10599 * @return {Number} The comparison value
10601 asDate : function(s) {
10605 if(s instanceof Date){
10606 return s.getTime();
10608 return Date.parse(String(s));
10613 * @param {Mixed} s The value being converted
10614 * @return {Float} The comparison value
10616 asFloat : function(s) {
10617 var val = parseFloat(String(s).replace(/,/g, ""));
10626 * @param {Mixed} s The value being converted
10627 * @return {Number} The comparison value
10629 asInt : function(s) {
10630 var val = parseInt(String(s).replace(/,/g, ""));
10638 * Ext JS Library 1.1.1
10639 * Copyright(c) 2006-2007, Ext JS, LLC.
10641 * Originally Released Under LGPL - original licence link has changed is not relivant.
10644 * <script type="text/javascript">
10648 * @class Roo.data.Record
10649 * Instances of this class encapsulate both record <em>definition</em> information, and record
10650 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10651 * to access Records cached in an {@link Roo.data.Store} object.<br>
10653 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10654 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10657 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10659 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10660 * {@link #create}. The parameters are the same.
10661 * @param {Array} data An associative Array of data values keyed by the field name.
10662 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10663 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10664 * not specified an integer id is generated.
10666 Roo.data.Record = function(data, id){
10667 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10672 * Generate a constructor for a specific record layout.
10673 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10674 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10675 * Each field definition object may contain the following properties: <ul>
10676 * <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,
10677 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10678 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10679 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10680 * is being used, then this is a string containing the javascript expression to reference the data relative to
10681 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10682 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10683 * this may be omitted.</p></li>
10684 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10685 * <ul><li>auto (Default, implies no conversion)</li>
10690 * <li>date</li></ul></p></li>
10691 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10692 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10693 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10694 * by the Reader into an object that will be stored in the Record. It is passed the
10695 * following parameters:<ul>
10696 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10698 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10700 * <br>usage:<br><pre><code>
10701 var TopicRecord = Roo.data.Record.create(
10702 {name: 'title', mapping: 'topic_title'},
10703 {name: 'author', mapping: 'username'},
10704 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10705 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10706 {name: 'lastPoster', mapping: 'user2'},
10707 {name: 'excerpt', mapping: 'post_text'}
10710 var myNewRecord = new TopicRecord({
10711 title: 'Do my job please',
10714 lastPost: new Date(),
10715 lastPoster: 'Animal',
10716 excerpt: 'No way dude!'
10718 myStore.add(myNewRecord);
10723 Roo.data.Record.create = function(o){
10724 var f = function(){
10725 f.superclass.constructor.apply(this, arguments);
10727 Roo.extend(f, Roo.data.Record);
10728 var p = f.prototype;
10729 p.fields = new Roo.util.MixedCollection(false, function(field){
10732 for(var i = 0, len = o.length; i < len; i++){
10733 p.fields.add(new Roo.data.Field(o[i]));
10735 f.getField = function(name){
10736 return p.fields.get(name);
10741 Roo.data.Record.AUTO_ID = 1000;
10742 Roo.data.Record.EDIT = 'edit';
10743 Roo.data.Record.REJECT = 'reject';
10744 Roo.data.Record.COMMIT = 'commit';
10746 Roo.data.Record.prototype = {
10748 * Readonly flag - true if this record has been modified.
10757 join : function(store){
10758 this.store = store;
10762 * Set the named field to the specified value.
10763 * @param {String} name The name of the field to set.
10764 * @param {Object} value The value to set the field to.
10766 set : function(name, value){
10767 if(this.data[name] == value){
10771 if(!this.modified){
10772 this.modified = {};
10774 if(typeof this.modified[name] == 'undefined'){
10775 this.modified[name] = this.data[name];
10777 this.data[name] = value;
10778 if(!this.editing && this.store){
10779 this.store.afterEdit(this);
10784 * Get the value of the named field.
10785 * @param {String} name The name of the field to get the value of.
10786 * @return {Object} The value of the field.
10788 get : function(name){
10789 return this.data[name];
10793 beginEdit : function(){
10794 this.editing = true;
10795 this.modified = {};
10799 cancelEdit : function(){
10800 this.editing = false;
10801 delete this.modified;
10805 endEdit : function(){
10806 this.editing = false;
10807 if(this.dirty && this.store){
10808 this.store.afterEdit(this);
10813 * Usually called by the {@link Roo.data.Store} which owns the Record.
10814 * Rejects all changes made to the Record since either creation, or the last commit operation.
10815 * Modified fields are reverted to their original values.
10817 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10818 * of reject operations.
10820 reject : function(){
10821 var m = this.modified;
10823 if(typeof m[n] != "function"){
10824 this.data[n] = m[n];
10827 this.dirty = false;
10828 delete this.modified;
10829 this.editing = false;
10831 this.store.afterReject(this);
10836 * Usually called by the {@link Roo.data.Store} which owns the Record.
10837 * Commits all changes made to the Record since either creation, or the last commit operation.
10839 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10840 * of commit operations.
10842 commit : function(){
10843 this.dirty = false;
10844 delete this.modified;
10845 this.editing = false;
10847 this.store.afterCommit(this);
10852 hasError : function(){
10853 return this.error != null;
10857 clearError : function(){
10862 * Creates a copy of this record.
10863 * @param {String} id (optional) A new record id if you don't want to use this record's id
10866 copy : function(newId) {
10867 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10871 * Ext JS Library 1.1.1
10872 * Copyright(c) 2006-2007, Ext JS, LLC.
10874 * Originally Released Under LGPL - original licence link has changed is not relivant.
10877 * <script type="text/javascript">
10883 * @class Roo.data.Store
10884 * @extends Roo.util.Observable
10885 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10886 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10888 * 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
10889 * has no knowledge of the format of the data returned by the Proxy.<br>
10891 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10892 * instances from the data object. These records are cached and made available through accessor functions.
10894 * Creates a new Store.
10895 * @param {Object} config A config object containing the objects needed for the Store to access data,
10896 * and read the data into Records.
10898 Roo.data.Store = function(config){
10899 this.data = new Roo.util.MixedCollection(false);
10900 this.data.getKey = function(o){
10903 this.baseParams = {};
10905 this.paramNames = {
10910 "multisort" : "_multisort"
10913 if(config && config.data){
10914 this.inlineData = config.data;
10915 delete config.data;
10918 Roo.apply(this, config);
10920 if(this.reader){ // reader passed
10921 this.reader = Roo.factory(this.reader, Roo.data);
10922 this.reader.xmodule = this.xmodule || false;
10923 if(!this.recordType){
10924 this.recordType = this.reader.recordType;
10926 if(this.reader.onMetaChange){
10927 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10931 if(this.recordType){
10932 this.fields = this.recordType.prototype.fields;
10934 this.modified = [];
10938 * @event datachanged
10939 * Fires when the data cache has changed, and a widget which is using this Store
10940 * as a Record cache should refresh its view.
10941 * @param {Store} this
10943 datachanged : true,
10945 * @event metachange
10946 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10947 * @param {Store} this
10948 * @param {Object} meta The JSON metadata
10953 * Fires when Records have been added to the Store
10954 * @param {Store} this
10955 * @param {Roo.data.Record[]} records The array of Records added
10956 * @param {Number} index The index at which the record(s) were added
10961 * Fires when a Record has been removed from the Store
10962 * @param {Store} this
10963 * @param {Roo.data.Record} record The Record that was removed
10964 * @param {Number} index The index at which the record was removed
10969 * Fires when a Record has been updated
10970 * @param {Store} this
10971 * @param {Roo.data.Record} record The Record that was updated
10972 * @param {String} operation The update operation being performed. Value may be one of:
10974 Roo.data.Record.EDIT
10975 Roo.data.Record.REJECT
10976 Roo.data.Record.COMMIT
10982 * Fires when the data cache has been cleared.
10983 * @param {Store} this
10987 * @event beforeload
10988 * Fires before a request is made for a new data object. If the beforeload handler returns false
10989 * the load action will be canceled.
10990 * @param {Store} this
10991 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10995 * @event beforeloadadd
10996 * Fires after a new set of Records has been loaded.
10997 * @param {Store} this
10998 * @param {Roo.data.Record[]} records The Records that were loaded
10999 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11001 beforeloadadd : true,
11004 * Fires after a new set of Records has been loaded, before they are added to the store.
11005 * @param {Store} this
11006 * @param {Roo.data.Record[]} records The Records that were loaded
11007 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11008 * @params {Object} return from reader
11012 * @event loadexception
11013 * Fires if an exception occurs in the Proxy during loading.
11014 * Called with the signature of the Proxy's "loadexception" event.
11015 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11018 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11019 * @param {Object} load options
11020 * @param {Object} jsonData from your request (normally this contains the Exception)
11022 loadexception : true
11026 this.proxy = Roo.factory(this.proxy, Roo.data);
11027 this.proxy.xmodule = this.xmodule || false;
11028 this.relayEvents(this.proxy, ["loadexception"]);
11030 this.sortToggle = {};
11031 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11033 Roo.data.Store.superclass.constructor.call(this);
11035 if(this.inlineData){
11036 this.loadData(this.inlineData);
11037 delete this.inlineData;
11041 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11043 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11044 * without a remote query - used by combo/forms at present.
11048 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11051 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11054 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11055 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11058 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11059 * on any HTTP request
11062 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11065 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11069 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11070 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11072 remoteSort : false,
11075 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11076 * loaded or when a record is removed. (defaults to false).
11078 pruneModifiedRecords : false,
11081 lastOptions : null,
11084 * Add Records to the Store and fires the add event.
11085 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11087 add : function(records){
11088 records = [].concat(records);
11089 for(var i = 0, len = records.length; i < len; i++){
11090 records[i].join(this);
11092 var index = this.data.length;
11093 this.data.addAll(records);
11094 this.fireEvent("add", this, records, index);
11098 * Remove a Record from the Store and fires the remove event.
11099 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11101 remove : function(record){
11102 var index = this.data.indexOf(record);
11103 this.data.removeAt(index);
11104 if(this.pruneModifiedRecords){
11105 this.modified.remove(record);
11107 this.fireEvent("remove", this, record, index);
11111 * Remove all Records from the Store and fires the clear event.
11113 removeAll : function(){
11115 if(this.pruneModifiedRecords){
11116 this.modified = [];
11118 this.fireEvent("clear", this);
11122 * Inserts Records to the Store at the given index and fires the add event.
11123 * @param {Number} index The start index at which to insert the passed Records.
11124 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11126 insert : function(index, records){
11127 records = [].concat(records);
11128 for(var i = 0, len = records.length; i < len; i++){
11129 this.data.insert(index, records[i]);
11130 records[i].join(this);
11132 this.fireEvent("add", this, records, index);
11136 * Get the index within the cache of the passed Record.
11137 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11138 * @return {Number} The index of the passed Record. Returns -1 if not found.
11140 indexOf : function(record){
11141 return this.data.indexOf(record);
11145 * Get the index within the cache of the Record with the passed id.
11146 * @param {String} id The id of the Record to find.
11147 * @return {Number} The index of the Record. Returns -1 if not found.
11149 indexOfId : function(id){
11150 return this.data.indexOfKey(id);
11154 * Get the Record with the specified id.
11155 * @param {String} id The id of the Record to find.
11156 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11158 getById : function(id){
11159 return this.data.key(id);
11163 * Get the Record at the specified index.
11164 * @param {Number} index The index of the Record to find.
11165 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11167 getAt : function(index){
11168 return this.data.itemAt(index);
11172 * Returns a range of Records between specified indices.
11173 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11174 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11175 * @return {Roo.data.Record[]} An array of Records
11177 getRange : function(start, end){
11178 return this.data.getRange(start, end);
11182 storeOptions : function(o){
11183 o = Roo.apply({}, o);
11186 this.lastOptions = o;
11190 * Loads the Record cache from the configured Proxy using the configured Reader.
11192 * If using remote paging, then the first load call must specify the <em>start</em>
11193 * and <em>limit</em> properties in the options.params property to establish the initial
11194 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11196 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11197 * and this call will return before the new data has been loaded. Perform any post-processing
11198 * in a callback function, or in a "load" event handler.</strong>
11200 * @param {Object} options An object containing properties which control loading options:<ul>
11201 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11202 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11203 * passed the following arguments:<ul>
11204 * <li>r : Roo.data.Record[]</li>
11205 * <li>options: Options object from the load call</li>
11206 * <li>success: Boolean success indicator</li></ul></li>
11207 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11208 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11211 load : function(options){
11212 options = options || {};
11213 if(this.fireEvent("beforeload", this, options) !== false){
11214 this.storeOptions(options);
11215 var p = Roo.apply(options.params || {}, this.baseParams);
11216 // if meta was not loaded from remote source.. try requesting it.
11217 if (!this.reader.metaFromRemote) {
11218 p._requestMeta = 1;
11220 if(this.sortInfo && this.remoteSort){
11221 var pn = this.paramNames;
11222 p[pn["sort"]] = this.sortInfo.field;
11223 p[pn["dir"]] = this.sortInfo.direction;
11225 if (this.multiSort) {
11226 var pn = this.paramNames;
11227 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11230 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11235 * Reloads the Record cache from the configured Proxy using the configured Reader and
11236 * the options from the last load operation performed.
11237 * @param {Object} options (optional) An object containing properties which may override the options
11238 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11239 * the most recently used options are reused).
11241 reload : function(options){
11242 this.load(Roo.applyIf(options||{}, this.lastOptions));
11246 // Called as a callback by the Reader during a load operation.
11247 loadRecords : function(o, options, success){
11248 if(!o || success === false){
11249 if(success !== false){
11250 this.fireEvent("load", this, [], options, o);
11252 if(options.callback){
11253 options.callback.call(options.scope || this, [], options, false);
11257 // if data returned failure - throw an exception.
11258 if (o.success === false) {
11259 // show a message if no listener is registered.
11260 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11261 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11263 // loadmask wil be hooked into this..
11264 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11267 var r = o.records, t = o.totalRecords || r.length;
11269 this.fireEvent("beforeloadadd", this, r, options, o);
11271 if(!options || options.add !== true){
11272 if(this.pruneModifiedRecords){
11273 this.modified = [];
11275 for(var i = 0, len = r.length; i < len; i++){
11279 this.data = this.snapshot;
11280 delete this.snapshot;
11283 this.data.addAll(r);
11284 this.totalLength = t;
11286 this.fireEvent("datachanged", this);
11288 this.totalLength = Math.max(t, this.data.length+r.length);
11292 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11294 var e = new Roo.data.Record({});
11296 e.set(this.parent.displayField, this.parent.emptyTitle);
11297 e.set(this.parent.valueField, '');
11302 this.fireEvent("load", this, r, options, o);
11303 if(options.callback){
11304 options.callback.call(options.scope || this, r, options, true);
11310 * Loads data from a passed data block. A Reader which understands the format of the data
11311 * must have been configured in the constructor.
11312 * @param {Object} data The data block from which to read the Records. The format of the data expected
11313 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11314 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11316 loadData : function(o, append){
11317 var r = this.reader.readRecords(o);
11318 this.loadRecords(r, {add: append}, true);
11322 * Gets the number of cached records.
11324 * <em>If using paging, this may not be the total size of the dataset. If the data object
11325 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11326 * the data set size</em>
11328 getCount : function(){
11329 return this.data.length || 0;
11333 * Gets the total number of records in the dataset as returned by the server.
11335 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11336 * the dataset size</em>
11338 getTotalCount : function(){
11339 return this.totalLength || 0;
11343 * Returns the sort state of the Store as an object with two properties:
11345 field {String} The name of the field by which the Records are sorted
11346 direction {String} The sort order, "ASC" or "DESC"
11349 getSortState : function(){
11350 return this.sortInfo;
11354 applySort : function(){
11355 if(this.sortInfo && !this.remoteSort){
11356 var s = this.sortInfo, f = s.field;
11357 var st = this.fields.get(f).sortType;
11358 var fn = function(r1, r2){
11359 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11360 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11362 this.data.sort(s.direction, fn);
11363 if(this.snapshot && this.snapshot != this.data){
11364 this.snapshot.sort(s.direction, fn);
11370 * Sets the default sort column and order to be used by the next load operation.
11371 * @param {String} fieldName The name of the field to sort by.
11372 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11374 setDefaultSort : function(field, dir){
11375 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11379 * Sort the Records.
11380 * If remote sorting is used, the sort is performed on the server, and the cache is
11381 * reloaded. If local sorting is used, the cache is sorted internally.
11382 * @param {String} fieldName The name of the field to sort by.
11383 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11385 sort : function(fieldName, dir){
11386 var f = this.fields.get(fieldName);
11388 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11390 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11391 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11396 this.sortToggle[f.name] = dir;
11397 this.sortInfo = {field: f.name, direction: dir};
11398 if(!this.remoteSort){
11400 this.fireEvent("datachanged", this);
11402 this.load(this.lastOptions);
11407 * Calls the specified function for each of the Records in the cache.
11408 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11409 * Returning <em>false</em> aborts and exits the iteration.
11410 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11412 each : function(fn, scope){
11413 this.data.each(fn, scope);
11417 * Gets all records modified since the last commit. Modified records are persisted across load operations
11418 * (e.g., during paging).
11419 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11421 getModifiedRecords : function(){
11422 return this.modified;
11426 createFilterFn : function(property, value, anyMatch){
11427 if(!value.exec){ // not a regex
11428 value = String(value);
11429 if(value.length == 0){
11432 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11434 return function(r){
11435 return value.test(r.data[property]);
11440 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11441 * @param {String} property A field on your records
11442 * @param {Number} start The record index to start at (defaults to 0)
11443 * @param {Number} end The last record index to include (defaults to length - 1)
11444 * @return {Number} The sum
11446 sum : function(property, start, end){
11447 var rs = this.data.items, v = 0;
11448 start = start || 0;
11449 end = (end || end === 0) ? end : rs.length-1;
11451 for(var i = start; i <= end; i++){
11452 v += (rs[i].data[property] || 0);
11458 * Filter the records by a specified property.
11459 * @param {String} field A field on your records
11460 * @param {String/RegExp} value Either a string that the field
11461 * should start with or a RegExp to test against the field
11462 * @param {Boolean} anyMatch True to match any part not just the beginning
11464 filter : function(property, value, anyMatch){
11465 var fn = this.createFilterFn(property, value, anyMatch);
11466 return fn ? this.filterBy(fn) : this.clearFilter();
11470 * Filter by a function. The specified function will be called with each
11471 * record in this data source. If the function returns true the record is included,
11472 * otherwise it is filtered.
11473 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11474 * @param {Object} scope (optional) The scope of the function (defaults to this)
11476 filterBy : function(fn, scope){
11477 this.snapshot = this.snapshot || this.data;
11478 this.data = this.queryBy(fn, scope||this);
11479 this.fireEvent("datachanged", this);
11483 * Query the records by a specified property.
11484 * @param {String} field A field on your records
11485 * @param {String/RegExp} value Either a string that the field
11486 * should start with or a RegExp to test against the field
11487 * @param {Boolean} anyMatch True to match any part not just the beginning
11488 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11490 query : function(property, value, anyMatch){
11491 var fn = this.createFilterFn(property, value, anyMatch);
11492 return fn ? this.queryBy(fn) : this.data.clone();
11496 * Query by a function. The specified function will be called with each
11497 * record in this data source. If the function returns true the record is included
11499 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11500 * @param {Object} scope (optional) The scope of the function (defaults to this)
11501 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11503 queryBy : function(fn, scope){
11504 var data = this.snapshot || this.data;
11505 return data.filterBy(fn, scope||this);
11509 * Collects unique values for a particular dataIndex from this store.
11510 * @param {String} dataIndex The property to collect
11511 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11512 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11513 * @return {Array} An array of the unique values
11515 collect : function(dataIndex, allowNull, bypassFilter){
11516 var d = (bypassFilter === true && this.snapshot) ?
11517 this.snapshot.items : this.data.items;
11518 var v, sv, r = [], l = {};
11519 for(var i = 0, len = d.length; i < len; i++){
11520 v = d[i].data[dataIndex];
11522 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11531 * Revert to a view of the Record cache with no filtering applied.
11532 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11534 clearFilter : function(suppressEvent){
11535 if(this.snapshot && this.snapshot != this.data){
11536 this.data = this.snapshot;
11537 delete this.snapshot;
11538 if(suppressEvent !== true){
11539 this.fireEvent("datachanged", this);
11545 afterEdit : function(record){
11546 if(this.modified.indexOf(record) == -1){
11547 this.modified.push(record);
11549 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11553 afterReject : function(record){
11554 this.modified.remove(record);
11555 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11559 afterCommit : function(record){
11560 this.modified.remove(record);
11561 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11565 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11566 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11568 commitChanges : function(){
11569 var m = this.modified.slice(0);
11570 this.modified = [];
11571 for(var i = 0, len = m.length; i < len; i++){
11577 * Cancel outstanding changes on all changed records.
11579 rejectChanges : function(){
11580 var m = this.modified.slice(0);
11581 this.modified = [];
11582 for(var i = 0, len = m.length; i < len; i++){
11587 onMetaChange : function(meta, rtype, o){
11588 this.recordType = rtype;
11589 this.fields = rtype.prototype.fields;
11590 delete this.snapshot;
11591 this.sortInfo = meta.sortInfo || this.sortInfo;
11592 this.modified = [];
11593 this.fireEvent('metachange', this, this.reader.meta);
11596 moveIndex : function(data, type)
11598 var index = this.indexOf(data);
11600 var newIndex = index + type;
11604 this.insert(newIndex, data);
11609 * Ext JS Library 1.1.1
11610 * Copyright(c) 2006-2007, Ext JS, LLC.
11612 * Originally Released Under LGPL - original licence link has changed is not relivant.
11615 * <script type="text/javascript">
11619 * @class Roo.data.SimpleStore
11620 * @extends Roo.data.Store
11621 * Small helper class to make creating Stores from Array data easier.
11622 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11623 * @cfg {Array} fields An array of field definition objects, or field name strings.
11624 * @cfg {Array} data The multi-dimensional array of data
11626 * @param {Object} config
11628 Roo.data.SimpleStore = function(config){
11629 Roo.data.SimpleStore.superclass.constructor.call(this, {
11631 reader: new Roo.data.ArrayReader({
11634 Roo.data.Record.create(config.fields)
11636 proxy : new Roo.data.MemoryProxy(config.data)
11640 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11642 * Ext JS Library 1.1.1
11643 * Copyright(c) 2006-2007, Ext JS, LLC.
11645 * Originally Released Under LGPL - original licence link has changed is not relivant.
11648 * <script type="text/javascript">
11653 * @extends Roo.data.Store
11654 * @class Roo.data.JsonStore
11655 * Small helper class to make creating Stores for JSON data easier. <br/>
11657 var store = new Roo.data.JsonStore({
11658 url: 'get-images.php',
11660 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11663 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11664 * JsonReader and HttpProxy (unless inline data is provided).</b>
11665 * @cfg {Array} fields An array of field definition objects, or field name strings.
11667 * @param {Object} config
11669 Roo.data.JsonStore = function(c){
11670 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11671 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11672 reader: new Roo.data.JsonReader(c, c.fields)
11675 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11677 * Ext JS Library 1.1.1
11678 * Copyright(c) 2006-2007, Ext JS, LLC.
11680 * Originally Released Under LGPL - original licence link has changed is not relivant.
11683 * <script type="text/javascript">
11687 Roo.data.Field = function(config){
11688 if(typeof config == "string"){
11689 config = {name: config};
11691 Roo.apply(this, config);
11694 this.type = "auto";
11697 var st = Roo.data.SortTypes;
11698 // named sortTypes are supported, here we look them up
11699 if(typeof this.sortType == "string"){
11700 this.sortType = st[this.sortType];
11703 // set default sortType for strings and dates
11704 if(!this.sortType){
11707 this.sortType = st.asUCString;
11710 this.sortType = st.asDate;
11713 this.sortType = st.none;
11718 var stripRe = /[\$,%]/g;
11720 // prebuilt conversion function for this field, instead of
11721 // switching every time we're reading a value
11723 var cv, dateFormat = this.dateFormat;
11728 cv = function(v){ return v; };
11731 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11735 return v !== undefined && v !== null && v !== '' ?
11736 parseInt(String(v).replace(stripRe, ""), 10) : '';
11741 return v !== undefined && v !== null && v !== '' ?
11742 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11747 cv = function(v){ return v === true || v === "true" || v == 1; };
11754 if(v instanceof Date){
11758 if(dateFormat == "timestamp"){
11759 return new Date(v*1000);
11761 return Date.parseDate(v, dateFormat);
11763 var parsed = Date.parse(v);
11764 return parsed ? new Date(parsed) : null;
11773 Roo.data.Field.prototype = {
11781 * Ext JS Library 1.1.1
11782 * Copyright(c) 2006-2007, Ext JS, LLC.
11784 * Originally Released Under LGPL - original licence link has changed is not relivant.
11787 * <script type="text/javascript">
11790 // Base class for reading structured data from a data source. This class is intended to be
11791 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11794 * @class Roo.data.DataReader
11795 * Base class for reading structured data from a data source. This class is intended to be
11796 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11799 Roo.data.DataReader = function(meta, recordType){
11803 this.recordType = recordType instanceof Array ?
11804 Roo.data.Record.create(recordType) : recordType;
11807 Roo.data.DataReader.prototype = {
11809 * Create an empty record
11810 * @param {Object} data (optional) - overlay some values
11811 * @return {Roo.data.Record} record created.
11813 newRow : function(d) {
11815 this.recordType.prototype.fields.each(function(c) {
11817 case 'int' : da[c.name] = 0; break;
11818 case 'date' : da[c.name] = new Date(); break;
11819 case 'float' : da[c.name] = 0.0; break;
11820 case 'boolean' : da[c.name] = false; break;
11821 default : da[c.name] = ""; break;
11825 return new this.recordType(Roo.apply(da, d));
11830 * Ext JS Library 1.1.1
11831 * Copyright(c) 2006-2007, Ext JS, LLC.
11833 * Originally Released Under LGPL - original licence link has changed is not relivant.
11836 * <script type="text/javascript">
11840 * @class Roo.data.DataProxy
11841 * @extends Roo.data.Observable
11842 * This class is an abstract base class for implementations which provide retrieval of
11843 * unformatted data objects.<br>
11845 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11846 * (of the appropriate type which knows how to parse the data object) to provide a block of
11847 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11849 * Custom implementations must implement the load method as described in
11850 * {@link Roo.data.HttpProxy#load}.
11852 Roo.data.DataProxy = function(){
11855 * @event beforeload
11856 * Fires before a network request is made to retrieve a data object.
11857 * @param {Object} This DataProxy object.
11858 * @param {Object} params The params parameter to the load function.
11863 * Fires before the load method's callback is called.
11864 * @param {Object} This DataProxy object.
11865 * @param {Object} o The data object.
11866 * @param {Object} arg The callback argument object passed to the load function.
11870 * @event loadexception
11871 * Fires if an Exception occurs during data retrieval.
11872 * @param {Object} This DataProxy object.
11873 * @param {Object} o The data object.
11874 * @param {Object} arg The callback argument object passed to the load function.
11875 * @param {Object} e The Exception.
11877 loadexception : true
11879 Roo.data.DataProxy.superclass.constructor.call(this);
11882 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11885 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11889 * Ext JS Library 1.1.1
11890 * Copyright(c) 2006-2007, Ext JS, LLC.
11892 * Originally Released Under LGPL - original licence link has changed is not relivant.
11895 * <script type="text/javascript">
11898 * @class Roo.data.MemoryProxy
11899 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11900 * to the Reader when its load method is called.
11902 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11904 Roo.data.MemoryProxy = function(data){
11908 Roo.data.MemoryProxy.superclass.constructor.call(this);
11912 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11915 * Load data from the requested source (in this case an in-memory
11916 * data object passed to the constructor), read the data object into
11917 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11918 * process that block using the passed callback.
11919 * @param {Object} params This parameter is not used by the MemoryProxy class.
11920 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11921 * object into a block of Roo.data.Records.
11922 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11923 * The function must be passed <ul>
11924 * <li>The Record block object</li>
11925 * <li>The "arg" argument from the load function</li>
11926 * <li>A boolean success indicator</li>
11928 * @param {Object} scope The scope in which to call the callback
11929 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11931 load : function(params, reader, callback, scope, arg){
11932 params = params || {};
11935 result = reader.readRecords(this.data);
11937 this.fireEvent("loadexception", this, arg, null, e);
11938 callback.call(scope, null, arg, false);
11941 callback.call(scope, result, arg, true);
11945 update : function(params, records){
11950 * Ext JS Library 1.1.1
11951 * Copyright(c) 2006-2007, Ext JS, LLC.
11953 * Originally Released Under LGPL - original licence link has changed is not relivant.
11956 * <script type="text/javascript">
11959 * @class Roo.data.HttpProxy
11960 * @extends Roo.data.DataProxy
11961 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11962 * configured to reference a certain URL.<br><br>
11964 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11965 * from which the running page was served.<br><br>
11967 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11969 * Be aware that to enable the browser to parse an XML document, the server must set
11970 * the Content-Type header in the HTTP response to "text/xml".
11972 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11973 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11974 * will be used to make the request.
11976 Roo.data.HttpProxy = function(conn){
11977 Roo.data.HttpProxy.superclass.constructor.call(this);
11978 // is conn a conn config or a real conn?
11980 this.useAjax = !conn || !conn.events;
11984 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11985 // thse are take from connection...
11988 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11991 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11992 * extra parameters to each request made by this object. (defaults to undefined)
11995 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11996 * to each request made by this object. (defaults to undefined)
11999 * @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)
12002 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12005 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12011 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12015 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12016 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12017 * a finer-grained basis than the DataProxy events.
12019 getConnection : function(){
12020 return this.useAjax ? Roo.Ajax : this.conn;
12024 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12025 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12026 * process that block using the passed callback.
12027 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12028 * for the request to the remote server.
12029 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12030 * object into a block of Roo.data.Records.
12031 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12032 * The function must be passed <ul>
12033 * <li>The Record block object</li>
12034 * <li>The "arg" argument from the load function</li>
12035 * <li>A boolean success indicator</li>
12037 * @param {Object} scope The scope in which to call the callback
12038 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12040 load : function(params, reader, callback, scope, arg){
12041 if(this.fireEvent("beforeload", this, params) !== false){
12043 params : params || {},
12045 callback : callback,
12050 callback : this.loadResponse,
12054 Roo.applyIf(o, this.conn);
12055 if(this.activeRequest){
12056 Roo.Ajax.abort(this.activeRequest);
12058 this.activeRequest = Roo.Ajax.request(o);
12060 this.conn.request(o);
12063 callback.call(scope||this, null, arg, false);
12068 loadResponse : function(o, success, response){
12069 delete this.activeRequest;
12071 this.fireEvent("loadexception", this, o, response);
12072 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12077 result = o.reader.read(response);
12079 this.fireEvent("loadexception", this, o, response, e);
12080 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12084 this.fireEvent("load", this, o, o.request.arg);
12085 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12089 update : function(dataSet){
12094 updateResponse : function(dataSet){
12099 * Ext JS Library 1.1.1
12100 * Copyright(c) 2006-2007, Ext JS, LLC.
12102 * Originally Released Under LGPL - original licence link has changed is not relivant.
12105 * <script type="text/javascript">
12109 * @class Roo.data.ScriptTagProxy
12110 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12111 * other than the originating domain of the running page.<br><br>
12113 * <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
12114 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12116 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12117 * source code that is used as the source inside a <script> tag.<br><br>
12119 * In order for the browser to process the returned data, the server must wrap the data object
12120 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12121 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12122 * depending on whether the callback name was passed:
12125 boolean scriptTag = false;
12126 String cb = request.getParameter("callback");
12129 response.setContentType("text/javascript");
12131 response.setContentType("application/x-json");
12133 Writer out = response.getWriter();
12135 out.write(cb + "(");
12137 out.print(dataBlock.toJsonString());
12144 * @param {Object} config A configuration object.
12146 Roo.data.ScriptTagProxy = function(config){
12147 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12148 Roo.apply(this, config);
12149 this.head = document.getElementsByTagName("head")[0];
12152 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12154 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12156 * @cfg {String} url The URL from which to request the data object.
12159 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12163 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12164 * the server the name of the callback function set up by the load call to process the returned data object.
12165 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12166 * javascript output which calls this named function passing the data object as its only parameter.
12168 callbackParam : "callback",
12170 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12171 * name to the request.
12176 * Load data from the configured URL, read the data object into
12177 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12178 * process that block using the passed callback.
12179 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12180 * for the request to the remote server.
12181 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12182 * object into a block of Roo.data.Records.
12183 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12184 * The function must be passed <ul>
12185 * <li>The Record block object</li>
12186 * <li>The "arg" argument from the load function</li>
12187 * <li>A boolean success indicator</li>
12189 * @param {Object} scope The scope in which to call the callback
12190 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12192 load : function(params, reader, callback, scope, arg){
12193 if(this.fireEvent("beforeload", this, params) !== false){
12195 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12197 var url = this.url;
12198 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12200 url += "&_dc=" + (new Date().getTime());
12202 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12205 cb : "stcCallback"+transId,
12206 scriptId : "stcScript"+transId,
12210 callback : callback,
12216 window[trans.cb] = function(o){
12217 conn.handleResponse(o, trans);
12220 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12222 if(this.autoAbort !== false){
12226 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12228 var script = document.createElement("script");
12229 script.setAttribute("src", url);
12230 script.setAttribute("type", "text/javascript");
12231 script.setAttribute("id", trans.scriptId);
12232 this.head.appendChild(script);
12234 this.trans = trans;
12236 callback.call(scope||this, null, arg, false);
12241 isLoading : function(){
12242 return this.trans ? true : false;
12246 * Abort the current server request.
12248 abort : function(){
12249 if(this.isLoading()){
12250 this.destroyTrans(this.trans);
12255 destroyTrans : function(trans, isLoaded){
12256 this.head.removeChild(document.getElementById(trans.scriptId));
12257 clearTimeout(trans.timeoutId);
12259 window[trans.cb] = undefined;
12261 delete window[trans.cb];
12264 // if hasn't been loaded, wait for load to remove it to prevent script error
12265 window[trans.cb] = function(){
12266 window[trans.cb] = undefined;
12268 delete window[trans.cb];
12275 handleResponse : function(o, trans){
12276 this.trans = false;
12277 this.destroyTrans(trans, true);
12280 result = trans.reader.readRecords(o);
12282 this.fireEvent("loadexception", this, o, trans.arg, e);
12283 trans.callback.call(trans.scope||window, null, trans.arg, false);
12286 this.fireEvent("load", this, o, trans.arg);
12287 trans.callback.call(trans.scope||window, result, trans.arg, true);
12291 handleFailure : function(trans){
12292 this.trans = false;
12293 this.destroyTrans(trans, false);
12294 this.fireEvent("loadexception", this, null, trans.arg);
12295 trans.callback.call(trans.scope||window, null, trans.arg, false);
12299 * Ext JS Library 1.1.1
12300 * Copyright(c) 2006-2007, Ext JS, LLC.
12302 * Originally Released Under LGPL - original licence link has changed is not relivant.
12305 * <script type="text/javascript">
12309 * @class Roo.data.JsonReader
12310 * @extends Roo.data.DataReader
12311 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12312 * based on mappings in a provided Roo.data.Record constructor.
12314 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12315 * in the reply previously.
12320 var RecordDef = Roo.data.Record.create([
12321 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12322 {name: 'occupation'} // This field will use "occupation" as the mapping.
12324 var myReader = new Roo.data.JsonReader({
12325 totalProperty: "results", // The property which contains the total dataset size (optional)
12326 root: "rows", // The property which contains an Array of row objects
12327 id: "id" // The property within each row object that provides an ID for the record (optional)
12331 * This would consume a JSON file like this:
12333 { 'results': 2, 'rows': [
12334 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12335 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12338 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12339 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12340 * paged from the remote server.
12341 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12342 * @cfg {String} root name of the property which contains the Array of row objects.
12343 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12344 * @cfg {Array} fields Array of field definition objects
12346 * Create a new JsonReader
12347 * @param {Object} meta Metadata configuration options
12348 * @param {Object} recordType Either an Array of field definition objects,
12349 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12351 Roo.data.JsonReader = function(meta, recordType){
12354 // set some defaults:
12355 Roo.applyIf(meta, {
12356 totalProperty: 'total',
12357 successProperty : 'success',
12362 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12364 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12367 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12368 * Used by Store query builder to append _requestMeta to params.
12371 metaFromRemote : false,
12373 * This method is only used by a DataProxy which has retrieved data from a remote server.
12374 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12375 * @return {Object} data A data block which is used by an Roo.data.Store object as
12376 * a cache of Roo.data.Records.
12378 read : function(response){
12379 var json = response.responseText;
12381 var o = /* eval:var:o */ eval("("+json+")");
12383 throw {message: "JsonReader.read: Json object not found"};
12389 this.metaFromRemote = true;
12390 this.meta = o.metaData;
12391 this.recordType = Roo.data.Record.create(o.metaData.fields);
12392 this.onMetaChange(this.meta, this.recordType, o);
12394 return this.readRecords(o);
12397 // private function a store will implement
12398 onMetaChange : function(meta, recordType, o){
12405 simpleAccess: function(obj, subsc) {
12412 getJsonAccessor: function(){
12414 return function(expr) {
12416 return(re.test(expr))
12417 ? new Function("obj", "return obj." + expr)
12422 return Roo.emptyFn;
12427 * Create a data block containing Roo.data.Records from an XML document.
12428 * @param {Object} o An object which contains an Array of row objects in the property specified
12429 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12430 * which contains the total size of the dataset.
12431 * @return {Object} data A data block which is used by an Roo.data.Store object as
12432 * a cache of Roo.data.Records.
12434 readRecords : function(o){
12436 * After any data loads, the raw JSON data is available for further custom processing.
12440 var s = this.meta, Record = this.recordType,
12441 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12443 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12445 if(s.totalProperty) {
12446 this.getTotal = this.getJsonAccessor(s.totalProperty);
12448 if(s.successProperty) {
12449 this.getSuccess = this.getJsonAccessor(s.successProperty);
12451 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12453 var g = this.getJsonAccessor(s.id);
12454 this.getId = function(rec) {
12456 return (r === undefined || r === "") ? null : r;
12459 this.getId = function(){return null;};
12462 for(var jj = 0; jj < fl; jj++){
12464 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12465 this.ef[jj] = this.getJsonAccessor(map);
12469 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12470 if(s.totalProperty){
12471 var vt = parseInt(this.getTotal(o), 10);
12476 if(s.successProperty){
12477 var vs = this.getSuccess(o);
12478 if(vs === false || vs === 'false'){
12483 for(var i = 0; i < c; i++){
12486 var id = this.getId(n);
12487 for(var j = 0; j < fl; j++){
12489 var v = this.ef[j](n);
12491 Roo.log('missing convert for ' + f.name);
12495 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12497 var record = new Record(values, id);
12499 records[i] = record;
12505 totalRecords : totalRecords
12510 * Ext JS Library 1.1.1
12511 * Copyright(c) 2006-2007, Ext JS, LLC.
12513 * Originally Released Under LGPL - original licence link has changed is not relivant.
12516 * <script type="text/javascript">
12520 * @class Roo.data.ArrayReader
12521 * @extends Roo.data.DataReader
12522 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12523 * Each element of that Array represents a row of data fields. The
12524 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12525 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12529 var RecordDef = Roo.data.Record.create([
12530 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12531 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12533 var myReader = new Roo.data.ArrayReader({
12534 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12538 * This would consume an Array like this:
12540 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12542 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12544 * Create a new JsonReader
12545 * @param {Object} meta Metadata configuration options.
12546 * @param {Object} recordType Either an Array of field definition objects
12547 * as specified to {@link Roo.data.Record#create},
12548 * or an {@link Roo.data.Record} object
12549 * created using {@link Roo.data.Record#create}.
12551 Roo.data.ArrayReader = function(meta, recordType){
12552 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12555 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12557 * Create a data block containing Roo.data.Records from an XML document.
12558 * @param {Object} o An Array of row objects which represents the dataset.
12559 * @return {Object} data A data block which is used by an Roo.data.Store object as
12560 * a cache of Roo.data.Records.
12562 readRecords : function(o){
12563 var sid = this.meta ? this.meta.id : null;
12564 var recordType = this.recordType, fields = recordType.prototype.fields;
12567 for(var i = 0; i < root.length; i++){
12570 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12571 for(var j = 0, jlen = fields.length; j < jlen; j++){
12572 var f = fields.items[j];
12573 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12574 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12576 values[f.name] = v;
12578 var record = new recordType(values, id);
12580 records[records.length] = record;
12584 totalRecords : records.length
12593 * @class Roo.bootstrap.ComboBox
12594 * @extends Roo.bootstrap.TriggerField
12595 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12596 * @cfg {Boolean} append (true|false) default false
12597 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12598 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12599 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12600 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12601 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12602 * @cfg {Boolean} animate default true
12603 * @cfg {Boolean} emptyResultText only for touch device
12604 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12605 * @cfg {String} emptyTitle default ''
12607 * Create a new ComboBox.
12608 * @param {Object} config Configuration options
12610 Roo.bootstrap.ComboBox = function(config){
12611 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12615 * Fires when the dropdown list is expanded
12616 * @param {Roo.bootstrap.ComboBox} combo This combo box
12621 * Fires when the dropdown list is collapsed
12622 * @param {Roo.bootstrap.ComboBox} combo This combo box
12626 * @event beforeselect
12627 * Fires before a list item is selected. Return false to cancel the selection.
12628 * @param {Roo.bootstrap.ComboBox} combo This combo box
12629 * @param {Roo.data.Record} record The data record returned from the underlying store
12630 * @param {Number} index The index of the selected item in the dropdown list
12632 'beforeselect' : true,
12635 * Fires when a list item is selected
12636 * @param {Roo.bootstrap.ComboBox} combo This combo box
12637 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12638 * @param {Number} index The index of the selected item in the dropdown list
12642 * @event beforequery
12643 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12644 * The event object passed has these properties:
12645 * @param {Roo.bootstrap.ComboBox} combo This combo box
12646 * @param {String} query The query
12647 * @param {Boolean} forceAll true to force "all" query
12648 * @param {Boolean} cancel true to cancel the query
12649 * @param {Object} e The query event object
12651 'beforequery': true,
12654 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12655 * @param {Roo.bootstrap.ComboBox} combo This combo box
12660 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12661 * @param {Roo.bootstrap.ComboBox} combo This combo box
12662 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12667 * Fires when the remove value from the combobox array
12668 * @param {Roo.bootstrap.ComboBox} combo This combo box
12672 * @event afterremove
12673 * Fires when the remove value from the combobox array
12674 * @param {Roo.bootstrap.ComboBox} combo This combo box
12676 'afterremove' : true,
12678 * @event specialfilter
12679 * Fires when specialfilter
12680 * @param {Roo.bootstrap.ComboBox} combo This combo box
12682 'specialfilter' : true,
12685 * Fires when tick the element
12686 * @param {Roo.bootstrap.ComboBox} combo This combo box
12690 * @event touchviewdisplay
12691 * Fires when touch view require special display (default is using displayField)
12692 * @param {Roo.bootstrap.ComboBox} combo This combo box
12693 * @param {Object} cfg set html .
12695 'touchviewdisplay' : true
12700 this.tickItems = [];
12702 this.selectedIndex = -1;
12703 if(this.mode == 'local'){
12704 if(config.queryDelay === undefined){
12705 this.queryDelay = 10;
12707 if(config.minChars === undefined){
12713 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12716 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12717 * rendering into an Roo.Editor, defaults to false)
12720 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12721 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12724 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12727 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12728 * the dropdown list (defaults to undefined, with no header element)
12732 * @cfg {String/Roo.Template} tpl The template to use to render the output
12736 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12738 listWidth: undefined,
12740 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12741 * mode = 'remote' or 'text' if mode = 'local')
12743 displayField: undefined,
12746 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12747 * mode = 'remote' or 'value' if mode = 'local').
12748 * Note: use of a valueField requires the user make a selection
12749 * in order for a value to be mapped.
12751 valueField: undefined,
12753 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12758 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12759 * field's data value (defaults to the underlying DOM element's name)
12761 hiddenName: undefined,
12763 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12767 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12769 selectedClass: 'active',
12772 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12776 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12777 * anchor positions (defaults to 'tl-bl')
12779 listAlign: 'tl-bl?',
12781 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12785 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12786 * query specified by the allQuery config option (defaults to 'query')
12788 triggerAction: 'query',
12790 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12791 * (defaults to 4, does not apply if editable = false)
12795 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12796 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12800 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12801 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12805 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12806 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12810 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12811 * when editable = true (defaults to false)
12813 selectOnFocus:false,
12815 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12817 queryParam: 'query',
12819 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12820 * when mode = 'remote' (defaults to 'Loading...')
12822 loadingText: 'Loading...',
12824 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12828 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12832 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12833 * traditional select (defaults to true)
12837 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12841 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12845 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12846 * listWidth has a higher value)
12850 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12851 * allow the user to set arbitrary text into the field (defaults to false)
12853 forceSelection:false,
12855 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12856 * if typeAhead = true (defaults to 250)
12858 typeAheadDelay : 250,
12860 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12861 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12863 valueNotFoundText : undefined,
12865 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12867 blockFocus : false,
12870 * @cfg {Boolean} disableClear Disable showing of clear button.
12872 disableClear : false,
12874 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12876 alwaysQuery : false,
12879 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12884 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12886 invalidClass : "has-warning",
12889 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12891 validClass : "has-success",
12894 * @cfg {Boolean} specialFilter (true|false) special filter default false
12896 specialFilter : false,
12899 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12901 mobileTouchView : true,
12904 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12906 useNativeIOS : false,
12908 ios_options : false,
12920 btnPosition : 'right',
12921 triggerList : true,
12922 showToggleBtn : true,
12924 emptyResultText: 'Empty',
12925 triggerText : 'Select',
12928 // element that contains real text value.. (when hidden is used..)
12930 getAutoCreate : function()
12935 * Render classic select for iso
12938 if(Roo.isIOS && this.useNativeIOS){
12939 cfg = this.getAutoCreateNativeIOS();
12947 if(Roo.isTouch && this.mobileTouchView){
12948 cfg = this.getAutoCreateTouchView();
12955 if(!this.tickable){
12956 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12961 * ComboBox with tickable selections
12964 var align = this.labelAlign || this.parentLabelAlign();
12967 cls : 'form-group roo-combobox-tickable' //input-group
12970 var btn_text_select = '';
12971 var btn_text_done = '';
12972 var btn_text_cancel = '';
12974 if (this.btn_text_show) {
12975 btn_text_select = 'Select';
12976 btn_text_done = 'Done';
12977 btn_text_cancel = 'Cancel';
12982 cls : 'tickable-buttons',
12987 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12988 //html : this.triggerText
12989 html: btn_text_select
12995 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12997 html: btn_text_done
13003 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13005 html: btn_text_cancel
13011 buttons.cn.unshift({
13013 cls: 'roo-select2-search-field-input'
13019 Roo.each(buttons.cn, function(c){
13021 c.cls += ' btn-' + _this.size;
13024 if (_this.disabled) {
13035 cls: 'form-hidden-field'
13039 cls: 'roo-select2-choices',
13043 cls: 'roo-select2-search-field',
13054 cls: 'roo-select2-container input-group roo-select2-container-multi',
13059 // cls: 'typeahead typeahead-long dropdown-menu',
13060 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13065 if(this.hasFeedback && !this.allowBlank){
13069 cls: 'glyphicon form-control-feedback'
13072 combobox.cn.push(feedback);
13076 if (align ==='left' && this.fieldLabel.length) {
13078 cfg.cls += ' roo-form-group-label-left';
13083 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13084 tooltip : 'This field is required'
13089 cls : 'control-label',
13090 html : this.fieldLabel
13102 var labelCfg = cfg.cn[1];
13103 var contentCfg = cfg.cn[2];
13106 if(this.indicatorpos == 'right'){
13112 cls : 'control-label',
13116 html : this.fieldLabel
13120 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13121 tooltip : 'This field is required'
13136 labelCfg = cfg.cn[0];
13137 contentCfg = cfg.cn[1];
13141 if(this.labelWidth > 12){
13142 labelCfg.style = "width: " + this.labelWidth + 'px';
13145 if(this.labelWidth < 13 && this.labelmd == 0){
13146 this.labelmd = this.labelWidth;
13149 if(this.labellg > 0){
13150 labelCfg.cls += ' col-lg-' + this.labellg;
13151 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13154 if(this.labelmd > 0){
13155 labelCfg.cls += ' col-md-' + this.labelmd;
13156 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13159 if(this.labelsm > 0){
13160 labelCfg.cls += ' col-sm-' + this.labelsm;
13161 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13164 if(this.labelxs > 0){
13165 labelCfg.cls += ' col-xs-' + this.labelxs;
13166 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13170 } else if ( this.fieldLabel.length) {
13171 // Roo.log(" label");
13175 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13176 tooltip : 'This field is required'
13180 //cls : 'input-group-addon',
13181 html : this.fieldLabel
13186 if(this.indicatorpos == 'right'){
13190 //cls : 'input-group-addon',
13191 html : this.fieldLabel
13195 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13196 tooltip : 'This field is required'
13205 // Roo.log(" no label && no align");
13212 ['xs','sm','md','lg'].map(function(size){
13213 if (settings[size]) {
13214 cfg.cls += ' col-' + size + '-' + settings[size];
13222 _initEventsCalled : false,
13225 initEvents: function()
13227 if (this._initEventsCalled) { // as we call render... prevent looping...
13230 this._initEventsCalled = true;
13233 throw "can not find store for combo";
13236 this.indicator = this.indicatorEl();
13238 this.store = Roo.factory(this.store, Roo.data);
13239 this.store.parent = this;
13241 // if we are building from html. then this element is so complex, that we can not really
13242 // use the rendered HTML.
13243 // so we have to trash and replace the previous code.
13244 if (Roo.XComponent.build_from_html) {
13245 // remove this element....
13246 var e = this.el.dom, k=0;
13247 while (e ) { e = e.previousSibling; ++k;}
13252 this.rendered = false;
13254 this.render(this.parent().getChildContainer(true), k);
13257 if(Roo.isIOS && this.useNativeIOS){
13258 this.initIOSView();
13266 if(Roo.isTouch && this.mobileTouchView){
13267 this.initTouchView();
13272 this.initTickableEvents();
13276 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13278 if(this.hiddenName){
13280 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13282 this.hiddenField.dom.value =
13283 this.hiddenValue !== undefined ? this.hiddenValue :
13284 this.value !== undefined ? this.value : '';
13286 // prevent input submission
13287 this.el.dom.removeAttribute('name');
13288 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13293 // this.el.dom.setAttribute('autocomplete', 'off');
13296 var cls = 'x-combo-list';
13298 //this.list = new Roo.Layer({
13299 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13305 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13306 _this.list.setWidth(lw);
13309 this.list.on('mouseover', this.onViewOver, this);
13310 this.list.on('mousemove', this.onViewMove, this);
13311 this.list.on('scroll', this.onViewScroll, this);
13314 this.list.swallowEvent('mousewheel');
13315 this.assetHeight = 0;
13318 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13319 this.assetHeight += this.header.getHeight();
13322 this.innerList = this.list.createChild({cls:cls+'-inner'});
13323 this.innerList.on('mouseover', this.onViewOver, this);
13324 this.innerList.on('mousemove', this.onViewMove, this);
13325 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13327 if(this.allowBlank && !this.pageSize && !this.disableClear){
13328 this.footer = this.list.createChild({cls:cls+'-ft'});
13329 this.pageTb = new Roo.Toolbar(this.footer);
13333 this.footer = this.list.createChild({cls:cls+'-ft'});
13334 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13335 {pageSize: this.pageSize});
13339 if (this.pageTb && this.allowBlank && !this.disableClear) {
13341 this.pageTb.add(new Roo.Toolbar.Fill(), {
13342 cls: 'x-btn-icon x-btn-clear',
13344 handler: function()
13347 _this.clearValue();
13348 _this.onSelect(false, -1);
13353 this.assetHeight += this.footer.getHeight();
13358 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13361 this.view = new Roo.View(this.list, this.tpl, {
13362 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13364 //this.view.wrapEl.setDisplayed(false);
13365 this.view.on('click', this.onViewClick, this);
13368 this.store.on('beforeload', this.onBeforeLoad, this);
13369 this.store.on('load', this.onLoad, this);
13370 this.store.on('loadexception', this.onLoadException, this);
13372 if(this.resizable){
13373 this.resizer = new Roo.Resizable(this.list, {
13374 pinned:true, handles:'se'
13376 this.resizer.on('resize', function(r, w, h){
13377 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13378 this.listWidth = w;
13379 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13380 this.restrictHeight();
13382 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13385 if(!this.editable){
13386 this.editable = true;
13387 this.setEditable(false);
13392 if (typeof(this.events.add.listeners) != 'undefined') {
13394 this.addicon = this.wrap.createChild(
13395 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13397 this.addicon.on('click', function(e) {
13398 this.fireEvent('add', this);
13401 if (typeof(this.events.edit.listeners) != 'undefined') {
13403 this.editicon = this.wrap.createChild(
13404 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13405 if (this.addicon) {
13406 this.editicon.setStyle('margin-left', '40px');
13408 this.editicon.on('click', function(e) {
13410 // we fire even if inothing is selected..
13411 this.fireEvent('edit', this, this.lastData );
13417 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13418 "up" : function(e){
13419 this.inKeyMode = true;
13423 "down" : function(e){
13424 if(!this.isExpanded()){
13425 this.onTriggerClick();
13427 this.inKeyMode = true;
13432 "enter" : function(e){
13433 // this.onViewClick();
13437 if(this.fireEvent("specialkey", this, e)){
13438 this.onViewClick(false);
13444 "esc" : function(e){
13448 "tab" : function(e){
13451 if(this.fireEvent("specialkey", this, e)){
13452 this.onViewClick(false);
13460 doRelay : function(foo, bar, hname){
13461 if(hname == 'down' || this.scope.isExpanded()){
13462 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13471 this.queryDelay = Math.max(this.queryDelay || 10,
13472 this.mode == 'local' ? 10 : 250);
13475 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13477 if(this.typeAhead){
13478 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13480 if(this.editable !== false){
13481 this.inputEl().on("keyup", this.onKeyUp, this);
13483 if(this.forceSelection){
13484 this.inputEl().on('blur', this.doForce, this);
13488 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13489 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13493 initTickableEvents: function()
13497 if(this.hiddenName){
13499 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13501 this.hiddenField.dom.value =
13502 this.hiddenValue !== undefined ? this.hiddenValue :
13503 this.value !== undefined ? this.value : '';
13505 // prevent input submission
13506 this.el.dom.removeAttribute('name');
13507 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13512 // this.list = this.el.select('ul.dropdown-menu',true).first();
13514 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13515 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13516 if(this.triggerList){
13517 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13520 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13521 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13523 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13524 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13526 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13527 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13529 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13530 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13531 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13534 this.cancelBtn.hide();
13539 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13540 _this.list.setWidth(lw);
13543 this.list.on('mouseover', this.onViewOver, this);
13544 this.list.on('mousemove', this.onViewMove, this);
13546 this.list.on('scroll', this.onViewScroll, this);
13549 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>';
13552 this.view = new Roo.View(this.list, this.tpl, {
13553 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13556 //this.view.wrapEl.setDisplayed(false);
13557 this.view.on('click', this.onViewClick, this);
13561 this.store.on('beforeload', this.onBeforeLoad, this);
13562 this.store.on('load', this.onLoad, this);
13563 this.store.on('loadexception', this.onLoadException, this);
13566 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13567 "up" : function(e){
13568 this.inKeyMode = true;
13572 "down" : function(e){
13573 this.inKeyMode = true;
13577 "enter" : function(e){
13578 if(this.fireEvent("specialkey", this, e)){
13579 this.onViewClick(false);
13585 "esc" : function(e){
13586 this.onTickableFooterButtonClick(e, false, false);
13589 "tab" : function(e){
13590 this.fireEvent("specialkey", this, e);
13592 this.onTickableFooterButtonClick(e, false, false);
13599 doRelay : function(e, fn, key){
13600 if(this.scope.isExpanded()){
13601 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13610 this.queryDelay = Math.max(this.queryDelay || 10,
13611 this.mode == 'local' ? 10 : 250);
13614 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13616 if(this.typeAhead){
13617 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13620 if(this.editable !== false){
13621 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13624 this.indicator = this.indicatorEl();
13626 if(this.indicator){
13627 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13628 this.indicator.hide();
13633 onDestroy : function(){
13635 this.view.setStore(null);
13636 this.view.el.removeAllListeners();
13637 this.view.el.remove();
13638 this.view.purgeListeners();
13641 this.list.dom.innerHTML = '';
13645 this.store.un('beforeload', this.onBeforeLoad, this);
13646 this.store.un('load', this.onLoad, this);
13647 this.store.un('loadexception', this.onLoadException, this);
13649 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13653 fireKey : function(e){
13654 if(e.isNavKeyPress() && !this.list.isVisible()){
13655 this.fireEvent("specialkey", this, e);
13660 onResize: function(w, h){
13661 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13663 // if(typeof w != 'number'){
13664 // // we do not handle it!?!?
13667 // var tw = this.trigger.getWidth();
13668 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13669 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13671 // this.inputEl().setWidth( this.adjustWidth('input', x));
13673 // //this.trigger.setStyle('left', x+'px');
13675 // if(this.list && this.listWidth === undefined){
13676 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13677 // this.list.setWidth(lw);
13678 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13686 * Allow or prevent the user from directly editing the field text. If false is passed,
13687 * the user will only be able to select from the items defined in the dropdown list. This method
13688 * is the runtime equivalent of setting the 'editable' config option at config time.
13689 * @param {Boolean} value True to allow the user to directly edit the field text
13691 setEditable : function(value){
13692 if(value == this.editable){
13695 this.editable = value;
13697 this.inputEl().dom.setAttribute('readOnly', true);
13698 this.inputEl().on('mousedown', this.onTriggerClick, this);
13699 this.inputEl().addClass('x-combo-noedit');
13701 this.inputEl().dom.setAttribute('readOnly', false);
13702 this.inputEl().un('mousedown', this.onTriggerClick, this);
13703 this.inputEl().removeClass('x-combo-noedit');
13709 onBeforeLoad : function(combo,opts){
13710 if(!this.hasFocus){
13714 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13716 this.restrictHeight();
13717 this.selectedIndex = -1;
13721 onLoad : function(){
13723 this.hasQuery = false;
13725 if(!this.hasFocus){
13729 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13730 this.loading.hide();
13733 if(this.store.getCount() > 0){
13736 this.restrictHeight();
13737 if(this.lastQuery == this.allQuery){
13738 if(this.editable && !this.tickable){
13739 this.inputEl().dom.select();
13743 !this.selectByValue(this.value, true) &&
13746 !this.store.lastOptions ||
13747 typeof(this.store.lastOptions.add) == 'undefined' ||
13748 this.store.lastOptions.add != true
13751 this.select(0, true);
13754 if(this.autoFocus){
13757 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13758 this.taTask.delay(this.typeAheadDelay);
13762 this.onEmptyResults();
13768 onLoadException : function()
13770 this.hasQuery = false;
13772 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13773 this.loading.hide();
13776 if(this.tickable && this.editable){
13781 // only causes errors at present
13782 //Roo.log(this.store.reader.jsonData);
13783 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13785 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13791 onTypeAhead : function(){
13792 if(this.store.getCount() > 0){
13793 var r = this.store.getAt(0);
13794 var newValue = r.data[this.displayField];
13795 var len = newValue.length;
13796 var selStart = this.getRawValue().length;
13798 if(selStart != len){
13799 this.setRawValue(newValue);
13800 this.selectText(selStart, newValue.length);
13806 onSelect : function(record, index){
13808 if(this.fireEvent('beforeselect', this, record, index) !== false){
13810 this.setFromData(index > -1 ? record.data : false);
13813 this.fireEvent('select', this, record, index);
13818 * Returns the currently selected field value or empty string if no value is set.
13819 * @return {String} value The selected value
13821 getValue : function()
13823 if(Roo.isIOS && this.useNativeIOS){
13824 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13828 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13831 if(this.valueField){
13832 return typeof this.value != 'undefined' ? this.value : '';
13834 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13838 getRawValue : function()
13840 if(Roo.isIOS && this.useNativeIOS){
13841 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13844 var v = this.inputEl().getValue();
13850 * Clears any text/value currently set in the field
13852 clearValue : function(){
13854 if(this.hiddenField){
13855 this.hiddenField.dom.value = '';
13858 this.setRawValue('');
13859 this.lastSelectionText = '';
13860 this.lastData = false;
13862 var close = this.closeTriggerEl();
13873 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13874 * will be displayed in the field. If the value does not match the data value of an existing item,
13875 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13876 * Otherwise the field will be blank (although the value will still be set).
13877 * @param {String} value The value to match
13879 setValue : function(v)
13881 if(Roo.isIOS && this.useNativeIOS){
13882 this.setIOSValue(v);
13892 if(this.valueField){
13893 var r = this.findRecord(this.valueField, v);
13895 text = r.data[this.displayField];
13896 }else if(this.valueNotFoundText !== undefined){
13897 text = this.valueNotFoundText;
13900 this.lastSelectionText = text;
13901 if(this.hiddenField){
13902 this.hiddenField.dom.value = v;
13904 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13907 var close = this.closeTriggerEl();
13910 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13916 * @property {Object} the last set data for the element
13921 * Sets the value of the field based on a object which is related to the record format for the store.
13922 * @param {Object} value the value to set as. or false on reset?
13924 setFromData : function(o){
13931 var dv = ''; // display value
13932 var vv = ''; // value value..
13934 if (this.displayField) {
13935 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13937 // this is an error condition!!!
13938 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13941 if(this.valueField){
13942 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13945 var close = this.closeTriggerEl();
13948 if(dv.length || vv * 1 > 0){
13950 this.blockFocus=true;
13956 if(this.hiddenField){
13957 this.hiddenField.dom.value = vv;
13959 this.lastSelectionText = dv;
13960 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13964 // no hidden field.. - we store the value in 'value', but still display
13965 // display field!!!!
13966 this.lastSelectionText = dv;
13967 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13974 reset : function(){
13975 // overridden so that last data is reset..
13982 this.setValue(this.originalValue);
13983 //this.clearInvalid();
13984 this.lastData = false;
13986 this.view.clearSelections();
13992 findRecord : function(prop, value){
13994 if(this.store.getCount() > 0){
13995 this.store.each(function(r){
13996 if(r.data[prop] == value){
14006 getName: function()
14008 // returns hidden if it's set..
14009 if (!this.rendered) {return ''};
14010 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14014 onViewMove : function(e, t){
14015 this.inKeyMode = false;
14019 onViewOver : function(e, t){
14020 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14023 var item = this.view.findItemFromChild(t);
14026 var index = this.view.indexOf(item);
14027 this.select(index, false);
14032 onViewClick : function(view, doFocus, el, e)
14034 var index = this.view.getSelectedIndexes()[0];
14036 var r = this.store.getAt(index);
14040 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14047 Roo.each(this.tickItems, function(v,k){
14049 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14051 _this.tickItems.splice(k, 1);
14053 if(typeof(e) == 'undefined' && view == false){
14054 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14066 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14067 this.tickItems.push(r.data);
14070 if(typeof(e) == 'undefined' && view == false){
14071 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14078 this.onSelect(r, index);
14080 if(doFocus !== false && !this.blockFocus){
14081 this.inputEl().focus();
14086 restrictHeight : function(){
14087 //this.innerList.dom.style.height = '';
14088 //var inner = this.innerList.dom;
14089 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14090 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14091 //this.list.beginUpdate();
14092 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14093 this.list.alignTo(this.inputEl(), this.listAlign);
14094 this.list.alignTo(this.inputEl(), this.listAlign);
14095 //this.list.endUpdate();
14099 onEmptyResults : function(){
14101 if(this.tickable && this.editable){
14102 this.hasFocus = false;
14103 this.restrictHeight();
14111 * Returns true if the dropdown list is expanded, else false.
14113 isExpanded : function(){
14114 return this.list.isVisible();
14118 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14119 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14120 * @param {String} value The data value of the item to select
14121 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14122 * selected item if it is not currently in view (defaults to true)
14123 * @return {Boolean} True if the value matched an item in the list, else false
14125 selectByValue : function(v, scrollIntoView){
14126 if(v !== undefined && v !== null){
14127 var r = this.findRecord(this.valueField || this.displayField, v);
14129 this.select(this.store.indexOf(r), scrollIntoView);
14137 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14138 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14139 * @param {Number} index The zero-based index of the list item to select
14140 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14141 * selected item if it is not currently in view (defaults to true)
14143 select : function(index, scrollIntoView){
14144 this.selectedIndex = index;
14145 this.view.select(index);
14146 if(scrollIntoView !== false){
14147 var el = this.view.getNode(index);
14149 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14152 this.list.scrollChildIntoView(el, false);
14158 selectNext : function(){
14159 var ct = this.store.getCount();
14161 if(this.selectedIndex == -1){
14163 }else if(this.selectedIndex < ct-1){
14164 this.select(this.selectedIndex+1);
14170 selectPrev : function(){
14171 var ct = this.store.getCount();
14173 if(this.selectedIndex == -1){
14175 }else if(this.selectedIndex != 0){
14176 this.select(this.selectedIndex-1);
14182 onKeyUp : function(e){
14183 if(this.editable !== false && !e.isSpecialKey()){
14184 this.lastKey = e.getKey();
14185 this.dqTask.delay(this.queryDelay);
14190 validateBlur : function(){
14191 return !this.list || !this.list.isVisible();
14195 initQuery : function(){
14197 var v = this.getRawValue();
14199 if(this.tickable && this.editable){
14200 v = this.tickableInputEl().getValue();
14207 doForce : function(){
14208 if(this.inputEl().dom.value.length > 0){
14209 this.inputEl().dom.value =
14210 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14216 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14217 * query allowing the query action to be canceled if needed.
14218 * @param {String} query The SQL query to execute
14219 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14220 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14221 * saved in the current store (defaults to false)
14223 doQuery : function(q, forceAll){
14225 if(q === undefined || q === null){
14230 forceAll: forceAll,
14234 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14239 forceAll = qe.forceAll;
14240 if(forceAll === true || (q.length >= this.minChars)){
14242 this.hasQuery = true;
14244 if(this.lastQuery != q || this.alwaysQuery){
14245 this.lastQuery = q;
14246 if(this.mode == 'local'){
14247 this.selectedIndex = -1;
14249 this.store.clearFilter();
14252 if(this.specialFilter){
14253 this.fireEvent('specialfilter', this);
14258 this.store.filter(this.displayField, q);
14261 this.store.fireEvent("datachanged", this.store);
14268 this.store.baseParams[this.queryParam] = q;
14270 var options = {params : this.getParams(q)};
14273 options.add = true;
14274 options.params.start = this.page * this.pageSize;
14277 this.store.load(options);
14280 * this code will make the page width larger, at the beginning, the list not align correctly,
14281 * we should expand the list on onLoad
14282 * so command out it
14287 this.selectedIndex = -1;
14292 this.loadNext = false;
14296 getParams : function(q){
14298 //p[this.queryParam] = q;
14302 p.limit = this.pageSize;
14308 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14310 collapse : function(){
14311 if(!this.isExpanded()){
14317 this.hasFocus = false;
14321 this.cancelBtn.hide();
14322 this.trigger.show();
14325 this.tickableInputEl().dom.value = '';
14326 this.tickableInputEl().blur();
14331 Roo.get(document).un('mousedown', this.collapseIf, this);
14332 Roo.get(document).un('mousewheel', this.collapseIf, this);
14333 if (!this.editable) {
14334 Roo.get(document).un('keydown', this.listKeyPress, this);
14336 this.fireEvent('collapse', this);
14342 collapseIf : function(e){
14343 var in_combo = e.within(this.el);
14344 var in_list = e.within(this.list);
14345 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14347 if (in_combo || in_list || is_list) {
14348 //e.stopPropagation();
14353 this.onTickableFooterButtonClick(e, false, false);
14361 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14363 expand : function(){
14365 if(this.isExpanded() || !this.hasFocus){
14369 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14370 this.list.setWidth(lw);
14376 this.restrictHeight();
14380 this.tickItems = Roo.apply([], this.item);
14383 this.cancelBtn.show();
14384 this.trigger.hide();
14387 this.tickableInputEl().focus();
14392 Roo.get(document).on('mousedown', this.collapseIf, this);
14393 Roo.get(document).on('mousewheel', this.collapseIf, this);
14394 if (!this.editable) {
14395 Roo.get(document).on('keydown', this.listKeyPress, this);
14398 this.fireEvent('expand', this);
14402 // Implements the default empty TriggerField.onTriggerClick function
14403 onTriggerClick : function(e)
14405 Roo.log('trigger click');
14407 if(this.disabled || !this.triggerList){
14412 this.loadNext = false;
14414 if(this.isExpanded()){
14416 if (!this.blockFocus) {
14417 this.inputEl().focus();
14421 this.hasFocus = true;
14422 if(this.triggerAction == 'all') {
14423 this.doQuery(this.allQuery, true);
14425 this.doQuery(this.getRawValue());
14427 if (!this.blockFocus) {
14428 this.inputEl().focus();
14433 onTickableTriggerClick : function(e)
14440 this.loadNext = false;
14441 this.hasFocus = true;
14443 if(this.triggerAction == 'all') {
14444 this.doQuery(this.allQuery, true);
14446 this.doQuery(this.getRawValue());
14450 onSearchFieldClick : function(e)
14452 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14453 this.onTickableFooterButtonClick(e, false, false);
14457 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14462 this.loadNext = false;
14463 this.hasFocus = true;
14465 if(this.triggerAction == 'all') {
14466 this.doQuery(this.allQuery, true);
14468 this.doQuery(this.getRawValue());
14472 listKeyPress : function(e)
14474 //Roo.log('listkeypress');
14475 // scroll to first matching element based on key pres..
14476 if (e.isSpecialKey()) {
14479 var k = String.fromCharCode(e.getKey()).toUpperCase();
14482 var csel = this.view.getSelectedNodes();
14483 var cselitem = false;
14485 var ix = this.view.indexOf(csel[0]);
14486 cselitem = this.store.getAt(ix);
14487 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14493 this.store.each(function(v) {
14495 // start at existing selection.
14496 if (cselitem.id == v.id) {
14502 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14503 match = this.store.indexOf(v);
14509 if (match === false) {
14510 return true; // no more action?
14513 this.view.select(match);
14514 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14515 sn.scrollIntoView(sn.dom.parentNode, false);
14518 onViewScroll : function(e, t){
14520 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){
14524 this.hasQuery = true;
14526 this.loading = this.list.select('.loading', true).first();
14528 if(this.loading === null){
14529 this.list.createChild({
14531 cls: 'loading roo-select2-more-results roo-select2-active',
14532 html: 'Loading more results...'
14535 this.loading = this.list.select('.loading', true).first();
14537 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14539 this.loading.hide();
14542 this.loading.show();
14547 this.loadNext = true;
14549 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14554 addItem : function(o)
14556 var dv = ''; // display value
14558 if (this.displayField) {
14559 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14561 // this is an error condition!!!
14562 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14569 var choice = this.choices.createChild({
14571 cls: 'roo-select2-search-choice',
14580 cls: 'roo-select2-search-choice-close fa fa-times',
14585 }, this.searchField);
14587 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14589 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14597 this.inputEl().dom.value = '';
14602 onRemoveItem : function(e, _self, o)
14604 e.preventDefault();
14606 this.lastItem = Roo.apply([], this.item);
14608 var index = this.item.indexOf(o.data) * 1;
14611 Roo.log('not this item?!');
14615 this.item.splice(index, 1);
14620 this.fireEvent('remove', this, e);
14626 syncValue : function()
14628 if(!this.item.length){
14635 Roo.each(this.item, function(i){
14636 if(_this.valueField){
14637 value.push(i[_this.valueField]);
14644 this.value = value.join(',');
14646 if(this.hiddenField){
14647 this.hiddenField.dom.value = this.value;
14650 this.store.fireEvent("datachanged", this.store);
14655 clearItem : function()
14657 if(!this.multiple){
14663 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14671 if(this.tickable && !Roo.isTouch){
14672 this.view.refresh();
14676 inputEl: function ()
14678 if(Roo.isIOS && this.useNativeIOS){
14679 return this.el.select('select.roo-ios-select', true).first();
14682 if(Roo.isTouch && this.mobileTouchView){
14683 return this.el.select('input.form-control',true).first();
14687 return this.searchField;
14690 return this.el.select('input.form-control',true).first();
14693 onTickableFooterButtonClick : function(e, btn, el)
14695 e.preventDefault();
14697 this.lastItem = Roo.apply([], this.item);
14699 if(btn && btn.name == 'cancel'){
14700 this.tickItems = Roo.apply([], this.item);
14709 Roo.each(this.tickItems, function(o){
14717 validate : function()
14719 if(this.getVisibilityEl().hasClass('hidden')){
14723 var v = this.getRawValue();
14726 v = this.getValue();
14729 if(this.disabled || this.allowBlank || v.length){
14734 this.markInvalid();
14738 tickableInputEl : function()
14740 if(!this.tickable || !this.editable){
14741 return this.inputEl();
14744 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14748 getAutoCreateTouchView : function()
14753 cls: 'form-group' //input-group
14759 type : this.inputType,
14760 cls : 'form-control x-combo-noedit',
14761 autocomplete: 'new-password',
14762 placeholder : this.placeholder || '',
14767 input.name = this.name;
14771 input.cls += ' input-' + this.size;
14774 if (this.disabled) {
14775 input.disabled = true;
14786 inputblock.cls += ' input-group';
14788 inputblock.cn.unshift({
14790 cls : 'input-group-addon',
14795 if(this.removable && !this.multiple){
14796 inputblock.cls += ' roo-removable';
14798 inputblock.cn.push({
14801 cls : 'roo-combo-removable-btn close'
14805 if(this.hasFeedback && !this.allowBlank){
14807 inputblock.cls += ' has-feedback';
14809 inputblock.cn.push({
14811 cls: 'glyphicon form-control-feedback'
14818 inputblock.cls += (this.before) ? '' : ' input-group';
14820 inputblock.cn.push({
14822 cls : 'input-group-addon',
14833 cls: 'form-hidden-field'
14847 cls: 'form-hidden-field'
14851 cls: 'roo-select2-choices',
14855 cls: 'roo-select2-search-field',
14868 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14874 if(!this.multiple && this.showToggleBtn){
14881 if (this.caret != false) {
14884 cls: 'fa fa-' + this.caret
14891 cls : 'input-group-addon btn dropdown-toggle',
14896 cls: 'combobox-clear',
14910 combobox.cls += ' roo-select2-container-multi';
14913 var align = this.labelAlign || this.parentLabelAlign();
14915 if (align ==='left' && this.fieldLabel.length) {
14920 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14921 tooltip : 'This field is required'
14925 cls : 'control-label',
14926 html : this.fieldLabel
14937 var labelCfg = cfg.cn[1];
14938 var contentCfg = cfg.cn[2];
14941 if(this.indicatorpos == 'right'){
14946 cls : 'control-label',
14950 html : this.fieldLabel
14954 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14955 tooltip : 'This field is required'
14968 labelCfg = cfg.cn[0];
14969 contentCfg = cfg.cn[1];
14974 if(this.labelWidth > 12){
14975 labelCfg.style = "width: " + this.labelWidth + 'px';
14978 if(this.labelWidth < 13 && this.labelmd == 0){
14979 this.labelmd = this.labelWidth;
14982 if(this.labellg > 0){
14983 labelCfg.cls += ' col-lg-' + this.labellg;
14984 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14987 if(this.labelmd > 0){
14988 labelCfg.cls += ' col-md-' + this.labelmd;
14989 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14992 if(this.labelsm > 0){
14993 labelCfg.cls += ' col-sm-' + this.labelsm;
14994 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14997 if(this.labelxs > 0){
14998 labelCfg.cls += ' col-xs-' + this.labelxs;
14999 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15003 } else if ( this.fieldLabel.length) {
15007 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15008 tooltip : 'This field is required'
15012 cls : 'control-label',
15013 html : this.fieldLabel
15024 if(this.indicatorpos == 'right'){
15028 cls : 'control-label',
15029 html : this.fieldLabel,
15033 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15034 tooltip : 'This field is required'
15051 var settings = this;
15053 ['xs','sm','md','lg'].map(function(size){
15054 if (settings[size]) {
15055 cfg.cls += ' col-' + size + '-' + settings[size];
15062 initTouchView : function()
15064 this.renderTouchView();
15066 this.touchViewEl.on('scroll', function(){
15067 this.el.dom.scrollTop = 0;
15070 this.originalValue = this.getValue();
15072 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15074 this.inputEl().on("click", this.showTouchView, this);
15075 if (this.triggerEl) {
15076 this.triggerEl.on("click", this.showTouchView, this);
15080 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15081 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15083 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15085 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15086 this.store.on('load', this.onTouchViewLoad, this);
15087 this.store.on('loadexception', this.onTouchViewLoadException, this);
15089 if(this.hiddenName){
15091 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15093 this.hiddenField.dom.value =
15094 this.hiddenValue !== undefined ? this.hiddenValue :
15095 this.value !== undefined ? this.value : '';
15097 this.el.dom.removeAttribute('name');
15098 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15102 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15103 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15106 if(this.removable && !this.multiple){
15107 var close = this.closeTriggerEl();
15109 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15110 close.on('click', this.removeBtnClick, this, close);
15114 * fix the bug in Safari iOS8
15116 this.inputEl().on("focus", function(e){
15117 document.activeElement.blur();
15125 renderTouchView : function()
15127 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15128 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15130 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15131 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15133 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15134 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15135 this.touchViewBodyEl.setStyle('overflow', 'auto');
15137 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15138 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15140 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15141 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15145 showTouchView : function()
15151 this.touchViewHeaderEl.hide();
15153 if(this.modalTitle.length){
15154 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15155 this.touchViewHeaderEl.show();
15158 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15159 this.touchViewEl.show();
15161 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15163 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15164 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15166 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15168 if(this.modalTitle.length){
15169 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15172 this.touchViewBodyEl.setHeight(bodyHeight);
15176 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15178 this.touchViewEl.addClass('in');
15181 this.doTouchViewQuery();
15185 hideTouchView : function()
15187 this.touchViewEl.removeClass('in');
15191 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15193 this.touchViewEl.setStyle('display', 'none');
15198 setTouchViewValue : function()
15205 Roo.each(this.tickItems, function(o){
15210 this.hideTouchView();
15213 doTouchViewQuery : function()
15222 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15226 if(!this.alwaysQuery || this.mode == 'local'){
15227 this.onTouchViewLoad();
15234 onTouchViewBeforeLoad : function(combo,opts)
15240 onTouchViewLoad : function()
15242 if(this.store.getCount() < 1){
15243 this.onTouchViewEmptyResults();
15247 this.clearTouchView();
15249 var rawValue = this.getRawValue();
15251 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15253 this.tickItems = [];
15255 this.store.data.each(function(d, rowIndex){
15256 var row = this.touchViewListGroup.createChild(template);
15258 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15259 row.addClass(d.data.cls);
15262 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15265 html : d.data[this.displayField]
15268 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15269 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15272 row.removeClass('selected');
15273 if(!this.multiple && this.valueField &&
15274 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15277 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15278 row.addClass('selected');
15281 if(this.multiple && this.valueField &&
15282 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15286 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15287 this.tickItems.push(d.data);
15290 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15294 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15296 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15298 if(this.modalTitle.length){
15299 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15302 var listHeight = this.touchViewListGroup.getHeight();
15306 if(firstChecked && listHeight > bodyHeight){
15307 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15312 onTouchViewLoadException : function()
15314 this.hideTouchView();
15317 onTouchViewEmptyResults : function()
15319 this.clearTouchView();
15321 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15323 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15327 clearTouchView : function()
15329 this.touchViewListGroup.dom.innerHTML = '';
15332 onTouchViewClick : function(e, el, o)
15334 e.preventDefault();
15337 var rowIndex = o.rowIndex;
15339 var r = this.store.getAt(rowIndex);
15341 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15343 if(!this.multiple){
15344 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15345 c.dom.removeAttribute('checked');
15348 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15350 this.setFromData(r.data);
15352 var close = this.closeTriggerEl();
15358 this.hideTouchView();
15360 this.fireEvent('select', this, r, rowIndex);
15365 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15366 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15367 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15371 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15372 this.addItem(r.data);
15373 this.tickItems.push(r.data);
15377 getAutoCreateNativeIOS : function()
15380 cls: 'form-group' //input-group,
15385 cls : 'roo-ios-select'
15389 combobox.name = this.name;
15392 if (this.disabled) {
15393 combobox.disabled = true;
15396 var settings = this;
15398 ['xs','sm','md','lg'].map(function(size){
15399 if (settings[size]) {
15400 cfg.cls += ' col-' + size + '-' + settings[size];
15410 initIOSView : function()
15412 this.store.on('load', this.onIOSViewLoad, this);
15417 onIOSViewLoad : function()
15419 if(this.store.getCount() < 1){
15423 this.clearIOSView();
15425 if(this.allowBlank) {
15427 var default_text = '-- SELECT --';
15429 if(this.placeholder.length){
15430 default_text = this.placeholder;
15433 if(this.emptyTitle.length){
15434 default_text += ' - ' + this.emptyTitle + ' -';
15437 var opt = this.inputEl().createChild({
15440 html : default_text
15444 o[this.valueField] = 0;
15445 o[this.displayField] = default_text;
15447 this.ios_options.push({
15454 this.store.data.each(function(d, rowIndex){
15458 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15459 html = d.data[this.displayField];
15464 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15465 value = d.data[this.valueField];
15474 if(this.value == d.data[this.valueField]){
15475 option['selected'] = true;
15478 var opt = this.inputEl().createChild(option);
15480 this.ios_options.push({
15487 this.inputEl().on('change', function(){
15488 this.fireEvent('select', this);
15493 clearIOSView: function()
15495 this.inputEl().dom.innerHTML = '';
15497 this.ios_options = [];
15500 setIOSValue: function(v)
15504 if(!this.ios_options){
15508 Roo.each(this.ios_options, function(opts){
15510 opts.el.dom.removeAttribute('selected');
15512 if(opts.data[this.valueField] != v){
15516 opts.el.dom.setAttribute('selected', true);
15522 * @cfg {Boolean} grow
15526 * @cfg {Number} growMin
15530 * @cfg {Number} growMax
15539 Roo.apply(Roo.bootstrap.ComboBox, {
15543 cls: 'modal-header',
15565 cls: 'list-group-item',
15569 cls: 'roo-combobox-list-group-item-value'
15573 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15587 listItemCheckbox : {
15589 cls: 'list-group-item',
15593 cls: 'roo-combobox-list-group-item-value'
15597 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15613 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15618 cls: 'modal-footer',
15626 cls: 'col-xs-6 text-left',
15629 cls: 'btn btn-danger roo-touch-view-cancel',
15635 cls: 'col-xs-6 text-right',
15638 cls: 'btn btn-success roo-touch-view-ok',
15649 Roo.apply(Roo.bootstrap.ComboBox, {
15651 touchViewTemplate : {
15653 cls: 'modal fade roo-combobox-touch-view',
15657 cls: 'modal-dialog',
15658 style : 'position:fixed', // we have to fix position....
15662 cls: 'modal-content',
15664 Roo.bootstrap.ComboBox.header,
15665 Roo.bootstrap.ComboBox.body,
15666 Roo.bootstrap.ComboBox.footer
15675 * Ext JS Library 1.1.1
15676 * Copyright(c) 2006-2007, Ext JS, LLC.
15678 * Originally Released Under LGPL - original licence link has changed is not relivant.
15681 * <script type="text/javascript">
15686 * @extends Roo.util.Observable
15687 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15688 * This class also supports single and multi selection modes. <br>
15689 * Create a data model bound view:
15691 var store = new Roo.data.Store(...);
15693 var view = new Roo.View({
15695 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15697 singleSelect: true,
15698 selectedClass: "ydataview-selected",
15702 // listen for node click?
15703 view.on("click", function(vw, index, node, e){
15704 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15708 dataModel.load("foobar.xml");
15710 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15712 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15713 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15715 * Note: old style constructor is still suported (container, template, config)
15718 * Create a new View
15719 * @param {Object} config The config object
15722 Roo.View = function(config, depreciated_tpl, depreciated_config){
15724 this.parent = false;
15726 if (typeof(depreciated_tpl) == 'undefined') {
15727 // new way.. - universal constructor.
15728 Roo.apply(this, config);
15729 this.el = Roo.get(this.el);
15732 this.el = Roo.get(config);
15733 this.tpl = depreciated_tpl;
15734 Roo.apply(this, depreciated_config);
15736 this.wrapEl = this.el.wrap().wrap();
15737 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15740 if(typeof(this.tpl) == "string"){
15741 this.tpl = new Roo.Template(this.tpl);
15743 // support xtype ctors..
15744 this.tpl = new Roo.factory(this.tpl, Roo);
15748 this.tpl.compile();
15753 * @event beforeclick
15754 * Fires before a click is processed. Returns false to cancel the default action.
15755 * @param {Roo.View} this
15756 * @param {Number} index The index of the target node
15757 * @param {HTMLElement} node The target node
15758 * @param {Roo.EventObject} e The raw event object
15760 "beforeclick" : true,
15763 * Fires when a template node is clicked.
15764 * @param {Roo.View} this
15765 * @param {Number} index The index of the target node
15766 * @param {HTMLElement} node The target node
15767 * @param {Roo.EventObject} e The raw event object
15772 * Fires when a template node is double clicked.
15773 * @param {Roo.View} this
15774 * @param {Number} index The index of the target node
15775 * @param {HTMLElement} node The target node
15776 * @param {Roo.EventObject} e The raw event object
15780 * @event contextmenu
15781 * Fires when a template node is right clicked.
15782 * @param {Roo.View} this
15783 * @param {Number} index The index of the target node
15784 * @param {HTMLElement} node The target node
15785 * @param {Roo.EventObject} e The raw event object
15787 "contextmenu" : true,
15789 * @event selectionchange
15790 * Fires when the selected nodes change.
15791 * @param {Roo.View} this
15792 * @param {Array} selections Array of the selected nodes
15794 "selectionchange" : true,
15797 * @event beforeselect
15798 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15799 * @param {Roo.View} this
15800 * @param {HTMLElement} node The node to be selected
15801 * @param {Array} selections Array of currently selected nodes
15803 "beforeselect" : true,
15805 * @event preparedata
15806 * Fires on every row to render, to allow you to change the data.
15807 * @param {Roo.View} this
15808 * @param {Object} data to be rendered (change this)
15810 "preparedata" : true
15818 "click": this.onClick,
15819 "dblclick": this.onDblClick,
15820 "contextmenu": this.onContextMenu,
15824 this.selections = [];
15826 this.cmp = new Roo.CompositeElementLite([]);
15828 this.store = Roo.factory(this.store, Roo.data);
15829 this.setStore(this.store, true);
15832 if ( this.footer && this.footer.xtype) {
15834 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15836 this.footer.dataSource = this.store;
15837 this.footer.container = fctr;
15838 this.footer = Roo.factory(this.footer, Roo);
15839 fctr.insertFirst(this.el);
15841 // this is a bit insane - as the paging toolbar seems to detach the el..
15842 // dom.parentNode.parentNode.parentNode
15843 // they get detached?
15847 Roo.View.superclass.constructor.call(this);
15852 Roo.extend(Roo.View, Roo.util.Observable, {
15855 * @cfg {Roo.data.Store} store Data store to load data from.
15860 * @cfg {String|Roo.Element} el The container element.
15865 * @cfg {String|Roo.Template} tpl The template used by this View
15869 * @cfg {String} dataName the named area of the template to use as the data area
15870 * Works with domtemplates roo-name="name"
15874 * @cfg {String} selectedClass The css class to add to selected nodes
15876 selectedClass : "x-view-selected",
15878 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15883 * @cfg {String} text to display on mask (default Loading)
15887 * @cfg {Boolean} multiSelect Allow multiple selection
15889 multiSelect : false,
15891 * @cfg {Boolean} singleSelect Allow single selection
15893 singleSelect: false,
15896 * @cfg {Boolean} toggleSelect - selecting
15898 toggleSelect : false,
15901 * @cfg {Boolean} tickable - selecting
15906 * Returns the element this view is bound to.
15907 * @return {Roo.Element}
15909 getEl : function(){
15910 return this.wrapEl;
15916 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15918 refresh : function(){
15919 //Roo.log('refresh');
15922 // if we are using something like 'domtemplate', then
15923 // the what gets used is:
15924 // t.applySubtemplate(NAME, data, wrapping data..)
15925 // the outer template then get' applied with
15926 // the store 'extra data'
15927 // and the body get's added to the
15928 // roo-name="data" node?
15929 // <span class='roo-tpl-{name}'></span> ?????
15933 this.clearSelections();
15934 this.el.update("");
15936 var records = this.store.getRange();
15937 if(records.length < 1) {
15939 // is this valid?? = should it render a template??
15941 this.el.update(this.emptyText);
15945 if (this.dataName) {
15946 this.el.update(t.apply(this.store.meta)); //????
15947 el = this.el.child('.roo-tpl-' + this.dataName);
15950 for(var i = 0, len = records.length; i < len; i++){
15951 var data = this.prepareData(records[i].data, i, records[i]);
15952 this.fireEvent("preparedata", this, data, i, records[i]);
15954 var d = Roo.apply({}, data);
15957 Roo.apply(d, {'roo-id' : Roo.id()});
15961 Roo.each(this.parent.item, function(item){
15962 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15965 Roo.apply(d, {'roo-data-checked' : 'checked'});
15969 html[html.length] = Roo.util.Format.trim(
15971 t.applySubtemplate(this.dataName, d, this.store.meta) :
15978 el.update(html.join(""));
15979 this.nodes = el.dom.childNodes;
15980 this.updateIndexes(0);
15985 * Function to override to reformat the data that is sent to
15986 * the template for each node.
15987 * DEPRICATED - use the preparedata event handler.
15988 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15989 * a JSON object for an UpdateManager bound view).
15991 prepareData : function(data, index, record)
15993 this.fireEvent("preparedata", this, data, index, record);
15997 onUpdate : function(ds, record){
15998 // Roo.log('on update');
15999 this.clearSelections();
16000 var index = this.store.indexOf(record);
16001 var n = this.nodes[index];
16002 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16003 n.parentNode.removeChild(n);
16004 this.updateIndexes(index, index);
16010 onAdd : function(ds, records, index)
16012 //Roo.log(['on Add', ds, records, index] );
16013 this.clearSelections();
16014 if(this.nodes.length == 0){
16018 var n = this.nodes[index];
16019 for(var i = 0, len = records.length; i < len; i++){
16020 var d = this.prepareData(records[i].data, i, records[i]);
16022 this.tpl.insertBefore(n, d);
16025 this.tpl.append(this.el, d);
16028 this.updateIndexes(index);
16031 onRemove : function(ds, record, index){
16032 // Roo.log('onRemove');
16033 this.clearSelections();
16034 var el = this.dataName ?
16035 this.el.child('.roo-tpl-' + this.dataName) :
16038 el.dom.removeChild(this.nodes[index]);
16039 this.updateIndexes(index);
16043 * Refresh an individual node.
16044 * @param {Number} index
16046 refreshNode : function(index){
16047 this.onUpdate(this.store, this.store.getAt(index));
16050 updateIndexes : function(startIndex, endIndex){
16051 var ns = this.nodes;
16052 startIndex = startIndex || 0;
16053 endIndex = endIndex || ns.length - 1;
16054 for(var i = startIndex; i <= endIndex; i++){
16055 ns[i].nodeIndex = i;
16060 * Changes the data store this view uses and refresh the view.
16061 * @param {Store} store
16063 setStore : function(store, initial){
16064 if(!initial && this.store){
16065 this.store.un("datachanged", this.refresh);
16066 this.store.un("add", this.onAdd);
16067 this.store.un("remove", this.onRemove);
16068 this.store.un("update", this.onUpdate);
16069 this.store.un("clear", this.refresh);
16070 this.store.un("beforeload", this.onBeforeLoad);
16071 this.store.un("load", this.onLoad);
16072 this.store.un("loadexception", this.onLoad);
16076 store.on("datachanged", this.refresh, this);
16077 store.on("add", this.onAdd, this);
16078 store.on("remove", this.onRemove, this);
16079 store.on("update", this.onUpdate, this);
16080 store.on("clear", this.refresh, this);
16081 store.on("beforeload", this.onBeforeLoad, this);
16082 store.on("load", this.onLoad, this);
16083 store.on("loadexception", this.onLoad, this);
16091 * onbeforeLoad - masks the loading area.
16094 onBeforeLoad : function(store,opts)
16096 //Roo.log('onBeforeLoad');
16098 this.el.update("");
16100 this.el.mask(this.mask ? this.mask : "Loading" );
16102 onLoad : function ()
16109 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16110 * @param {HTMLElement} node
16111 * @return {HTMLElement} The template node
16113 findItemFromChild : function(node){
16114 var el = this.dataName ?
16115 this.el.child('.roo-tpl-' + this.dataName,true) :
16118 if(!node || node.parentNode == el){
16121 var p = node.parentNode;
16122 while(p && p != el){
16123 if(p.parentNode == el){
16132 onClick : function(e){
16133 var item = this.findItemFromChild(e.getTarget());
16135 var index = this.indexOf(item);
16136 if(this.onItemClick(item, index, e) !== false){
16137 this.fireEvent("click", this, index, item, e);
16140 this.clearSelections();
16145 onContextMenu : function(e){
16146 var item = this.findItemFromChild(e.getTarget());
16148 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16153 onDblClick : function(e){
16154 var item = this.findItemFromChild(e.getTarget());
16156 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16160 onItemClick : function(item, index, e)
16162 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16165 if (this.toggleSelect) {
16166 var m = this.isSelected(item) ? 'unselect' : 'select';
16169 _t[m](item, true, false);
16172 if(this.multiSelect || this.singleSelect){
16173 if(this.multiSelect && e.shiftKey && this.lastSelection){
16174 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16176 this.select(item, this.multiSelect && e.ctrlKey);
16177 this.lastSelection = item;
16180 if(!this.tickable){
16181 e.preventDefault();
16189 * Get the number of selected nodes.
16192 getSelectionCount : function(){
16193 return this.selections.length;
16197 * Get the currently selected nodes.
16198 * @return {Array} An array of HTMLElements
16200 getSelectedNodes : function(){
16201 return this.selections;
16205 * Get the indexes of the selected nodes.
16208 getSelectedIndexes : function(){
16209 var indexes = [], s = this.selections;
16210 for(var i = 0, len = s.length; i < len; i++){
16211 indexes.push(s[i].nodeIndex);
16217 * Clear all selections
16218 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16220 clearSelections : function(suppressEvent){
16221 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16222 this.cmp.elements = this.selections;
16223 this.cmp.removeClass(this.selectedClass);
16224 this.selections = [];
16225 if(!suppressEvent){
16226 this.fireEvent("selectionchange", this, this.selections);
16232 * Returns true if the passed node is selected
16233 * @param {HTMLElement/Number} node The node or node index
16234 * @return {Boolean}
16236 isSelected : function(node){
16237 var s = this.selections;
16241 node = this.getNode(node);
16242 return s.indexOf(node) !== -1;
16247 * @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
16248 * @param {Boolean} keepExisting (optional) true to keep existing selections
16249 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16251 select : function(nodeInfo, keepExisting, suppressEvent){
16252 if(nodeInfo instanceof Array){
16254 this.clearSelections(true);
16256 for(var i = 0, len = nodeInfo.length; i < len; i++){
16257 this.select(nodeInfo[i], true, true);
16261 var node = this.getNode(nodeInfo);
16262 if(!node || this.isSelected(node)){
16263 return; // already selected.
16266 this.clearSelections(true);
16269 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16270 Roo.fly(node).addClass(this.selectedClass);
16271 this.selections.push(node);
16272 if(!suppressEvent){
16273 this.fireEvent("selectionchange", this, this.selections);
16281 * @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
16282 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16283 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16285 unselect : function(nodeInfo, keepExisting, suppressEvent)
16287 if(nodeInfo instanceof Array){
16288 Roo.each(this.selections, function(s) {
16289 this.unselect(s, nodeInfo);
16293 var node = this.getNode(nodeInfo);
16294 if(!node || !this.isSelected(node)){
16295 //Roo.log("not selected");
16296 return; // not selected.
16300 Roo.each(this.selections, function(s) {
16302 Roo.fly(node).removeClass(this.selectedClass);
16309 this.selections= ns;
16310 this.fireEvent("selectionchange", this, this.selections);
16314 * Gets a template node.
16315 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16316 * @return {HTMLElement} The node or null if it wasn't found
16318 getNode : function(nodeInfo){
16319 if(typeof nodeInfo == "string"){
16320 return document.getElementById(nodeInfo);
16321 }else if(typeof nodeInfo == "number"){
16322 return this.nodes[nodeInfo];
16328 * Gets a range template nodes.
16329 * @param {Number} startIndex
16330 * @param {Number} endIndex
16331 * @return {Array} An array of nodes
16333 getNodes : function(start, end){
16334 var ns = this.nodes;
16335 start = start || 0;
16336 end = typeof end == "undefined" ? ns.length - 1 : end;
16339 for(var i = start; i <= end; i++){
16343 for(var i = start; i >= end; i--){
16351 * Finds the index of the passed node
16352 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16353 * @return {Number} The index of the node or -1
16355 indexOf : function(node){
16356 node = this.getNode(node);
16357 if(typeof node.nodeIndex == "number"){
16358 return node.nodeIndex;
16360 var ns = this.nodes;
16361 for(var i = 0, len = ns.length; i < len; i++){
16372 * based on jquery fullcalendar
16376 Roo.bootstrap = Roo.bootstrap || {};
16378 * @class Roo.bootstrap.Calendar
16379 * @extends Roo.bootstrap.Component
16380 * Bootstrap Calendar class
16381 * @cfg {Boolean} loadMask (true|false) default false
16382 * @cfg {Object} header generate the user specific header of the calendar, default false
16385 * Create a new Container
16386 * @param {Object} config The config object
16391 Roo.bootstrap.Calendar = function(config){
16392 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16396 * Fires when a date is selected
16397 * @param {DatePicker} this
16398 * @param {Date} date The selected date
16402 * @event monthchange
16403 * Fires when the displayed month changes
16404 * @param {DatePicker} this
16405 * @param {Date} date The selected month
16407 'monthchange': true,
16409 * @event evententer
16410 * Fires when mouse over an event
16411 * @param {Calendar} this
16412 * @param {event} Event
16414 'evententer': true,
16416 * @event eventleave
16417 * Fires when the mouse leaves an
16418 * @param {Calendar} this
16421 'eventleave': true,
16423 * @event eventclick
16424 * Fires when the mouse click an
16425 * @param {Calendar} this
16434 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16437 * @cfg {Number} startDay
16438 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16446 getAutoCreate : function(){
16449 var fc_button = function(name, corner, style, content ) {
16450 return Roo.apply({},{
16452 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16454 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16457 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16468 style : 'width:100%',
16475 cls : 'fc-header-left',
16477 fc_button('prev', 'left', 'arrow', '‹' ),
16478 fc_button('next', 'right', 'arrow', '›' ),
16479 { tag: 'span', cls: 'fc-header-space' },
16480 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16488 cls : 'fc-header-center',
16492 cls: 'fc-header-title',
16495 html : 'month / year'
16503 cls : 'fc-header-right',
16505 /* fc_button('month', 'left', '', 'month' ),
16506 fc_button('week', '', '', 'week' ),
16507 fc_button('day', 'right', '', 'day' )
16519 header = this.header;
16522 var cal_heads = function() {
16524 // fixme - handle this.
16526 for (var i =0; i < Date.dayNames.length; i++) {
16527 var d = Date.dayNames[i];
16530 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16531 html : d.substring(0,3)
16535 ret[0].cls += ' fc-first';
16536 ret[6].cls += ' fc-last';
16539 var cal_cell = function(n) {
16542 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16547 cls: 'fc-day-number',
16551 cls: 'fc-day-content',
16555 style: 'position: relative;' // height: 17px;
16567 var cal_rows = function() {
16570 for (var r = 0; r < 6; r++) {
16577 for (var i =0; i < Date.dayNames.length; i++) {
16578 var d = Date.dayNames[i];
16579 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16582 row.cn[0].cls+=' fc-first';
16583 row.cn[0].cn[0].style = 'min-height:90px';
16584 row.cn[6].cls+=' fc-last';
16588 ret[0].cls += ' fc-first';
16589 ret[4].cls += ' fc-prev-last';
16590 ret[5].cls += ' fc-last';
16597 cls: 'fc-border-separate',
16598 style : 'width:100%',
16606 cls : 'fc-first fc-last',
16624 cls : 'fc-content',
16625 style : "position: relative;",
16628 cls : 'fc-view fc-view-month fc-grid',
16629 style : 'position: relative',
16630 unselectable : 'on',
16633 cls : 'fc-event-container',
16634 style : 'position:absolute;z-index:8;top:0;left:0;'
16652 initEvents : function()
16655 throw "can not find store for calendar";
16661 style: "text-align:center",
16665 style: "background-color:white;width:50%;margin:250 auto",
16669 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16680 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16682 var size = this.el.select('.fc-content', true).first().getSize();
16683 this.maskEl.setSize(size.width, size.height);
16684 this.maskEl.enableDisplayMode("block");
16685 if(!this.loadMask){
16686 this.maskEl.hide();
16689 this.store = Roo.factory(this.store, Roo.data);
16690 this.store.on('load', this.onLoad, this);
16691 this.store.on('beforeload', this.onBeforeLoad, this);
16695 this.cells = this.el.select('.fc-day',true);
16696 //Roo.log(this.cells);
16697 this.textNodes = this.el.query('.fc-day-number');
16698 this.cells.addClassOnOver('fc-state-hover');
16700 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16701 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16702 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16703 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16705 this.on('monthchange', this.onMonthChange, this);
16707 this.update(new Date().clearTime());
16710 resize : function() {
16711 var sz = this.el.getSize();
16713 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16714 this.el.select('.fc-day-content div',true).setHeight(34);
16719 showPrevMonth : function(e){
16720 this.update(this.activeDate.add("mo", -1));
16722 showToday : function(e){
16723 this.update(new Date().clearTime());
16726 showNextMonth : function(e){
16727 this.update(this.activeDate.add("mo", 1));
16731 showPrevYear : function(){
16732 this.update(this.activeDate.add("y", -1));
16736 showNextYear : function(){
16737 this.update(this.activeDate.add("y", 1));
16742 update : function(date)
16744 var vd = this.activeDate;
16745 this.activeDate = date;
16746 // if(vd && this.el){
16747 // var t = date.getTime();
16748 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16749 // Roo.log('using add remove');
16751 // this.fireEvent('monthchange', this, date);
16753 // this.cells.removeClass("fc-state-highlight");
16754 // this.cells.each(function(c){
16755 // if(c.dateValue == t){
16756 // c.addClass("fc-state-highlight");
16757 // setTimeout(function(){
16758 // try{c.dom.firstChild.focus();}catch(e){}
16768 var days = date.getDaysInMonth();
16770 var firstOfMonth = date.getFirstDateOfMonth();
16771 var startingPos = firstOfMonth.getDay()-this.startDay;
16773 if(startingPos < this.startDay){
16777 var pm = date.add(Date.MONTH, -1);
16778 var prevStart = pm.getDaysInMonth()-startingPos;
16780 this.cells = this.el.select('.fc-day',true);
16781 this.textNodes = this.el.query('.fc-day-number');
16782 this.cells.addClassOnOver('fc-state-hover');
16784 var cells = this.cells.elements;
16785 var textEls = this.textNodes;
16787 Roo.each(cells, function(cell){
16788 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16791 days += startingPos;
16793 // convert everything to numbers so it's fast
16794 var day = 86400000;
16795 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16798 //Roo.log(prevStart);
16800 var today = new Date().clearTime().getTime();
16801 var sel = date.clearTime().getTime();
16802 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16803 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16804 var ddMatch = this.disabledDatesRE;
16805 var ddText = this.disabledDatesText;
16806 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16807 var ddaysText = this.disabledDaysText;
16808 var format = this.format;
16810 var setCellClass = function(cal, cell){
16814 //Roo.log('set Cell Class');
16816 var t = d.getTime();
16820 cell.dateValue = t;
16822 cell.className += " fc-today";
16823 cell.className += " fc-state-highlight";
16824 cell.title = cal.todayText;
16827 // disable highlight in other month..
16828 //cell.className += " fc-state-highlight";
16833 cell.className = " fc-state-disabled";
16834 cell.title = cal.minText;
16838 cell.className = " fc-state-disabled";
16839 cell.title = cal.maxText;
16843 if(ddays.indexOf(d.getDay()) != -1){
16844 cell.title = ddaysText;
16845 cell.className = " fc-state-disabled";
16848 if(ddMatch && format){
16849 var fvalue = d.dateFormat(format);
16850 if(ddMatch.test(fvalue)){
16851 cell.title = ddText.replace("%0", fvalue);
16852 cell.className = " fc-state-disabled";
16856 if (!cell.initialClassName) {
16857 cell.initialClassName = cell.dom.className;
16860 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16865 for(; i < startingPos; i++) {
16866 textEls[i].innerHTML = (++prevStart);
16867 d.setDate(d.getDate()+1);
16869 cells[i].className = "fc-past fc-other-month";
16870 setCellClass(this, cells[i]);
16875 for(; i < days; i++){
16876 intDay = i - startingPos + 1;
16877 textEls[i].innerHTML = (intDay);
16878 d.setDate(d.getDate()+1);
16880 cells[i].className = ''; // "x-date-active";
16881 setCellClass(this, cells[i]);
16885 for(; i < 42; i++) {
16886 textEls[i].innerHTML = (++extraDays);
16887 d.setDate(d.getDate()+1);
16889 cells[i].className = "fc-future fc-other-month";
16890 setCellClass(this, cells[i]);
16893 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16895 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16897 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16898 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16900 if(totalRows != 6){
16901 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16902 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16905 this.fireEvent('monthchange', this, date);
16909 if(!this.internalRender){
16910 var main = this.el.dom.firstChild;
16911 var w = main.offsetWidth;
16912 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16913 Roo.fly(main).setWidth(w);
16914 this.internalRender = true;
16915 // opera does not respect the auto grow header center column
16916 // then, after it gets a width opera refuses to recalculate
16917 // without a second pass
16918 if(Roo.isOpera && !this.secondPass){
16919 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16920 this.secondPass = true;
16921 this.update.defer(10, this, [date]);
16928 findCell : function(dt) {
16929 dt = dt.clearTime().getTime();
16931 this.cells.each(function(c){
16932 //Roo.log("check " +c.dateValue + '?=' + dt);
16933 if(c.dateValue == dt){
16943 findCells : function(ev) {
16944 var s = ev.start.clone().clearTime().getTime();
16946 var e= ev.end.clone().clearTime().getTime();
16949 this.cells.each(function(c){
16950 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16952 if(c.dateValue > e){
16955 if(c.dateValue < s){
16964 // findBestRow: function(cells)
16968 // for (var i =0 ; i < cells.length;i++) {
16969 // ret = Math.max(cells[i].rows || 0,ret);
16976 addItem : function(ev)
16978 // look for vertical location slot in
16979 var cells = this.findCells(ev);
16981 // ev.row = this.findBestRow(cells);
16983 // work out the location.
16987 for(var i =0; i < cells.length; i++) {
16989 cells[i].row = cells[0].row;
16992 cells[i].row = cells[i].row + 1;
17002 if (crow.start.getY() == cells[i].getY()) {
17004 crow.end = cells[i];
17021 cells[0].events.push(ev);
17023 this.calevents.push(ev);
17026 clearEvents: function() {
17028 if(!this.calevents){
17032 Roo.each(this.cells.elements, function(c){
17038 Roo.each(this.calevents, function(e) {
17039 Roo.each(e.els, function(el) {
17040 el.un('mouseenter' ,this.onEventEnter, this);
17041 el.un('mouseleave' ,this.onEventLeave, this);
17046 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17052 renderEvents: function()
17056 this.cells.each(function(c) {
17065 if(c.row != c.events.length){
17066 r = 4 - (4 - (c.row - c.events.length));
17069 c.events = ev.slice(0, r);
17070 c.more = ev.slice(r);
17072 if(c.more.length && c.more.length == 1){
17073 c.events.push(c.more.pop());
17076 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17080 this.cells.each(function(c) {
17082 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17085 for (var e = 0; e < c.events.length; e++){
17086 var ev = c.events[e];
17087 var rows = ev.rows;
17089 for(var i = 0; i < rows.length; i++) {
17091 // how many rows should it span..
17094 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17095 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17097 unselectable : "on",
17100 cls: 'fc-event-inner',
17104 // cls: 'fc-event-time',
17105 // html : cells.length > 1 ? '' : ev.time
17109 cls: 'fc-event-title',
17110 html : String.format('{0}', ev.title)
17117 cls: 'ui-resizable-handle ui-resizable-e',
17118 html : '  '
17125 cfg.cls += ' fc-event-start';
17127 if ((i+1) == rows.length) {
17128 cfg.cls += ' fc-event-end';
17131 var ctr = _this.el.select('.fc-event-container',true).first();
17132 var cg = ctr.createChild(cfg);
17134 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17135 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17137 var r = (c.more.length) ? 1 : 0;
17138 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17139 cg.setWidth(ebox.right - sbox.x -2);
17141 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17142 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17143 cg.on('click', _this.onEventClick, _this, ev);
17154 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17155 style : 'position: absolute',
17156 unselectable : "on",
17159 cls: 'fc-event-inner',
17163 cls: 'fc-event-title',
17171 cls: 'ui-resizable-handle ui-resizable-e',
17172 html : '  '
17178 var ctr = _this.el.select('.fc-event-container',true).first();
17179 var cg = ctr.createChild(cfg);
17181 var sbox = c.select('.fc-day-content',true).first().getBox();
17182 var ebox = c.select('.fc-day-content',true).first().getBox();
17184 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17185 cg.setWidth(ebox.right - sbox.x -2);
17187 cg.on('click', _this.onMoreEventClick, _this, c.more);
17197 onEventEnter: function (e, el,event,d) {
17198 this.fireEvent('evententer', this, el, event);
17201 onEventLeave: function (e, el,event,d) {
17202 this.fireEvent('eventleave', this, el, event);
17205 onEventClick: function (e, el,event,d) {
17206 this.fireEvent('eventclick', this, el, event);
17209 onMonthChange: function () {
17213 onMoreEventClick: function(e, el, more)
17217 this.calpopover.placement = 'right';
17218 this.calpopover.setTitle('More');
17220 this.calpopover.setContent('');
17222 var ctr = this.calpopover.el.select('.popover-content', true).first();
17224 Roo.each(more, function(m){
17226 cls : 'fc-event-hori fc-event-draggable',
17229 var cg = ctr.createChild(cfg);
17231 cg.on('click', _this.onEventClick, _this, m);
17234 this.calpopover.show(el);
17239 onLoad: function ()
17241 this.calevents = [];
17244 if(this.store.getCount() > 0){
17245 this.store.data.each(function(d){
17248 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17249 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17250 time : d.data.start_time,
17251 title : d.data.title,
17252 description : d.data.description,
17253 venue : d.data.venue
17258 this.renderEvents();
17260 if(this.calevents.length && this.loadMask){
17261 this.maskEl.hide();
17265 onBeforeLoad: function()
17267 this.clearEvents();
17269 this.maskEl.show();
17283 * @class Roo.bootstrap.Popover
17284 * @extends Roo.bootstrap.Component
17285 * Bootstrap Popover class
17286 * @cfg {String} html contents of the popover (or false to use children..)
17287 * @cfg {String} title of popover (or false to hide)
17288 * @cfg {String} placement how it is placed
17289 * @cfg {String} trigger click || hover (or false to trigger manually)
17290 * @cfg {String} over what (parent or false to trigger manually.)
17291 * @cfg {Number} delay - delay before showing
17294 * Create a new Popover
17295 * @param {Object} config The config object
17298 Roo.bootstrap.Popover = function(config){
17299 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17305 * After the popover show
17307 * @param {Roo.bootstrap.Popover} this
17312 * After the popover hide
17314 * @param {Roo.bootstrap.Popover} this
17320 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17322 title: 'Fill in a title',
17325 placement : 'right',
17326 trigger : 'hover', // hover
17332 can_build_overlaid : false,
17334 getChildContainer : function()
17336 return this.el.select('.popover-content',true).first();
17339 getAutoCreate : function(){
17342 cls : 'popover roo-dynamic',
17343 style: 'display:block',
17349 cls : 'popover-inner',
17353 cls: 'popover-title',
17357 cls : 'popover-content',
17368 setTitle: function(str)
17371 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17373 setContent: function(str)
17376 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17378 // as it get's added to the bottom of the page.
17379 onRender : function(ct, position)
17381 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17383 var cfg = Roo.apply({}, this.getAutoCreate());
17387 cfg.cls += ' ' + this.cls;
17390 cfg.style = this.style;
17392 //Roo.log("adding to ");
17393 this.el = Roo.get(document.body).createChild(cfg, position);
17394 // Roo.log(this.el);
17399 initEvents : function()
17401 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17402 this.el.enableDisplayMode('block');
17404 if (this.over === false) {
17407 if (this.triggers === false) {
17410 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17411 var triggers = this.trigger ? this.trigger.split(' ') : [];
17412 Roo.each(triggers, function(trigger) {
17414 if (trigger == 'click') {
17415 on_el.on('click', this.toggle, this);
17416 } else if (trigger != 'manual') {
17417 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17418 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17420 on_el.on(eventIn ,this.enter, this);
17421 on_el.on(eventOut, this.leave, this);
17432 toggle : function () {
17433 this.hoverState == 'in' ? this.leave() : this.enter();
17436 enter : function () {
17438 clearTimeout(this.timeout);
17440 this.hoverState = 'in';
17442 if (!this.delay || !this.delay.show) {
17447 this.timeout = setTimeout(function () {
17448 if (_t.hoverState == 'in') {
17451 }, this.delay.show)
17454 leave : function() {
17455 clearTimeout(this.timeout);
17457 this.hoverState = 'out';
17459 if (!this.delay || !this.delay.hide) {
17464 this.timeout = setTimeout(function () {
17465 if (_t.hoverState == 'out') {
17468 }, this.delay.hide)
17471 show : function (on_el)
17474 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17478 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17479 if (this.html !== false) {
17480 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17482 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17483 if (!this.title.length) {
17484 this.el.select('.popover-title',true).hide();
17487 var placement = typeof this.placement == 'function' ?
17488 this.placement.call(this, this.el, on_el) :
17491 var autoToken = /\s?auto?\s?/i;
17492 var autoPlace = autoToken.test(placement);
17494 placement = placement.replace(autoToken, '') || 'top';
17498 //this.el.setXY([0,0]);
17500 this.el.dom.style.display='block';
17501 this.el.addClass(placement);
17503 //this.el.appendTo(on_el);
17505 var p = this.getPosition();
17506 var box = this.el.getBox();
17511 var align = Roo.bootstrap.Popover.alignment[placement];
17514 this.el.alignTo(on_el, align[0],align[1]);
17515 //var arrow = this.el.select('.arrow',true).first();
17516 //arrow.set(align[2],
17518 this.el.addClass('in');
17521 if (this.el.hasClass('fade')) {
17525 this.hoverState = 'in';
17527 this.fireEvent('show', this);
17532 this.el.setXY([0,0]);
17533 this.el.removeClass('in');
17535 this.hoverState = null;
17537 this.fireEvent('hide', this);
17542 Roo.bootstrap.Popover.alignment = {
17543 'left' : ['r-l', [-10,0], 'right'],
17544 'right' : ['l-r', [10,0], 'left'],
17545 'bottom' : ['t-b', [0,10], 'top'],
17546 'top' : [ 'b-t', [0,-10], 'bottom']
17557 * @class Roo.bootstrap.Progress
17558 * @extends Roo.bootstrap.Component
17559 * Bootstrap Progress class
17560 * @cfg {Boolean} striped striped of the progress bar
17561 * @cfg {Boolean} active animated of the progress bar
17565 * Create a new Progress
17566 * @param {Object} config The config object
17569 Roo.bootstrap.Progress = function(config){
17570 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17573 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17578 getAutoCreate : function(){
17586 cfg.cls += ' progress-striped';
17590 cfg.cls += ' active';
17609 * @class Roo.bootstrap.ProgressBar
17610 * @extends Roo.bootstrap.Component
17611 * Bootstrap ProgressBar class
17612 * @cfg {Number} aria_valuenow aria-value now
17613 * @cfg {Number} aria_valuemin aria-value min
17614 * @cfg {Number} aria_valuemax aria-value max
17615 * @cfg {String} label label for the progress bar
17616 * @cfg {String} panel (success | info | warning | danger )
17617 * @cfg {String} role role of the progress bar
17618 * @cfg {String} sr_only text
17622 * Create a new ProgressBar
17623 * @param {Object} config The config object
17626 Roo.bootstrap.ProgressBar = function(config){
17627 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17630 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17634 aria_valuemax : 100,
17640 getAutoCreate : function()
17645 cls: 'progress-bar',
17646 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17658 cfg.role = this.role;
17661 if(this.aria_valuenow){
17662 cfg['aria-valuenow'] = this.aria_valuenow;
17665 if(this.aria_valuemin){
17666 cfg['aria-valuemin'] = this.aria_valuemin;
17669 if(this.aria_valuemax){
17670 cfg['aria-valuemax'] = this.aria_valuemax;
17673 if(this.label && !this.sr_only){
17674 cfg.html = this.label;
17678 cfg.cls += ' progress-bar-' + this.panel;
17684 update : function(aria_valuenow)
17686 this.aria_valuenow = aria_valuenow;
17688 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17703 * @class Roo.bootstrap.TabGroup
17704 * @extends Roo.bootstrap.Column
17705 * Bootstrap Column class
17706 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17707 * @cfg {Boolean} carousel true to make the group behave like a carousel
17708 * @cfg {Boolean} bullets show bullets for the panels
17709 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17710 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17711 * @cfg {Boolean} showarrow (true|false) show arrow default true
17714 * Create a new TabGroup
17715 * @param {Object} config The config object
17718 Roo.bootstrap.TabGroup = function(config){
17719 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17721 this.navId = Roo.id();
17724 Roo.bootstrap.TabGroup.register(this);
17728 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17731 transition : false,
17736 slideOnTouch : false,
17739 getAutoCreate : function()
17741 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17743 cfg.cls += ' tab-content';
17745 if (this.carousel) {
17746 cfg.cls += ' carousel slide';
17749 cls : 'carousel-inner',
17753 if(this.bullets && !Roo.isTouch){
17756 cls : 'carousel-bullets',
17760 if(this.bullets_cls){
17761 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17768 cfg.cn[0].cn.push(bullets);
17771 if(this.showarrow){
17772 cfg.cn[0].cn.push({
17774 class : 'carousel-arrow',
17778 class : 'carousel-prev',
17782 class : 'fa fa-chevron-left'
17788 class : 'carousel-next',
17792 class : 'fa fa-chevron-right'
17805 initEvents: function()
17807 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17808 // this.el.on("touchstart", this.onTouchStart, this);
17811 if(this.autoslide){
17814 this.slideFn = window.setInterval(function() {
17815 _this.showPanelNext();
17819 if(this.showarrow){
17820 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17821 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17827 // onTouchStart : function(e, el, o)
17829 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17833 // this.showPanelNext();
17837 getChildContainer : function()
17839 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17843 * register a Navigation item
17844 * @param {Roo.bootstrap.NavItem} the navitem to add
17846 register : function(item)
17848 this.tabs.push( item);
17849 item.navId = this.navId; // not really needed..
17854 getActivePanel : function()
17857 Roo.each(this.tabs, function(t) {
17867 getPanelByName : function(n)
17870 Roo.each(this.tabs, function(t) {
17871 if (t.tabId == n) {
17879 indexOfPanel : function(p)
17882 Roo.each(this.tabs, function(t,i) {
17883 if (t.tabId == p.tabId) {
17892 * show a specific panel
17893 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17894 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17896 showPanel : function (pan)
17898 if(this.transition || typeof(pan) == 'undefined'){
17899 Roo.log("waiting for the transitionend");
17903 if (typeof(pan) == 'number') {
17904 pan = this.tabs[pan];
17907 if (typeof(pan) == 'string') {
17908 pan = this.getPanelByName(pan);
17911 var cur = this.getActivePanel();
17914 Roo.log('pan or acitve pan is undefined');
17918 if (pan.tabId == this.getActivePanel().tabId) {
17922 if (false === cur.fireEvent('beforedeactivate')) {
17926 if(this.bullets > 0 && !Roo.isTouch){
17927 this.setActiveBullet(this.indexOfPanel(pan));
17930 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17932 this.transition = true;
17933 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17934 var lr = dir == 'next' ? 'left' : 'right';
17935 pan.el.addClass(dir); // or prev
17936 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17937 cur.el.addClass(lr); // or right
17938 pan.el.addClass(lr);
17941 cur.el.on('transitionend', function() {
17942 Roo.log("trans end?");
17944 pan.el.removeClass([lr,dir]);
17945 pan.setActive(true);
17947 cur.el.removeClass([lr]);
17948 cur.setActive(false);
17950 _this.transition = false;
17952 }, this, { single: true } );
17957 cur.setActive(false);
17958 pan.setActive(true);
17963 showPanelNext : function()
17965 var i = this.indexOfPanel(this.getActivePanel());
17967 if (i >= this.tabs.length - 1 && !this.autoslide) {
17971 if (i >= this.tabs.length - 1 && this.autoslide) {
17975 this.showPanel(this.tabs[i+1]);
17978 showPanelPrev : function()
17980 var i = this.indexOfPanel(this.getActivePanel());
17982 if (i < 1 && !this.autoslide) {
17986 if (i < 1 && this.autoslide) {
17987 i = this.tabs.length;
17990 this.showPanel(this.tabs[i-1]);
17994 addBullet: function()
17996 if(!this.bullets || Roo.isTouch){
17999 var ctr = this.el.select('.carousel-bullets',true).first();
18000 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18001 var bullet = ctr.createChild({
18002 cls : 'bullet bullet-' + i
18003 },ctr.dom.lastChild);
18008 bullet.on('click', (function(e, el, o, ii, t){
18010 e.preventDefault();
18012 this.showPanel(ii);
18014 if(this.autoslide && this.slideFn){
18015 clearInterval(this.slideFn);
18016 this.slideFn = window.setInterval(function() {
18017 _this.showPanelNext();
18021 }).createDelegate(this, [i, bullet], true));
18026 setActiveBullet : function(i)
18032 Roo.each(this.el.select('.bullet', true).elements, function(el){
18033 el.removeClass('selected');
18036 var bullet = this.el.select('.bullet-' + i, true).first();
18042 bullet.addClass('selected');
18053 Roo.apply(Roo.bootstrap.TabGroup, {
18057 * register a Navigation Group
18058 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18060 register : function(navgrp)
18062 this.groups[navgrp.navId] = navgrp;
18066 * fetch a Navigation Group based on the navigation ID
18067 * if one does not exist , it will get created.
18068 * @param {string} the navgroup to add
18069 * @returns {Roo.bootstrap.NavGroup} the navgroup
18071 get: function(navId) {
18072 if (typeof(this.groups[navId]) == 'undefined') {
18073 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18075 return this.groups[navId] ;
18090 * @class Roo.bootstrap.TabPanel
18091 * @extends Roo.bootstrap.Component
18092 * Bootstrap TabPanel class
18093 * @cfg {Boolean} active panel active
18094 * @cfg {String} html panel content
18095 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18096 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18097 * @cfg {String} href click to link..
18101 * Create a new TabPanel
18102 * @param {Object} config The config object
18105 Roo.bootstrap.TabPanel = function(config){
18106 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18110 * Fires when the active status changes
18111 * @param {Roo.bootstrap.TabPanel} this
18112 * @param {Boolean} state the new state
18117 * @event beforedeactivate
18118 * Fires before a tab is de-activated - can be used to do validation on a form.
18119 * @param {Roo.bootstrap.TabPanel} this
18120 * @return {Boolean} false if there is an error
18123 'beforedeactivate': true
18126 this.tabId = this.tabId || Roo.id();
18130 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18138 getAutoCreate : function(){
18141 // item is needed for carousel - not sure if it has any effect otherwise
18142 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18143 html: this.html || ''
18147 cfg.cls += ' active';
18151 cfg.tabId = this.tabId;
18158 initEvents: function()
18160 var p = this.parent();
18162 this.navId = this.navId || p.navId;
18164 if (typeof(this.navId) != 'undefined') {
18165 // not really needed.. but just in case.. parent should be a NavGroup.
18166 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18170 var i = tg.tabs.length - 1;
18172 if(this.active && tg.bullets > 0 && i < tg.bullets){
18173 tg.setActiveBullet(i);
18177 this.el.on('click', this.onClick, this);
18180 this.el.on("touchstart", this.onTouchStart, this);
18181 this.el.on("touchmove", this.onTouchMove, this);
18182 this.el.on("touchend", this.onTouchEnd, this);
18187 onRender : function(ct, position)
18189 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18192 setActive : function(state)
18194 Roo.log("panel - set active " + this.tabId + "=" + state);
18196 this.active = state;
18198 this.el.removeClass('active');
18200 } else if (!this.el.hasClass('active')) {
18201 this.el.addClass('active');
18204 this.fireEvent('changed', this, state);
18207 onClick : function(e)
18209 e.preventDefault();
18211 if(!this.href.length){
18215 window.location.href = this.href;
18224 onTouchStart : function(e)
18226 this.swiping = false;
18228 this.startX = e.browserEvent.touches[0].clientX;
18229 this.startY = e.browserEvent.touches[0].clientY;
18232 onTouchMove : function(e)
18234 this.swiping = true;
18236 this.endX = e.browserEvent.touches[0].clientX;
18237 this.endY = e.browserEvent.touches[0].clientY;
18240 onTouchEnd : function(e)
18247 var tabGroup = this.parent();
18249 if(this.endX > this.startX){ // swiping right
18250 tabGroup.showPanelPrev();
18254 if(this.startX > this.endX){ // swiping left
18255 tabGroup.showPanelNext();
18274 * @class Roo.bootstrap.DateField
18275 * @extends Roo.bootstrap.Input
18276 * Bootstrap DateField class
18277 * @cfg {Number} weekStart default 0
18278 * @cfg {String} viewMode default empty, (months|years)
18279 * @cfg {String} minViewMode default empty, (months|years)
18280 * @cfg {Number} startDate default -Infinity
18281 * @cfg {Number} endDate default Infinity
18282 * @cfg {Boolean} todayHighlight default false
18283 * @cfg {Boolean} todayBtn default false
18284 * @cfg {Boolean} calendarWeeks default false
18285 * @cfg {Object} daysOfWeekDisabled default empty
18286 * @cfg {Boolean} singleMode default false (true | false)
18288 * @cfg {Boolean} keyboardNavigation default true
18289 * @cfg {String} language default en
18292 * Create a new DateField
18293 * @param {Object} config The config object
18296 Roo.bootstrap.DateField = function(config){
18297 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18301 * Fires when this field show.
18302 * @param {Roo.bootstrap.DateField} this
18303 * @param {Mixed} date The date value
18308 * Fires when this field hide.
18309 * @param {Roo.bootstrap.DateField} this
18310 * @param {Mixed} date The date value
18315 * Fires when select a date.
18316 * @param {Roo.bootstrap.DateField} this
18317 * @param {Mixed} date The date value
18321 * @event beforeselect
18322 * Fires when before select a date.
18323 * @param {Roo.bootstrap.DateField} this
18324 * @param {Mixed} date The date value
18326 beforeselect : true
18330 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18333 * @cfg {String} format
18334 * The default date format string which can be overriden for localization support. The format must be
18335 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18339 * @cfg {String} altFormats
18340 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18341 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18343 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18351 todayHighlight : false,
18357 keyboardNavigation: true,
18359 calendarWeeks: false,
18361 startDate: -Infinity,
18365 daysOfWeekDisabled: [],
18369 singleMode : false,
18371 UTCDate: function()
18373 return new Date(Date.UTC.apply(Date, arguments));
18376 UTCToday: function()
18378 var today = new Date();
18379 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18382 getDate: function() {
18383 var d = this.getUTCDate();
18384 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18387 getUTCDate: function() {
18391 setDate: function(d) {
18392 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18395 setUTCDate: function(d) {
18397 this.setValue(this.formatDate(this.date));
18400 onRender: function(ct, position)
18403 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18405 this.language = this.language || 'en';
18406 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18407 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18409 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18410 this.format = this.format || 'm/d/y';
18411 this.isInline = false;
18412 this.isInput = true;
18413 this.component = this.el.select('.add-on', true).first() || false;
18414 this.component = (this.component && this.component.length === 0) ? false : this.component;
18415 this.hasInput = this.component && this.inputEl().length;
18417 if (typeof(this.minViewMode === 'string')) {
18418 switch (this.minViewMode) {
18420 this.minViewMode = 1;
18423 this.minViewMode = 2;
18426 this.minViewMode = 0;
18431 if (typeof(this.viewMode === 'string')) {
18432 switch (this.viewMode) {
18445 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18447 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18449 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18451 this.picker().on('mousedown', this.onMousedown, this);
18452 this.picker().on('click', this.onClick, this);
18454 this.picker().addClass('datepicker-dropdown');
18456 this.startViewMode = this.viewMode;
18458 if(this.singleMode){
18459 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18460 v.setVisibilityMode(Roo.Element.DISPLAY);
18464 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18465 v.setStyle('width', '189px');
18469 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18470 if(!this.calendarWeeks){
18475 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18476 v.attr('colspan', function(i, val){
18477 return parseInt(val) + 1;
18482 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18484 this.setStartDate(this.startDate);
18485 this.setEndDate(this.endDate);
18487 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18494 if(this.isInline) {
18499 picker : function()
18501 return this.pickerEl;
18502 // return this.el.select('.datepicker', true).first();
18505 fillDow: function()
18507 var dowCnt = this.weekStart;
18516 if(this.calendarWeeks){
18524 while (dowCnt < this.weekStart + 7) {
18528 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18532 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18535 fillMonths: function()
18538 var months = this.picker().select('>.datepicker-months td', true).first();
18540 months.dom.innerHTML = '';
18546 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18549 months.createChild(month);
18556 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;
18558 if (this.date < this.startDate) {
18559 this.viewDate = new Date(this.startDate);
18560 } else if (this.date > this.endDate) {
18561 this.viewDate = new Date(this.endDate);
18563 this.viewDate = new Date(this.date);
18571 var d = new Date(this.viewDate),
18572 year = d.getUTCFullYear(),
18573 month = d.getUTCMonth(),
18574 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18575 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18576 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18577 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18578 currentDate = this.date && this.date.valueOf(),
18579 today = this.UTCToday();
18581 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18583 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18585 // this.picker.select('>tfoot th.today').
18586 // .text(dates[this.language].today)
18587 // .toggle(this.todayBtn !== false);
18589 this.updateNavArrows();
18592 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18594 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18596 prevMonth.setUTCDate(day);
18598 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18600 var nextMonth = new Date(prevMonth);
18602 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18604 nextMonth = nextMonth.valueOf();
18606 var fillMonths = false;
18608 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18610 while(prevMonth.valueOf() < nextMonth) {
18613 if (prevMonth.getUTCDay() === this.weekStart) {
18615 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18623 if(this.calendarWeeks){
18624 // ISO 8601: First week contains first thursday.
18625 // ISO also states week starts on Monday, but we can be more abstract here.
18627 // Start of current week: based on weekstart/current date
18628 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18629 // Thursday of this week
18630 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18631 // First Thursday of year, year from thursday
18632 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18633 // Calendar week: ms between thursdays, div ms per day, div 7 days
18634 calWeek = (th - yth) / 864e5 / 7 + 1;
18636 fillMonths.cn.push({
18644 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18646 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18649 if (this.todayHighlight &&
18650 prevMonth.getUTCFullYear() == today.getFullYear() &&
18651 prevMonth.getUTCMonth() == today.getMonth() &&
18652 prevMonth.getUTCDate() == today.getDate()) {
18653 clsName += ' today';
18656 if (currentDate && prevMonth.valueOf() === currentDate) {
18657 clsName += ' active';
18660 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18661 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18662 clsName += ' disabled';
18665 fillMonths.cn.push({
18667 cls: 'day ' + clsName,
18668 html: prevMonth.getDate()
18671 prevMonth.setDate(prevMonth.getDate()+1);
18674 var currentYear = this.date && this.date.getUTCFullYear();
18675 var currentMonth = this.date && this.date.getUTCMonth();
18677 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18679 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18680 v.removeClass('active');
18682 if(currentYear === year && k === currentMonth){
18683 v.addClass('active');
18686 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18687 v.addClass('disabled');
18693 year = parseInt(year/10, 10) * 10;
18695 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18697 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18700 for (var i = -1; i < 11; i++) {
18701 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18703 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18711 showMode: function(dir)
18714 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18717 Roo.each(this.picker().select('>div',true).elements, function(v){
18718 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18721 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18726 if(this.isInline) {
18730 this.picker().removeClass(['bottom', 'top']);
18732 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18734 * place to the top of element!
18738 this.picker().addClass('top');
18739 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18744 this.picker().addClass('bottom');
18746 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18749 parseDate : function(value)
18751 if(!value || value instanceof Date){
18754 var v = Date.parseDate(value, this.format);
18755 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18756 v = Date.parseDate(value, 'Y-m-d');
18758 if(!v && this.altFormats){
18759 if(!this.altFormatsArray){
18760 this.altFormatsArray = this.altFormats.split("|");
18762 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18763 v = Date.parseDate(value, this.altFormatsArray[i]);
18769 formatDate : function(date, fmt)
18771 return (!date || !(date instanceof Date)) ?
18772 date : date.dateFormat(fmt || this.format);
18775 onFocus : function()
18777 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18781 onBlur : function()
18783 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18785 var d = this.inputEl().getValue();
18794 this.picker().show();
18798 this.fireEvent('show', this, this.date);
18803 if(this.isInline) {
18806 this.picker().hide();
18807 this.viewMode = this.startViewMode;
18810 this.fireEvent('hide', this, this.date);
18814 onMousedown: function(e)
18816 e.stopPropagation();
18817 e.preventDefault();
18822 Roo.bootstrap.DateField.superclass.keyup.call(this);
18826 setValue: function(v)
18828 if(this.fireEvent('beforeselect', this, v) !== false){
18829 var d = new Date(this.parseDate(v) ).clearTime();
18831 if(isNaN(d.getTime())){
18832 this.date = this.viewDate = '';
18833 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18837 v = this.formatDate(d);
18839 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18841 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18845 this.fireEvent('select', this, this.date);
18849 getValue: function()
18851 return this.formatDate(this.date);
18854 fireKey: function(e)
18856 if (!this.picker().isVisible()){
18857 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18863 var dateChanged = false,
18865 newDate, newViewDate;
18870 e.preventDefault();
18874 if (!this.keyboardNavigation) {
18877 dir = e.keyCode == 37 ? -1 : 1;
18880 newDate = this.moveYear(this.date, dir);
18881 newViewDate = this.moveYear(this.viewDate, dir);
18882 } else if (e.shiftKey){
18883 newDate = this.moveMonth(this.date, dir);
18884 newViewDate = this.moveMonth(this.viewDate, dir);
18886 newDate = new Date(this.date);
18887 newDate.setUTCDate(this.date.getUTCDate() + dir);
18888 newViewDate = new Date(this.viewDate);
18889 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18891 if (this.dateWithinRange(newDate)){
18892 this.date = newDate;
18893 this.viewDate = newViewDate;
18894 this.setValue(this.formatDate(this.date));
18896 e.preventDefault();
18897 dateChanged = true;
18902 if (!this.keyboardNavigation) {
18905 dir = e.keyCode == 38 ? -1 : 1;
18907 newDate = this.moveYear(this.date, dir);
18908 newViewDate = this.moveYear(this.viewDate, dir);
18909 } else if (e.shiftKey){
18910 newDate = this.moveMonth(this.date, dir);
18911 newViewDate = this.moveMonth(this.viewDate, dir);
18913 newDate = new Date(this.date);
18914 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18915 newViewDate = new Date(this.viewDate);
18916 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18918 if (this.dateWithinRange(newDate)){
18919 this.date = newDate;
18920 this.viewDate = newViewDate;
18921 this.setValue(this.formatDate(this.date));
18923 e.preventDefault();
18924 dateChanged = true;
18928 this.setValue(this.formatDate(this.date));
18930 e.preventDefault();
18933 this.setValue(this.formatDate(this.date));
18947 onClick: function(e)
18949 e.stopPropagation();
18950 e.preventDefault();
18952 var target = e.getTarget();
18954 if(target.nodeName.toLowerCase() === 'i'){
18955 target = Roo.get(target).dom.parentNode;
18958 var nodeName = target.nodeName;
18959 var className = target.className;
18960 var html = target.innerHTML;
18961 //Roo.log(nodeName);
18963 switch(nodeName.toLowerCase()) {
18965 switch(className) {
18971 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18972 switch(this.viewMode){
18974 this.viewDate = this.moveMonth(this.viewDate, dir);
18978 this.viewDate = this.moveYear(this.viewDate, dir);
18984 var date = new Date();
18985 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18987 this.setValue(this.formatDate(this.date));
18994 if (className.indexOf('disabled') < 0) {
18995 this.viewDate.setUTCDate(1);
18996 if (className.indexOf('month') > -1) {
18997 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18999 var year = parseInt(html, 10) || 0;
19000 this.viewDate.setUTCFullYear(year);
19004 if(this.singleMode){
19005 this.setValue(this.formatDate(this.viewDate));
19016 //Roo.log(className);
19017 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19018 var day = parseInt(html, 10) || 1;
19019 var year = this.viewDate.getUTCFullYear(),
19020 month = this.viewDate.getUTCMonth();
19022 if (className.indexOf('old') > -1) {
19029 } else if (className.indexOf('new') > -1) {
19037 //Roo.log([year,month,day]);
19038 this.date = this.UTCDate(year, month, day,0,0,0,0);
19039 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19041 //Roo.log(this.formatDate(this.date));
19042 this.setValue(this.formatDate(this.date));
19049 setStartDate: function(startDate)
19051 this.startDate = startDate || -Infinity;
19052 if (this.startDate !== -Infinity) {
19053 this.startDate = this.parseDate(this.startDate);
19056 this.updateNavArrows();
19059 setEndDate: function(endDate)
19061 this.endDate = endDate || Infinity;
19062 if (this.endDate !== Infinity) {
19063 this.endDate = this.parseDate(this.endDate);
19066 this.updateNavArrows();
19069 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19071 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19072 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19073 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19075 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19076 return parseInt(d, 10);
19079 this.updateNavArrows();
19082 updateNavArrows: function()
19084 if(this.singleMode){
19088 var d = new Date(this.viewDate),
19089 year = d.getUTCFullYear(),
19090 month = d.getUTCMonth();
19092 Roo.each(this.picker().select('.prev', true).elements, function(v){
19094 switch (this.viewMode) {
19097 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19103 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19110 Roo.each(this.picker().select('.next', true).elements, function(v){
19112 switch (this.viewMode) {
19115 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19121 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19129 moveMonth: function(date, dir)
19134 var new_date = new Date(date.valueOf()),
19135 day = new_date.getUTCDate(),
19136 month = new_date.getUTCMonth(),
19137 mag = Math.abs(dir),
19139 dir = dir > 0 ? 1 : -1;
19142 // If going back one month, make sure month is not current month
19143 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19145 return new_date.getUTCMonth() == month;
19147 // If going forward one month, make sure month is as expected
19148 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19150 return new_date.getUTCMonth() != new_month;
19152 new_month = month + dir;
19153 new_date.setUTCMonth(new_month);
19154 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19155 if (new_month < 0 || new_month > 11) {
19156 new_month = (new_month + 12) % 12;
19159 // For magnitudes >1, move one month at a time...
19160 for (var i=0; i<mag; i++) {
19161 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19162 new_date = this.moveMonth(new_date, dir);
19164 // ...then reset the day, keeping it in the new month
19165 new_month = new_date.getUTCMonth();
19166 new_date.setUTCDate(day);
19168 return new_month != new_date.getUTCMonth();
19171 // Common date-resetting loop -- if date is beyond end of month, make it
19174 new_date.setUTCDate(--day);
19175 new_date.setUTCMonth(new_month);
19180 moveYear: function(date, dir)
19182 return this.moveMonth(date, dir*12);
19185 dateWithinRange: function(date)
19187 return date >= this.startDate && date <= this.endDate;
19193 this.picker().remove();
19196 validateValue : function(value)
19198 if(this.getVisibilityEl().hasClass('hidden')){
19202 if(value.length < 1) {
19203 if(this.allowBlank){
19209 if(value.length < this.minLength){
19212 if(value.length > this.maxLength){
19216 var vt = Roo.form.VTypes;
19217 if(!vt[this.vtype](value, this)){
19221 if(typeof this.validator == "function"){
19222 var msg = this.validator(value);
19228 if(this.regex && !this.regex.test(value)){
19232 if(typeof(this.parseDate(value)) == 'undefined'){
19236 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19240 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19248 setVisible : function(visible)
19254 this.getEl().removeClass('hidden');
19260 this.getEl().addClass('hidden');
19265 Roo.apply(Roo.bootstrap.DateField, {
19276 html: '<i class="fa fa-arrow-left"/>'
19286 html: '<i class="fa fa-arrow-right"/>'
19328 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19329 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19330 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19331 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19332 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19345 navFnc: 'FullYear',
19350 navFnc: 'FullYear',
19355 Roo.apply(Roo.bootstrap.DateField, {
19359 cls: 'datepicker dropdown-menu roo-dynamic',
19363 cls: 'datepicker-days',
19367 cls: 'table-condensed',
19369 Roo.bootstrap.DateField.head,
19373 Roo.bootstrap.DateField.footer
19380 cls: 'datepicker-months',
19384 cls: 'table-condensed',
19386 Roo.bootstrap.DateField.head,
19387 Roo.bootstrap.DateField.content,
19388 Roo.bootstrap.DateField.footer
19395 cls: 'datepicker-years',
19399 cls: 'table-condensed',
19401 Roo.bootstrap.DateField.head,
19402 Roo.bootstrap.DateField.content,
19403 Roo.bootstrap.DateField.footer
19422 * @class Roo.bootstrap.TimeField
19423 * @extends Roo.bootstrap.Input
19424 * Bootstrap DateField class
19428 * Create a new TimeField
19429 * @param {Object} config The config object
19432 Roo.bootstrap.TimeField = function(config){
19433 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19437 * Fires when this field show.
19438 * @param {Roo.bootstrap.DateField} thisthis
19439 * @param {Mixed} date The date value
19444 * Fires when this field hide.
19445 * @param {Roo.bootstrap.DateField} this
19446 * @param {Mixed} date The date value
19451 * Fires when select a date.
19452 * @param {Roo.bootstrap.DateField} this
19453 * @param {Mixed} date The date value
19459 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19462 * @cfg {String} format
19463 * The default time format string which can be overriden for localization support. The format must be
19464 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19468 onRender: function(ct, position)
19471 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19473 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19475 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19477 this.pop = this.picker().select('>.datepicker-time',true).first();
19478 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19480 this.picker().on('mousedown', this.onMousedown, this);
19481 this.picker().on('click', this.onClick, this);
19483 this.picker().addClass('datepicker-dropdown');
19488 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19489 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19490 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19491 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19492 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19493 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19497 fireKey: function(e){
19498 if (!this.picker().isVisible()){
19499 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19505 e.preventDefault();
19513 this.onTogglePeriod();
19516 this.onIncrementMinutes();
19519 this.onDecrementMinutes();
19528 onClick: function(e) {
19529 e.stopPropagation();
19530 e.preventDefault();
19533 picker : function()
19535 return this.el.select('.datepicker', true).first();
19538 fillTime: function()
19540 var time = this.pop.select('tbody', true).first();
19542 time.dom.innerHTML = '';
19557 cls: 'hours-up glyphicon glyphicon-chevron-up'
19577 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19598 cls: 'timepicker-hour',
19613 cls: 'timepicker-minute',
19628 cls: 'btn btn-primary period',
19650 cls: 'hours-down glyphicon glyphicon-chevron-down'
19670 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19688 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19695 var hours = this.time.getHours();
19696 var minutes = this.time.getMinutes();
19709 hours = hours - 12;
19713 hours = '0' + hours;
19717 minutes = '0' + minutes;
19720 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19721 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19722 this.pop.select('button', true).first().dom.innerHTML = period;
19728 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19730 var cls = ['bottom'];
19732 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19739 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19744 this.picker().addClass(cls.join('-'));
19748 Roo.each(cls, function(c){
19750 _this.picker().setTop(_this.inputEl().getHeight());
19754 _this.picker().setTop(0 - _this.picker().getHeight());
19759 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19763 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19770 onFocus : function()
19772 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19776 onBlur : function()
19778 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19784 this.picker().show();
19789 this.fireEvent('show', this, this.date);
19794 this.picker().hide();
19797 this.fireEvent('hide', this, this.date);
19800 setTime : function()
19803 this.setValue(this.time.format(this.format));
19805 this.fireEvent('select', this, this.date);
19810 onMousedown: function(e){
19811 e.stopPropagation();
19812 e.preventDefault();
19815 onIncrementHours: function()
19817 Roo.log('onIncrementHours');
19818 this.time = this.time.add(Date.HOUR, 1);
19823 onDecrementHours: function()
19825 Roo.log('onDecrementHours');
19826 this.time = this.time.add(Date.HOUR, -1);
19830 onIncrementMinutes: function()
19832 Roo.log('onIncrementMinutes');
19833 this.time = this.time.add(Date.MINUTE, 1);
19837 onDecrementMinutes: function()
19839 Roo.log('onDecrementMinutes');
19840 this.time = this.time.add(Date.MINUTE, -1);
19844 onTogglePeriod: function()
19846 Roo.log('onTogglePeriod');
19847 this.time = this.time.add(Date.HOUR, 12);
19854 Roo.apply(Roo.bootstrap.TimeField, {
19884 cls: 'btn btn-info ok',
19896 Roo.apply(Roo.bootstrap.TimeField, {
19900 cls: 'datepicker dropdown-menu',
19904 cls: 'datepicker-time',
19908 cls: 'table-condensed',
19910 Roo.bootstrap.TimeField.content,
19911 Roo.bootstrap.TimeField.footer
19930 * @class Roo.bootstrap.MonthField
19931 * @extends Roo.bootstrap.Input
19932 * Bootstrap MonthField class
19934 * @cfg {String} language default en
19937 * Create a new MonthField
19938 * @param {Object} config The config object
19941 Roo.bootstrap.MonthField = function(config){
19942 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19947 * Fires when this field show.
19948 * @param {Roo.bootstrap.MonthField} this
19949 * @param {Mixed} date The date value
19954 * Fires when this field hide.
19955 * @param {Roo.bootstrap.MonthField} this
19956 * @param {Mixed} date The date value
19961 * Fires when select a date.
19962 * @param {Roo.bootstrap.MonthField} this
19963 * @param {String} oldvalue The old value
19964 * @param {String} newvalue The new value
19970 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19972 onRender: function(ct, position)
19975 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19977 this.language = this.language || 'en';
19978 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19979 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19981 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19982 this.isInline = false;
19983 this.isInput = true;
19984 this.component = this.el.select('.add-on', true).first() || false;
19985 this.component = (this.component && this.component.length === 0) ? false : this.component;
19986 this.hasInput = this.component && this.inputEL().length;
19988 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19990 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19992 this.picker().on('mousedown', this.onMousedown, this);
19993 this.picker().on('click', this.onClick, this);
19995 this.picker().addClass('datepicker-dropdown');
19997 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19998 v.setStyle('width', '189px');
20005 if(this.isInline) {
20011 setValue: function(v, suppressEvent)
20013 var o = this.getValue();
20015 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20019 if(suppressEvent !== true){
20020 this.fireEvent('select', this, o, v);
20025 getValue: function()
20030 onClick: function(e)
20032 e.stopPropagation();
20033 e.preventDefault();
20035 var target = e.getTarget();
20037 if(target.nodeName.toLowerCase() === 'i'){
20038 target = Roo.get(target).dom.parentNode;
20041 var nodeName = target.nodeName;
20042 var className = target.className;
20043 var html = target.innerHTML;
20045 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20049 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20051 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20057 picker : function()
20059 return this.pickerEl;
20062 fillMonths: function()
20065 var months = this.picker().select('>.datepicker-months td', true).first();
20067 months.dom.innerHTML = '';
20073 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20076 months.createChild(month);
20085 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20086 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20089 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20090 e.removeClass('active');
20092 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20093 e.addClass('active');
20100 if(this.isInline) {
20104 this.picker().removeClass(['bottom', 'top']);
20106 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20108 * place to the top of element!
20112 this.picker().addClass('top');
20113 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20118 this.picker().addClass('bottom');
20120 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20123 onFocus : function()
20125 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20129 onBlur : function()
20131 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20133 var d = this.inputEl().getValue();
20142 this.picker().show();
20143 this.picker().select('>.datepicker-months', true).first().show();
20147 this.fireEvent('show', this, this.date);
20152 if(this.isInline) {
20155 this.picker().hide();
20156 this.fireEvent('hide', this, this.date);
20160 onMousedown: function(e)
20162 e.stopPropagation();
20163 e.preventDefault();
20168 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20172 fireKey: function(e)
20174 if (!this.picker().isVisible()){
20175 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20186 e.preventDefault();
20190 dir = e.keyCode == 37 ? -1 : 1;
20192 this.vIndex = this.vIndex + dir;
20194 if(this.vIndex < 0){
20198 if(this.vIndex > 11){
20202 if(isNaN(this.vIndex)){
20206 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20212 dir = e.keyCode == 38 ? -1 : 1;
20214 this.vIndex = this.vIndex + dir * 4;
20216 if(this.vIndex < 0){
20220 if(this.vIndex > 11){
20224 if(isNaN(this.vIndex)){
20228 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20233 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20234 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20238 e.preventDefault();
20241 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20242 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20258 this.picker().remove();
20263 Roo.apply(Roo.bootstrap.MonthField, {
20282 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20283 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20288 Roo.apply(Roo.bootstrap.MonthField, {
20292 cls: 'datepicker dropdown-menu roo-dynamic',
20296 cls: 'datepicker-months',
20300 cls: 'table-condensed',
20302 Roo.bootstrap.DateField.content
20322 * @class Roo.bootstrap.CheckBox
20323 * @extends Roo.bootstrap.Input
20324 * Bootstrap CheckBox class
20326 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20327 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20328 * @cfg {String} boxLabel The text that appears beside the checkbox
20329 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20330 * @cfg {Boolean} checked initnal the element
20331 * @cfg {Boolean} inline inline the element (default false)
20332 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20333 * @cfg {String} tooltip label tooltip
20336 * Create a new CheckBox
20337 * @param {Object} config The config object
20340 Roo.bootstrap.CheckBox = function(config){
20341 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20346 * Fires when the element is checked or unchecked.
20347 * @param {Roo.bootstrap.CheckBox} this This input
20348 * @param {Boolean} checked The new checked value
20353 * Fires when the element is click.
20354 * @param {Roo.bootstrap.CheckBox} this This input
20361 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20363 inputType: 'checkbox',
20372 getAutoCreate : function()
20374 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20380 cfg.cls = 'form-group ' + this.inputType; //input-group
20383 cfg.cls += ' ' + this.inputType + '-inline';
20389 type : this.inputType,
20390 value : this.inputValue,
20391 cls : 'roo-' + this.inputType, //'form-box',
20392 placeholder : this.placeholder || ''
20396 if(this.inputType != 'radio'){
20400 cls : 'roo-hidden-value',
20401 value : this.checked ? this.inputValue : this.valueOff
20406 if (this.weight) { // Validity check?
20407 cfg.cls += " " + this.inputType + "-" + this.weight;
20410 if (this.disabled) {
20411 input.disabled=true;
20415 input.checked = this.checked;
20420 input.name = this.name;
20422 if(this.inputType != 'radio'){
20423 hidden.name = this.name;
20424 input.name = '_hidden_' + this.name;
20429 input.cls += ' input-' + this.size;
20434 ['xs','sm','md','lg'].map(function(size){
20435 if (settings[size]) {
20436 cfg.cls += ' col-' + size + '-' + settings[size];
20440 var inputblock = input;
20442 if (this.before || this.after) {
20445 cls : 'input-group',
20450 inputblock.cn.push({
20452 cls : 'input-group-addon',
20457 inputblock.cn.push(input);
20459 if(this.inputType != 'radio'){
20460 inputblock.cn.push(hidden);
20464 inputblock.cn.push({
20466 cls : 'input-group-addon',
20473 if (align ==='left' && this.fieldLabel.length) {
20474 // Roo.log("left and has label");
20479 cls : 'control-label',
20480 html : this.fieldLabel
20490 if(this.labelWidth > 12){
20491 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20494 if(this.labelWidth < 13 && this.labelmd == 0){
20495 this.labelmd = this.labelWidth;
20498 if(this.labellg > 0){
20499 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20500 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20503 if(this.labelmd > 0){
20504 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20505 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20508 if(this.labelsm > 0){
20509 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20510 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20513 if(this.labelxs > 0){
20514 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20515 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20518 } else if ( this.fieldLabel.length) {
20519 // Roo.log(" label");
20523 tag: this.boxLabel ? 'span' : 'label',
20525 cls: 'control-label box-input-label',
20526 //cls : 'input-group-addon',
20527 html : this.fieldLabel
20536 // Roo.log(" no label && no align");
20537 cfg.cn = [ inputblock ] ;
20543 var boxLabelCfg = {
20545 //'for': id, // box label is handled by onclick - so no for...
20547 html: this.boxLabel
20551 boxLabelCfg.tooltip = this.tooltip;
20554 cfg.cn.push(boxLabelCfg);
20557 if(this.inputType != 'radio'){
20558 cfg.cn.push(hidden);
20566 * return the real input element.
20568 inputEl: function ()
20570 return this.el.select('input.roo-' + this.inputType,true).first();
20572 hiddenEl: function ()
20574 return this.el.select('input.roo-hidden-value',true).first();
20577 labelEl: function()
20579 return this.el.select('label.control-label',true).first();
20581 /* depricated... */
20585 return this.labelEl();
20588 boxLabelEl: function()
20590 return this.el.select('label.box-label',true).first();
20593 initEvents : function()
20595 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20597 this.inputEl().on('click', this.onClick, this);
20599 if (this.boxLabel) {
20600 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20603 this.startValue = this.getValue();
20606 Roo.bootstrap.CheckBox.register(this);
20610 onClick : function(e)
20612 if(this.fireEvent('click', this, e) !== false){
20613 this.setChecked(!this.checked);
20618 setChecked : function(state,suppressEvent)
20620 this.startValue = this.getValue();
20622 if(this.inputType == 'radio'){
20624 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20625 e.dom.checked = false;
20628 this.inputEl().dom.checked = true;
20630 this.inputEl().dom.value = this.inputValue;
20632 if(suppressEvent !== true){
20633 this.fireEvent('check', this, true);
20641 this.checked = state;
20643 this.inputEl().dom.checked = state;
20646 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20648 if(suppressEvent !== true){
20649 this.fireEvent('check', this, state);
20655 getValue : function()
20657 if(this.inputType == 'radio'){
20658 return this.getGroupValue();
20661 return this.hiddenEl().dom.value;
20665 getGroupValue : function()
20667 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20671 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20674 setValue : function(v,suppressEvent)
20676 if(this.inputType == 'radio'){
20677 this.setGroupValue(v, suppressEvent);
20681 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20686 setGroupValue : function(v, suppressEvent)
20688 this.startValue = this.getValue();
20690 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20691 e.dom.checked = false;
20693 if(e.dom.value == v){
20694 e.dom.checked = true;
20698 if(suppressEvent !== true){
20699 this.fireEvent('check', this, true);
20707 validate : function()
20709 if(this.getVisibilityEl().hasClass('hidden')){
20715 (this.inputType == 'radio' && this.validateRadio()) ||
20716 (this.inputType == 'checkbox' && this.validateCheckbox())
20722 this.markInvalid();
20726 validateRadio : function()
20728 if(this.getVisibilityEl().hasClass('hidden')){
20732 if(this.allowBlank){
20738 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20739 if(!e.dom.checked){
20751 validateCheckbox : function()
20754 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20755 //return (this.getValue() == this.inputValue) ? true : false;
20758 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20766 for(var i in group){
20767 if(group[i].el.isVisible(true)){
20775 for(var i in group){
20780 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20787 * Mark this field as valid
20789 markValid : function()
20793 this.fireEvent('valid', this);
20795 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20798 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20805 if(this.inputType == 'radio'){
20806 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20807 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20808 e.findParent('.form-group', false, true).addClass(_this.validClass);
20815 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20816 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20820 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20826 for(var i in group){
20827 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20828 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20833 * Mark this field as invalid
20834 * @param {String} msg The validation message
20836 markInvalid : function(msg)
20838 if(this.allowBlank){
20844 this.fireEvent('invalid', this, msg);
20846 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20849 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20853 label.markInvalid();
20856 if(this.inputType == 'radio'){
20857 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20858 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20859 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20866 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20867 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20871 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20877 for(var i in group){
20878 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20879 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20884 clearInvalid : function()
20886 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20888 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20890 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20892 if (label && label.iconEl) {
20893 label.iconEl.removeClass(label.validClass);
20894 label.iconEl.removeClass(label.invalidClass);
20898 disable : function()
20900 if(this.inputType != 'radio'){
20901 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20908 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20909 _this.getActionEl().addClass(this.disabledClass);
20910 e.dom.disabled = true;
20914 this.disabled = true;
20915 this.fireEvent("disable", this);
20919 enable : function()
20921 if(this.inputType != 'radio'){
20922 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20929 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20930 _this.getActionEl().removeClass(this.disabledClass);
20931 e.dom.disabled = false;
20935 this.disabled = false;
20936 this.fireEvent("enable", this);
20940 setBoxLabel : function(v)
20945 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20951 Roo.apply(Roo.bootstrap.CheckBox, {
20956 * register a CheckBox Group
20957 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20959 register : function(checkbox)
20961 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20962 this.groups[checkbox.groupId] = {};
20965 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20969 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20973 * fetch a CheckBox Group based on the group ID
20974 * @param {string} the group ID
20975 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20977 get: function(groupId) {
20978 if (typeof(this.groups[groupId]) == 'undefined') {
20982 return this.groups[groupId] ;
20995 * @class Roo.bootstrap.Radio
20996 * @extends Roo.bootstrap.Component
20997 * Bootstrap Radio class
20998 * @cfg {String} boxLabel - the label associated
20999 * @cfg {String} value - the value of radio
21002 * Create a new Radio
21003 * @param {Object} config The config object
21005 Roo.bootstrap.Radio = function(config){
21006 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21010 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21016 getAutoCreate : function()
21020 cls : 'form-group radio',
21025 html : this.boxLabel
21033 initEvents : function()
21035 this.parent().register(this);
21037 this.el.on('click', this.onClick, this);
21041 onClick : function(e)
21043 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21044 this.setChecked(true);
21048 setChecked : function(state, suppressEvent)
21050 this.parent().setValue(this.value, suppressEvent);
21054 setBoxLabel : function(v)
21059 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21074 * @class Roo.bootstrap.SecurePass
21075 * @extends Roo.bootstrap.Input
21076 * Bootstrap SecurePass class
21080 * Create a new SecurePass
21081 * @param {Object} config The config object
21084 Roo.bootstrap.SecurePass = function (config) {
21085 // these go here, so the translation tool can replace them..
21087 PwdEmpty: "Please type a password, and then retype it to confirm.",
21088 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21089 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21090 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21091 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21092 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21093 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21094 TooWeak: "Your password is Too Weak."
21096 this.meterLabel = "Password strength:";
21097 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21098 this.meterClass = [
21099 "roo-password-meter-tooweak",
21100 "roo-password-meter-weak",
21101 "roo-password-meter-medium",
21102 "roo-password-meter-strong",
21103 "roo-password-meter-grey"
21108 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21111 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21113 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21115 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21116 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21117 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21118 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21119 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21120 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21121 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21131 * @cfg {String/Object} Label for the strength meter (defaults to
21132 * 'Password strength:')
21137 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21138 * ['Weak', 'Medium', 'Strong'])
21141 pwdStrengths: false,
21154 initEvents: function ()
21156 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21158 if (this.el.is('input[type=password]') && Roo.isSafari) {
21159 this.el.on('keydown', this.SafariOnKeyDown, this);
21162 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21165 onRender: function (ct, position)
21167 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21168 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21169 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21171 this.trigger.createChild({
21176 cls: 'roo-password-meter-grey col-xs-12',
21179 //width: this.meterWidth + 'px'
21183 cls: 'roo-password-meter-text'
21189 if (this.hideTrigger) {
21190 this.trigger.setDisplayed(false);
21192 this.setSize(this.width || '', this.height || '');
21195 onDestroy: function ()
21197 if (this.trigger) {
21198 this.trigger.removeAllListeners();
21199 this.trigger.remove();
21202 this.wrap.remove();
21204 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21207 checkStrength: function ()
21209 var pwd = this.inputEl().getValue();
21210 if (pwd == this._lastPwd) {
21215 if (this.ClientSideStrongPassword(pwd)) {
21217 } else if (this.ClientSideMediumPassword(pwd)) {
21219 } else if (this.ClientSideWeakPassword(pwd)) {
21225 Roo.log('strength1: ' + strength);
21227 //var pm = this.trigger.child('div/div/div').dom;
21228 var pm = this.trigger.child('div/div');
21229 pm.removeClass(this.meterClass);
21230 pm.addClass(this.meterClass[strength]);
21233 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21235 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21237 this._lastPwd = pwd;
21241 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21243 this._lastPwd = '';
21245 var pm = this.trigger.child('div/div');
21246 pm.removeClass(this.meterClass);
21247 pm.addClass('roo-password-meter-grey');
21250 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21253 this.inputEl().dom.type='password';
21256 validateValue: function (value)
21259 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21262 if (value.length == 0) {
21263 if (this.allowBlank) {
21264 this.clearInvalid();
21268 this.markInvalid(this.errors.PwdEmpty);
21269 this.errorMsg = this.errors.PwdEmpty;
21277 if ('[\x21-\x7e]*'.match(value)) {
21278 this.markInvalid(this.errors.PwdBadChar);
21279 this.errorMsg = this.errors.PwdBadChar;
21282 if (value.length < 6) {
21283 this.markInvalid(this.errors.PwdShort);
21284 this.errorMsg = this.errors.PwdShort;
21287 if (value.length > 16) {
21288 this.markInvalid(this.errors.PwdLong);
21289 this.errorMsg = this.errors.PwdLong;
21293 if (this.ClientSideStrongPassword(value)) {
21295 } else if (this.ClientSideMediumPassword(value)) {
21297 } else if (this.ClientSideWeakPassword(value)) {
21304 if (strength < 2) {
21305 //this.markInvalid(this.errors.TooWeak);
21306 this.errorMsg = this.errors.TooWeak;
21311 console.log('strength2: ' + strength);
21313 //var pm = this.trigger.child('div/div/div').dom;
21315 var pm = this.trigger.child('div/div');
21316 pm.removeClass(this.meterClass);
21317 pm.addClass(this.meterClass[strength]);
21319 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21321 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21323 this.errorMsg = '';
21327 CharacterSetChecks: function (type)
21330 this.fResult = false;
21333 isctype: function (character, type)
21336 case this.kCapitalLetter:
21337 if (character >= 'A' && character <= 'Z') {
21342 case this.kSmallLetter:
21343 if (character >= 'a' && character <= 'z') {
21349 if (character >= '0' && character <= '9') {
21354 case this.kPunctuation:
21355 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21366 IsLongEnough: function (pwd, size)
21368 return !(pwd == null || isNaN(size) || pwd.length < size);
21371 SpansEnoughCharacterSets: function (word, nb)
21373 if (!this.IsLongEnough(word, nb))
21378 var characterSetChecks = new Array(
21379 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21380 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21383 for (var index = 0; index < word.length; ++index) {
21384 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21385 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21386 characterSetChecks[nCharSet].fResult = true;
21393 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21394 if (characterSetChecks[nCharSet].fResult) {
21399 if (nCharSets < nb) {
21405 ClientSideStrongPassword: function (pwd)
21407 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21410 ClientSideMediumPassword: function (pwd)
21412 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21415 ClientSideWeakPassword: function (pwd)
21417 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21420 })//<script type="text/javascript">
21423 * Based Ext JS Library 1.1.1
21424 * Copyright(c) 2006-2007, Ext JS, LLC.
21430 * @class Roo.HtmlEditorCore
21431 * @extends Roo.Component
21432 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21434 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21437 Roo.HtmlEditorCore = function(config){
21440 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21445 * @event initialize
21446 * Fires when the editor is fully initialized (including the iframe)
21447 * @param {Roo.HtmlEditorCore} this
21452 * Fires when the editor is first receives the focus. Any insertion must wait
21453 * until after this event.
21454 * @param {Roo.HtmlEditorCore} this
21458 * @event beforesync
21459 * Fires before the textarea is updated with content from the editor iframe. Return false
21460 * to cancel the sync.
21461 * @param {Roo.HtmlEditorCore} this
21462 * @param {String} html
21466 * @event beforepush
21467 * Fires before the iframe editor is updated with content from the textarea. Return false
21468 * to cancel the push.
21469 * @param {Roo.HtmlEditorCore} this
21470 * @param {String} html
21475 * Fires when the textarea is updated with content from the editor iframe.
21476 * @param {Roo.HtmlEditorCore} this
21477 * @param {String} html
21482 * Fires when the iframe editor is updated with content from the textarea.
21483 * @param {Roo.HtmlEditorCore} this
21484 * @param {String} html
21489 * @event editorevent
21490 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21491 * @param {Roo.HtmlEditorCore} this
21497 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21499 // defaults : white / black...
21500 this.applyBlacklists();
21507 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21511 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21517 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21522 * @cfg {Number} height (in pixels)
21526 * @cfg {Number} width (in pixels)
21531 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21534 stylesheets: false,
21539 // private properties
21540 validationEvent : false,
21542 initialized : false,
21544 sourceEditMode : false,
21545 onFocus : Roo.emptyFn,
21547 hideMode:'offsets',
21551 // blacklist + whitelisted elements..
21558 * Protected method that will not generally be called directly. It
21559 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21560 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21562 getDocMarkup : function(){
21566 // inherit styels from page...??
21567 if (this.stylesheets === false) {
21569 Roo.get(document.head).select('style').each(function(node) {
21570 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21573 Roo.get(document.head).select('link').each(function(node) {
21574 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21577 } else if (!this.stylesheets.length) {
21579 st = '<style type="text/css">' +
21580 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21583 st = '<style type="text/css">' +
21588 st += '<style type="text/css">' +
21589 'IMG { cursor: pointer } ' +
21592 var cls = 'roo-htmleditor-body';
21594 if(this.bodyCls.length){
21595 cls += ' ' + this.bodyCls;
21598 return '<html><head>' + st +
21599 //<style type="text/css">' +
21600 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21602 ' </head><body class="' + cls + '"></body></html>';
21606 onRender : function(ct, position)
21609 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21610 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21613 this.el.dom.style.border = '0 none';
21614 this.el.dom.setAttribute('tabIndex', -1);
21615 this.el.addClass('x-hidden hide');
21619 if(Roo.isIE){ // fix IE 1px bogus margin
21620 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21624 this.frameId = Roo.id();
21628 var iframe = this.owner.wrap.createChild({
21630 cls: 'form-control', // bootstrap..
21632 name: this.frameId,
21633 frameBorder : 'no',
21634 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21639 this.iframe = iframe.dom;
21641 this.assignDocWin();
21643 this.doc.designMode = 'on';
21646 this.doc.write(this.getDocMarkup());
21650 var task = { // must defer to wait for browser to be ready
21652 //console.log("run task?" + this.doc.readyState);
21653 this.assignDocWin();
21654 if(this.doc.body || this.doc.readyState == 'complete'){
21656 this.doc.designMode="on";
21660 Roo.TaskMgr.stop(task);
21661 this.initEditor.defer(10, this);
21668 Roo.TaskMgr.start(task);
21673 onResize : function(w, h)
21675 Roo.log('resize: ' +w + ',' + h );
21676 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21680 if(typeof w == 'number'){
21682 this.iframe.style.width = w + 'px';
21684 if(typeof h == 'number'){
21686 this.iframe.style.height = h + 'px';
21688 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21695 * Toggles the editor between standard and source edit mode.
21696 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21698 toggleSourceEdit : function(sourceEditMode){
21700 this.sourceEditMode = sourceEditMode === true;
21702 if(this.sourceEditMode){
21704 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21707 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21708 //this.iframe.className = '';
21711 //this.setSize(this.owner.wrap.getSize());
21712 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21719 * Protected method that will not generally be called directly. If you need/want
21720 * custom HTML cleanup, this is the method you should override.
21721 * @param {String} html The HTML to be cleaned
21722 * return {String} The cleaned HTML
21724 cleanHtml : function(html){
21725 html = String(html);
21726 if(html.length > 5){
21727 if(Roo.isSafari){ // strip safari nonsense
21728 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21731 if(html == ' '){
21738 * HTML Editor -> Textarea
21739 * Protected method that will not generally be called directly. Syncs the contents
21740 * of the editor iframe with the textarea.
21742 syncValue : function(){
21743 if(this.initialized){
21744 var bd = (this.doc.body || this.doc.documentElement);
21745 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21746 var html = bd.innerHTML;
21748 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21749 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21751 html = '<div style="'+m[0]+'">' + html + '</div>';
21754 html = this.cleanHtml(html);
21755 // fix up the special chars.. normaly like back quotes in word...
21756 // however we do not want to do this with chinese..
21757 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21758 var cc = b.charCodeAt();
21760 (cc >= 0x4E00 && cc < 0xA000 ) ||
21761 (cc >= 0x3400 && cc < 0x4E00 ) ||
21762 (cc >= 0xf900 && cc < 0xfb00 )
21768 if(this.owner.fireEvent('beforesync', this, html) !== false){
21769 this.el.dom.value = html;
21770 this.owner.fireEvent('sync', this, html);
21776 * Protected method that will not generally be called directly. Pushes the value of the textarea
21777 * into the iframe editor.
21779 pushValue : function(){
21780 if(this.initialized){
21781 var v = this.el.dom.value.trim();
21783 // if(v.length < 1){
21787 if(this.owner.fireEvent('beforepush', this, v) !== false){
21788 var d = (this.doc.body || this.doc.documentElement);
21790 this.cleanUpPaste();
21791 this.el.dom.value = d.innerHTML;
21792 this.owner.fireEvent('push', this, v);
21798 deferFocus : function(){
21799 this.focus.defer(10, this);
21803 focus : function(){
21804 if(this.win && !this.sourceEditMode){
21811 assignDocWin: function()
21813 var iframe = this.iframe;
21816 this.doc = iframe.contentWindow.document;
21817 this.win = iframe.contentWindow;
21819 // if (!Roo.get(this.frameId)) {
21822 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21823 // this.win = Roo.get(this.frameId).dom.contentWindow;
21825 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21829 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21830 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21835 initEditor : function(){
21836 //console.log("INIT EDITOR");
21837 this.assignDocWin();
21841 this.doc.designMode="on";
21843 this.doc.write(this.getDocMarkup());
21846 var dbody = (this.doc.body || this.doc.documentElement);
21847 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21848 // this copies styles from the containing element into thsi one..
21849 // not sure why we need all of this..
21850 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21852 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21853 //ss['background-attachment'] = 'fixed'; // w3c
21854 dbody.bgProperties = 'fixed'; // ie
21855 //Roo.DomHelper.applyStyles(dbody, ss);
21856 Roo.EventManager.on(this.doc, {
21857 //'mousedown': this.onEditorEvent,
21858 'mouseup': this.onEditorEvent,
21859 'dblclick': this.onEditorEvent,
21860 'click': this.onEditorEvent,
21861 'keyup': this.onEditorEvent,
21866 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21868 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21869 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21871 this.initialized = true;
21873 this.owner.fireEvent('initialize', this);
21878 onDestroy : function(){
21884 //for (var i =0; i < this.toolbars.length;i++) {
21885 // // fixme - ask toolbars for heights?
21886 // this.toolbars[i].onDestroy();
21889 //this.wrap.dom.innerHTML = '';
21890 //this.wrap.remove();
21895 onFirstFocus : function(){
21897 this.assignDocWin();
21900 this.activated = true;
21903 if(Roo.isGecko){ // prevent silly gecko errors
21905 var s = this.win.getSelection();
21906 if(!s.focusNode || s.focusNode.nodeType != 3){
21907 var r = s.getRangeAt(0);
21908 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21913 this.execCmd('useCSS', true);
21914 this.execCmd('styleWithCSS', false);
21917 this.owner.fireEvent('activate', this);
21921 adjustFont: function(btn){
21922 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21923 //if(Roo.isSafari){ // safari
21926 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21927 if(Roo.isSafari){ // safari
21928 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21929 v = (v < 10) ? 10 : v;
21930 v = (v > 48) ? 48 : v;
21931 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21936 v = Math.max(1, v+adjust);
21938 this.execCmd('FontSize', v );
21941 onEditorEvent : function(e)
21943 this.owner.fireEvent('editorevent', this, e);
21944 // this.updateToolbar();
21945 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21948 insertTag : function(tg)
21950 // could be a bit smarter... -> wrap the current selected tRoo..
21951 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21953 range = this.createRange(this.getSelection());
21954 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21955 wrappingNode.appendChild(range.extractContents());
21956 range.insertNode(wrappingNode);
21963 this.execCmd("formatblock", tg);
21967 insertText : function(txt)
21971 var range = this.createRange();
21972 range.deleteContents();
21973 //alert(Sender.getAttribute('label'));
21975 range.insertNode(this.doc.createTextNode(txt));
21981 * Executes a Midas editor command on the editor document and performs necessary focus and
21982 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21983 * @param {String} cmd The Midas command
21984 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21986 relayCmd : function(cmd, value){
21988 this.execCmd(cmd, value);
21989 this.owner.fireEvent('editorevent', this);
21990 //this.updateToolbar();
21991 this.owner.deferFocus();
21995 * Executes a Midas editor command directly on the editor document.
21996 * For visual commands, you should use {@link #relayCmd} instead.
21997 * <b>This should only be called after the editor is initialized.</b>
21998 * @param {String} cmd The Midas command
21999 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22001 execCmd : function(cmd, value){
22002 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22009 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22011 * @param {String} text | dom node..
22013 insertAtCursor : function(text)
22016 if(!this.activated){
22022 var r = this.doc.selection.createRange();
22033 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22037 // from jquery ui (MIT licenced)
22039 var win = this.win;
22041 if (win.getSelection && win.getSelection().getRangeAt) {
22042 range = win.getSelection().getRangeAt(0);
22043 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22044 range.insertNode(node);
22045 } else if (win.document.selection && win.document.selection.createRange) {
22046 // no firefox support
22047 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22048 win.document.selection.createRange().pasteHTML(txt);
22050 // no firefox support
22051 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22052 this.execCmd('InsertHTML', txt);
22061 mozKeyPress : function(e){
22063 var c = e.getCharCode(), cmd;
22066 c = String.fromCharCode(c).toLowerCase();
22080 this.cleanUpPaste.defer(100, this);
22088 e.preventDefault();
22096 fixKeys : function(){ // load time branching for fastest keydown performance
22098 return function(e){
22099 var k = e.getKey(), r;
22102 r = this.doc.selection.createRange();
22105 r.pasteHTML('    ');
22112 r = this.doc.selection.createRange();
22114 var target = r.parentElement();
22115 if(!target || target.tagName.toLowerCase() != 'li'){
22117 r.pasteHTML('<br />');
22123 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22124 this.cleanUpPaste.defer(100, this);
22130 }else if(Roo.isOpera){
22131 return function(e){
22132 var k = e.getKey();
22136 this.execCmd('InsertHTML','    ');
22139 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22140 this.cleanUpPaste.defer(100, this);
22145 }else if(Roo.isSafari){
22146 return function(e){
22147 var k = e.getKey();
22151 this.execCmd('InsertText','\t');
22155 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22156 this.cleanUpPaste.defer(100, this);
22164 getAllAncestors: function()
22166 var p = this.getSelectedNode();
22169 a.push(p); // push blank onto stack..
22170 p = this.getParentElement();
22174 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22178 a.push(this.doc.body);
22182 lastSelNode : false,
22185 getSelection : function()
22187 this.assignDocWin();
22188 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22191 getSelectedNode: function()
22193 // this may only work on Gecko!!!
22195 // should we cache this!!!!
22200 var range = this.createRange(this.getSelection()).cloneRange();
22203 var parent = range.parentElement();
22205 var testRange = range.duplicate();
22206 testRange.moveToElementText(parent);
22207 if (testRange.inRange(range)) {
22210 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22213 parent = parent.parentElement;
22218 // is ancestor a text element.
22219 var ac = range.commonAncestorContainer;
22220 if (ac.nodeType == 3) {
22221 ac = ac.parentNode;
22224 var ar = ac.childNodes;
22227 var other_nodes = [];
22228 var has_other_nodes = false;
22229 for (var i=0;i<ar.length;i++) {
22230 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22233 // fullly contained node.
22235 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22240 // probably selected..
22241 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22242 other_nodes.push(ar[i]);
22246 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22251 has_other_nodes = true;
22253 if (!nodes.length && other_nodes.length) {
22254 nodes= other_nodes;
22256 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22262 createRange: function(sel)
22264 // this has strange effects when using with
22265 // top toolbar - not sure if it's a great idea.
22266 //this.editor.contentWindow.focus();
22267 if (typeof sel != "undefined") {
22269 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22271 return this.doc.createRange();
22274 return this.doc.createRange();
22277 getParentElement: function()
22280 this.assignDocWin();
22281 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22283 var range = this.createRange(sel);
22286 var p = range.commonAncestorContainer;
22287 while (p.nodeType == 3) { // text node
22298 * Range intersection.. the hard stuff...
22302 * [ -- selected range --- ]
22306 * if end is before start or hits it. fail.
22307 * if start is after end or hits it fail.
22309 * if either hits (but other is outside. - then it's not
22315 // @see http://www.thismuchiknow.co.uk/?p=64.
22316 rangeIntersectsNode : function(range, node)
22318 var nodeRange = node.ownerDocument.createRange();
22320 nodeRange.selectNode(node);
22322 nodeRange.selectNodeContents(node);
22325 var rangeStartRange = range.cloneRange();
22326 rangeStartRange.collapse(true);
22328 var rangeEndRange = range.cloneRange();
22329 rangeEndRange.collapse(false);
22331 var nodeStartRange = nodeRange.cloneRange();
22332 nodeStartRange.collapse(true);
22334 var nodeEndRange = nodeRange.cloneRange();
22335 nodeEndRange.collapse(false);
22337 return rangeStartRange.compareBoundaryPoints(
22338 Range.START_TO_START, nodeEndRange) == -1 &&
22339 rangeEndRange.compareBoundaryPoints(
22340 Range.START_TO_START, nodeStartRange) == 1;
22344 rangeCompareNode : function(range, node)
22346 var nodeRange = node.ownerDocument.createRange();
22348 nodeRange.selectNode(node);
22350 nodeRange.selectNodeContents(node);
22354 range.collapse(true);
22356 nodeRange.collapse(true);
22358 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22359 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22361 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22363 var nodeIsBefore = ss == 1;
22364 var nodeIsAfter = ee == -1;
22366 if (nodeIsBefore && nodeIsAfter) {
22369 if (!nodeIsBefore && nodeIsAfter) {
22370 return 1; //right trailed.
22373 if (nodeIsBefore && !nodeIsAfter) {
22374 return 2; // left trailed.
22380 // private? - in a new class?
22381 cleanUpPaste : function()
22383 // cleans up the whole document..
22384 Roo.log('cleanuppaste');
22386 this.cleanUpChildren(this.doc.body);
22387 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22388 if (clean != this.doc.body.innerHTML) {
22389 this.doc.body.innerHTML = clean;
22394 cleanWordChars : function(input) {// change the chars to hex code
22395 var he = Roo.HtmlEditorCore;
22397 var output = input;
22398 Roo.each(he.swapCodes, function(sw) {
22399 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22401 output = output.replace(swapper, sw[1]);
22408 cleanUpChildren : function (n)
22410 if (!n.childNodes.length) {
22413 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22414 this.cleanUpChild(n.childNodes[i]);
22421 cleanUpChild : function (node)
22424 //console.log(node);
22425 if (node.nodeName == "#text") {
22426 // clean up silly Windows -- stuff?
22429 if (node.nodeName == "#comment") {
22430 node.parentNode.removeChild(node);
22431 // clean up silly Windows -- stuff?
22434 var lcname = node.tagName.toLowerCase();
22435 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22436 // whitelist of tags..
22438 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22440 node.parentNode.removeChild(node);
22445 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22447 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22448 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22450 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22451 // remove_keep_children = true;
22454 if (remove_keep_children) {
22455 this.cleanUpChildren(node);
22456 // inserts everything just before this node...
22457 while (node.childNodes.length) {
22458 var cn = node.childNodes[0];
22459 node.removeChild(cn);
22460 node.parentNode.insertBefore(cn, node);
22462 node.parentNode.removeChild(node);
22466 if (!node.attributes || !node.attributes.length) {
22467 this.cleanUpChildren(node);
22471 function cleanAttr(n,v)
22474 if (v.match(/^\./) || v.match(/^\//)) {
22477 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22480 if (v.match(/^#/)) {
22483 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22484 node.removeAttribute(n);
22488 var cwhite = this.cwhite;
22489 var cblack = this.cblack;
22491 function cleanStyle(n,v)
22493 if (v.match(/expression/)) { //XSS?? should we even bother..
22494 node.removeAttribute(n);
22498 var parts = v.split(/;/);
22501 Roo.each(parts, function(p) {
22502 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22506 var l = p.split(':').shift().replace(/\s+/g,'');
22507 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22509 if ( cwhite.length && cblack.indexOf(l) > -1) {
22510 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22511 //node.removeAttribute(n);
22515 // only allow 'c whitelisted system attributes'
22516 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22517 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22518 //node.removeAttribute(n);
22528 if (clean.length) {
22529 node.setAttribute(n, clean.join(';'));
22531 node.removeAttribute(n);
22537 for (var i = node.attributes.length-1; i > -1 ; i--) {
22538 var a = node.attributes[i];
22541 if (a.name.toLowerCase().substr(0,2)=='on') {
22542 node.removeAttribute(a.name);
22545 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22546 node.removeAttribute(a.name);
22549 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22550 cleanAttr(a.name,a.value); // fixme..
22553 if (a.name == 'style') {
22554 cleanStyle(a.name,a.value);
22557 /// clean up MS crap..
22558 // tecnically this should be a list of valid class'es..
22561 if (a.name == 'class') {
22562 if (a.value.match(/^Mso/)) {
22563 node.className = '';
22566 if (a.value.match(/^body$/)) {
22567 node.className = '';
22578 this.cleanUpChildren(node);
22584 * Clean up MS wordisms...
22586 cleanWord : function(node)
22591 this.cleanWord(this.doc.body);
22594 if (node.nodeName == "#text") {
22595 // clean up silly Windows -- stuff?
22598 if (node.nodeName == "#comment") {
22599 node.parentNode.removeChild(node);
22600 // clean up silly Windows -- stuff?
22604 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22605 node.parentNode.removeChild(node);
22609 // remove - but keep children..
22610 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22611 while (node.childNodes.length) {
22612 var cn = node.childNodes[0];
22613 node.removeChild(cn);
22614 node.parentNode.insertBefore(cn, node);
22616 node.parentNode.removeChild(node);
22617 this.iterateChildren(node, this.cleanWord);
22621 if (node.className.length) {
22623 var cn = node.className.split(/\W+/);
22625 Roo.each(cn, function(cls) {
22626 if (cls.match(/Mso[a-zA-Z]+/)) {
22631 node.className = cna.length ? cna.join(' ') : '';
22633 node.removeAttribute("class");
22637 if (node.hasAttribute("lang")) {
22638 node.removeAttribute("lang");
22641 if (node.hasAttribute("style")) {
22643 var styles = node.getAttribute("style").split(";");
22645 Roo.each(styles, function(s) {
22646 if (!s.match(/:/)) {
22649 var kv = s.split(":");
22650 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22653 // what ever is left... we allow.
22656 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22657 if (!nstyle.length) {
22658 node.removeAttribute('style');
22661 this.iterateChildren(node, this.cleanWord);
22667 * iterateChildren of a Node, calling fn each time, using this as the scole..
22668 * @param {DomNode} node node to iterate children of.
22669 * @param {Function} fn method of this class to call on each item.
22671 iterateChildren : function(node, fn)
22673 if (!node.childNodes.length) {
22676 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22677 fn.call(this, node.childNodes[i])
22683 * cleanTableWidths.
22685 * Quite often pasting from word etc.. results in tables with column and widths.
22686 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22689 cleanTableWidths : function(node)
22694 this.cleanTableWidths(this.doc.body);
22699 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22702 Roo.log(node.tagName);
22703 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22704 this.iterateChildren(node, this.cleanTableWidths);
22707 if (node.hasAttribute('width')) {
22708 node.removeAttribute('width');
22712 if (node.hasAttribute("style")) {
22715 var styles = node.getAttribute("style").split(";");
22717 Roo.each(styles, function(s) {
22718 if (!s.match(/:/)) {
22721 var kv = s.split(":");
22722 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22725 // what ever is left... we allow.
22728 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22729 if (!nstyle.length) {
22730 node.removeAttribute('style');
22734 this.iterateChildren(node, this.cleanTableWidths);
22742 domToHTML : function(currentElement, depth, nopadtext) {
22744 depth = depth || 0;
22745 nopadtext = nopadtext || false;
22747 if (!currentElement) {
22748 return this.domToHTML(this.doc.body);
22751 //Roo.log(currentElement);
22753 var allText = false;
22754 var nodeName = currentElement.nodeName;
22755 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22757 if (nodeName == '#text') {
22759 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22764 if (nodeName != 'BODY') {
22767 // Prints the node tagName, such as <A>, <IMG>, etc
22770 for(i = 0; i < currentElement.attributes.length;i++) {
22772 var aname = currentElement.attributes.item(i).name;
22773 if (!currentElement.attributes.item(i).value.length) {
22776 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22779 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22788 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22791 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22796 // Traverse the tree
22798 var currentElementChild = currentElement.childNodes.item(i);
22799 var allText = true;
22800 var innerHTML = '';
22802 while (currentElementChild) {
22803 // Formatting code (indent the tree so it looks nice on the screen)
22804 var nopad = nopadtext;
22805 if (lastnode == 'SPAN') {
22809 if (currentElementChild.nodeName == '#text') {
22810 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22811 toadd = nopadtext ? toadd : toadd.trim();
22812 if (!nopad && toadd.length > 80) {
22813 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22815 innerHTML += toadd;
22818 currentElementChild = currentElement.childNodes.item(i);
22824 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22826 // Recursively traverse the tree structure of the child node
22827 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22828 lastnode = currentElementChild.nodeName;
22830 currentElementChild=currentElement.childNodes.item(i);
22836 // The remaining code is mostly for formatting the tree
22837 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22842 ret+= "</"+tagName+">";
22848 applyBlacklists : function()
22850 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22851 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22855 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22856 if (b.indexOf(tag) > -1) {
22859 this.white.push(tag);
22863 Roo.each(w, function(tag) {
22864 if (b.indexOf(tag) > -1) {
22867 if (this.white.indexOf(tag) > -1) {
22870 this.white.push(tag);
22875 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22876 if (w.indexOf(tag) > -1) {
22879 this.black.push(tag);
22883 Roo.each(b, function(tag) {
22884 if (w.indexOf(tag) > -1) {
22887 if (this.black.indexOf(tag) > -1) {
22890 this.black.push(tag);
22895 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22896 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22900 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22901 if (b.indexOf(tag) > -1) {
22904 this.cwhite.push(tag);
22908 Roo.each(w, function(tag) {
22909 if (b.indexOf(tag) > -1) {
22912 if (this.cwhite.indexOf(tag) > -1) {
22915 this.cwhite.push(tag);
22920 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22921 if (w.indexOf(tag) > -1) {
22924 this.cblack.push(tag);
22928 Roo.each(b, function(tag) {
22929 if (w.indexOf(tag) > -1) {
22932 if (this.cblack.indexOf(tag) > -1) {
22935 this.cblack.push(tag);
22940 setStylesheets : function(stylesheets)
22942 if(typeof(stylesheets) == 'string'){
22943 Roo.get(this.iframe.contentDocument.head).createChild({
22945 rel : 'stylesheet',
22954 Roo.each(stylesheets, function(s) {
22959 Roo.get(_this.iframe.contentDocument.head).createChild({
22961 rel : 'stylesheet',
22970 removeStylesheets : function()
22974 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22979 setStyle : function(style)
22981 Roo.get(this.iframe.contentDocument.head).createChild({
22990 // hide stuff that is not compatible
23004 * @event specialkey
23008 * @cfg {String} fieldClass @hide
23011 * @cfg {String} focusClass @hide
23014 * @cfg {String} autoCreate @hide
23017 * @cfg {String} inputType @hide
23020 * @cfg {String} invalidClass @hide
23023 * @cfg {String} invalidText @hide
23026 * @cfg {String} msgFx @hide
23029 * @cfg {String} validateOnBlur @hide
23033 Roo.HtmlEditorCore.white = [
23034 'area', 'br', 'img', 'input', 'hr', 'wbr',
23036 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23037 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23038 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23039 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23040 'table', 'ul', 'xmp',
23042 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23045 'dir', 'menu', 'ol', 'ul', 'dl',
23051 Roo.HtmlEditorCore.black = [
23052 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23054 'base', 'basefont', 'bgsound', 'blink', 'body',
23055 'frame', 'frameset', 'head', 'html', 'ilayer',
23056 'iframe', 'layer', 'link', 'meta', 'object',
23057 'script', 'style' ,'title', 'xml' // clean later..
23059 Roo.HtmlEditorCore.clean = [
23060 'script', 'style', 'title', 'xml'
23062 Roo.HtmlEditorCore.remove = [
23067 Roo.HtmlEditorCore.ablack = [
23071 Roo.HtmlEditorCore.aclean = [
23072 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23076 Roo.HtmlEditorCore.pwhite= [
23077 'http', 'https', 'mailto'
23080 // white listed style attributes.
23081 Roo.HtmlEditorCore.cwhite= [
23082 // 'text-align', /// default is to allow most things..
23088 // black listed style attributes.
23089 Roo.HtmlEditorCore.cblack= [
23090 // 'font-size' -- this can be set by the project
23094 Roo.HtmlEditorCore.swapCodes =[
23113 * @class Roo.bootstrap.HtmlEditor
23114 * @extends Roo.bootstrap.TextArea
23115 * Bootstrap HtmlEditor class
23118 * Create a new HtmlEditor
23119 * @param {Object} config The config object
23122 Roo.bootstrap.HtmlEditor = function(config){
23123 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23124 if (!this.toolbars) {
23125 this.toolbars = [];
23128 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23131 * @event initialize
23132 * Fires when the editor is fully initialized (including the iframe)
23133 * @param {HtmlEditor} this
23138 * Fires when the editor is first receives the focus. Any insertion must wait
23139 * until after this event.
23140 * @param {HtmlEditor} this
23144 * @event beforesync
23145 * Fires before the textarea is updated with content from the editor iframe. Return false
23146 * to cancel the sync.
23147 * @param {HtmlEditor} this
23148 * @param {String} html
23152 * @event beforepush
23153 * Fires before the iframe editor is updated with content from the textarea. Return false
23154 * to cancel the push.
23155 * @param {HtmlEditor} this
23156 * @param {String} html
23161 * Fires when the textarea is updated with content from the editor iframe.
23162 * @param {HtmlEditor} this
23163 * @param {String} html
23168 * Fires when the iframe editor is updated with content from the textarea.
23169 * @param {HtmlEditor} this
23170 * @param {String} html
23174 * @event editmodechange
23175 * Fires when the editor switches edit modes
23176 * @param {HtmlEditor} this
23177 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23179 editmodechange: true,
23181 * @event editorevent
23182 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23183 * @param {HtmlEditor} this
23187 * @event firstfocus
23188 * Fires when on first focus - needed by toolbars..
23189 * @param {HtmlEditor} this
23194 * Auto save the htmlEditor value as a file into Events
23195 * @param {HtmlEditor} this
23199 * @event savedpreview
23200 * preview the saved version of htmlEditor
23201 * @param {HtmlEditor} this
23208 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23212 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23217 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23222 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23227 * @cfg {Number} height (in pixels)
23231 * @cfg {Number} width (in pixels)
23236 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23239 stylesheets: false,
23244 // private properties
23245 validationEvent : false,
23247 initialized : false,
23250 onFocus : Roo.emptyFn,
23252 hideMode:'offsets',
23254 tbContainer : false,
23258 toolbarContainer :function() {
23259 return this.wrap.select('.x-html-editor-tb',true).first();
23263 * Protected method that will not generally be called directly. It
23264 * is called when the editor creates its toolbar. Override this method if you need to
23265 * add custom toolbar buttons.
23266 * @param {HtmlEditor} editor
23268 createToolbar : function(){
23269 Roo.log('renewing');
23270 Roo.log("create toolbars");
23272 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23273 this.toolbars[0].render(this.toolbarContainer());
23277 // if (!editor.toolbars || !editor.toolbars.length) {
23278 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23281 // for (var i =0 ; i < editor.toolbars.length;i++) {
23282 // editor.toolbars[i] = Roo.factory(
23283 // typeof(editor.toolbars[i]) == 'string' ?
23284 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23285 // Roo.bootstrap.HtmlEditor);
23286 // editor.toolbars[i].init(editor);
23292 onRender : function(ct, position)
23294 // Roo.log("Call onRender: " + this.xtype);
23296 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23298 this.wrap = this.inputEl().wrap({
23299 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23302 this.editorcore.onRender(ct, position);
23304 if (this.resizable) {
23305 this.resizeEl = new Roo.Resizable(this.wrap, {
23309 minHeight : this.height,
23310 height: this.height,
23311 handles : this.resizable,
23314 resize : function(r, w, h) {
23315 _t.onResize(w,h); // -something
23321 this.createToolbar(this);
23324 if(!this.width && this.resizable){
23325 this.setSize(this.wrap.getSize());
23327 if (this.resizeEl) {
23328 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23329 // should trigger onReize..
23335 onResize : function(w, h)
23337 Roo.log('resize: ' +w + ',' + h );
23338 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23342 if(this.inputEl() ){
23343 if(typeof w == 'number'){
23344 var aw = w - this.wrap.getFrameWidth('lr');
23345 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23348 if(typeof h == 'number'){
23349 var tbh = -11; // fixme it needs to tool bar size!
23350 for (var i =0; i < this.toolbars.length;i++) {
23351 // fixme - ask toolbars for heights?
23352 tbh += this.toolbars[i].el.getHeight();
23353 //if (this.toolbars[i].footer) {
23354 // tbh += this.toolbars[i].footer.el.getHeight();
23362 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23363 ah -= 5; // knock a few pixes off for look..
23364 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23368 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23369 this.editorcore.onResize(ew,eh);
23374 * Toggles the editor between standard and source edit mode.
23375 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23377 toggleSourceEdit : function(sourceEditMode)
23379 this.editorcore.toggleSourceEdit(sourceEditMode);
23381 if(this.editorcore.sourceEditMode){
23382 Roo.log('editor - showing textarea');
23385 // Roo.log(this.syncValue());
23387 this.inputEl().removeClass(['hide', 'x-hidden']);
23388 this.inputEl().dom.removeAttribute('tabIndex');
23389 this.inputEl().focus();
23391 Roo.log('editor - hiding textarea');
23393 // Roo.log(this.pushValue());
23396 this.inputEl().addClass(['hide', 'x-hidden']);
23397 this.inputEl().dom.setAttribute('tabIndex', -1);
23398 //this.deferFocus();
23401 if(this.resizable){
23402 this.setSize(this.wrap.getSize());
23405 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23408 // private (for BoxComponent)
23409 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23411 // private (for BoxComponent)
23412 getResizeEl : function(){
23416 // private (for BoxComponent)
23417 getPositionEl : function(){
23422 initEvents : function(){
23423 this.originalValue = this.getValue();
23427 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23430 // markInvalid : Roo.emptyFn,
23432 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23435 // clearInvalid : Roo.emptyFn,
23437 setValue : function(v){
23438 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23439 this.editorcore.pushValue();
23444 deferFocus : function(){
23445 this.focus.defer(10, this);
23449 focus : function(){
23450 this.editorcore.focus();
23456 onDestroy : function(){
23462 for (var i =0; i < this.toolbars.length;i++) {
23463 // fixme - ask toolbars for heights?
23464 this.toolbars[i].onDestroy();
23467 this.wrap.dom.innerHTML = '';
23468 this.wrap.remove();
23473 onFirstFocus : function(){
23474 //Roo.log("onFirstFocus");
23475 this.editorcore.onFirstFocus();
23476 for (var i =0; i < this.toolbars.length;i++) {
23477 this.toolbars[i].onFirstFocus();
23483 syncValue : function()
23485 this.editorcore.syncValue();
23488 pushValue : function()
23490 this.editorcore.pushValue();
23494 // hide stuff that is not compatible
23508 * @event specialkey
23512 * @cfg {String} fieldClass @hide
23515 * @cfg {String} focusClass @hide
23518 * @cfg {String} autoCreate @hide
23521 * @cfg {String} inputType @hide
23524 * @cfg {String} invalidClass @hide
23527 * @cfg {String} invalidText @hide
23530 * @cfg {String} msgFx @hide
23533 * @cfg {String} validateOnBlur @hide
23542 Roo.namespace('Roo.bootstrap.htmleditor');
23544 * @class Roo.bootstrap.HtmlEditorToolbar1
23549 new Roo.bootstrap.HtmlEditor({
23552 new Roo.bootstrap.HtmlEditorToolbar1({
23553 disable : { fonts: 1 , format: 1, ..., ... , ...],
23559 * @cfg {Object} disable List of elements to disable..
23560 * @cfg {Array} btns List of additional buttons.
23564 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23567 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23570 Roo.apply(this, config);
23572 // default disabled, based on 'good practice'..
23573 this.disable = this.disable || {};
23574 Roo.applyIf(this.disable, {
23577 specialElements : true
23579 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23581 this.editor = config.editor;
23582 this.editorcore = config.editor.editorcore;
23584 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23586 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23587 // dont call parent... till later.
23589 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23594 editorcore : false,
23599 "h1","h2","h3","h4","h5","h6",
23601 "abbr", "acronym", "address", "cite", "samp", "var",
23605 onRender : function(ct, position)
23607 // Roo.log("Call onRender: " + this.xtype);
23609 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23611 this.el.dom.style.marginBottom = '0';
23613 var editorcore = this.editorcore;
23614 var editor= this.editor;
23617 var btn = function(id,cmd , toggle, handler, html){
23619 var event = toggle ? 'toggle' : 'click';
23624 xns: Roo.bootstrap,
23627 enableToggle:toggle !== false,
23629 pressed : toggle ? false : null,
23632 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23633 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23639 // var cb_box = function...
23644 xns: Roo.bootstrap,
23645 glyphicon : 'font',
23649 xns: Roo.bootstrap,
23653 Roo.each(this.formats, function(f) {
23654 style.menu.items.push({
23656 xns: Roo.bootstrap,
23657 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23662 editorcore.insertTag(this.tagname);
23669 children.push(style);
23671 btn('bold',false,true);
23672 btn('italic',false,true);
23673 btn('align-left', 'justifyleft',true);
23674 btn('align-center', 'justifycenter',true);
23675 btn('align-right' , 'justifyright',true);
23676 btn('link', false, false, function(btn) {
23677 //Roo.log("create link?");
23678 var url = prompt(this.createLinkText, this.defaultLinkValue);
23679 if(url && url != 'http:/'+'/'){
23680 this.editorcore.relayCmd('createlink', url);
23683 btn('list','insertunorderedlist',true);
23684 btn('pencil', false,true, function(btn){
23686 this.toggleSourceEdit(btn.pressed);
23689 if (this.editor.btns.length > 0) {
23690 for (var i = 0; i<this.editor.btns.length; i++) {
23691 children.push(this.editor.btns[i]);
23699 xns: Roo.bootstrap,
23704 xns: Roo.bootstrap,
23709 cog.menu.items.push({
23711 xns: Roo.bootstrap,
23712 html : Clean styles,
23717 editorcore.insertTag(this.tagname);
23726 this.xtype = 'NavSimplebar';
23728 for(var i=0;i< children.length;i++) {
23730 this.buttons.add(this.addxtypeChild(children[i]));
23734 editor.on('editorevent', this.updateToolbar, this);
23736 onBtnClick : function(id)
23738 this.editorcore.relayCmd(id);
23739 this.editorcore.focus();
23743 * Protected method that will not generally be called directly. It triggers
23744 * a toolbar update by reading the markup state of the current selection in the editor.
23746 updateToolbar: function(){
23748 if(!this.editorcore.activated){
23749 this.editor.onFirstFocus(); // is this neeed?
23753 var btns = this.buttons;
23754 var doc = this.editorcore.doc;
23755 btns.get('bold').setActive(doc.queryCommandState('bold'));
23756 btns.get('italic').setActive(doc.queryCommandState('italic'));
23757 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23759 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23760 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23761 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23763 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23764 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23767 var ans = this.editorcore.getAllAncestors();
23768 if (this.formatCombo) {
23771 var store = this.formatCombo.store;
23772 this.formatCombo.setValue("");
23773 for (var i =0; i < ans.length;i++) {
23774 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23776 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23784 // hides menus... - so this cant be on a menu...
23785 Roo.bootstrap.MenuMgr.hideAll();
23787 Roo.bootstrap.MenuMgr.hideAll();
23788 //this.editorsyncValue();
23790 onFirstFocus: function() {
23791 this.buttons.each(function(item){
23795 toggleSourceEdit : function(sourceEditMode){
23798 if(sourceEditMode){
23799 Roo.log("disabling buttons");
23800 this.buttons.each( function(item){
23801 if(item.cmd != 'pencil'){
23807 Roo.log("enabling buttons");
23808 if(this.editorcore.initialized){
23809 this.buttons.each( function(item){
23815 Roo.log("calling toggole on editor");
23816 // tell the editor that it's been pressed..
23817 this.editor.toggleSourceEdit(sourceEditMode);
23827 * @class Roo.bootstrap.Table.AbstractSelectionModel
23828 * @extends Roo.util.Observable
23829 * Abstract base class for grid SelectionModels. It provides the interface that should be
23830 * implemented by descendant classes. This class should not be directly instantiated.
23833 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23834 this.locked = false;
23835 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23839 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23840 /** @ignore Called by the grid automatically. Do not call directly. */
23841 init : function(grid){
23847 * Locks the selections.
23850 this.locked = true;
23854 * Unlocks the selections.
23856 unlock : function(){
23857 this.locked = false;
23861 * Returns true if the selections are locked.
23862 * @return {Boolean}
23864 isLocked : function(){
23865 return this.locked;
23869 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23870 * @class Roo.bootstrap.Table.RowSelectionModel
23871 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23872 * It supports multiple selections and keyboard selection/navigation.
23874 * @param {Object} config
23877 Roo.bootstrap.Table.RowSelectionModel = function(config){
23878 Roo.apply(this, config);
23879 this.selections = new Roo.util.MixedCollection(false, function(o){
23884 this.lastActive = false;
23888 * @event selectionchange
23889 * Fires when the selection changes
23890 * @param {SelectionModel} this
23892 "selectionchange" : true,
23894 * @event afterselectionchange
23895 * Fires after the selection changes (eg. by key press or clicking)
23896 * @param {SelectionModel} this
23898 "afterselectionchange" : true,
23900 * @event beforerowselect
23901 * Fires when a row is selected being selected, return false to cancel.
23902 * @param {SelectionModel} this
23903 * @param {Number} rowIndex The selected index
23904 * @param {Boolean} keepExisting False if other selections will be cleared
23906 "beforerowselect" : true,
23909 * Fires when a row is selected.
23910 * @param {SelectionModel} this
23911 * @param {Number} rowIndex The selected index
23912 * @param {Roo.data.Record} r The record
23914 "rowselect" : true,
23916 * @event rowdeselect
23917 * Fires when a row is deselected.
23918 * @param {SelectionModel} this
23919 * @param {Number} rowIndex The selected index
23921 "rowdeselect" : true
23923 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23924 this.locked = false;
23927 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23929 * @cfg {Boolean} singleSelect
23930 * True to allow selection of only one row at a time (defaults to false)
23932 singleSelect : false,
23935 initEvents : function()
23938 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23939 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23940 //}else{ // allow click to work like normal
23941 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23943 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23944 this.grid.on("rowclick", this.handleMouseDown, this);
23946 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23947 "up" : function(e){
23949 this.selectPrevious(e.shiftKey);
23950 }else if(this.last !== false && this.lastActive !== false){
23951 var last = this.last;
23952 this.selectRange(this.last, this.lastActive-1);
23953 this.grid.getView().focusRow(this.lastActive);
23954 if(last !== false){
23958 this.selectFirstRow();
23960 this.fireEvent("afterselectionchange", this);
23962 "down" : function(e){
23964 this.selectNext(e.shiftKey);
23965 }else if(this.last !== false && this.lastActive !== false){
23966 var last = this.last;
23967 this.selectRange(this.last, this.lastActive+1);
23968 this.grid.getView().focusRow(this.lastActive);
23969 if(last !== false){
23973 this.selectFirstRow();
23975 this.fireEvent("afterselectionchange", this);
23979 this.grid.store.on('load', function(){
23980 this.selections.clear();
23983 var view = this.grid.view;
23984 view.on("refresh", this.onRefresh, this);
23985 view.on("rowupdated", this.onRowUpdated, this);
23986 view.on("rowremoved", this.onRemove, this);
23991 onRefresh : function()
23993 var ds = this.grid.store, i, v = this.grid.view;
23994 var s = this.selections;
23995 s.each(function(r){
23996 if((i = ds.indexOfId(r.id)) != -1){
24005 onRemove : function(v, index, r){
24006 this.selections.remove(r);
24010 onRowUpdated : function(v, index, r){
24011 if(this.isSelected(r)){
24012 v.onRowSelect(index);
24018 * @param {Array} records The records to select
24019 * @param {Boolean} keepExisting (optional) True to keep existing selections
24021 selectRecords : function(records, keepExisting)
24024 this.clearSelections();
24026 var ds = this.grid.store;
24027 for(var i = 0, len = records.length; i < len; i++){
24028 this.selectRow(ds.indexOf(records[i]), true);
24033 * Gets the number of selected rows.
24036 getCount : function(){
24037 return this.selections.length;
24041 * Selects the first row in the grid.
24043 selectFirstRow : function(){
24048 * Select the last row.
24049 * @param {Boolean} keepExisting (optional) True to keep existing selections
24051 selectLastRow : function(keepExisting){
24052 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24053 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24057 * Selects the row immediately following the last selected row.
24058 * @param {Boolean} keepExisting (optional) True to keep existing selections
24060 selectNext : function(keepExisting)
24062 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24063 this.selectRow(this.last+1, keepExisting);
24064 this.grid.getView().focusRow(this.last);
24069 * Selects the row that precedes the last selected row.
24070 * @param {Boolean} keepExisting (optional) True to keep existing selections
24072 selectPrevious : function(keepExisting){
24074 this.selectRow(this.last-1, keepExisting);
24075 this.grid.getView().focusRow(this.last);
24080 * Returns the selected records
24081 * @return {Array} Array of selected records
24083 getSelections : function(){
24084 return [].concat(this.selections.items);
24088 * Returns the first selected record.
24091 getSelected : function(){
24092 return this.selections.itemAt(0);
24097 * Clears all selections.
24099 clearSelections : function(fast)
24105 var ds = this.grid.store;
24106 var s = this.selections;
24107 s.each(function(r){
24108 this.deselectRow(ds.indexOfId(r.id));
24112 this.selections.clear();
24119 * Selects all rows.
24121 selectAll : function(){
24125 this.selections.clear();
24126 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24127 this.selectRow(i, true);
24132 * Returns True if there is a selection.
24133 * @return {Boolean}
24135 hasSelection : function(){
24136 return this.selections.length > 0;
24140 * Returns True if the specified row is selected.
24141 * @param {Number/Record} record The record or index of the record to check
24142 * @return {Boolean}
24144 isSelected : function(index){
24145 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24146 return (r && this.selections.key(r.id) ? true : false);
24150 * Returns True if the specified record id is selected.
24151 * @param {String} id The id of record to check
24152 * @return {Boolean}
24154 isIdSelected : function(id){
24155 return (this.selections.key(id) ? true : false);
24160 handleMouseDBClick : function(e, t){
24164 handleMouseDown : function(e, t)
24166 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24167 if(this.isLocked() || rowIndex < 0 ){
24170 if(e.shiftKey && this.last !== false){
24171 var last = this.last;
24172 this.selectRange(last, rowIndex, e.ctrlKey);
24173 this.last = last; // reset the last
24177 var isSelected = this.isSelected(rowIndex);
24178 //Roo.log("select row:" + rowIndex);
24180 this.deselectRow(rowIndex);
24182 this.selectRow(rowIndex, true);
24186 if(e.button !== 0 && isSelected){
24187 alert('rowIndex 2: ' + rowIndex);
24188 view.focusRow(rowIndex);
24189 }else if(e.ctrlKey && isSelected){
24190 this.deselectRow(rowIndex);
24191 }else if(!isSelected){
24192 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24193 view.focusRow(rowIndex);
24197 this.fireEvent("afterselectionchange", this);
24200 handleDragableRowClick : function(grid, rowIndex, e)
24202 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24203 this.selectRow(rowIndex, false);
24204 grid.view.focusRow(rowIndex);
24205 this.fireEvent("afterselectionchange", this);
24210 * Selects multiple rows.
24211 * @param {Array} rows Array of the indexes of the row to select
24212 * @param {Boolean} keepExisting (optional) True to keep existing selections
24214 selectRows : function(rows, keepExisting){
24216 this.clearSelections();
24218 for(var i = 0, len = rows.length; i < len; i++){
24219 this.selectRow(rows[i], true);
24224 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24225 * @param {Number} startRow The index of the first row in the range
24226 * @param {Number} endRow The index of the last row in the range
24227 * @param {Boolean} keepExisting (optional) True to retain existing selections
24229 selectRange : function(startRow, endRow, keepExisting){
24234 this.clearSelections();
24236 if(startRow <= endRow){
24237 for(var i = startRow; i <= endRow; i++){
24238 this.selectRow(i, true);
24241 for(var i = startRow; i >= endRow; i--){
24242 this.selectRow(i, true);
24248 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24249 * @param {Number} startRow The index of the first row in the range
24250 * @param {Number} endRow The index of the last row in the range
24252 deselectRange : function(startRow, endRow, preventViewNotify){
24256 for(var i = startRow; i <= endRow; i++){
24257 this.deselectRow(i, preventViewNotify);
24263 * @param {Number} row The index of the row to select
24264 * @param {Boolean} keepExisting (optional) True to keep existing selections
24266 selectRow : function(index, keepExisting, preventViewNotify)
24268 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24271 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24272 if(!keepExisting || this.singleSelect){
24273 this.clearSelections();
24276 var r = this.grid.store.getAt(index);
24277 //console.log('selectRow - record id :' + r.id);
24279 this.selections.add(r);
24280 this.last = this.lastActive = index;
24281 if(!preventViewNotify){
24282 var proxy = new Roo.Element(
24283 this.grid.getRowDom(index)
24285 proxy.addClass('bg-info info');
24287 this.fireEvent("rowselect", this, index, r);
24288 this.fireEvent("selectionchange", this);
24294 * @param {Number} row The index of the row to deselect
24296 deselectRow : function(index, preventViewNotify)
24301 if(this.last == index){
24304 if(this.lastActive == index){
24305 this.lastActive = false;
24308 var r = this.grid.store.getAt(index);
24313 this.selections.remove(r);
24314 //.console.log('deselectRow - record id :' + r.id);
24315 if(!preventViewNotify){
24317 var proxy = new Roo.Element(
24318 this.grid.getRowDom(index)
24320 proxy.removeClass('bg-info info');
24322 this.fireEvent("rowdeselect", this, index);
24323 this.fireEvent("selectionchange", this);
24327 restoreLast : function(){
24329 this.last = this._last;
24334 acceptsNav : function(row, col, cm){
24335 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24339 onEditorKey : function(field, e){
24340 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24345 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24347 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24349 }else if(k == e.ENTER && !e.ctrlKey){
24353 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24355 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24357 }else if(k == e.ESC){
24361 g.startEditing(newCell[0], newCell[1]);
24367 * Ext JS Library 1.1.1
24368 * Copyright(c) 2006-2007, Ext JS, LLC.
24370 * Originally Released Under LGPL - original licence link has changed is not relivant.
24373 * <script type="text/javascript">
24377 * @class Roo.bootstrap.PagingToolbar
24378 * @extends Roo.bootstrap.NavSimplebar
24379 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24381 * Create a new PagingToolbar
24382 * @param {Object} config The config object
24383 * @param {Roo.data.Store} store
24385 Roo.bootstrap.PagingToolbar = function(config)
24387 // old args format still supported... - xtype is prefered..
24388 // created from xtype...
24390 this.ds = config.dataSource;
24392 if (config.store && !this.ds) {
24393 this.store= Roo.factory(config.store, Roo.data);
24394 this.ds = this.store;
24395 this.ds.xmodule = this.xmodule || false;
24398 this.toolbarItems = [];
24399 if (config.items) {
24400 this.toolbarItems = config.items;
24403 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24408 this.bind(this.ds);
24411 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24415 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24417 * @cfg {Roo.data.Store} dataSource
24418 * The underlying data store providing the paged data
24421 * @cfg {String/HTMLElement/Element} container
24422 * container The id or element that will contain the toolbar
24425 * @cfg {Boolean} displayInfo
24426 * True to display the displayMsg (defaults to false)
24429 * @cfg {Number} pageSize
24430 * The number of records to display per page (defaults to 20)
24434 * @cfg {String} displayMsg
24435 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24437 displayMsg : 'Displaying {0} - {1} of {2}',
24439 * @cfg {String} emptyMsg
24440 * The message to display when no records are found (defaults to "No data to display")
24442 emptyMsg : 'No data to display',
24444 * Customizable piece of the default paging text (defaults to "Page")
24447 beforePageText : "Page",
24449 * Customizable piece of the default paging text (defaults to "of %0")
24452 afterPageText : "of {0}",
24454 * Customizable piece of the default paging text (defaults to "First Page")
24457 firstText : "First Page",
24459 * Customizable piece of the default paging text (defaults to "Previous Page")
24462 prevText : "Previous Page",
24464 * Customizable piece of the default paging text (defaults to "Next Page")
24467 nextText : "Next Page",
24469 * Customizable piece of the default paging text (defaults to "Last Page")
24472 lastText : "Last Page",
24474 * Customizable piece of the default paging text (defaults to "Refresh")
24477 refreshText : "Refresh",
24481 onRender : function(ct, position)
24483 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24484 this.navgroup.parentId = this.id;
24485 this.navgroup.onRender(this.el, null);
24486 // add the buttons to the navgroup
24488 if(this.displayInfo){
24489 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24490 this.displayEl = this.el.select('.x-paging-info', true).first();
24491 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24492 // this.displayEl = navel.el.select('span',true).first();
24498 Roo.each(_this.buttons, function(e){ // this might need to use render????
24499 Roo.factory(e).onRender(_this.el, null);
24503 Roo.each(_this.toolbarItems, function(e) {
24504 _this.navgroup.addItem(e);
24508 this.first = this.navgroup.addItem({
24509 tooltip: this.firstText,
24511 icon : 'fa fa-backward',
24513 preventDefault: true,
24514 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24517 this.prev = this.navgroup.addItem({
24518 tooltip: this.prevText,
24520 icon : 'fa fa-step-backward',
24522 preventDefault: true,
24523 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24525 //this.addSeparator();
24528 var field = this.navgroup.addItem( {
24530 cls : 'x-paging-position',
24532 html : this.beforePageText +
24533 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24534 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24537 this.field = field.el.select('input', true).first();
24538 this.field.on("keydown", this.onPagingKeydown, this);
24539 this.field.on("focus", function(){this.dom.select();});
24542 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24543 //this.field.setHeight(18);
24544 //this.addSeparator();
24545 this.next = this.navgroup.addItem({
24546 tooltip: this.nextText,
24548 html : ' <i class="fa fa-step-forward">',
24550 preventDefault: true,
24551 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24553 this.last = this.navgroup.addItem({
24554 tooltip: this.lastText,
24555 icon : 'fa fa-forward',
24558 preventDefault: true,
24559 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24561 //this.addSeparator();
24562 this.loading = this.navgroup.addItem({
24563 tooltip: this.refreshText,
24564 icon: 'fa fa-refresh',
24565 preventDefault: true,
24566 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24572 updateInfo : function(){
24573 if(this.displayEl){
24574 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24575 var msg = count == 0 ?
24579 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24581 this.displayEl.update(msg);
24586 onLoad : function(ds, r, o)
24588 this.cursor = o.params.start ? o.params.start : 0;
24590 var d = this.getPageData(),
24595 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24596 this.field.dom.value = ap;
24597 this.first.setDisabled(ap == 1);
24598 this.prev.setDisabled(ap == 1);
24599 this.next.setDisabled(ap == ps);
24600 this.last.setDisabled(ap == ps);
24601 this.loading.enable();
24606 getPageData : function(){
24607 var total = this.ds.getTotalCount();
24610 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24611 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24616 onLoadError : function(){
24617 this.loading.enable();
24621 onPagingKeydown : function(e){
24622 var k = e.getKey();
24623 var d = this.getPageData();
24625 var v = this.field.dom.value, pageNum;
24626 if(!v || isNaN(pageNum = parseInt(v, 10))){
24627 this.field.dom.value = d.activePage;
24630 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24631 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24634 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))
24636 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24637 this.field.dom.value = pageNum;
24638 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24641 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24643 var v = this.field.dom.value, pageNum;
24644 var increment = (e.shiftKey) ? 10 : 1;
24645 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24648 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24649 this.field.dom.value = d.activePage;
24652 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24654 this.field.dom.value = parseInt(v, 10) + increment;
24655 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24656 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24663 beforeLoad : function(){
24665 this.loading.disable();
24670 onClick : function(which){
24679 ds.load({params:{start: 0, limit: this.pageSize}});
24682 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24685 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24688 var total = ds.getTotalCount();
24689 var extra = total % this.pageSize;
24690 var lastStart = extra ? (total - extra) : total-this.pageSize;
24691 ds.load({params:{start: lastStart, limit: this.pageSize}});
24694 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24700 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24701 * @param {Roo.data.Store} store The data store to unbind
24703 unbind : function(ds){
24704 ds.un("beforeload", this.beforeLoad, this);
24705 ds.un("load", this.onLoad, this);
24706 ds.un("loadexception", this.onLoadError, this);
24707 ds.un("remove", this.updateInfo, this);
24708 ds.un("add", this.updateInfo, this);
24709 this.ds = undefined;
24713 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24714 * @param {Roo.data.Store} store The data store to bind
24716 bind : function(ds){
24717 ds.on("beforeload", this.beforeLoad, this);
24718 ds.on("load", this.onLoad, this);
24719 ds.on("loadexception", this.onLoadError, this);
24720 ds.on("remove", this.updateInfo, this);
24721 ds.on("add", this.updateInfo, this);
24732 * @class Roo.bootstrap.MessageBar
24733 * @extends Roo.bootstrap.Component
24734 * Bootstrap MessageBar class
24735 * @cfg {String} html contents of the MessageBar
24736 * @cfg {String} weight (info | success | warning | danger) default info
24737 * @cfg {String} beforeClass insert the bar before the given class
24738 * @cfg {Boolean} closable (true | false) default false
24739 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24742 * Create a new Element
24743 * @param {Object} config The config object
24746 Roo.bootstrap.MessageBar = function(config){
24747 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24750 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24756 beforeClass: 'bootstrap-sticky-wrap',
24758 getAutoCreate : function(){
24762 cls: 'alert alert-dismissable alert-' + this.weight,
24767 html: this.html || ''
24773 cfg.cls += ' alert-messages-fixed';
24787 onRender : function(ct, position)
24789 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24792 var cfg = Roo.apply({}, this.getAutoCreate());
24796 cfg.cls += ' ' + this.cls;
24799 cfg.style = this.style;
24801 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24803 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24806 this.el.select('>button.close').on('click', this.hide, this);
24812 if (!this.rendered) {
24818 this.fireEvent('show', this);
24824 if (!this.rendered) {
24830 this.fireEvent('hide', this);
24833 update : function()
24835 // var e = this.el.dom.firstChild;
24837 // if(this.closable){
24838 // e = e.nextSibling;
24841 // e.data = this.html || '';
24843 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24859 * @class Roo.bootstrap.Graph
24860 * @extends Roo.bootstrap.Component
24861 * Bootstrap Graph class
24865 @cfg {String} graphtype bar | vbar | pie
24866 @cfg {number} g_x coodinator | centre x (pie)
24867 @cfg {number} g_y coodinator | centre y (pie)
24868 @cfg {number} g_r radius (pie)
24869 @cfg {number} g_height height of the chart (respected by all elements in the set)
24870 @cfg {number} g_width width of the chart (respected by all elements in the set)
24871 @cfg {Object} title The title of the chart
24874 -opts (object) options for the chart
24876 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24877 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24879 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.
24880 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24882 o stretch (boolean)
24884 -opts (object) options for the pie
24887 o startAngle (number)
24888 o endAngle (number)
24892 * Create a new Input
24893 * @param {Object} config The config object
24896 Roo.bootstrap.Graph = function(config){
24897 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24903 * The img click event for the img.
24904 * @param {Roo.EventObject} e
24910 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24921 //g_colors: this.colors,
24928 getAutoCreate : function(){
24939 onRender : function(ct,position){
24942 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24944 if (typeof(Raphael) == 'undefined') {
24945 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24949 this.raphael = Raphael(this.el.dom);
24951 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24952 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24953 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24954 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24956 r.text(160, 10, "Single Series Chart").attr(txtattr);
24957 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24958 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24959 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24961 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24962 r.barchart(330, 10, 300, 220, data1);
24963 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24964 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24967 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24968 // r.barchart(30, 30, 560, 250, xdata, {
24969 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24970 // axis : "0 0 1 1",
24971 // axisxlabels : xdata
24972 // //yvalues : cols,
24975 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24977 // this.load(null,xdata,{
24978 // axis : "0 0 1 1",
24979 // axisxlabels : xdata
24984 load : function(graphtype,xdata,opts)
24986 this.raphael.clear();
24988 graphtype = this.graphtype;
24993 var r = this.raphael,
24994 fin = function () {
24995 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24997 fout = function () {
24998 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25000 pfin = function() {
25001 this.sector.stop();
25002 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25005 this.label[0].stop();
25006 this.label[0].attr({ r: 7.5 });
25007 this.label[1].attr({ "font-weight": 800 });
25010 pfout = function() {
25011 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25014 this.label[0].animate({ r: 5 }, 500, "bounce");
25015 this.label[1].attr({ "font-weight": 400 });
25021 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25024 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25027 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25028 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25030 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25037 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25042 setTitle: function(o)
25047 initEvents: function() {
25050 this.el.on('click', this.onClick, this);
25054 onClick : function(e)
25056 Roo.log('img onclick');
25057 this.fireEvent('click', this, e);
25069 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25072 * @class Roo.bootstrap.dash.NumberBox
25073 * @extends Roo.bootstrap.Component
25074 * Bootstrap NumberBox class
25075 * @cfg {String} headline Box headline
25076 * @cfg {String} content Box content
25077 * @cfg {String} icon Box icon
25078 * @cfg {String} footer Footer text
25079 * @cfg {String} fhref Footer href
25082 * Create a new NumberBox
25083 * @param {Object} config The config object
25087 Roo.bootstrap.dash.NumberBox = function(config){
25088 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25092 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25101 getAutoCreate : function(){
25105 cls : 'small-box ',
25113 cls : 'roo-headline',
25114 html : this.headline
25118 cls : 'roo-content',
25119 html : this.content
25133 cls : 'ion ' + this.icon
25142 cls : 'small-box-footer',
25143 href : this.fhref || '#',
25147 cfg.cn.push(footer);
25154 onRender : function(ct,position){
25155 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25162 setHeadline: function (value)
25164 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25167 setFooter: function (value, href)
25169 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25172 this.el.select('a.small-box-footer',true).first().attr('href', href);
25177 setContent: function (value)
25179 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25182 initEvents: function()
25196 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25199 * @class Roo.bootstrap.dash.TabBox
25200 * @extends Roo.bootstrap.Component
25201 * Bootstrap TabBox class
25202 * @cfg {String} title Title of the TabBox
25203 * @cfg {String} icon Icon of the TabBox
25204 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25205 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25208 * Create a new TabBox
25209 * @param {Object} config The config object
25213 Roo.bootstrap.dash.TabBox = function(config){
25214 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25219 * When a pane is added
25220 * @param {Roo.bootstrap.dash.TabPane} pane
25224 * @event activatepane
25225 * When a pane is activated
25226 * @param {Roo.bootstrap.dash.TabPane} pane
25228 "activatepane" : true
25236 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25241 tabScrollable : false,
25243 getChildContainer : function()
25245 return this.el.select('.tab-content', true).first();
25248 getAutoCreate : function(){
25252 cls: 'pull-left header',
25260 cls: 'fa ' + this.icon
25266 cls: 'nav nav-tabs pull-right',
25272 if(this.tabScrollable){
25279 cls: 'nav nav-tabs pull-right',
25290 cls: 'nav-tabs-custom',
25295 cls: 'tab-content no-padding',
25303 initEvents : function()
25305 //Roo.log('add add pane handler');
25306 this.on('addpane', this.onAddPane, this);
25309 * Updates the box title
25310 * @param {String} html to set the title to.
25312 setTitle : function(value)
25314 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25316 onAddPane : function(pane)
25318 this.panes.push(pane);
25319 //Roo.log('addpane');
25321 // tabs are rendere left to right..
25322 if(!this.showtabs){
25326 var ctr = this.el.select('.nav-tabs', true).first();
25329 var existing = ctr.select('.nav-tab',true);
25330 var qty = existing.getCount();;
25333 var tab = ctr.createChild({
25335 cls : 'nav-tab' + (qty ? '' : ' active'),
25343 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25346 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25348 pane.el.addClass('active');
25353 onTabClick : function(ev,un,ob,pane)
25355 //Roo.log('tab - prev default');
25356 ev.preventDefault();
25359 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25360 pane.tab.addClass('active');
25361 //Roo.log(pane.title);
25362 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25363 // technically we should have a deactivate event.. but maybe add later.
25364 // and it should not de-activate the selected tab...
25365 this.fireEvent('activatepane', pane);
25366 pane.el.addClass('active');
25367 pane.fireEvent('activate');
25372 getActivePane : function()
25375 Roo.each(this.panes, function(p) {
25376 if(p.el.hasClass('active')){
25397 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25399 * @class Roo.bootstrap.TabPane
25400 * @extends Roo.bootstrap.Component
25401 * Bootstrap TabPane class
25402 * @cfg {Boolean} active (false | true) Default false
25403 * @cfg {String} title title of panel
25407 * Create a new TabPane
25408 * @param {Object} config The config object
25411 Roo.bootstrap.dash.TabPane = function(config){
25412 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25418 * When a pane is activated
25419 * @param {Roo.bootstrap.dash.TabPane} pane
25426 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25431 // the tabBox that this is attached to.
25434 getAutoCreate : function()
25442 cfg.cls += ' active';
25447 initEvents : function()
25449 //Roo.log('trigger add pane handler');
25450 this.parent().fireEvent('addpane', this)
25454 * Updates the tab title
25455 * @param {String} html to set the title to.
25457 setTitle: function(str)
25463 this.tab.select('a', true).first().dom.innerHTML = str;
25480 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25483 * @class Roo.bootstrap.menu.Menu
25484 * @extends Roo.bootstrap.Component
25485 * Bootstrap Menu class - container for Menu
25486 * @cfg {String} html Text of the menu
25487 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25488 * @cfg {String} icon Font awesome icon
25489 * @cfg {String} pos Menu align to (top | bottom) default bottom
25493 * Create a new Menu
25494 * @param {Object} config The config object
25498 Roo.bootstrap.menu.Menu = function(config){
25499 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25503 * @event beforeshow
25504 * Fires before this menu is displayed
25505 * @param {Roo.bootstrap.menu.Menu} this
25509 * @event beforehide
25510 * Fires before this menu is hidden
25511 * @param {Roo.bootstrap.menu.Menu} this
25516 * Fires after this menu is displayed
25517 * @param {Roo.bootstrap.menu.Menu} this
25522 * Fires after this menu is hidden
25523 * @param {Roo.bootstrap.menu.Menu} this
25528 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25529 * @param {Roo.bootstrap.menu.Menu} this
25530 * @param {Roo.EventObject} e
25537 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25541 weight : 'default',
25546 getChildContainer : function() {
25547 if(this.isSubMenu){
25551 return this.el.select('ul.dropdown-menu', true).first();
25554 getAutoCreate : function()
25559 cls : 'roo-menu-text',
25567 cls : 'fa ' + this.icon
25578 cls : 'dropdown-button btn btn-' + this.weight,
25583 cls : 'dropdown-toggle btn btn-' + this.weight,
25593 cls : 'dropdown-menu'
25599 if(this.pos == 'top'){
25600 cfg.cls += ' dropup';
25603 if(this.isSubMenu){
25606 cls : 'dropdown-menu'
25613 onRender : function(ct, position)
25615 this.isSubMenu = ct.hasClass('dropdown-submenu');
25617 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25620 initEvents : function()
25622 if(this.isSubMenu){
25626 this.hidden = true;
25628 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25629 this.triggerEl.on('click', this.onTriggerPress, this);
25631 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25632 this.buttonEl.on('click', this.onClick, this);
25638 if(this.isSubMenu){
25642 return this.el.select('ul.dropdown-menu', true).first();
25645 onClick : function(e)
25647 this.fireEvent("click", this, e);
25650 onTriggerPress : function(e)
25652 if (this.isVisible()) {
25659 isVisible : function(){
25660 return !this.hidden;
25665 this.fireEvent("beforeshow", this);
25667 this.hidden = false;
25668 this.el.addClass('open');
25670 Roo.get(document).on("mouseup", this.onMouseUp, this);
25672 this.fireEvent("show", this);
25679 this.fireEvent("beforehide", this);
25681 this.hidden = true;
25682 this.el.removeClass('open');
25684 Roo.get(document).un("mouseup", this.onMouseUp);
25686 this.fireEvent("hide", this);
25689 onMouseUp : function()
25703 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25706 * @class Roo.bootstrap.menu.Item
25707 * @extends Roo.bootstrap.Component
25708 * Bootstrap MenuItem class
25709 * @cfg {Boolean} submenu (true | false) default false
25710 * @cfg {String} html text of the item
25711 * @cfg {String} href the link
25712 * @cfg {Boolean} disable (true | false) default false
25713 * @cfg {Boolean} preventDefault (true | false) default true
25714 * @cfg {String} icon Font awesome icon
25715 * @cfg {String} pos Submenu align to (left | right) default right
25719 * Create a new Item
25720 * @param {Object} config The config object
25724 Roo.bootstrap.menu.Item = function(config){
25725 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25729 * Fires when the mouse is hovering over this menu
25730 * @param {Roo.bootstrap.menu.Item} this
25731 * @param {Roo.EventObject} e
25736 * Fires when the mouse exits this menu
25737 * @param {Roo.bootstrap.menu.Item} this
25738 * @param {Roo.EventObject} e
25744 * The raw click event for the entire grid.
25745 * @param {Roo.EventObject} e
25751 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25756 preventDefault: true,
25761 getAutoCreate : function()
25766 cls : 'roo-menu-item-text',
25774 cls : 'fa ' + this.icon
25783 href : this.href || '#',
25790 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25794 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25796 if(this.pos == 'left'){
25797 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25804 initEvents : function()
25806 this.el.on('mouseover', this.onMouseOver, this);
25807 this.el.on('mouseout', this.onMouseOut, this);
25809 this.el.select('a', true).first().on('click', this.onClick, this);
25813 onClick : function(e)
25815 if(this.preventDefault){
25816 e.preventDefault();
25819 this.fireEvent("click", this, e);
25822 onMouseOver : function(e)
25824 if(this.submenu && this.pos == 'left'){
25825 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25828 this.fireEvent("mouseover", this, e);
25831 onMouseOut : function(e)
25833 this.fireEvent("mouseout", this, e);
25845 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25848 * @class Roo.bootstrap.menu.Separator
25849 * @extends Roo.bootstrap.Component
25850 * Bootstrap Separator class
25853 * Create a new Separator
25854 * @param {Object} config The config object
25858 Roo.bootstrap.menu.Separator = function(config){
25859 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25862 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25864 getAutoCreate : function(){
25885 * @class Roo.bootstrap.Tooltip
25886 * Bootstrap Tooltip class
25887 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25888 * to determine which dom element triggers the tooltip.
25890 * It needs to add support for additional attributes like tooltip-position
25893 * Create a new Toolti
25894 * @param {Object} config The config object
25897 Roo.bootstrap.Tooltip = function(config){
25898 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25900 this.alignment = Roo.bootstrap.Tooltip.alignment;
25902 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25903 this.alignment = config.alignment;
25908 Roo.apply(Roo.bootstrap.Tooltip, {
25910 * @function init initialize tooltip monitoring.
25914 currentTip : false,
25915 currentRegion : false,
25921 Roo.get(document).on('mouseover', this.enter ,this);
25922 Roo.get(document).on('mouseout', this.leave, this);
25925 this.currentTip = new Roo.bootstrap.Tooltip();
25928 enter : function(ev)
25930 var dom = ev.getTarget();
25932 //Roo.log(['enter',dom]);
25933 var el = Roo.fly(dom);
25934 if (this.currentEl) {
25936 //Roo.log(this.currentEl);
25937 //Roo.log(this.currentEl.contains(dom));
25938 if (this.currentEl == el) {
25941 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25947 if (this.currentTip.el) {
25948 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25952 if(!el || el.dom == document){
25958 // you can not look for children, as if el is the body.. then everythign is the child..
25959 if (!el.attr('tooltip')) { //
25960 if (!el.select("[tooltip]").elements.length) {
25963 // is the mouse over this child...?
25964 bindEl = el.select("[tooltip]").first();
25965 var xy = ev.getXY();
25966 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25967 //Roo.log("not in region.");
25970 //Roo.log("child element over..");
25973 this.currentEl = bindEl;
25974 this.currentTip.bind(bindEl);
25975 this.currentRegion = Roo.lib.Region.getRegion(dom);
25976 this.currentTip.enter();
25979 leave : function(ev)
25981 var dom = ev.getTarget();
25982 //Roo.log(['leave',dom]);
25983 if (!this.currentEl) {
25988 if (dom != this.currentEl.dom) {
25991 var xy = ev.getXY();
25992 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25995 // only activate leave if mouse cursor is outside... bounding box..
26000 if (this.currentTip) {
26001 this.currentTip.leave();
26003 //Roo.log('clear currentEl');
26004 this.currentEl = false;
26009 'left' : ['r-l', [-2,0], 'right'],
26010 'right' : ['l-r', [2,0], 'left'],
26011 'bottom' : ['t-b', [0,2], 'top'],
26012 'top' : [ 'b-t', [0,-2], 'bottom']
26018 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26023 delay : null, // can be { show : 300 , hide: 500}
26027 hoverState : null, //???
26029 placement : 'bottom',
26033 getAutoCreate : function(){
26040 cls : 'tooltip-arrow'
26043 cls : 'tooltip-inner'
26050 bind : function(el)
26056 enter : function () {
26058 if (this.timeout != null) {
26059 clearTimeout(this.timeout);
26062 this.hoverState = 'in';
26063 //Roo.log("enter - show");
26064 if (!this.delay || !this.delay.show) {
26069 this.timeout = setTimeout(function () {
26070 if (_t.hoverState == 'in') {
26073 }, this.delay.show);
26077 clearTimeout(this.timeout);
26079 this.hoverState = 'out';
26080 if (!this.delay || !this.delay.hide) {
26086 this.timeout = setTimeout(function () {
26087 //Roo.log("leave - timeout");
26089 if (_t.hoverState == 'out') {
26091 Roo.bootstrap.Tooltip.currentEl = false;
26096 show : function (msg)
26099 this.render(document.body);
26102 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26104 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26106 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26108 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26110 var placement = typeof this.placement == 'function' ?
26111 this.placement.call(this, this.el, on_el) :
26114 var autoToken = /\s?auto?\s?/i;
26115 var autoPlace = autoToken.test(placement);
26117 placement = placement.replace(autoToken, '') || 'top';
26121 //this.el.setXY([0,0]);
26123 //this.el.dom.style.display='block';
26125 //this.el.appendTo(on_el);
26127 var p = this.getPosition();
26128 var box = this.el.getBox();
26134 var align = this.alignment[placement];
26136 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26138 if(placement == 'top' || placement == 'bottom'){
26140 placement = 'right';
26143 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26144 placement = 'left';
26147 var scroll = Roo.select('body', true).first().getScroll();
26149 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26155 this.el.alignTo(this.bindEl, align[0],align[1]);
26156 //var arrow = this.el.select('.arrow',true).first();
26157 //arrow.set(align[2],
26159 this.el.addClass(placement);
26161 this.el.addClass('in fade');
26163 this.hoverState = null;
26165 if (this.el.hasClass('fade')) {
26176 //this.el.setXY([0,0]);
26177 this.el.removeClass('in');
26193 * @class Roo.bootstrap.LocationPicker
26194 * @extends Roo.bootstrap.Component
26195 * Bootstrap LocationPicker class
26196 * @cfg {Number} latitude Position when init default 0
26197 * @cfg {Number} longitude Position when init default 0
26198 * @cfg {Number} zoom default 15
26199 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26200 * @cfg {Boolean} mapTypeControl default false
26201 * @cfg {Boolean} disableDoubleClickZoom default false
26202 * @cfg {Boolean} scrollwheel default true
26203 * @cfg {Boolean} streetViewControl default false
26204 * @cfg {Number} radius default 0
26205 * @cfg {String} locationName
26206 * @cfg {Boolean} draggable default true
26207 * @cfg {Boolean} enableAutocomplete default false
26208 * @cfg {Boolean} enableReverseGeocode default true
26209 * @cfg {String} markerTitle
26212 * Create a new LocationPicker
26213 * @param {Object} config The config object
26217 Roo.bootstrap.LocationPicker = function(config){
26219 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26224 * Fires when the picker initialized.
26225 * @param {Roo.bootstrap.LocationPicker} this
26226 * @param {Google Location} location
26230 * @event positionchanged
26231 * Fires when the picker position changed.
26232 * @param {Roo.bootstrap.LocationPicker} this
26233 * @param {Google Location} location
26235 positionchanged : true,
26238 * Fires when the map resize.
26239 * @param {Roo.bootstrap.LocationPicker} this
26244 * Fires when the map show.
26245 * @param {Roo.bootstrap.LocationPicker} this
26250 * Fires when the map hide.
26251 * @param {Roo.bootstrap.LocationPicker} this
26256 * Fires when click the map.
26257 * @param {Roo.bootstrap.LocationPicker} this
26258 * @param {Map event} e
26262 * @event mapRightClick
26263 * Fires when right click the map.
26264 * @param {Roo.bootstrap.LocationPicker} this
26265 * @param {Map event} e
26267 mapRightClick : true,
26269 * @event markerClick
26270 * Fires when click the marker.
26271 * @param {Roo.bootstrap.LocationPicker} this
26272 * @param {Map event} e
26274 markerClick : true,
26276 * @event markerRightClick
26277 * Fires when right click the marker.
26278 * @param {Roo.bootstrap.LocationPicker} this
26279 * @param {Map event} e
26281 markerRightClick : true,
26283 * @event OverlayViewDraw
26284 * Fires when OverlayView Draw
26285 * @param {Roo.bootstrap.LocationPicker} this
26287 OverlayViewDraw : true,
26289 * @event OverlayViewOnAdd
26290 * Fires when OverlayView Draw
26291 * @param {Roo.bootstrap.LocationPicker} this
26293 OverlayViewOnAdd : true,
26295 * @event OverlayViewOnRemove
26296 * Fires when OverlayView Draw
26297 * @param {Roo.bootstrap.LocationPicker} this
26299 OverlayViewOnRemove : true,
26301 * @event OverlayViewShow
26302 * Fires when OverlayView Draw
26303 * @param {Roo.bootstrap.LocationPicker} this
26304 * @param {Pixel} cpx
26306 OverlayViewShow : true,
26308 * @event OverlayViewHide
26309 * Fires when OverlayView Draw
26310 * @param {Roo.bootstrap.LocationPicker} this
26312 OverlayViewHide : true,
26314 * @event loadexception
26315 * Fires when load google lib failed.
26316 * @param {Roo.bootstrap.LocationPicker} this
26318 loadexception : true
26323 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26325 gMapContext: false,
26331 mapTypeControl: false,
26332 disableDoubleClickZoom: false,
26334 streetViewControl: false,
26338 enableAutocomplete: false,
26339 enableReverseGeocode: true,
26342 getAutoCreate: function()
26347 cls: 'roo-location-picker'
26353 initEvents: function(ct, position)
26355 if(!this.el.getWidth() || this.isApplied()){
26359 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26364 initial: function()
26366 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26367 this.fireEvent('loadexception', this);
26371 if(!this.mapTypeId){
26372 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26375 this.gMapContext = this.GMapContext();
26377 this.initOverlayView();
26379 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26383 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26384 _this.setPosition(_this.gMapContext.marker.position);
26387 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26388 _this.fireEvent('mapClick', this, event);
26392 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26393 _this.fireEvent('mapRightClick', this, event);
26397 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26398 _this.fireEvent('markerClick', this, event);
26402 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26403 _this.fireEvent('markerRightClick', this, event);
26407 this.setPosition(this.gMapContext.location);
26409 this.fireEvent('initial', this, this.gMapContext.location);
26412 initOverlayView: function()
26416 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26420 _this.fireEvent('OverlayViewDraw', _this);
26425 _this.fireEvent('OverlayViewOnAdd', _this);
26428 onRemove: function()
26430 _this.fireEvent('OverlayViewOnRemove', _this);
26433 show: function(cpx)
26435 _this.fireEvent('OverlayViewShow', _this, cpx);
26440 _this.fireEvent('OverlayViewHide', _this);
26446 fromLatLngToContainerPixel: function(event)
26448 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26451 isApplied: function()
26453 return this.getGmapContext() == false ? false : true;
26456 getGmapContext: function()
26458 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26461 GMapContext: function()
26463 var position = new google.maps.LatLng(this.latitude, this.longitude);
26465 var _map = new google.maps.Map(this.el.dom, {
26468 mapTypeId: this.mapTypeId,
26469 mapTypeControl: this.mapTypeControl,
26470 disableDoubleClickZoom: this.disableDoubleClickZoom,
26471 scrollwheel: this.scrollwheel,
26472 streetViewControl: this.streetViewControl,
26473 locationName: this.locationName,
26474 draggable: this.draggable,
26475 enableAutocomplete: this.enableAutocomplete,
26476 enableReverseGeocode: this.enableReverseGeocode
26479 var _marker = new google.maps.Marker({
26480 position: position,
26482 title: this.markerTitle,
26483 draggable: this.draggable
26490 location: position,
26491 radius: this.radius,
26492 locationName: this.locationName,
26493 addressComponents: {
26494 formatted_address: null,
26495 addressLine1: null,
26496 addressLine2: null,
26498 streetNumber: null,
26502 stateOrProvince: null
26505 domContainer: this.el.dom,
26506 geodecoder: new google.maps.Geocoder()
26510 drawCircle: function(center, radius, options)
26512 if (this.gMapContext.circle != null) {
26513 this.gMapContext.circle.setMap(null);
26517 options = Roo.apply({}, options, {
26518 strokeColor: "#0000FF",
26519 strokeOpacity: .35,
26521 fillColor: "#0000FF",
26525 options.map = this.gMapContext.map;
26526 options.radius = radius;
26527 options.center = center;
26528 this.gMapContext.circle = new google.maps.Circle(options);
26529 return this.gMapContext.circle;
26535 setPosition: function(location)
26537 this.gMapContext.location = location;
26538 this.gMapContext.marker.setPosition(location);
26539 this.gMapContext.map.panTo(location);
26540 this.drawCircle(location, this.gMapContext.radius, {});
26544 if (this.gMapContext.settings.enableReverseGeocode) {
26545 this.gMapContext.geodecoder.geocode({
26546 latLng: this.gMapContext.location
26547 }, function(results, status) {
26549 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26550 _this.gMapContext.locationName = results[0].formatted_address;
26551 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26553 _this.fireEvent('positionchanged', this, location);
26560 this.fireEvent('positionchanged', this, location);
26565 google.maps.event.trigger(this.gMapContext.map, "resize");
26567 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26569 this.fireEvent('resize', this);
26572 setPositionByLatLng: function(latitude, longitude)
26574 this.setPosition(new google.maps.LatLng(latitude, longitude));
26577 getCurrentPosition: function()
26580 latitude: this.gMapContext.location.lat(),
26581 longitude: this.gMapContext.location.lng()
26585 getAddressName: function()
26587 return this.gMapContext.locationName;
26590 getAddressComponents: function()
26592 return this.gMapContext.addressComponents;
26595 address_component_from_google_geocode: function(address_components)
26599 for (var i = 0; i < address_components.length; i++) {
26600 var component = address_components[i];
26601 if (component.types.indexOf("postal_code") >= 0) {
26602 result.postalCode = component.short_name;
26603 } else if (component.types.indexOf("street_number") >= 0) {
26604 result.streetNumber = component.short_name;
26605 } else if (component.types.indexOf("route") >= 0) {
26606 result.streetName = component.short_name;
26607 } else if (component.types.indexOf("neighborhood") >= 0) {
26608 result.city = component.short_name;
26609 } else if (component.types.indexOf("locality") >= 0) {
26610 result.city = component.short_name;
26611 } else if (component.types.indexOf("sublocality") >= 0) {
26612 result.district = component.short_name;
26613 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26614 result.stateOrProvince = component.short_name;
26615 } else if (component.types.indexOf("country") >= 0) {
26616 result.country = component.short_name;
26620 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26621 result.addressLine2 = "";
26625 setZoomLevel: function(zoom)
26627 this.gMapContext.map.setZoom(zoom);
26640 this.fireEvent('show', this);
26651 this.fireEvent('hide', this);
26656 Roo.apply(Roo.bootstrap.LocationPicker, {
26658 OverlayView : function(map, options)
26660 options = options || {};
26674 * @class Roo.bootstrap.Alert
26675 * @extends Roo.bootstrap.Component
26676 * Bootstrap Alert class
26677 * @cfg {String} title The title of alert
26678 * @cfg {String} html The content of alert
26679 * @cfg {String} weight ( success | info | warning | danger )
26680 * @cfg {String} faicon font-awesomeicon
26683 * Create a new alert
26684 * @param {Object} config The config object
26688 Roo.bootstrap.Alert = function(config){
26689 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26693 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26700 getAutoCreate : function()
26709 cls : 'roo-alert-icon'
26714 cls : 'roo-alert-title',
26719 cls : 'roo-alert-text',
26726 cfg.cn[0].cls += ' fa ' + this.faicon;
26730 cfg.cls += ' alert-' + this.weight;
26736 initEvents: function()
26738 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26741 setTitle : function(str)
26743 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26746 setText : function(str)
26748 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26751 setWeight : function(weight)
26754 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26757 this.weight = weight;
26759 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26762 setIcon : function(icon)
26765 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26768 this.faicon = icon;
26770 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26791 * @class Roo.bootstrap.UploadCropbox
26792 * @extends Roo.bootstrap.Component
26793 * Bootstrap UploadCropbox class
26794 * @cfg {String} emptyText show when image has been loaded
26795 * @cfg {String} rotateNotify show when image too small to rotate
26796 * @cfg {Number} errorTimeout default 3000
26797 * @cfg {Number} minWidth default 300
26798 * @cfg {Number} minHeight default 300
26799 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26800 * @cfg {Boolean} isDocument (true|false) default false
26801 * @cfg {String} url action url
26802 * @cfg {String} paramName default 'imageUpload'
26803 * @cfg {String} method default POST
26804 * @cfg {Boolean} loadMask (true|false) default true
26805 * @cfg {Boolean} loadingText default 'Loading...'
26808 * Create a new UploadCropbox
26809 * @param {Object} config The config object
26812 Roo.bootstrap.UploadCropbox = function(config){
26813 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26817 * @event beforeselectfile
26818 * Fire before select file
26819 * @param {Roo.bootstrap.UploadCropbox} this
26821 "beforeselectfile" : true,
26824 * Fire after initEvent
26825 * @param {Roo.bootstrap.UploadCropbox} this
26830 * Fire after initEvent
26831 * @param {Roo.bootstrap.UploadCropbox} this
26832 * @param {String} data
26837 * Fire when preparing the file data
26838 * @param {Roo.bootstrap.UploadCropbox} this
26839 * @param {Object} file
26844 * Fire when get exception
26845 * @param {Roo.bootstrap.UploadCropbox} this
26846 * @param {XMLHttpRequest} xhr
26848 "exception" : true,
26850 * @event beforeloadcanvas
26851 * Fire before load the canvas
26852 * @param {Roo.bootstrap.UploadCropbox} this
26853 * @param {String} src
26855 "beforeloadcanvas" : true,
26858 * Fire when trash image
26859 * @param {Roo.bootstrap.UploadCropbox} this
26864 * Fire when download the image
26865 * @param {Roo.bootstrap.UploadCropbox} this
26869 * @event footerbuttonclick
26870 * Fire when footerbuttonclick
26871 * @param {Roo.bootstrap.UploadCropbox} this
26872 * @param {String} type
26874 "footerbuttonclick" : true,
26878 * @param {Roo.bootstrap.UploadCropbox} this
26883 * Fire when rotate the image
26884 * @param {Roo.bootstrap.UploadCropbox} this
26885 * @param {String} pos
26890 * Fire when inspect the file
26891 * @param {Roo.bootstrap.UploadCropbox} this
26892 * @param {Object} file
26897 * Fire when xhr upload the file
26898 * @param {Roo.bootstrap.UploadCropbox} this
26899 * @param {Object} data
26904 * Fire when arrange the file data
26905 * @param {Roo.bootstrap.UploadCropbox} this
26906 * @param {Object} formData
26911 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26914 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26916 emptyText : 'Click to upload image',
26917 rotateNotify : 'Image is too small to rotate',
26918 errorTimeout : 3000,
26932 cropType : 'image/jpeg',
26934 canvasLoaded : false,
26935 isDocument : false,
26937 paramName : 'imageUpload',
26939 loadingText : 'Loading...',
26942 getAutoCreate : function()
26946 cls : 'roo-upload-cropbox',
26950 cls : 'roo-upload-cropbox-selector',
26955 cls : 'roo-upload-cropbox-body',
26956 style : 'cursor:pointer',
26960 cls : 'roo-upload-cropbox-preview'
26964 cls : 'roo-upload-cropbox-thumb'
26968 cls : 'roo-upload-cropbox-empty-notify',
26969 html : this.emptyText
26973 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26974 html : this.rotateNotify
26980 cls : 'roo-upload-cropbox-footer',
26983 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26993 onRender : function(ct, position)
26995 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26997 if (this.buttons.length) {
26999 Roo.each(this.buttons, function(bb) {
27001 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27003 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27009 this.maskEl = this.el;
27013 initEvents : function()
27015 this.urlAPI = (window.createObjectURL && window) ||
27016 (window.URL && URL.revokeObjectURL && URL) ||
27017 (window.webkitURL && webkitURL);
27019 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27020 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27022 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27023 this.selectorEl.hide();
27025 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27026 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27028 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27029 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27030 this.thumbEl.hide();
27032 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27033 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27035 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27036 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27037 this.errorEl.hide();
27039 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27040 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27041 this.footerEl.hide();
27043 this.setThumbBoxSize();
27049 this.fireEvent('initial', this);
27056 window.addEventListener("resize", function() { _this.resize(); } );
27058 this.bodyEl.on('click', this.beforeSelectFile, this);
27061 this.bodyEl.on('touchstart', this.onTouchStart, this);
27062 this.bodyEl.on('touchmove', this.onTouchMove, this);
27063 this.bodyEl.on('touchend', this.onTouchEnd, this);
27067 this.bodyEl.on('mousedown', this.onMouseDown, this);
27068 this.bodyEl.on('mousemove', this.onMouseMove, this);
27069 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27070 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27071 Roo.get(document).on('mouseup', this.onMouseUp, this);
27074 this.selectorEl.on('change', this.onFileSelected, this);
27080 this.baseScale = 1;
27082 this.baseRotate = 1;
27083 this.dragable = false;
27084 this.pinching = false;
27087 this.cropData = false;
27088 this.notifyEl.dom.innerHTML = this.emptyText;
27090 this.selectorEl.dom.value = '';
27094 resize : function()
27096 if(this.fireEvent('resize', this) != false){
27097 this.setThumbBoxPosition();
27098 this.setCanvasPosition();
27102 onFooterButtonClick : function(e, el, o, type)
27105 case 'rotate-left' :
27106 this.onRotateLeft(e);
27108 case 'rotate-right' :
27109 this.onRotateRight(e);
27112 this.beforeSelectFile(e);
27127 this.fireEvent('footerbuttonclick', this, type);
27130 beforeSelectFile : function(e)
27132 e.preventDefault();
27134 if(this.fireEvent('beforeselectfile', this) != false){
27135 this.selectorEl.dom.click();
27139 onFileSelected : function(e)
27141 e.preventDefault();
27143 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27147 var file = this.selectorEl.dom.files[0];
27149 if(this.fireEvent('inspect', this, file) != false){
27150 this.prepare(file);
27155 trash : function(e)
27157 this.fireEvent('trash', this);
27160 download : function(e)
27162 this.fireEvent('download', this);
27165 loadCanvas : function(src)
27167 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27171 this.imageEl = document.createElement('img');
27175 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27177 this.imageEl.src = src;
27181 onLoadCanvas : function()
27183 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27184 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27186 this.bodyEl.un('click', this.beforeSelectFile, this);
27188 this.notifyEl.hide();
27189 this.thumbEl.show();
27190 this.footerEl.show();
27192 this.baseRotateLevel();
27194 if(this.isDocument){
27195 this.setThumbBoxSize();
27198 this.setThumbBoxPosition();
27200 this.baseScaleLevel();
27206 this.canvasLoaded = true;
27209 this.maskEl.unmask();
27214 setCanvasPosition : function()
27216 if(!this.canvasEl){
27220 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27221 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27223 this.previewEl.setLeft(pw);
27224 this.previewEl.setTop(ph);
27228 onMouseDown : function(e)
27232 this.dragable = true;
27233 this.pinching = false;
27235 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27236 this.dragable = false;
27240 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27241 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27245 onMouseMove : function(e)
27249 if(!this.canvasLoaded){
27253 if (!this.dragable){
27257 var minX = Math.ceil(this.thumbEl.getLeft(true));
27258 var minY = Math.ceil(this.thumbEl.getTop(true));
27260 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27261 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27263 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27264 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27266 x = x - this.mouseX;
27267 y = y - this.mouseY;
27269 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27270 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27272 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27273 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27275 this.previewEl.setLeft(bgX);
27276 this.previewEl.setTop(bgY);
27278 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27279 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27282 onMouseUp : function(e)
27286 this.dragable = false;
27289 onMouseWheel : function(e)
27293 this.startScale = this.scale;
27295 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27297 if(!this.zoomable()){
27298 this.scale = this.startScale;
27307 zoomable : function()
27309 var minScale = this.thumbEl.getWidth() / this.minWidth;
27311 if(this.minWidth < this.minHeight){
27312 minScale = this.thumbEl.getHeight() / this.minHeight;
27315 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27316 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27320 (this.rotate == 0 || this.rotate == 180) &&
27322 width > this.imageEl.OriginWidth ||
27323 height > this.imageEl.OriginHeight ||
27324 (width < this.minWidth && height < this.minHeight)
27332 (this.rotate == 90 || this.rotate == 270) &&
27334 width > this.imageEl.OriginWidth ||
27335 height > this.imageEl.OriginHeight ||
27336 (width < this.minHeight && height < this.minWidth)
27343 !this.isDocument &&
27344 (this.rotate == 0 || this.rotate == 180) &&
27346 width < this.minWidth ||
27347 width > this.imageEl.OriginWidth ||
27348 height < this.minHeight ||
27349 height > this.imageEl.OriginHeight
27356 !this.isDocument &&
27357 (this.rotate == 90 || this.rotate == 270) &&
27359 width < this.minHeight ||
27360 width > this.imageEl.OriginWidth ||
27361 height < this.minWidth ||
27362 height > this.imageEl.OriginHeight
27372 onRotateLeft : function(e)
27374 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27376 var minScale = this.thumbEl.getWidth() / this.minWidth;
27378 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27379 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27381 this.startScale = this.scale;
27383 while (this.getScaleLevel() < minScale){
27385 this.scale = this.scale + 1;
27387 if(!this.zoomable()){
27392 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27393 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27398 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27405 this.scale = this.startScale;
27407 this.onRotateFail();
27412 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27414 if(this.isDocument){
27415 this.setThumbBoxSize();
27416 this.setThumbBoxPosition();
27417 this.setCanvasPosition();
27422 this.fireEvent('rotate', this, 'left');
27426 onRotateRight : function(e)
27428 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27430 var minScale = this.thumbEl.getWidth() / this.minWidth;
27432 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27433 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27435 this.startScale = this.scale;
27437 while (this.getScaleLevel() < minScale){
27439 this.scale = this.scale + 1;
27441 if(!this.zoomable()){
27446 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27447 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27452 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27459 this.scale = this.startScale;
27461 this.onRotateFail();
27466 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27468 if(this.isDocument){
27469 this.setThumbBoxSize();
27470 this.setThumbBoxPosition();
27471 this.setCanvasPosition();
27476 this.fireEvent('rotate', this, 'right');
27479 onRotateFail : function()
27481 this.errorEl.show(true);
27485 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27490 this.previewEl.dom.innerHTML = '';
27492 var canvasEl = document.createElement("canvas");
27494 var contextEl = canvasEl.getContext("2d");
27496 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27497 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27498 var center = this.imageEl.OriginWidth / 2;
27500 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27501 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27502 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27503 center = this.imageEl.OriginHeight / 2;
27506 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27508 contextEl.translate(center, center);
27509 contextEl.rotate(this.rotate * Math.PI / 180);
27511 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27513 this.canvasEl = document.createElement("canvas");
27515 this.contextEl = this.canvasEl.getContext("2d");
27517 switch (this.rotate) {
27520 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27521 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27523 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27528 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27529 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27531 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27532 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);
27536 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27541 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27542 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27544 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27545 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);
27549 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);
27554 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27555 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27557 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27558 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27562 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);
27569 this.previewEl.appendChild(this.canvasEl);
27571 this.setCanvasPosition();
27576 if(!this.canvasLoaded){
27580 var imageCanvas = document.createElement("canvas");
27582 var imageContext = imageCanvas.getContext("2d");
27584 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27585 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27587 var center = imageCanvas.width / 2;
27589 imageContext.translate(center, center);
27591 imageContext.rotate(this.rotate * Math.PI / 180);
27593 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27595 var canvas = document.createElement("canvas");
27597 var context = canvas.getContext("2d");
27599 canvas.width = this.minWidth;
27600 canvas.height = this.minHeight;
27602 switch (this.rotate) {
27605 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27606 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27608 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27609 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27611 var targetWidth = this.minWidth - 2 * x;
27612 var targetHeight = this.minHeight - 2 * y;
27616 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27617 scale = targetWidth / width;
27620 if(x > 0 && y == 0){
27621 scale = targetHeight / height;
27624 if(x > 0 && y > 0){
27625 scale = targetWidth / width;
27627 if(width < height){
27628 scale = targetHeight / height;
27632 context.scale(scale, scale);
27634 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27635 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27637 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27638 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27640 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27645 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27646 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27648 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27649 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27651 var targetWidth = this.minWidth - 2 * x;
27652 var targetHeight = this.minHeight - 2 * y;
27656 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27657 scale = targetWidth / width;
27660 if(x > 0 && y == 0){
27661 scale = targetHeight / height;
27664 if(x > 0 && y > 0){
27665 scale = targetWidth / width;
27667 if(width < height){
27668 scale = targetHeight / height;
27672 context.scale(scale, scale);
27674 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27675 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27677 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27678 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27680 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27682 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27687 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27688 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27690 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27691 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27693 var targetWidth = this.minWidth - 2 * x;
27694 var targetHeight = this.minHeight - 2 * y;
27698 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27699 scale = targetWidth / width;
27702 if(x > 0 && y == 0){
27703 scale = targetHeight / height;
27706 if(x > 0 && y > 0){
27707 scale = targetWidth / width;
27709 if(width < height){
27710 scale = targetHeight / height;
27714 context.scale(scale, scale);
27716 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27717 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27719 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27720 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27722 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27723 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27725 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27730 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27731 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27733 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27734 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27736 var targetWidth = this.minWidth - 2 * x;
27737 var targetHeight = this.minHeight - 2 * y;
27741 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27742 scale = targetWidth / width;
27745 if(x > 0 && y == 0){
27746 scale = targetHeight / height;
27749 if(x > 0 && y > 0){
27750 scale = targetWidth / width;
27752 if(width < height){
27753 scale = targetHeight / height;
27757 context.scale(scale, scale);
27759 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27760 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27762 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27763 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27765 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27767 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27774 this.cropData = canvas.toDataURL(this.cropType);
27776 if(this.fireEvent('crop', this, this.cropData) !== false){
27777 this.process(this.file, this.cropData);
27784 setThumbBoxSize : function()
27788 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27789 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27790 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27792 this.minWidth = width;
27793 this.minHeight = height;
27795 if(this.rotate == 90 || this.rotate == 270){
27796 this.minWidth = height;
27797 this.minHeight = width;
27802 width = Math.ceil(this.minWidth * height / this.minHeight);
27804 if(this.minWidth > this.minHeight){
27806 height = Math.ceil(this.minHeight * width / this.minWidth);
27809 this.thumbEl.setStyle({
27810 width : width + 'px',
27811 height : height + 'px'
27818 setThumbBoxPosition : function()
27820 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27821 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27823 this.thumbEl.setLeft(x);
27824 this.thumbEl.setTop(y);
27828 baseRotateLevel : function()
27830 this.baseRotate = 1;
27833 typeof(this.exif) != 'undefined' &&
27834 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27835 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27837 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27840 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27844 baseScaleLevel : function()
27848 if(this.isDocument){
27850 if(this.baseRotate == 6 || this.baseRotate == 8){
27852 height = this.thumbEl.getHeight();
27853 this.baseScale = height / this.imageEl.OriginWidth;
27855 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27856 width = this.thumbEl.getWidth();
27857 this.baseScale = width / this.imageEl.OriginHeight;
27863 height = this.thumbEl.getHeight();
27864 this.baseScale = height / this.imageEl.OriginHeight;
27866 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27867 width = this.thumbEl.getWidth();
27868 this.baseScale = width / this.imageEl.OriginWidth;
27874 if(this.baseRotate == 6 || this.baseRotate == 8){
27876 width = this.thumbEl.getHeight();
27877 this.baseScale = width / this.imageEl.OriginHeight;
27879 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27880 height = this.thumbEl.getWidth();
27881 this.baseScale = height / this.imageEl.OriginHeight;
27884 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27885 height = this.thumbEl.getWidth();
27886 this.baseScale = height / this.imageEl.OriginHeight;
27888 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27889 width = this.thumbEl.getHeight();
27890 this.baseScale = width / this.imageEl.OriginWidth;
27897 width = this.thumbEl.getWidth();
27898 this.baseScale = width / this.imageEl.OriginWidth;
27900 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27901 height = this.thumbEl.getHeight();
27902 this.baseScale = height / this.imageEl.OriginHeight;
27905 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27907 height = this.thumbEl.getHeight();
27908 this.baseScale = height / this.imageEl.OriginHeight;
27910 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27911 width = this.thumbEl.getWidth();
27912 this.baseScale = width / this.imageEl.OriginWidth;
27920 getScaleLevel : function()
27922 return this.baseScale * Math.pow(1.1, this.scale);
27925 onTouchStart : function(e)
27927 if(!this.canvasLoaded){
27928 this.beforeSelectFile(e);
27932 var touches = e.browserEvent.touches;
27938 if(touches.length == 1){
27939 this.onMouseDown(e);
27943 if(touches.length != 2){
27949 for(var i = 0, finger; finger = touches[i]; i++){
27950 coords.push(finger.pageX, finger.pageY);
27953 var x = Math.pow(coords[0] - coords[2], 2);
27954 var y = Math.pow(coords[1] - coords[3], 2);
27956 this.startDistance = Math.sqrt(x + y);
27958 this.startScale = this.scale;
27960 this.pinching = true;
27961 this.dragable = false;
27965 onTouchMove : function(e)
27967 if(!this.pinching && !this.dragable){
27971 var touches = e.browserEvent.touches;
27978 this.onMouseMove(e);
27984 for(var i = 0, finger; finger = touches[i]; i++){
27985 coords.push(finger.pageX, finger.pageY);
27988 var x = Math.pow(coords[0] - coords[2], 2);
27989 var y = Math.pow(coords[1] - coords[3], 2);
27991 this.endDistance = Math.sqrt(x + y);
27993 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27995 if(!this.zoomable()){
27996 this.scale = this.startScale;
28004 onTouchEnd : function(e)
28006 this.pinching = false;
28007 this.dragable = false;
28011 process : function(file, crop)
28014 this.maskEl.mask(this.loadingText);
28017 this.xhr = new XMLHttpRequest();
28019 file.xhr = this.xhr;
28021 this.xhr.open(this.method, this.url, true);
28024 "Accept": "application/json",
28025 "Cache-Control": "no-cache",
28026 "X-Requested-With": "XMLHttpRequest"
28029 for (var headerName in headers) {
28030 var headerValue = headers[headerName];
28032 this.xhr.setRequestHeader(headerName, headerValue);
28038 this.xhr.onload = function()
28040 _this.xhrOnLoad(_this.xhr);
28043 this.xhr.onerror = function()
28045 _this.xhrOnError(_this.xhr);
28048 var formData = new FormData();
28050 formData.append('returnHTML', 'NO');
28053 formData.append('crop', crop);
28056 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28057 formData.append(this.paramName, file, file.name);
28060 if(typeof(file.filename) != 'undefined'){
28061 formData.append('filename', file.filename);
28064 if(typeof(file.mimetype) != 'undefined'){
28065 formData.append('mimetype', file.mimetype);
28068 if(this.fireEvent('arrange', this, formData) != false){
28069 this.xhr.send(formData);
28073 xhrOnLoad : function(xhr)
28076 this.maskEl.unmask();
28079 if (xhr.readyState !== 4) {
28080 this.fireEvent('exception', this, xhr);
28084 var response = Roo.decode(xhr.responseText);
28086 if(!response.success){
28087 this.fireEvent('exception', this, xhr);
28091 var response = Roo.decode(xhr.responseText);
28093 this.fireEvent('upload', this, response);
28097 xhrOnError : function()
28100 this.maskEl.unmask();
28103 Roo.log('xhr on error');
28105 var response = Roo.decode(xhr.responseText);
28111 prepare : function(file)
28114 this.maskEl.mask(this.loadingText);
28120 if(typeof(file) === 'string'){
28121 this.loadCanvas(file);
28125 if(!file || !this.urlAPI){
28130 this.cropType = file.type;
28134 if(this.fireEvent('prepare', this, this.file) != false){
28136 var reader = new FileReader();
28138 reader.onload = function (e) {
28139 if (e.target.error) {
28140 Roo.log(e.target.error);
28144 var buffer = e.target.result,
28145 dataView = new DataView(buffer),
28147 maxOffset = dataView.byteLength - 4,
28151 if (dataView.getUint16(0) === 0xffd8) {
28152 while (offset < maxOffset) {
28153 markerBytes = dataView.getUint16(offset);
28155 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28156 markerLength = dataView.getUint16(offset + 2) + 2;
28157 if (offset + markerLength > dataView.byteLength) {
28158 Roo.log('Invalid meta data: Invalid segment size.');
28162 if(markerBytes == 0xffe1){
28163 _this.parseExifData(
28170 offset += markerLength;
28180 var url = _this.urlAPI.createObjectURL(_this.file);
28182 _this.loadCanvas(url);
28187 reader.readAsArrayBuffer(this.file);
28193 parseExifData : function(dataView, offset, length)
28195 var tiffOffset = offset + 10,
28199 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28200 // No Exif data, might be XMP data instead
28204 // Check for the ASCII code for "Exif" (0x45786966):
28205 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28206 // No Exif data, might be XMP data instead
28209 if (tiffOffset + 8 > dataView.byteLength) {
28210 Roo.log('Invalid Exif data: Invalid segment size.');
28213 // Check for the two null bytes:
28214 if (dataView.getUint16(offset + 8) !== 0x0000) {
28215 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28218 // Check the byte alignment:
28219 switch (dataView.getUint16(tiffOffset)) {
28221 littleEndian = true;
28224 littleEndian = false;
28227 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28230 // Check for the TIFF tag marker (0x002A):
28231 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28232 Roo.log('Invalid Exif data: Missing TIFF marker.');
28235 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28236 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28238 this.parseExifTags(
28241 tiffOffset + dirOffset,
28246 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28251 if (dirOffset + 6 > dataView.byteLength) {
28252 Roo.log('Invalid Exif data: Invalid directory offset.');
28255 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28256 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28257 if (dirEndOffset + 4 > dataView.byteLength) {
28258 Roo.log('Invalid Exif data: Invalid directory size.');
28261 for (i = 0; i < tagsNumber; i += 1) {
28265 dirOffset + 2 + 12 * i, // tag offset
28269 // Return the offset to the next directory:
28270 return dataView.getUint32(dirEndOffset, littleEndian);
28273 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28275 var tag = dataView.getUint16(offset, littleEndian);
28277 this.exif[tag] = this.getExifValue(
28281 dataView.getUint16(offset + 2, littleEndian), // tag type
28282 dataView.getUint32(offset + 4, littleEndian), // tag length
28287 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28289 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28298 Roo.log('Invalid Exif data: Invalid tag type.');
28302 tagSize = tagType.size * length;
28303 // Determine if the value is contained in the dataOffset bytes,
28304 // or if the value at the dataOffset is a pointer to the actual data:
28305 dataOffset = tagSize > 4 ?
28306 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28307 if (dataOffset + tagSize > dataView.byteLength) {
28308 Roo.log('Invalid Exif data: Invalid data offset.');
28311 if (length === 1) {
28312 return tagType.getValue(dataView, dataOffset, littleEndian);
28315 for (i = 0; i < length; i += 1) {
28316 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28319 if (tagType.ascii) {
28321 // Concatenate the chars:
28322 for (i = 0; i < values.length; i += 1) {
28324 // Ignore the terminating NULL byte(s):
28325 if (c === '\u0000') {
28337 Roo.apply(Roo.bootstrap.UploadCropbox, {
28339 'Orientation': 0x0112
28343 1: 0, //'top-left',
28345 3: 180, //'bottom-right',
28346 // 4: 'bottom-left',
28348 6: 90, //'right-top',
28349 // 7: 'right-bottom',
28350 8: 270 //'left-bottom'
28354 // byte, 8-bit unsigned int:
28356 getValue: function (dataView, dataOffset) {
28357 return dataView.getUint8(dataOffset);
28361 // ascii, 8-bit byte:
28363 getValue: function (dataView, dataOffset) {
28364 return String.fromCharCode(dataView.getUint8(dataOffset));
28369 // short, 16 bit int:
28371 getValue: function (dataView, dataOffset, littleEndian) {
28372 return dataView.getUint16(dataOffset, littleEndian);
28376 // long, 32 bit int:
28378 getValue: function (dataView, dataOffset, littleEndian) {
28379 return dataView.getUint32(dataOffset, littleEndian);
28383 // rational = two long values, first is numerator, second is denominator:
28385 getValue: function (dataView, dataOffset, littleEndian) {
28386 return dataView.getUint32(dataOffset, littleEndian) /
28387 dataView.getUint32(dataOffset + 4, littleEndian);
28391 // slong, 32 bit signed int:
28393 getValue: function (dataView, dataOffset, littleEndian) {
28394 return dataView.getInt32(dataOffset, littleEndian);
28398 // srational, two slongs, first is numerator, second is denominator:
28400 getValue: function (dataView, dataOffset, littleEndian) {
28401 return dataView.getInt32(dataOffset, littleEndian) /
28402 dataView.getInt32(dataOffset + 4, littleEndian);
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-picture',
28425 action : 'picture',
28429 cls : 'btn btn-default',
28430 html : '<i class="fa fa-picture-o"></i>'
28436 cls : 'btn-group roo-upload-cropbox-rotate-right',
28437 action : 'rotate-right',
28441 cls : 'btn btn-default',
28442 html : '<i class="fa fa-repeat"></i>'
28450 cls : 'btn-group roo-upload-cropbox-rotate-left',
28451 action : 'rotate-left',
28455 cls : 'btn btn-default',
28456 html : '<i class="fa fa-undo"></i>'
28462 cls : 'btn-group roo-upload-cropbox-download',
28463 action : 'download',
28467 cls : 'btn btn-default',
28468 html : '<i class="fa fa-download"></i>'
28474 cls : 'btn-group roo-upload-cropbox-crop',
28479 cls : 'btn btn-default',
28480 html : '<i class="fa fa-crop"></i>'
28486 cls : 'btn-group roo-upload-cropbox-trash',
28491 cls : 'btn btn-default',
28492 html : '<i class="fa fa-trash"></i>'
28498 cls : 'btn-group roo-upload-cropbox-rotate-right',
28499 action : 'rotate-right',
28503 cls : 'btn btn-default',
28504 html : '<i class="fa fa-repeat"></i>'
28512 cls : 'btn-group roo-upload-cropbox-rotate-left',
28513 action : 'rotate-left',
28517 cls : 'btn btn-default',
28518 html : '<i class="fa fa-undo"></i>'
28524 cls : 'btn-group roo-upload-cropbox-rotate-right',
28525 action : 'rotate-right',
28529 cls : 'btn btn-default',
28530 html : '<i class="fa fa-repeat"></i>'
28543 * @class Roo.bootstrap.DocumentManager
28544 * @extends Roo.bootstrap.Component
28545 * Bootstrap DocumentManager class
28546 * @cfg {String} paramName default 'imageUpload'
28547 * @cfg {String} toolTipName default 'filename'
28548 * @cfg {String} method default POST
28549 * @cfg {String} url action url
28550 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28551 * @cfg {Boolean} multiple multiple upload default true
28552 * @cfg {Number} thumbSize default 300
28553 * @cfg {String} fieldLabel
28554 * @cfg {Number} labelWidth default 4
28555 * @cfg {String} labelAlign (left|top) default left
28556 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28557 * @cfg {Number} labellg set the width of label (1-12)
28558 * @cfg {Number} labelmd set the width of label (1-12)
28559 * @cfg {Number} labelsm set the width of label (1-12)
28560 * @cfg {Number} labelxs set the width of label (1-12)
28563 * Create a new DocumentManager
28564 * @param {Object} config The config object
28567 Roo.bootstrap.DocumentManager = function(config){
28568 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28571 this.delegates = [];
28576 * Fire when initial the DocumentManager
28577 * @param {Roo.bootstrap.DocumentManager} this
28582 * inspect selected file
28583 * @param {Roo.bootstrap.DocumentManager} this
28584 * @param {File} file
28589 * Fire when xhr load exception
28590 * @param {Roo.bootstrap.DocumentManager} this
28591 * @param {XMLHttpRequest} xhr
28593 "exception" : true,
28595 * @event afterupload
28596 * Fire when xhr load exception
28597 * @param {Roo.bootstrap.DocumentManager} this
28598 * @param {XMLHttpRequest} xhr
28600 "afterupload" : true,
28603 * prepare the form data
28604 * @param {Roo.bootstrap.DocumentManager} this
28605 * @param {Object} formData
28610 * Fire when remove the file
28611 * @param {Roo.bootstrap.DocumentManager} this
28612 * @param {Object} file
28617 * Fire after refresh the file
28618 * @param {Roo.bootstrap.DocumentManager} this
28623 * Fire after click the image
28624 * @param {Roo.bootstrap.DocumentManager} this
28625 * @param {Object} file
28630 * Fire when upload a image and editable set to true
28631 * @param {Roo.bootstrap.DocumentManager} this
28632 * @param {Object} file
28636 * @event beforeselectfile
28637 * Fire before select file
28638 * @param {Roo.bootstrap.DocumentManager} this
28640 "beforeselectfile" : true,
28643 * Fire before process file
28644 * @param {Roo.bootstrap.DocumentManager} this
28645 * @param {Object} file
28649 * @event previewrendered
28650 * Fire when preview rendered
28651 * @param {Roo.bootstrap.DocumentManager} this
28652 * @param {Object} file
28654 "previewrendered" : true
28659 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28668 paramName : 'imageUpload',
28669 toolTipName : 'filename',
28672 labelAlign : 'left',
28682 getAutoCreate : function()
28684 var managerWidget = {
28686 cls : 'roo-document-manager',
28690 cls : 'roo-document-manager-selector',
28695 cls : 'roo-document-manager-uploader',
28699 cls : 'roo-document-manager-upload-btn',
28700 html : '<i class="fa fa-plus"></i>'
28711 cls : 'column col-md-12',
28716 if(this.fieldLabel.length){
28721 cls : 'column col-md-12',
28722 html : this.fieldLabel
28726 cls : 'column col-md-12',
28731 if(this.labelAlign == 'left'){
28736 html : this.fieldLabel
28745 if(this.labelWidth > 12){
28746 content[0].style = "width: " + this.labelWidth + 'px';
28749 if(this.labelWidth < 13 && this.labelmd == 0){
28750 this.labelmd = this.labelWidth;
28753 if(this.labellg > 0){
28754 content[0].cls += ' col-lg-' + this.labellg;
28755 content[1].cls += ' col-lg-' + (12 - this.labellg);
28758 if(this.labelmd > 0){
28759 content[0].cls += ' col-md-' + this.labelmd;
28760 content[1].cls += ' col-md-' + (12 - this.labelmd);
28763 if(this.labelsm > 0){
28764 content[0].cls += ' col-sm-' + this.labelsm;
28765 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28768 if(this.labelxs > 0){
28769 content[0].cls += ' col-xs-' + this.labelxs;
28770 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28778 cls : 'row clearfix',
28786 initEvents : function()
28788 this.managerEl = this.el.select('.roo-document-manager', true).first();
28789 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28791 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28792 this.selectorEl.hide();
28795 this.selectorEl.attr('multiple', 'multiple');
28798 this.selectorEl.on('change', this.onFileSelected, this);
28800 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28801 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28803 this.uploader.on('click', this.onUploaderClick, this);
28805 this.renderProgressDialog();
28809 window.addEventListener("resize", function() { _this.refresh(); } );
28811 this.fireEvent('initial', this);
28814 renderProgressDialog : function()
28818 this.progressDialog = new Roo.bootstrap.Modal({
28819 cls : 'roo-document-manager-progress-dialog',
28820 allow_close : false,
28830 btnclick : function() {
28831 _this.uploadCancel();
28837 this.progressDialog.render(Roo.get(document.body));
28839 this.progress = new Roo.bootstrap.Progress({
28840 cls : 'roo-document-manager-progress',
28845 this.progress.render(this.progressDialog.getChildContainer());
28847 this.progressBar = new Roo.bootstrap.ProgressBar({
28848 cls : 'roo-document-manager-progress-bar',
28851 aria_valuemax : 12,
28855 this.progressBar.render(this.progress.getChildContainer());
28858 onUploaderClick : function(e)
28860 e.preventDefault();
28862 if(this.fireEvent('beforeselectfile', this) != false){
28863 this.selectorEl.dom.click();
28868 onFileSelected : function(e)
28870 e.preventDefault();
28872 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28876 Roo.each(this.selectorEl.dom.files, function(file){
28877 if(this.fireEvent('inspect', this, file) != false){
28878 this.files.push(file);
28888 this.selectorEl.dom.value = '';
28890 if(!this.files || !this.files.length){
28894 if(this.boxes > 0 && this.files.length > this.boxes){
28895 this.files = this.files.slice(0, this.boxes);
28898 this.uploader.show();
28900 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28901 this.uploader.hide();
28910 Roo.each(this.files, function(file){
28912 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28913 var f = this.renderPreview(file);
28918 if(file.type.indexOf('image') != -1){
28919 this.delegates.push(
28921 _this.process(file);
28922 }).createDelegate(this)
28930 _this.process(file);
28931 }).createDelegate(this)
28936 this.files = files;
28938 this.delegates = this.delegates.concat(docs);
28940 if(!this.delegates.length){
28945 this.progressBar.aria_valuemax = this.delegates.length;
28952 arrange : function()
28954 if(!this.delegates.length){
28955 this.progressDialog.hide();
28960 var delegate = this.delegates.shift();
28962 this.progressDialog.show();
28964 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28966 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28971 refresh : function()
28973 this.uploader.show();
28975 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28976 this.uploader.hide();
28979 Roo.isTouch ? this.closable(false) : this.closable(true);
28981 this.fireEvent('refresh', this);
28984 onRemove : function(e, el, o)
28986 e.preventDefault();
28988 this.fireEvent('remove', this, o);
28992 remove : function(o)
28996 Roo.each(this.files, function(file){
28997 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29006 this.files = files;
29013 Roo.each(this.files, function(file){
29018 file.target.remove();
29027 onClick : function(e, el, o)
29029 e.preventDefault();
29031 this.fireEvent('click', this, o);
29035 closable : function(closable)
29037 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29039 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29051 xhrOnLoad : function(xhr)
29053 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29057 if (xhr.readyState !== 4) {
29059 this.fireEvent('exception', this, xhr);
29063 var response = Roo.decode(xhr.responseText);
29065 if(!response.success){
29067 this.fireEvent('exception', this, xhr);
29071 var file = this.renderPreview(response.data);
29073 this.files.push(file);
29077 this.fireEvent('afterupload', this, xhr);
29081 xhrOnError : function(xhr)
29083 Roo.log('xhr on error');
29085 var response = Roo.decode(xhr.responseText);
29092 process : function(file)
29094 if(this.fireEvent('process', this, file) !== false){
29095 if(this.editable && file.type.indexOf('image') != -1){
29096 this.fireEvent('edit', this, file);
29100 this.uploadStart(file, false);
29107 uploadStart : function(file, crop)
29109 this.xhr = new XMLHttpRequest();
29111 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29116 file.xhr = this.xhr;
29118 this.managerEl.createChild({
29120 cls : 'roo-document-manager-loading',
29124 tooltip : file.name,
29125 cls : 'roo-document-manager-thumb',
29126 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29132 this.xhr.open(this.method, this.url, true);
29135 "Accept": "application/json",
29136 "Cache-Control": "no-cache",
29137 "X-Requested-With": "XMLHttpRequest"
29140 for (var headerName in headers) {
29141 var headerValue = headers[headerName];
29143 this.xhr.setRequestHeader(headerName, headerValue);
29149 this.xhr.onload = function()
29151 _this.xhrOnLoad(_this.xhr);
29154 this.xhr.onerror = function()
29156 _this.xhrOnError(_this.xhr);
29159 var formData = new FormData();
29161 formData.append('returnHTML', 'NO');
29164 formData.append('crop', crop);
29167 formData.append(this.paramName, file, file.name);
29174 if(this.fireEvent('prepare', this, formData, options) != false){
29176 if(options.manually){
29180 this.xhr.send(formData);
29184 this.uploadCancel();
29187 uploadCancel : function()
29193 this.delegates = [];
29195 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29202 renderPreview : function(file)
29204 if(typeof(file.target) != 'undefined' && file.target){
29208 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29210 var previewEl = this.managerEl.createChild({
29212 cls : 'roo-document-manager-preview',
29216 tooltip : file[this.toolTipName],
29217 cls : 'roo-document-manager-thumb',
29218 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29223 html : '<i class="fa fa-times-circle"></i>'
29228 var close = previewEl.select('button.close', true).first();
29230 close.on('click', this.onRemove, this, file);
29232 file.target = previewEl;
29234 var image = previewEl.select('img', true).first();
29238 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29240 image.on('click', this.onClick, this, file);
29242 this.fireEvent('previewrendered', this, file);
29248 onPreviewLoad : function(file, image)
29250 if(typeof(file.target) == 'undefined' || !file.target){
29254 var width = image.dom.naturalWidth || image.dom.width;
29255 var height = image.dom.naturalHeight || image.dom.height;
29257 if(width > height){
29258 file.target.addClass('wide');
29262 file.target.addClass('tall');
29267 uploadFromSource : function(file, crop)
29269 this.xhr = new XMLHttpRequest();
29271 this.managerEl.createChild({
29273 cls : 'roo-document-manager-loading',
29277 tooltip : file.name,
29278 cls : 'roo-document-manager-thumb',
29279 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29285 this.xhr.open(this.method, this.url, true);
29288 "Accept": "application/json",
29289 "Cache-Control": "no-cache",
29290 "X-Requested-With": "XMLHttpRequest"
29293 for (var headerName in headers) {
29294 var headerValue = headers[headerName];
29296 this.xhr.setRequestHeader(headerName, headerValue);
29302 this.xhr.onload = function()
29304 _this.xhrOnLoad(_this.xhr);
29307 this.xhr.onerror = function()
29309 _this.xhrOnError(_this.xhr);
29312 var formData = new FormData();
29314 formData.append('returnHTML', 'NO');
29316 formData.append('crop', crop);
29318 if(typeof(file.filename) != 'undefined'){
29319 formData.append('filename', file.filename);
29322 if(typeof(file.mimetype) != 'undefined'){
29323 formData.append('mimetype', file.mimetype);
29328 if(this.fireEvent('prepare', this, formData) != false){
29329 this.xhr.send(formData);
29339 * @class Roo.bootstrap.DocumentViewer
29340 * @extends Roo.bootstrap.Component
29341 * Bootstrap DocumentViewer class
29342 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29343 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29346 * Create a new DocumentViewer
29347 * @param {Object} config The config object
29350 Roo.bootstrap.DocumentViewer = function(config){
29351 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29356 * Fire after initEvent
29357 * @param {Roo.bootstrap.DocumentViewer} this
29363 * @param {Roo.bootstrap.DocumentViewer} this
29368 * Fire after download button
29369 * @param {Roo.bootstrap.DocumentViewer} this
29374 * Fire after trash button
29375 * @param {Roo.bootstrap.DocumentViewer} this
29382 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29384 showDownload : true,
29388 getAutoCreate : function()
29392 cls : 'roo-document-viewer',
29396 cls : 'roo-document-viewer-body',
29400 cls : 'roo-document-viewer-thumb',
29404 cls : 'roo-document-viewer-image'
29412 cls : 'roo-document-viewer-footer',
29415 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29419 cls : 'btn-group roo-document-viewer-download',
29423 cls : 'btn btn-default',
29424 html : '<i class="fa fa-download"></i>'
29430 cls : 'btn-group roo-document-viewer-trash',
29434 cls : 'btn btn-default',
29435 html : '<i class="fa fa-trash"></i>'
29448 initEvents : function()
29450 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29451 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29453 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29454 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29456 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29457 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29459 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29460 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29462 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29463 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29465 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29466 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29468 this.bodyEl.on('click', this.onClick, this);
29469 this.downloadBtn.on('click', this.onDownload, this);
29470 this.trashBtn.on('click', this.onTrash, this);
29472 this.downloadBtn.hide();
29473 this.trashBtn.hide();
29475 if(this.showDownload){
29476 this.downloadBtn.show();
29479 if(this.showTrash){
29480 this.trashBtn.show();
29483 if(!this.showDownload && !this.showTrash) {
29484 this.footerEl.hide();
29489 initial : function()
29491 this.fireEvent('initial', this);
29495 onClick : function(e)
29497 e.preventDefault();
29499 this.fireEvent('click', this);
29502 onDownload : function(e)
29504 e.preventDefault();
29506 this.fireEvent('download', this);
29509 onTrash : function(e)
29511 e.preventDefault();
29513 this.fireEvent('trash', this);
29525 * @class Roo.bootstrap.NavProgressBar
29526 * @extends Roo.bootstrap.Component
29527 * Bootstrap NavProgressBar class
29530 * Create a new nav progress bar
29531 * @param {Object} config The config object
29534 Roo.bootstrap.NavProgressBar = function(config){
29535 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29537 this.bullets = this.bullets || [];
29539 // Roo.bootstrap.NavProgressBar.register(this);
29543 * Fires when the active item changes
29544 * @param {Roo.bootstrap.NavProgressBar} this
29545 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29546 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29553 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29558 getAutoCreate : function()
29560 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29564 cls : 'roo-navigation-bar-group',
29568 cls : 'roo-navigation-top-bar'
29572 cls : 'roo-navigation-bullets-bar',
29576 cls : 'roo-navigation-bar'
29583 cls : 'roo-navigation-bottom-bar'
29593 initEvents: function()
29598 onRender : function(ct, position)
29600 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29602 if(this.bullets.length){
29603 Roo.each(this.bullets, function(b){
29612 addItem : function(cfg)
29614 var item = new Roo.bootstrap.NavProgressItem(cfg);
29616 item.parentId = this.id;
29617 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29620 var top = new Roo.bootstrap.Element({
29622 cls : 'roo-navigation-bar-text'
29625 var bottom = new Roo.bootstrap.Element({
29627 cls : 'roo-navigation-bar-text'
29630 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29631 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29633 var topText = new Roo.bootstrap.Element({
29635 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29638 var bottomText = new Roo.bootstrap.Element({
29640 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29643 topText.onRender(top.el, null);
29644 bottomText.onRender(bottom.el, null);
29647 item.bottomEl = bottom;
29650 this.barItems.push(item);
29655 getActive : function()
29657 var active = false;
29659 Roo.each(this.barItems, function(v){
29661 if (!v.isActive()) {
29673 setActiveItem : function(item)
29677 Roo.each(this.barItems, function(v){
29678 if (v.rid == item.rid) {
29682 if (v.isActive()) {
29683 v.setActive(false);
29688 item.setActive(true);
29690 this.fireEvent('changed', this, item, prev);
29693 getBarItem: function(rid)
29697 Roo.each(this.barItems, function(e) {
29698 if (e.rid != rid) {
29709 indexOfItem : function(item)
29713 Roo.each(this.barItems, function(v, i){
29715 if (v.rid != item.rid) {
29726 setActiveNext : function()
29728 var i = this.indexOfItem(this.getActive());
29730 if (i > this.barItems.length) {
29734 this.setActiveItem(this.barItems[i+1]);
29737 setActivePrev : function()
29739 var i = this.indexOfItem(this.getActive());
29745 this.setActiveItem(this.barItems[i-1]);
29748 format : function()
29750 if(!this.barItems.length){
29754 var width = 100 / this.barItems.length;
29756 Roo.each(this.barItems, function(i){
29757 i.el.setStyle('width', width + '%');
29758 i.topEl.el.setStyle('width', width + '%');
29759 i.bottomEl.el.setStyle('width', width + '%');
29768 * Nav Progress Item
29773 * @class Roo.bootstrap.NavProgressItem
29774 * @extends Roo.bootstrap.Component
29775 * Bootstrap NavProgressItem class
29776 * @cfg {String} rid the reference id
29777 * @cfg {Boolean} active (true|false) Is item active default false
29778 * @cfg {Boolean} disabled (true|false) Is item active default false
29779 * @cfg {String} html
29780 * @cfg {String} position (top|bottom) text position default bottom
29781 * @cfg {String} icon show icon instead of number
29784 * Create a new NavProgressItem
29785 * @param {Object} config The config object
29787 Roo.bootstrap.NavProgressItem = function(config){
29788 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29793 * The raw click event for the entire grid.
29794 * @param {Roo.bootstrap.NavProgressItem} this
29795 * @param {Roo.EventObject} e
29802 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29808 position : 'bottom',
29811 getAutoCreate : function()
29813 var iconCls = 'roo-navigation-bar-item-icon';
29815 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29819 cls: 'roo-navigation-bar-item',
29829 cfg.cls += ' active';
29832 cfg.cls += ' disabled';
29838 disable : function()
29840 this.setDisabled(true);
29843 enable : function()
29845 this.setDisabled(false);
29848 initEvents: function()
29850 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29852 this.iconEl.on('click', this.onClick, this);
29855 onClick : function(e)
29857 e.preventDefault();
29863 if(this.fireEvent('click', this, e) === false){
29867 this.parent().setActiveItem(this);
29870 isActive: function ()
29872 return this.active;
29875 setActive : function(state)
29877 if(this.active == state){
29881 this.active = state;
29884 this.el.addClass('active');
29888 this.el.removeClass('active');
29893 setDisabled : function(state)
29895 if(this.disabled == state){
29899 this.disabled = state;
29902 this.el.addClass('disabled');
29906 this.el.removeClass('disabled');
29909 tooltipEl : function()
29911 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29924 * @class Roo.bootstrap.FieldLabel
29925 * @extends Roo.bootstrap.Component
29926 * Bootstrap FieldLabel class
29927 * @cfg {String} html contents of the element
29928 * @cfg {String} tag tag of the element default label
29929 * @cfg {String} cls class of the element
29930 * @cfg {String} target label target
29931 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29932 * @cfg {String} invalidClass default "text-warning"
29933 * @cfg {String} validClass default "text-success"
29934 * @cfg {String} iconTooltip default "This field is required"
29935 * @cfg {String} indicatorpos (left|right) default left
29938 * Create a new FieldLabel
29939 * @param {Object} config The config object
29942 Roo.bootstrap.FieldLabel = function(config){
29943 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29948 * Fires after the field has been marked as invalid.
29949 * @param {Roo.form.FieldLabel} this
29950 * @param {String} msg The validation message
29955 * Fires after the field has been validated with no errors.
29956 * @param {Roo.form.FieldLabel} this
29962 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29969 invalidClass : 'has-warning',
29970 validClass : 'has-success',
29971 iconTooltip : 'This field is required',
29972 indicatorpos : 'left',
29974 getAutoCreate : function(){
29978 cls : 'roo-bootstrap-field-label ' + this.cls,
29983 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29984 tooltip : this.iconTooltip
29993 if(this.indicatorpos == 'right'){
29996 cls : 'roo-bootstrap-field-label ' + this.cls,
30005 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30006 tooltip : this.iconTooltip
30015 initEvents: function()
30017 Roo.bootstrap.Element.superclass.initEvents.call(this);
30019 this.indicator = this.indicatorEl();
30021 if(this.indicator){
30022 this.indicator.removeClass('visible');
30023 this.indicator.addClass('invisible');
30026 Roo.bootstrap.FieldLabel.register(this);
30029 indicatorEl : function()
30031 var indicator = this.el.select('i.roo-required-indicator',true).first();
30042 * Mark this field as valid
30044 markValid : function()
30046 if(this.indicator){
30047 this.indicator.removeClass('visible');
30048 this.indicator.addClass('invisible');
30051 this.el.removeClass(this.invalidClass);
30053 this.el.addClass(this.validClass);
30055 this.fireEvent('valid', this);
30059 * Mark this field as invalid
30060 * @param {String} msg The validation message
30062 markInvalid : function(msg)
30064 if(this.indicator){
30065 this.indicator.removeClass('invisible');
30066 this.indicator.addClass('visible');
30069 this.el.removeClass(this.validClass);
30071 this.el.addClass(this.invalidClass);
30073 this.fireEvent('invalid', this, msg);
30079 Roo.apply(Roo.bootstrap.FieldLabel, {
30084 * register a FieldLabel Group
30085 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30087 register : function(label)
30089 if(this.groups.hasOwnProperty(label.target)){
30093 this.groups[label.target] = label;
30097 * fetch a FieldLabel Group based on the target
30098 * @param {string} target
30099 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30101 get: function(target) {
30102 if (typeof(this.groups[target]) == 'undefined') {
30106 return this.groups[target] ;
30115 * page DateSplitField.
30121 * @class Roo.bootstrap.DateSplitField
30122 * @extends Roo.bootstrap.Component
30123 * Bootstrap DateSplitField class
30124 * @cfg {string} fieldLabel - the label associated
30125 * @cfg {Number} labelWidth set the width of label (0-12)
30126 * @cfg {String} labelAlign (top|left)
30127 * @cfg {Boolean} dayAllowBlank (true|false) default false
30128 * @cfg {Boolean} monthAllowBlank (true|false) default false
30129 * @cfg {Boolean} yearAllowBlank (true|false) default false
30130 * @cfg {string} dayPlaceholder
30131 * @cfg {string} monthPlaceholder
30132 * @cfg {string} yearPlaceholder
30133 * @cfg {string} dayFormat default 'd'
30134 * @cfg {string} monthFormat default 'm'
30135 * @cfg {string} yearFormat default 'Y'
30136 * @cfg {Number} labellg set the width of label (1-12)
30137 * @cfg {Number} labelmd set the width of label (1-12)
30138 * @cfg {Number} labelsm set the width of label (1-12)
30139 * @cfg {Number} labelxs set the width of label (1-12)
30143 * Create a new DateSplitField
30144 * @param {Object} config The config object
30147 Roo.bootstrap.DateSplitField = function(config){
30148 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30154 * getting the data of years
30155 * @param {Roo.bootstrap.DateSplitField} this
30156 * @param {Object} years
30161 * getting the data of days
30162 * @param {Roo.bootstrap.DateSplitField} this
30163 * @param {Object} days
30168 * Fires after the field has been marked as invalid.
30169 * @param {Roo.form.Field} this
30170 * @param {String} msg The validation message
30175 * Fires after the field has been validated with no errors.
30176 * @param {Roo.form.Field} this
30182 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30185 labelAlign : 'top',
30187 dayAllowBlank : false,
30188 monthAllowBlank : false,
30189 yearAllowBlank : false,
30190 dayPlaceholder : '',
30191 monthPlaceholder : '',
30192 yearPlaceholder : '',
30196 isFormField : true,
30202 getAutoCreate : function()
30206 cls : 'row roo-date-split-field-group',
30211 cls : 'form-hidden-field roo-date-split-field-group-value',
30217 var labelCls = 'col-md-12';
30218 var contentCls = 'col-md-4';
30220 if(this.fieldLabel){
30224 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30228 html : this.fieldLabel
30233 if(this.labelAlign == 'left'){
30235 if(this.labelWidth > 12){
30236 label.style = "width: " + this.labelWidth + 'px';
30239 if(this.labelWidth < 13 && this.labelmd == 0){
30240 this.labelmd = this.labelWidth;
30243 if(this.labellg > 0){
30244 labelCls = ' col-lg-' + this.labellg;
30245 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30248 if(this.labelmd > 0){
30249 labelCls = ' col-md-' + this.labelmd;
30250 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30253 if(this.labelsm > 0){
30254 labelCls = ' col-sm-' + this.labelsm;
30255 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30258 if(this.labelxs > 0){
30259 labelCls = ' col-xs-' + this.labelxs;
30260 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30264 label.cls += ' ' + labelCls;
30266 cfg.cn.push(label);
30269 Roo.each(['day', 'month', 'year'], function(t){
30272 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30279 inputEl: function ()
30281 return this.el.select('.roo-date-split-field-group-value', true).first();
30284 onRender : function(ct, position)
30288 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30290 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30292 this.dayField = new Roo.bootstrap.ComboBox({
30293 allowBlank : this.dayAllowBlank,
30294 alwaysQuery : true,
30295 displayField : 'value',
30298 forceSelection : true,
30300 placeholder : this.dayPlaceholder,
30301 selectOnFocus : true,
30302 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30303 triggerAction : 'all',
30305 valueField : 'value',
30306 store : new Roo.data.SimpleStore({
30307 data : (function() {
30309 _this.fireEvent('days', _this, days);
30312 fields : [ 'value' ]
30315 select : function (_self, record, index)
30317 _this.setValue(_this.getValue());
30322 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30324 this.monthField = new Roo.bootstrap.MonthField({
30325 after : '<i class=\"fa fa-calendar\"></i>',
30326 allowBlank : this.monthAllowBlank,
30327 placeholder : this.monthPlaceholder,
30330 render : function (_self)
30332 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30333 e.preventDefault();
30337 select : function (_self, oldvalue, newvalue)
30339 _this.setValue(_this.getValue());
30344 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30346 this.yearField = new Roo.bootstrap.ComboBox({
30347 allowBlank : this.yearAllowBlank,
30348 alwaysQuery : true,
30349 displayField : 'value',
30352 forceSelection : true,
30354 placeholder : this.yearPlaceholder,
30355 selectOnFocus : true,
30356 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30357 triggerAction : 'all',
30359 valueField : 'value',
30360 store : new Roo.data.SimpleStore({
30361 data : (function() {
30363 _this.fireEvent('years', _this, years);
30366 fields : [ 'value' ]
30369 select : function (_self, record, index)
30371 _this.setValue(_this.getValue());
30376 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30379 setValue : function(v, format)
30381 this.inputEl.dom.value = v;
30383 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30385 var d = Date.parseDate(v, f);
30392 this.setDay(d.format(this.dayFormat));
30393 this.setMonth(d.format(this.monthFormat));
30394 this.setYear(d.format(this.yearFormat));
30401 setDay : function(v)
30403 this.dayField.setValue(v);
30404 this.inputEl.dom.value = this.getValue();
30409 setMonth : function(v)
30411 this.monthField.setValue(v, true);
30412 this.inputEl.dom.value = this.getValue();
30417 setYear : function(v)
30419 this.yearField.setValue(v);
30420 this.inputEl.dom.value = this.getValue();
30425 getDay : function()
30427 return this.dayField.getValue();
30430 getMonth : function()
30432 return this.monthField.getValue();
30435 getYear : function()
30437 return this.yearField.getValue();
30440 getValue : function()
30442 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30444 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30454 this.inputEl.dom.value = '';
30459 validate : function()
30461 var d = this.dayField.validate();
30462 var m = this.monthField.validate();
30463 var y = this.yearField.validate();
30468 (!this.dayAllowBlank && !d) ||
30469 (!this.monthAllowBlank && !m) ||
30470 (!this.yearAllowBlank && !y)
30475 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30484 this.markInvalid();
30489 markValid : function()
30492 var label = this.el.select('label', true).first();
30493 var icon = this.el.select('i.fa-star', true).first();
30499 this.fireEvent('valid', this);
30503 * Mark this field as invalid
30504 * @param {String} msg The validation message
30506 markInvalid : function(msg)
30509 var label = this.el.select('label', true).first();
30510 var icon = this.el.select('i.fa-star', true).first();
30512 if(label && !icon){
30513 this.el.select('.roo-date-split-field-label', true).createChild({
30515 cls : 'text-danger fa fa-lg fa-star',
30516 tooltip : 'This field is required',
30517 style : 'margin-right:5px;'
30521 this.fireEvent('invalid', this, msg);
30524 clearInvalid : function()
30526 var label = this.el.select('label', true).first();
30527 var icon = this.el.select('i.fa-star', true).first();
30533 this.fireEvent('valid', this);
30536 getName: function()
30546 * http://masonry.desandro.com
30548 * The idea is to render all the bricks based on vertical width...
30550 * The original code extends 'outlayer' - we might need to use that....
30556 * @class Roo.bootstrap.LayoutMasonry
30557 * @extends Roo.bootstrap.Component
30558 * Bootstrap Layout Masonry class
30561 * Create a new Element
30562 * @param {Object} config The config object
30565 Roo.bootstrap.LayoutMasonry = function(config){
30567 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30571 Roo.bootstrap.LayoutMasonry.register(this);
30577 * Fire after layout the items
30578 * @param {Roo.bootstrap.LayoutMasonry} this
30579 * @param {Roo.EventObject} e
30586 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30589 * @cfg {Boolean} isLayoutInstant = no animation?
30591 isLayoutInstant : false, // needed?
30594 * @cfg {Number} boxWidth width of the columns
30599 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30604 * @cfg {Number} padWidth padding below box..
30609 * @cfg {Number} gutter gutter width..
30614 * @cfg {Number} maxCols maximum number of columns
30620 * @cfg {Boolean} isAutoInitial defalut true
30622 isAutoInitial : true,
30627 * @cfg {Boolean} isHorizontal defalut false
30629 isHorizontal : false,
30631 currentSize : null,
30637 bricks: null, //CompositeElement
30641 _isLayoutInited : false,
30643 // isAlternative : false, // only use for vertical layout...
30646 * @cfg {Number} alternativePadWidth padding below box..
30648 alternativePadWidth : 50,
30650 selectedBrick : [],
30652 getAutoCreate : function(){
30654 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30658 cls: 'blog-masonary-wrapper ' + this.cls,
30660 cls : 'mas-boxes masonary'
30667 getChildContainer: function( )
30669 if (this.boxesEl) {
30670 return this.boxesEl;
30673 this.boxesEl = this.el.select('.mas-boxes').first();
30675 return this.boxesEl;
30679 initEvents : function()
30683 if(this.isAutoInitial){
30684 Roo.log('hook children rendered');
30685 this.on('childrenrendered', function() {
30686 Roo.log('children rendered');
30692 initial : function()
30694 this.selectedBrick = [];
30696 this.currentSize = this.el.getBox(true);
30698 Roo.EventManager.onWindowResize(this.resize, this);
30700 if(!this.isAutoInitial){
30708 //this.layout.defer(500,this);
30712 resize : function()
30714 var cs = this.el.getBox(true);
30717 this.currentSize.width == cs.width &&
30718 this.currentSize.x == cs.x &&
30719 this.currentSize.height == cs.height &&
30720 this.currentSize.y == cs.y
30722 Roo.log("no change in with or X or Y");
30726 this.currentSize = cs;
30732 layout : function()
30734 this._resetLayout();
30736 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30738 this.layoutItems( isInstant );
30740 this._isLayoutInited = true;
30742 this.fireEvent('layout', this);
30746 _resetLayout : function()
30748 if(this.isHorizontal){
30749 this.horizontalMeasureColumns();
30753 this.verticalMeasureColumns();
30757 verticalMeasureColumns : function()
30759 this.getContainerWidth();
30761 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30762 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30766 var boxWidth = this.boxWidth + this.padWidth;
30768 if(this.containerWidth < this.boxWidth){
30769 boxWidth = this.containerWidth
30772 var containerWidth = this.containerWidth;
30774 var cols = Math.floor(containerWidth / boxWidth);
30776 this.cols = Math.max( cols, 1 );
30778 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30780 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30782 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30784 this.colWidth = boxWidth + avail - this.padWidth;
30786 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30787 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30790 horizontalMeasureColumns : function()
30792 this.getContainerWidth();
30794 var boxWidth = this.boxWidth;
30796 if(this.containerWidth < boxWidth){
30797 boxWidth = this.containerWidth;
30800 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30802 this.el.setHeight(boxWidth);
30806 getContainerWidth : function()
30808 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30811 layoutItems : function( isInstant )
30813 Roo.log(this.bricks);
30815 var items = Roo.apply([], this.bricks);
30817 if(this.isHorizontal){
30818 this._horizontalLayoutItems( items , isInstant );
30822 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30823 // this._verticalAlternativeLayoutItems( items , isInstant );
30827 this._verticalLayoutItems( items , isInstant );
30831 _verticalLayoutItems : function ( items , isInstant)
30833 if ( !items || !items.length ) {
30838 ['xs', 'xs', 'xs', 'tall'],
30839 ['xs', 'xs', 'tall'],
30840 ['xs', 'xs', 'sm'],
30841 ['xs', 'xs', 'xs'],
30847 ['sm', 'xs', 'xs'],
30851 ['tall', 'xs', 'xs', 'xs'],
30852 ['tall', 'xs', 'xs'],
30864 Roo.each(items, function(item, k){
30866 switch (item.size) {
30867 // these layouts take up a full box,
30878 boxes.push([item]);
30901 var filterPattern = function(box, length)
30909 var pattern = box.slice(0, length);
30913 Roo.each(pattern, function(i){
30914 format.push(i.size);
30917 Roo.each(standard, function(s){
30919 if(String(s) != String(format)){
30928 if(!match && length == 1){
30933 filterPattern(box, length - 1);
30937 queue.push(pattern);
30939 box = box.slice(length, box.length);
30941 filterPattern(box, 4);
30947 Roo.each(boxes, function(box, k){
30953 if(box.length == 1){
30958 filterPattern(box, 4);
30962 this._processVerticalLayoutQueue( queue, isInstant );
30966 // _verticalAlternativeLayoutItems : function( items , isInstant )
30968 // if ( !items || !items.length ) {
30972 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30976 _horizontalLayoutItems : function ( items , isInstant)
30978 if ( !items || !items.length || items.length < 3) {
30984 var eItems = items.slice(0, 3);
30986 items = items.slice(3, items.length);
30989 ['xs', 'xs', 'xs', 'wide'],
30990 ['xs', 'xs', 'wide'],
30991 ['xs', 'xs', 'sm'],
30992 ['xs', 'xs', 'xs'],
30998 ['sm', 'xs', 'xs'],
31002 ['wide', 'xs', 'xs', 'xs'],
31003 ['wide', 'xs', 'xs'],
31016 Roo.each(items, function(item, k){
31018 switch (item.size) {
31029 boxes.push([item]);
31053 var filterPattern = function(box, length)
31061 var pattern = box.slice(0, length);
31065 Roo.each(pattern, function(i){
31066 format.push(i.size);
31069 Roo.each(standard, function(s){
31071 if(String(s) != String(format)){
31080 if(!match && length == 1){
31085 filterPattern(box, length - 1);
31089 queue.push(pattern);
31091 box = box.slice(length, box.length);
31093 filterPattern(box, 4);
31099 Roo.each(boxes, function(box, k){
31105 if(box.length == 1){
31110 filterPattern(box, 4);
31117 var pos = this.el.getBox(true);
31121 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31123 var hit_end = false;
31125 Roo.each(queue, function(box){
31129 Roo.each(box, function(b){
31131 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31141 Roo.each(box, function(b){
31143 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31146 mx = Math.max(mx, b.x);
31150 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31154 Roo.each(box, function(b){
31156 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31170 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31173 /** Sets position of item in DOM
31174 * @param {Element} item
31175 * @param {Number} x - horizontal position
31176 * @param {Number} y - vertical position
31177 * @param {Boolean} isInstant - disables transitions
31179 _processVerticalLayoutQueue : function( queue, isInstant )
31181 var pos = this.el.getBox(true);
31186 for (var i = 0; i < this.cols; i++){
31190 Roo.each(queue, function(box, k){
31192 var col = k % this.cols;
31194 Roo.each(box, function(b,kk){
31196 b.el.position('absolute');
31198 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31199 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31201 if(b.size == 'md-left' || b.size == 'md-right'){
31202 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31203 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31206 b.el.setWidth(width);
31207 b.el.setHeight(height);
31209 b.el.select('iframe',true).setSize(width,height);
31213 for (var i = 0; i < this.cols; i++){
31215 if(maxY[i] < maxY[col]){
31220 col = Math.min(col, i);
31224 x = pos.x + col * (this.colWidth + this.padWidth);
31228 var positions = [];
31230 switch (box.length){
31232 positions = this.getVerticalOneBoxColPositions(x, y, box);
31235 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31238 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31241 positions = this.getVerticalFourBoxColPositions(x, y, box);
31247 Roo.each(box, function(b,kk){
31249 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31251 var sz = b.el.getSize();
31253 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31261 for (var i = 0; i < this.cols; i++){
31262 mY = Math.max(mY, maxY[i]);
31265 this.el.setHeight(mY - pos.y);
31269 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31271 // var pos = this.el.getBox(true);
31274 // var maxX = pos.right;
31276 // var maxHeight = 0;
31278 // Roo.each(items, function(item, k){
31282 // item.el.position('absolute');
31284 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31286 // item.el.setWidth(width);
31288 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31290 // item.el.setHeight(height);
31293 // item.el.setXY([x, y], isInstant ? false : true);
31295 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31298 // y = y + height + this.alternativePadWidth;
31300 // maxHeight = maxHeight + height + this.alternativePadWidth;
31304 // this.el.setHeight(maxHeight);
31308 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31310 var pos = this.el.getBox(true);
31315 var maxX = pos.right;
31317 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31319 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31321 Roo.each(queue, function(box, k){
31323 Roo.each(box, function(b, kk){
31325 b.el.position('absolute');
31327 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31328 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31330 if(b.size == 'md-left' || b.size == 'md-right'){
31331 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31332 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31335 b.el.setWidth(width);
31336 b.el.setHeight(height);
31344 var positions = [];
31346 switch (box.length){
31348 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31351 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31354 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31357 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31363 Roo.each(box, function(b,kk){
31365 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31367 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31375 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31377 Roo.each(eItems, function(b,k){
31379 b.size = (k == 0) ? 'sm' : 'xs';
31380 b.x = (k == 0) ? 2 : 1;
31381 b.y = (k == 0) ? 2 : 1;
31383 b.el.position('absolute');
31385 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31387 b.el.setWidth(width);
31389 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31391 b.el.setHeight(height);
31395 var positions = [];
31398 x : maxX - this.unitWidth * 2 - this.gutter,
31403 x : maxX - this.unitWidth,
31404 y : minY + (this.unitWidth + this.gutter) * 2
31408 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31412 Roo.each(eItems, function(b,k){
31414 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31420 getVerticalOneBoxColPositions : function(x, y, box)
31424 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31426 if(box[0].size == 'md-left'){
31430 if(box[0].size == 'md-right'){
31435 x : x + (this.unitWidth + this.gutter) * rand,
31442 getVerticalTwoBoxColPositions : function(x, y, box)
31446 if(box[0].size == 'xs'){
31450 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31454 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31468 x : x + (this.unitWidth + this.gutter) * 2,
31469 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31476 getVerticalThreeBoxColPositions : function(x, y, box)
31480 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31488 x : x + (this.unitWidth + this.gutter) * 1,
31493 x : x + (this.unitWidth + this.gutter) * 2,
31501 if(box[0].size == 'xs' && box[1].size == 'xs'){
31510 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31514 x : x + (this.unitWidth + this.gutter) * 1,
31528 x : x + (this.unitWidth + this.gutter) * 2,
31533 x : x + (this.unitWidth + this.gutter) * 2,
31534 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31541 getVerticalFourBoxColPositions : function(x, y, box)
31545 if(box[0].size == 'xs'){
31554 y : y + (this.unitHeight + this.gutter) * 1
31559 y : y + (this.unitHeight + this.gutter) * 2
31563 x : x + (this.unitWidth + this.gutter) * 1,
31577 x : x + (this.unitWidth + this.gutter) * 2,
31582 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31583 y : y + (this.unitHeight + this.gutter) * 1
31587 x : x + (this.unitWidth + this.gutter) * 2,
31588 y : y + (this.unitWidth + this.gutter) * 2
31595 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31599 if(box[0].size == 'md-left'){
31601 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31608 if(box[0].size == 'md-right'){
31610 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31611 y : minY + (this.unitWidth + this.gutter) * 1
31617 var rand = Math.floor(Math.random() * (4 - box[0].y));
31620 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31621 y : minY + (this.unitWidth + this.gutter) * rand
31628 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31632 if(box[0].size == 'xs'){
31635 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31640 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31641 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31649 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31654 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31655 y : minY + (this.unitWidth + this.gutter) * 2
31662 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31666 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31669 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31674 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31675 y : minY + (this.unitWidth + this.gutter) * 1
31679 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31680 y : minY + (this.unitWidth + this.gutter) * 2
31687 if(box[0].size == 'xs' && box[1].size == 'xs'){
31690 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31695 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31700 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31701 y : minY + (this.unitWidth + this.gutter) * 1
31709 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31714 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31715 y : minY + (this.unitWidth + this.gutter) * 2
31719 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31720 y : minY + (this.unitWidth + this.gutter) * 2
31727 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31731 if(box[0].size == 'xs'){
31734 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31739 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31744 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),
31749 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31750 y : minY + (this.unitWidth + this.gutter) * 1
31758 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31763 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31764 y : minY + (this.unitWidth + this.gutter) * 2
31768 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31769 y : minY + (this.unitWidth + this.gutter) * 2
31773 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),
31774 y : minY + (this.unitWidth + this.gutter) * 2
31782 * remove a Masonry Brick
31783 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31785 removeBrick : function(brick_id)
31791 for (var i = 0; i<this.bricks.length; i++) {
31792 if (this.bricks[i].id == brick_id) {
31793 this.bricks.splice(i,1);
31794 this.el.dom.removeChild(Roo.get(brick_id).dom);
31801 * adds a Masonry Brick
31802 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31804 addBrick : function(cfg)
31806 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31807 //this.register(cn);
31808 cn.parentId = this.id;
31809 cn.onRender(this.el, null);
31814 * register a Masonry Brick
31815 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31818 register : function(brick)
31820 this.bricks.push(brick);
31821 brick.masonryId = this.id;
31825 * clear all the Masonry Brick
31827 clearAll : function()
31830 //this.getChildContainer().dom.innerHTML = "";
31831 this.el.dom.innerHTML = '';
31834 getSelected : function()
31836 if (!this.selectedBrick) {
31840 return this.selectedBrick;
31844 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31848 * register a Masonry Layout
31849 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31852 register : function(layout)
31854 this.groups[layout.id] = layout;
31857 * fetch a Masonry Layout based on the masonry layout ID
31858 * @param {string} the masonry layout to add
31859 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31862 get: function(layout_id) {
31863 if (typeof(this.groups[layout_id]) == 'undefined') {
31866 return this.groups[layout_id] ;
31878 * http://masonry.desandro.com
31880 * The idea is to render all the bricks based on vertical width...
31882 * The original code extends 'outlayer' - we might need to use that....
31888 * @class Roo.bootstrap.LayoutMasonryAuto
31889 * @extends Roo.bootstrap.Component
31890 * Bootstrap Layout Masonry class
31893 * Create a new Element
31894 * @param {Object} config The config object
31897 Roo.bootstrap.LayoutMasonryAuto = function(config){
31898 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31901 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31904 * @cfg {Boolean} isFitWidth - resize the width..
31906 isFitWidth : false, // options..
31908 * @cfg {Boolean} isOriginLeft = left align?
31910 isOriginLeft : true,
31912 * @cfg {Boolean} isOriginTop = top align?
31914 isOriginTop : false,
31916 * @cfg {Boolean} isLayoutInstant = no animation?
31918 isLayoutInstant : false, // needed?
31920 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31922 isResizingContainer : true,
31924 * @cfg {Number} columnWidth width of the columns
31930 * @cfg {Number} maxCols maximum number of columns
31935 * @cfg {Number} padHeight padding below box..
31941 * @cfg {Boolean} isAutoInitial defalut true
31944 isAutoInitial : true,
31950 initialColumnWidth : 0,
31951 currentSize : null,
31953 colYs : null, // array.
31960 bricks: null, //CompositeElement
31961 cols : 0, // array?
31962 // element : null, // wrapped now this.el
31963 _isLayoutInited : null,
31966 getAutoCreate : function(){
31970 cls: 'blog-masonary-wrapper ' + this.cls,
31972 cls : 'mas-boxes masonary'
31979 getChildContainer: function( )
31981 if (this.boxesEl) {
31982 return this.boxesEl;
31985 this.boxesEl = this.el.select('.mas-boxes').first();
31987 return this.boxesEl;
31991 initEvents : function()
31995 if(this.isAutoInitial){
31996 Roo.log('hook children rendered');
31997 this.on('childrenrendered', function() {
31998 Roo.log('children rendered');
32005 initial : function()
32007 this.reloadItems();
32009 this.currentSize = this.el.getBox(true);
32011 /// was window resize... - let's see if this works..
32012 Roo.EventManager.onWindowResize(this.resize, this);
32014 if(!this.isAutoInitial){
32019 this.layout.defer(500,this);
32022 reloadItems: function()
32024 this.bricks = this.el.select('.masonry-brick', true);
32026 this.bricks.each(function(b) {
32027 //Roo.log(b.getSize());
32028 if (!b.attr('originalwidth')) {
32029 b.attr('originalwidth', b.getSize().width);
32034 Roo.log(this.bricks.elements.length);
32037 resize : function()
32040 var cs = this.el.getBox(true);
32042 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32043 Roo.log("no change in with or X");
32046 this.currentSize = cs;
32050 layout : function()
32053 this._resetLayout();
32054 //this._manageStamps();
32056 // don't animate first layout
32057 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32058 this.layoutItems( isInstant );
32060 // flag for initalized
32061 this._isLayoutInited = true;
32064 layoutItems : function( isInstant )
32066 //var items = this._getItemsForLayout( this.items );
32067 // original code supports filtering layout items.. we just ignore it..
32069 this._layoutItems( this.bricks , isInstant );
32071 this._postLayout();
32073 _layoutItems : function ( items , isInstant)
32075 //this.fireEvent( 'layout', this, items );
32078 if ( !items || !items.elements.length ) {
32079 // no items, emit event with empty array
32084 items.each(function(item) {
32085 Roo.log("layout item");
32087 // get x/y object from method
32088 var position = this._getItemLayoutPosition( item );
32090 position.item = item;
32091 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32092 queue.push( position );
32095 this._processLayoutQueue( queue );
32097 /** Sets position of item in DOM
32098 * @param {Element} item
32099 * @param {Number} x - horizontal position
32100 * @param {Number} y - vertical position
32101 * @param {Boolean} isInstant - disables transitions
32103 _processLayoutQueue : function( queue )
32105 for ( var i=0, len = queue.length; i < len; i++ ) {
32106 var obj = queue[i];
32107 obj.item.position('absolute');
32108 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32114 * Any logic you want to do after each layout,
32115 * i.e. size the container
32117 _postLayout : function()
32119 this.resizeContainer();
32122 resizeContainer : function()
32124 if ( !this.isResizingContainer ) {
32127 var size = this._getContainerSize();
32129 this.el.setSize(size.width,size.height);
32130 this.boxesEl.setSize(size.width,size.height);
32136 _resetLayout : function()
32138 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32139 this.colWidth = this.el.getWidth();
32140 //this.gutter = this.el.getWidth();
32142 this.measureColumns();
32148 this.colYs.push( 0 );
32154 measureColumns : function()
32156 this.getContainerWidth();
32157 // if columnWidth is 0, default to outerWidth of first item
32158 if ( !this.columnWidth ) {
32159 var firstItem = this.bricks.first();
32160 Roo.log(firstItem);
32161 this.columnWidth = this.containerWidth;
32162 if (firstItem && firstItem.attr('originalwidth') ) {
32163 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32165 // columnWidth fall back to item of first element
32166 Roo.log("set column width?");
32167 this.initialColumnWidth = this.columnWidth ;
32169 // if first elem has no width, default to size of container
32174 if (this.initialColumnWidth) {
32175 this.columnWidth = this.initialColumnWidth;
32180 // column width is fixed at the top - however if container width get's smaller we should
32183 // this bit calcs how man columns..
32185 var columnWidth = this.columnWidth += this.gutter;
32187 // calculate columns
32188 var containerWidth = this.containerWidth + this.gutter;
32190 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32191 // fix rounding errors, typically with gutters
32192 var excess = columnWidth - containerWidth % columnWidth;
32195 // if overshoot is less than a pixel, round up, otherwise floor it
32196 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32197 cols = Math[ mathMethod ]( cols );
32198 this.cols = Math.max( cols, 1 );
32199 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32201 // padding positioning..
32202 var totalColWidth = this.cols * this.columnWidth;
32203 var padavail = this.containerWidth - totalColWidth;
32204 // so for 2 columns - we need 3 'pads'
32206 var padNeeded = (1+this.cols) * this.padWidth;
32208 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32210 this.columnWidth += padExtra
32211 //this.padWidth = Math.floor(padavail / ( this.cols));
32213 // adjust colum width so that padding is fixed??
32215 // we have 3 columns ... total = width * 3
32216 // we have X left over... that should be used by
32218 //if (this.expandC) {
32226 getContainerWidth : function()
32228 /* // container is parent if fit width
32229 var container = this.isFitWidth ? this.element.parentNode : this.element;
32230 // check that this.size and size are there
32231 // IE8 triggers resize on body size change, so they might not be
32233 var size = getSize( container ); //FIXME
32234 this.containerWidth = size && size.innerWidth; //FIXME
32237 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32241 _getItemLayoutPosition : function( item ) // what is item?
32243 // we resize the item to our columnWidth..
32245 item.setWidth(this.columnWidth);
32246 item.autoBoxAdjust = false;
32248 var sz = item.getSize();
32250 // how many columns does this brick span
32251 var remainder = this.containerWidth % this.columnWidth;
32253 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32254 // round if off by 1 pixel, otherwise use ceil
32255 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32256 colSpan = Math.min( colSpan, this.cols );
32258 // normally this should be '1' as we dont' currently allow multi width columns..
32260 var colGroup = this._getColGroup( colSpan );
32261 // get the minimum Y value from the columns
32262 var minimumY = Math.min.apply( Math, colGroup );
32263 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32265 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32267 // position the brick
32269 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32270 y: this.currentSize.y + minimumY + this.padHeight
32274 // apply setHeight to necessary columns
32275 var setHeight = minimumY + sz.height + this.padHeight;
32276 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32278 var setSpan = this.cols + 1 - colGroup.length;
32279 for ( var i = 0; i < setSpan; i++ ) {
32280 this.colYs[ shortColIndex + i ] = setHeight ;
32287 * @param {Number} colSpan - number of columns the element spans
32288 * @returns {Array} colGroup
32290 _getColGroup : function( colSpan )
32292 if ( colSpan < 2 ) {
32293 // if brick spans only one column, use all the column Ys
32298 // how many different places could this brick fit horizontally
32299 var groupCount = this.cols + 1 - colSpan;
32300 // for each group potential horizontal position
32301 for ( var i = 0; i < groupCount; i++ ) {
32302 // make an array of colY values for that one group
32303 var groupColYs = this.colYs.slice( i, i + colSpan );
32304 // and get the max value of the array
32305 colGroup[i] = Math.max.apply( Math, groupColYs );
32310 _manageStamp : function( stamp )
32312 var stampSize = stamp.getSize();
32313 var offset = stamp.getBox();
32314 // get the columns that this stamp affects
32315 var firstX = this.isOriginLeft ? offset.x : offset.right;
32316 var lastX = firstX + stampSize.width;
32317 var firstCol = Math.floor( firstX / this.columnWidth );
32318 firstCol = Math.max( 0, firstCol );
32320 var lastCol = Math.floor( lastX / this.columnWidth );
32321 // lastCol should not go over if multiple of columnWidth #425
32322 lastCol -= lastX % this.columnWidth ? 0 : 1;
32323 lastCol = Math.min( this.cols - 1, lastCol );
32325 // set colYs to bottom of the stamp
32326 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32329 for ( var i = firstCol; i <= lastCol; i++ ) {
32330 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32335 _getContainerSize : function()
32337 this.maxY = Math.max.apply( Math, this.colYs );
32342 if ( this.isFitWidth ) {
32343 size.width = this._getContainerFitWidth();
32349 _getContainerFitWidth : function()
32351 var unusedCols = 0;
32352 // count unused columns
32355 if ( this.colYs[i] !== 0 ) {
32360 // fit container to columns that have been used
32361 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32364 needsResizeLayout : function()
32366 var previousWidth = this.containerWidth;
32367 this.getContainerWidth();
32368 return previousWidth !== this.containerWidth;
32383 * @class Roo.bootstrap.MasonryBrick
32384 * @extends Roo.bootstrap.Component
32385 * Bootstrap MasonryBrick class
32388 * Create a new MasonryBrick
32389 * @param {Object} config The config object
32392 Roo.bootstrap.MasonryBrick = function(config){
32394 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32396 Roo.bootstrap.MasonryBrick.register(this);
32402 * When a MasonryBrick is clcik
32403 * @param {Roo.bootstrap.MasonryBrick} this
32404 * @param {Roo.EventObject} e
32410 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32413 * @cfg {String} title
32417 * @cfg {String} html
32421 * @cfg {String} bgimage
32425 * @cfg {String} videourl
32429 * @cfg {String} cls
32433 * @cfg {String} href
32437 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32442 * @cfg {String} placetitle (center|bottom)
32447 * @cfg {Boolean} isFitContainer defalut true
32449 isFitContainer : true,
32452 * @cfg {Boolean} preventDefault defalut false
32454 preventDefault : false,
32457 * @cfg {Boolean} inverse defalut false
32459 maskInverse : false,
32461 getAutoCreate : function()
32463 if(!this.isFitContainer){
32464 return this.getSplitAutoCreate();
32467 var cls = 'masonry-brick masonry-brick-full';
32469 if(this.href.length){
32470 cls += ' masonry-brick-link';
32473 if(this.bgimage.length){
32474 cls += ' masonry-brick-image';
32477 if(this.maskInverse){
32478 cls += ' mask-inverse';
32481 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32482 cls += ' enable-mask';
32486 cls += ' masonry-' + this.size + '-brick';
32489 if(this.placetitle.length){
32491 switch (this.placetitle) {
32493 cls += ' masonry-center-title';
32496 cls += ' masonry-bottom-title';
32503 if(!this.html.length && !this.bgimage.length){
32504 cls += ' masonry-center-title';
32507 if(!this.html.length && this.bgimage.length){
32508 cls += ' masonry-bottom-title';
32513 cls += ' ' + this.cls;
32517 tag: (this.href.length) ? 'a' : 'div',
32522 cls: 'masonry-brick-mask'
32526 cls: 'masonry-brick-paragraph',
32532 if(this.href.length){
32533 cfg.href = this.href;
32536 var cn = cfg.cn[1].cn;
32538 if(this.title.length){
32541 cls: 'masonry-brick-title',
32546 if(this.html.length){
32549 cls: 'masonry-brick-text',
32554 if (!this.title.length && !this.html.length) {
32555 cfg.cn[1].cls += ' hide';
32558 if(this.bgimage.length){
32561 cls: 'masonry-brick-image-view',
32566 if(this.videourl.length){
32567 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32568 // youtube support only?
32571 cls: 'masonry-brick-image-view',
32574 allowfullscreen : true
32582 getSplitAutoCreate : function()
32584 var cls = 'masonry-brick masonry-brick-split';
32586 if(this.href.length){
32587 cls += ' masonry-brick-link';
32590 if(this.bgimage.length){
32591 cls += ' masonry-brick-image';
32595 cls += ' masonry-' + this.size + '-brick';
32598 switch (this.placetitle) {
32600 cls += ' masonry-center-title';
32603 cls += ' masonry-bottom-title';
32606 if(!this.bgimage.length){
32607 cls += ' masonry-center-title';
32610 if(this.bgimage.length){
32611 cls += ' masonry-bottom-title';
32617 cls += ' ' + this.cls;
32621 tag: (this.href.length) ? 'a' : 'div',
32626 cls: 'masonry-brick-split-head',
32630 cls: 'masonry-brick-paragraph',
32637 cls: 'masonry-brick-split-body',
32643 if(this.href.length){
32644 cfg.href = this.href;
32647 if(this.title.length){
32648 cfg.cn[0].cn[0].cn.push({
32650 cls: 'masonry-brick-title',
32655 if(this.html.length){
32656 cfg.cn[1].cn.push({
32658 cls: 'masonry-brick-text',
32663 if(this.bgimage.length){
32664 cfg.cn[0].cn.push({
32666 cls: 'masonry-brick-image-view',
32671 if(this.videourl.length){
32672 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32673 // youtube support only?
32674 cfg.cn[0].cn.cn.push({
32676 cls: 'masonry-brick-image-view',
32679 allowfullscreen : true
32686 initEvents: function()
32688 switch (this.size) {
32721 this.el.on('touchstart', this.onTouchStart, this);
32722 this.el.on('touchmove', this.onTouchMove, this);
32723 this.el.on('touchend', this.onTouchEnd, this);
32724 this.el.on('contextmenu', this.onContextMenu, this);
32726 this.el.on('mouseenter' ,this.enter, this);
32727 this.el.on('mouseleave', this.leave, this);
32728 this.el.on('click', this.onClick, this);
32731 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32732 this.parent().bricks.push(this);
32737 onClick: function(e, el)
32739 var time = this.endTimer - this.startTimer;
32740 // Roo.log(e.preventDefault());
32743 e.preventDefault();
32748 if(!this.preventDefault){
32752 e.preventDefault();
32754 if (this.activeClass != '') {
32755 this.selectBrick();
32758 this.fireEvent('click', this, e);
32761 enter: function(e, el)
32763 e.preventDefault();
32765 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32769 if(this.bgimage.length && this.html.length){
32770 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32774 leave: function(e, el)
32776 e.preventDefault();
32778 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32782 if(this.bgimage.length && this.html.length){
32783 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32787 onTouchStart: function(e, el)
32789 // e.preventDefault();
32791 this.touchmoved = false;
32793 if(!this.isFitContainer){
32797 if(!this.bgimage.length || !this.html.length){
32801 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32803 this.timer = new Date().getTime();
32807 onTouchMove: function(e, el)
32809 this.touchmoved = true;
32812 onContextMenu : function(e,el)
32814 e.preventDefault();
32815 e.stopPropagation();
32819 onTouchEnd: function(e, el)
32821 // e.preventDefault();
32823 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32830 if(!this.bgimage.length || !this.html.length){
32832 if(this.href.length){
32833 window.location.href = this.href;
32839 if(!this.isFitContainer){
32843 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32845 window.location.href = this.href;
32848 //selection on single brick only
32849 selectBrick : function() {
32851 if (!this.parentId) {
32855 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32856 var index = m.selectedBrick.indexOf(this.id);
32859 m.selectedBrick.splice(index,1);
32860 this.el.removeClass(this.activeClass);
32864 for(var i = 0; i < m.selectedBrick.length; i++) {
32865 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32866 b.el.removeClass(b.activeClass);
32869 m.selectedBrick = [];
32871 m.selectedBrick.push(this.id);
32872 this.el.addClass(this.activeClass);
32876 isSelected : function(){
32877 return this.el.hasClass(this.activeClass);
32882 Roo.apply(Roo.bootstrap.MasonryBrick, {
32885 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32887 * register a Masonry Brick
32888 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32891 register : function(brick)
32893 //this.groups[brick.id] = brick;
32894 this.groups.add(brick.id, brick);
32897 * fetch a masonry brick based on the masonry brick ID
32898 * @param {string} the masonry brick to add
32899 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32902 get: function(brick_id)
32904 // if (typeof(this.groups[brick_id]) == 'undefined') {
32907 // return this.groups[brick_id] ;
32909 if(this.groups.key(brick_id)) {
32910 return this.groups.key(brick_id);
32928 * @class Roo.bootstrap.Brick
32929 * @extends Roo.bootstrap.Component
32930 * Bootstrap Brick class
32933 * Create a new Brick
32934 * @param {Object} config The config object
32937 Roo.bootstrap.Brick = function(config){
32938 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32944 * When a Brick is click
32945 * @param {Roo.bootstrap.Brick} this
32946 * @param {Roo.EventObject} e
32952 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32955 * @cfg {String} title
32959 * @cfg {String} html
32963 * @cfg {String} bgimage
32967 * @cfg {String} cls
32971 * @cfg {String} href
32975 * @cfg {String} video
32979 * @cfg {Boolean} square
32983 getAutoCreate : function()
32985 var cls = 'roo-brick';
32987 if(this.href.length){
32988 cls += ' roo-brick-link';
32991 if(this.bgimage.length){
32992 cls += ' roo-brick-image';
32995 if(!this.html.length && !this.bgimage.length){
32996 cls += ' roo-brick-center-title';
32999 if(!this.html.length && this.bgimage.length){
33000 cls += ' roo-brick-bottom-title';
33004 cls += ' ' + this.cls;
33008 tag: (this.href.length) ? 'a' : 'div',
33013 cls: 'roo-brick-paragraph',
33019 if(this.href.length){
33020 cfg.href = this.href;
33023 var cn = cfg.cn[0].cn;
33025 if(this.title.length){
33028 cls: 'roo-brick-title',
33033 if(this.html.length){
33036 cls: 'roo-brick-text',
33043 if(this.bgimage.length){
33046 cls: 'roo-brick-image-view',
33054 initEvents: function()
33056 if(this.title.length || this.html.length){
33057 this.el.on('mouseenter' ,this.enter, this);
33058 this.el.on('mouseleave', this.leave, this);
33061 Roo.EventManager.onWindowResize(this.resize, this);
33063 if(this.bgimage.length){
33064 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33065 this.imageEl.on('load', this.onImageLoad, this);
33072 onImageLoad : function()
33077 resize : function()
33079 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33081 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33083 if(this.bgimage.length){
33084 var image = this.el.select('.roo-brick-image-view', true).first();
33086 image.setWidth(paragraph.getWidth());
33089 image.setHeight(paragraph.getWidth());
33092 this.el.setHeight(image.getHeight());
33093 paragraph.setHeight(image.getHeight());
33099 enter: function(e, el)
33101 e.preventDefault();
33103 if(this.bgimage.length){
33104 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33105 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33109 leave: function(e, el)
33111 e.preventDefault();
33113 if(this.bgimage.length){
33114 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33115 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33130 * @class Roo.bootstrap.NumberField
33131 * @extends Roo.bootstrap.Input
33132 * Bootstrap NumberField class
33138 * Create a new NumberField
33139 * @param {Object} config The config object
33142 Roo.bootstrap.NumberField = function(config){
33143 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33146 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33149 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33151 allowDecimals : true,
33153 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33155 decimalSeparator : ".",
33157 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33159 decimalPrecision : 2,
33161 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33163 allowNegative : true,
33166 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33170 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33172 minValue : Number.NEGATIVE_INFINITY,
33174 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33176 maxValue : Number.MAX_VALUE,
33178 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33180 minText : "The minimum value for this field is {0}",
33182 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33184 maxText : "The maximum value for this field is {0}",
33186 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33187 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33189 nanText : "{0} is not a valid number",
33191 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33195 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33197 thousandsDelimiter : false,
33199 * @cfg {String} valueAlign alignment of value
33201 valueAlign : "left",
33203 getAutoCreate : function()
33205 var hiddenInput = {
33209 cls: 'hidden-number-input'
33213 hiddenInput.name = this.name;
33218 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33220 this.name = hiddenInput.name;
33222 if(cfg.cn.length > 0) {
33223 cfg.cn.push(hiddenInput);
33230 initEvents : function()
33232 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33234 var allowed = "0123456789";
33236 if(this.allowDecimals){
33237 allowed += this.decimalSeparator;
33240 if(this.allowNegative){
33244 if(this.thousandsDelimiter) {
33248 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33250 var keyPress = function(e){
33252 var k = e.getKey();
33254 var c = e.getCharCode();
33257 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33258 allowed.indexOf(String.fromCharCode(c)) === -1
33264 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33268 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33273 this.el.on("keypress", keyPress, this);
33276 validateValue : function(value)
33279 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33283 var num = this.parseValue(value);
33286 this.markInvalid(String.format(this.nanText, value));
33290 if(num < this.minValue){
33291 this.markInvalid(String.format(this.minText, this.minValue));
33295 if(num > this.maxValue){
33296 this.markInvalid(String.format(this.maxText, this.maxValue));
33303 getValue : function()
33305 var v = this.hiddenEl().getValue();
33307 return this.fixPrecision(this.parseValue(v));
33310 parseValue : function(value)
33312 if(this.thousandsDelimiter) {
33314 r = new RegExp(",", "g");
33315 value = value.replace(r, "");
33318 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33319 return isNaN(value) ? '' : value;
33322 fixPrecision : function(value)
33324 if(this.thousandsDelimiter) {
33326 r = new RegExp(",", "g");
33327 value = value.replace(r, "");
33330 var nan = isNaN(value);
33332 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33333 return nan ? '' : value;
33335 return parseFloat(value).toFixed(this.decimalPrecision);
33338 setValue : function(v)
33340 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33346 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33348 this.inputEl().dom.value = (v == '') ? '' :
33349 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33351 if(!this.allowZero && v === '0') {
33352 this.hiddenEl().dom.value = '';
33353 this.inputEl().dom.value = '';
33360 decimalPrecisionFcn : function(v)
33362 return Math.floor(v);
33365 beforeBlur : function()
33371 var v = this.parseValue(this.getRawValue());
33378 hiddenEl : function()
33380 return this.el.select('input.hidden-number-input',true).first();
33392 * @class Roo.bootstrap.DocumentSlider
33393 * @extends Roo.bootstrap.Component
33394 * Bootstrap DocumentSlider class
33397 * Create a new DocumentViewer
33398 * @param {Object} config The config object
33401 Roo.bootstrap.DocumentSlider = function(config){
33402 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33409 * Fire after initEvent
33410 * @param {Roo.bootstrap.DocumentSlider} this
33415 * Fire after update
33416 * @param {Roo.bootstrap.DocumentSlider} this
33422 * @param {Roo.bootstrap.DocumentSlider} this
33428 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33434 getAutoCreate : function()
33438 cls : 'roo-document-slider',
33442 cls : 'roo-document-slider-header',
33446 cls : 'roo-document-slider-header-title'
33452 cls : 'roo-document-slider-body',
33456 cls : 'roo-document-slider-prev',
33460 cls : 'fa fa-chevron-left'
33466 cls : 'roo-document-slider-thumb',
33470 cls : 'roo-document-slider-image'
33476 cls : 'roo-document-slider-next',
33480 cls : 'fa fa-chevron-right'
33492 initEvents : function()
33494 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33495 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33497 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33498 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33500 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33501 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33503 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33504 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33506 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33507 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33509 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33510 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33512 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33513 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33515 this.thumbEl.on('click', this.onClick, this);
33517 this.prevIndicator.on('click', this.prev, this);
33519 this.nextIndicator.on('click', this.next, this);
33523 initial : function()
33525 if(this.files.length){
33526 this.indicator = 1;
33530 this.fireEvent('initial', this);
33533 update : function()
33535 this.imageEl.attr('src', this.files[this.indicator - 1]);
33537 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33539 this.prevIndicator.show();
33541 if(this.indicator == 1){
33542 this.prevIndicator.hide();
33545 this.nextIndicator.show();
33547 if(this.indicator == this.files.length){
33548 this.nextIndicator.hide();
33551 this.thumbEl.scrollTo('top');
33553 this.fireEvent('update', this);
33556 onClick : function(e)
33558 e.preventDefault();
33560 this.fireEvent('click', this);
33565 e.preventDefault();
33567 this.indicator = Math.max(1, this.indicator - 1);
33574 e.preventDefault();
33576 this.indicator = Math.min(this.files.length, this.indicator + 1);
33590 * @class Roo.bootstrap.RadioSet
33591 * @extends Roo.bootstrap.Input
33592 * Bootstrap RadioSet class
33593 * @cfg {String} indicatorpos (left|right) default left
33594 * @cfg {Boolean} inline (true|false) inline the element (default true)
33595 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33597 * Create a new RadioSet
33598 * @param {Object} config The config object
33601 Roo.bootstrap.RadioSet = function(config){
33603 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33607 Roo.bootstrap.RadioSet.register(this);
33612 * Fires when the element is checked or unchecked.
33613 * @param {Roo.bootstrap.RadioSet} this This radio
33614 * @param {Roo.bootstrap.Radio} item The checked item
33619 * Fires when the element is click.
33620 * @param {Roo.bootstrap.RadioSet} this This radio set
33621 * @param {Roo.bootstrap.Radio} item The checked item
33622 * @param {Roo.EventObject} e The event object
33629 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33637 indicatorpos : 'left',
33639 getAutoCreate : function()
33643 cls : 'roo-radio-set-label',
33647 html : this.fieldLabel
33652 if(this.indicatorpos == 'left'){
33655 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33656 tooltip : 'This field is required'
33661 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33662 tooltip : 'This field is required'
33668 cls : 'roo-radio-set-items'
33671 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33673 if (align === 'left' && this.fieldLabel.length) {
33676 cls : "roo-radio-set-right",
33682 if(this.labelWidth > 12){
33683 label.style = "width: " + this.labelWidth + 'px';
33686 if(this.labelWidth < 13 && this.labelmd == 0){
33687 this.labelmd = this.labelWidth;
33690 if(this.labellg > 0){
33691 label.cls += ' col-lg-' + this.labellg;
33692 items.cls += ' col-lg-' + (12 - this.labellg);
33695 if(this.labelmd > 0){
33696 label.cls += ' col-md-' + this.labelmd;
33697 items.cls += ' col-md-' + (12 - this.labelmd);
33700 if(this.labelsm > 0){
33701 label.cls += ' col-sm-' + this.labelsm;
33702 items.cls += ' col-sm-' + (12 - this.labelsm);
33705 if(this.labelxs > 0){
33706 label.cls += ' col-xs-' + this.labelxs;
33707 items.cls += ' col-xs-' + (12 - this.labelxs);
33713 cls : 'roo-radio-set',
33717 cls : 'roo-radio-set-input',
33720 value : this.value ? this.value : ''
33727 if(this.weight.length){
33728 cfg.cls += ' roo-radio-' + this.weight;
33732 cfg.cls += ' roo-radio-set-inline';
33736 ['xs','sm','md','lg'].map(function(size){
33737 if (settings[size]) {
33738 cfg.cls += ' col-' + size + '-' + settings[size];
33746 initEvents : function()
33748 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33749 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33751 if(!this.fieldLabel.length){
33752 this.labelEl.hide();
33755 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33756 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33758 this.indicator = this.indicatorEl();
33760 if(this.indicator){
33761 this.indicator.addClass('invisible');
33764 this.originalValue = this.getValue();
33768 inputEl: function ()
33770 return this.el.select('.roo-radio-set-input', true).first();
33773 getChildContainer : function()
33775 return this.itemsEl;
33778 register : function(item)
33780 this.radioes.push(item);
33784 validate : function()
33786 if(this.getVisibilityEl().hasClass('hidden')){
33792 Roo.each(this.radioes, function(i){
33801 if(this.allowBlank) {
33805 if(this.disabled || valid){
33810 this.markInvalid();
33815 markValid : function()
33817 if(this.labelEl.isVisible(true)){
33818 this.indicatorEl().removeClass('visible');
33819 this.indicatorEl().addClass('invisible');
33822 this.el.removeClass([this.invalidClass, this.validClass]);
33823 this.el.addClass(this.validClass);
33825 this.fireEvent('valid', this);
33828 markInvalid : function(msg)
33830 if(this.allowBlank || this.disabled){
33834 if(this.labelEl.isVisible(true)){
33835 this.indicatorEl().removeClass('invisible');
33836 this.indicatorEl().addClass('visible');
33839 this.el.removeClass([this.invalidClass, this.validClass]);
33840 this.el.addClass(this.invalidClass);
33842 this.fireEvent('invalid', this, msg);
33846 setValue : function(v, suppressEvent)
33848 if(this.value === v){
33855 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33858 Roo.each(this.radioes, function(i){
33860 i.el.removeClass('checked');
33863 Roo.each(this.radioes, function(i){
33865 if(i.value === v || i.value.toString() === v.toString()){
33867 i.el.addClass('checked');
33869 if(suppressEvent !== true){
33870 this.fireEvent('check', this, i);
33881 clearInvalid : function(){
33883 if(!this.el || this.preventMark){
33887 this.el.removeClass([this.invalidClass]);
33889 this.fireEvent('valid', this);
33894 Roo.apply(Roo.bootstrap.RadioSet, {
33898 register : function(set)
33900 this.groups[set.name] = set;
33903 get: function(name)
33905 if (typeof(this.groups[name]) == 'undefined') {
33909 return this.groups[name] ;
33915 * Ext JS Library 1.1.1
33916 * Copyright(c) 2006-2007, Ext JS, LLC.
33918 * Originally Released Under LGPL - original licence link has changed is not relivant.
33921 * <script type="text/javascript">
33926 * @class Roo.bootstrap.SplitBar
33927 * @extends Roo.util.Observable
33928 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33932 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33933 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33934 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33935 split.minSize = 100;
33936 split.maxSize = 600;
33937 split.animate = true;
33938 split.on('moved', splitterMoved);
33941 * Create a new SplitBar
33942 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33943 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33944 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33945 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33946 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33947 position of the SplitBar).
33949 Roo.bootstrap.SplitBar = function(cfg){
33954 // dragElement : elm
33955 // resizingElement: el,
33957 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33958 // placement : Roo.bootstrap.SplitBar.LEFT ,
33959 // existingProxy ???
33962 this.el = Roo.get(cfg.dragElement, true);
33963 this.el.dom.unselectable = "on";
33965 this.resizingEl = Roo.get(cfg.resizingElement, true);
33969 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33970 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33973 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33976 * The minimum size of the resizing element. (Defaults to 0)
33982 * The maximum size of the resizing element. (Defaults to 2000)
33985 this.maxSize = 2000;
33988 * Whether to animate the transition to the new size
33991 this.animate = false;
33994 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33997 this.useShim = false;
34002 if(!cfg.existingProxy){
34004 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34006 this.proxy = Roo.get(cfg.existingProxy).dom;
34009 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34012 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34015 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34018 this.dragSpecs = {};
34021 * @private The adapter to use to positon and resize elements
34023 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34024 this.adapter.init(this);
34026 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34028 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34029 this.el.addClass("roo-splitbar-h");
34032 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34033 this.el.addClass("roo-splitbar-v");
34039 * Fires when the splitter is moved (alias for {@link #event-moved})
34040 * @param {Roo.bootstrap.SplitBar} this
34041 * @param {Number} newSize the new width or height
34046 * Fires when the splitter is moved
34047 * @param {Roo.bootstrap.SplitBar} this
34048 * @param {Number} newSize the new width or height
34052 * @event beforeresize
34053 * Fires before the splitter is dragged
34054 * @param {Roo.bootstrap.SplitBar} this
34056 "beforeresize" : true,
34058 "beforeapply" : true
34061 Roo.util.Observable.call(this);
34064 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34065 onStartProxyDrag : function(x, y){
34066 this.fireEvent("beforeresize", this);
34068 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34070 o.enableDisplayMode("block");
34071 // all splitbars share the same overlay
34072 Roo.bootstrap.SplitBar.prototype.overlay = o;
34074 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34075 this.overlay.show();
34076 Roo.get(this.proxy).setDisplayed("block");
34077 var size = this.adapter.getElementSize(this);
34078 this.activeMinSize = this.getMinimumSize();;
34079 this.activeMaxSize = this.getMaximumSize();;
34080 var c1 = size - this.activeMinSize;
34081 var c2 = Math.max(this.activeMaxSize - size, 0);
34082 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34083 this.dd.resetConstraints();
34084 this.dd.setXConstraint(
34085 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34086 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34088 this.dd.setYConstraint(0, 0);
34090 this.dd.resetConstraints();
34091 this.dd.setXConstraint(0, 0);
34092 this.dd.setYConstraint(
34093 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34094 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34097 this.dragSpecs.startSize = size;
34098 this.dragSpecs.startPoint = [x, y];
34099 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34103 * @private Called after the drag operation by the DDProxy
34105 onEndProxyDrag : function(e){
34106 Roo.get(this.proxy).setDisplayed(false);
34107 var endPoint = Roo.lib.Event.getXY(e);
34109 this.overlay.hide();
34112 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34113 newSize = this.dragSpecs.startSize +
34114 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34115 endPoint[0] - this.dragSpecs.startPoint[0] :
34116 this.dragSpecs.startPoint[0] - endPoint[0]
34119 newSize = this.dragSpecs.startSize +
34120 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34121 endPoint[1] - this.dragSpecs.startPoint[1] :
34122 this.dragSpecs.startPoint[1] - endPoint[1]
34125 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34126 if(newSize != this.dragSpecs.startSize){
34127 if(this.fireEvent('beforeapply', this, newSize) !== false){
34128 this.adapter.setElementSize(this, newSize);
34129 this.fireEvent("moved", this, newSize);
34130 this.fireEvent("resize", this, newSize);
34136 * Get the adapter this SplitBar uses
34137 * @return The adapter object
34139 getAdapter : function(){
34140 return this.adapter;
34144 * Set the adapter this SplitBar uses
34145 * @param {Object} adapter A SplitBar adapter object
34147 setAdapter : function(adapter){
34148 this.adapter = adapter;
34149 this.adapter.init(this);
34153 * Gets the minimum size for the resizing element
34154 * @return {Number} The minimum size
34156 getMinimumSize : function(){
34157 return this.minSize;
34161 * Sets the minimum size for the resizing element
34162 * @param {Number} minSize The minimum size
34164 setMinimumSize : function(minSize){
34165 this.minSize = minSize;
34169 * Gets the maximum size for the resizing element
34170 * @return {Number} The maximum size
34172 getMaximumSize : function(){
34173 return this.maxSize;
34177 * Sets the maximum size for the resizing element
34178 * @param {Number} maxSize The maximum size
34180 setMaximumSize : function(maxSize){
34181 this.maxSize = maxSize;
34185 * Sets the initialize size for the resizing element
34186 * @param {Number} size The initial size
34188 setCurrentSize : function(size){
34189 var oldAnimate = this.animate;
34190 this.animate = false;
34191 this.adapter.setElementSize(this, size);
34192 this.animate = oldAnimate;
34196 * Destroy this splitbar.
34197 * @param {Boolean} removeEl True to remove the element
34199 destroy : function(removeEl){
34201 this.shim.remove();
34204 this.proxy.parentNode.removeChild(this.proxy);
34212 * @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.
34214 Roo.bootstrap.SplitBar.createProxy = function(dir){
34215 var proxy = new Roo.Element(document.createElement("div"));
34216 proxy.unselectable();
34217 var cls = 'roo-splitbar-proxy';
34218 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34219 document.body.appendChild(proxy.dom);
34224 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34225 * Default Adapter. It assumes the splitter and resizing element are not positioned
34226 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34228 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34231 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34232 // do nothing for now
34233 init : function(s){
34237 * Called before drag operations to get the current size of the resizing element.
34238 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34240 getElementSize : function(s){
34241 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34242 return s.resizingEl.getWidth();
34244 return s.resizingEl.getHeight();
34249 * Called after drag operations to set the size of the resizing element.
34250 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34251 * @param {Number} newSize The new size to set
34252 * @param {Function} onComplete A function to be invoked when resizing is complete
34254 setElementSize : function(s, newSize, onComplete){
34255 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34257 s.resizingEl.setWidth(newSize);
34259 onComplete(s, newSize);
34262 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34267 s.resizingEl.setHeight(newSize);
34269 onComplete(s, newSize);
34272 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34279 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34280 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34281 * Adapter that moves the splitter element to align with the resized sizing element.
34282 * Used with an absolute positioned SplitBar.
34283 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34284 * document.body, make sure you assign an id to the body element.
34286 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34287 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34288 this.container = Roo.get(container);
34291 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34292 init : function(s){
34293 this.basic.init(s);
34296 getElementSize : function(s){
34297 return this.basic.getElementSize(s);
34300 setElementSize : function(s, newSize, onComplete){
34301 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34304 moveSplitter : function(s){
34305 var yes = Roo.bootstrap.SplitBar;
34306 switch(s.placement){
34308 s.el.setX(s.resizingEl.getRight());
34311 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34314 s.el.setY(s.resizingEl.getBottom());
34317 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34324 * Orientation constant - Create a vertical SplitBar
34328 Roo.bootstrap.SplitBar.VERTICAL = 1;
34331 * Orientation constant - Create a horizontal SplitBar
34335 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34338 * Placement constant - The resizing element is to the left of the splitter element
34342 Roo.bootstrap.SplitBar.LEFT = 1;
34345 * Placement constant - The resizing element is to the right of the splitter element
34349 Roo.bootstrap.SplitBar.RIGHT = 2;
34352 * Placement constant - The resizing element is positioned above the splitter element
34356 Roo.bootstrap.SplitBar.TOP = 3;
34359 * Placement constant - The resizing element is positioned under splitter element
34363 Roo.bootstrap.SplitBar.BOTTOM = 4;
34364 Roo.namespace("Roo.bootstrap.layout");/*
34366 * Ext JS Library 1.1.1
34367 * Copyright(c) 2006-2007, Ext JS, LLC.
34369 * Originally Released Under LGPL - original licence link has changed is not relivant.
34372 * <script type="text/javascript">
34376 * @class Roo.bootstrap.layout.Manager
34377 * @extends Roo.bootstrap.Component
34378 * Base class for layout managers.
34380 Roo.bootstrap.layout.Manager = function(config)
34382 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34388 /** false to disable window resize monitoring @type Boolean */
34389 this.monitorWindowResize = true;
34394 * Fires when a layout is performed.
34395 * @param {Roo.LayoutManager} this
34399 * @event regionresized
34400 * Fires when the user resizes a region.
34401 * @param {Roo.LayoutRegion} region The resized region
34402 * @param {Number} newSize The new size (width for east/west, height for north/south)
34404 "regionresized" : true,
34406 * @event regioncollapsed
34407 * Fires when a region is collapsed.
34408 * @param {Roo.LayoutRegion} region The collapsed region
34410 "regioncollapsed" : true,
34412 * @event regionexpanded
34413 * Fires when a region is expanded.
34414 * @param {Roo.LayoutRegion} region The expanded region
34416 "regionexpanded" : true
34418 this.updating = false;
34421 this.el = Roo.get(config.el);
34427 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34432 monitorWindowResize : true,
34438 onRender : function(ct, position)
34441 this.el = Roo.get(ct);
34444 //this.fireEvent('render',this);
34448 initEvents: function()
34452 // ie scrollbar fix
34453 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34454 document.body.scroll = "no";
34455 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34456 this.el.position('relative');
34458 this.id = this.el.id;
34459 this.el.addClass("roo-layout-container");
34460 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34461 if(this.el.dom != document.body ) {
34462 this.el.on('resize', this.layout,this);
34463 this.el.on('show', this.layout,this);
34469 * Returns true if this layout is currently being updated
34470 * @return {Boolean}
34472 isUpdating : function(){
34473 return this.updating;
34477 * Suspend the LayoutManager from doing auto-layouts while
34478 * making multiple add or remove calls
34480 beginUpdate : function(){
34481 this.updating = true;
34485 * Restore auto-layouts and optionally disable the manager from performing a layout
34486 * @param {Boolean} noLayout true to disable a layout update
34488 endUpdate : function(noLayout){
34489 this.updating = false;
34495 layout: function(){
34499 onRegionResized : function(region, newSize){
34500 this.fireEvent("regionresized", region, newSize);
34504 onRegionCollapsed : function(region){
34505 this.fireEvent("regioncollapsed", region);
34508 onRegionExpanded : function(region){
34509 this.fireEvent("regionexpanded", region);
34513 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34514 * performs box-model adjustments.
34515 * @return {Object} The size as an object {width: (the width), height: (the height)}
34517 getViewSize : function()
34520 if(this.el.dom != document.body){
34521 size = this.el.getSize();
34523 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34525 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34526 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34531 * Returns the Element this layout is bound to.
34532 * @return {Roo.Element}
34534 getEl : function(){
34539 * Returns the specified region.
34540 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34541 * @return {Roo.LayoutRegion}
34543 getRegion : function(target){
34544 return this.regions[target.toLowerCase()];
34547 onWindowResize : function(){
34548 if(this.monitorWindowResize){
34555 * Ext JS Library 1.1.1
34556 * Copyright(c) 2006-2007, Ext JS, LLC.
34558 * Originally Released Under LGPL - original licence link has changed is not relivant.
34561 * <script type="text/javascript">
34564 * @class Roo.bootstrap.layout.Border
34565 * @extends Roo.bootstrap.layout.Manager
34566 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34567 * please see: examples/bootstrap/nested.html<br><br>
34569 <b>The container the layout is rendered into can be either the body element or any other element.
34570 If it is not the body element, the container needs to either be an absolute positioned element,
34571 or you will need to add "position:relative" to the css of the container. You will also need to specify
34572 the container size if it is not the body element.</b>
34575 * Create a new Border
34576 * @param {Object} config Configuration options
34578 Roo.bootstrap.layout.Border = function(config){
34579 config = config || {};
34580 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34584 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34585 if(config[region]){
34586 config[region].region = region;
34587 this.addRegion(config[region]);
34593 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34595 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34597 * Creates and adds a new region if it doesn't already exist.
34598 * @param {String} target The target region key (north, south, east, west or center).
34599 * @param {Object} config The regions config object
34600 * @return {BorderLayoutRegion} The new region
34602 addRegion : function(config)
34604 if(!this.regions[config.region]){
34605 var r = this.factory(config);
34606 this.bindRegion(r);
34608 return this.regions[config.region];
34612 bindRegion : function(r){
34613 this.regions[r.config.region] = r;
34615 r.on("visibilitychange", this.layout, this);
34616 r.on("paneladded", this.layout, this);
34617 r.on("panelremoved", this.layout, this);
34618 r.on("invalidated", this.layout, this);
34619 r.on("resized", this.onRegionResized, this);
34620 r.on("collapsed", this.onRegionCollapsed, this);
34621 r.on("expanded", this.onRegionExpanded, this);
34625 * Performs a layout update.
34627 layout : function()
34629 if(this.updating) {
34633 // render all the rebions if they have not been done alreayd?
34634 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34635 if(this.regions[region] && !this.regions[region].bodyEl){
34636 this.regions[region].onRender(this.el)
34640 var size = this.getViewSize();
34641 var w = size.width;
34642 var h = size.height;
34647 //var x = 0, y = 0;
34649 var rs = this.regions;
34650 var north = rs["north"];
34651 var south = rs["south"];
34652 var west = rs["west"];
34653 var east = rs["east"];
34654 var center = rs["center"];
34655 //if(this.hideOnLayout){ // not supported anymore
34656 //c.el.setStyle("display", "none");
34658 if(north && north.isVisible()){
34659 var b = north.getBox();
34660 var m = north.getMargins();
34661 b.width = w - (m.left+m.right);
34664 centerY = b.height + b.y + m.bottom;
34665 centerH -= centerY;
34666 north.updateBox(this.safeBox(b));
34668 if(south && south.isVisible()){
34669 var b = south.getBox();
34670 var m = south.getMargins();
34671 b.width = w - (m.left+m.right);
34673 var totalHeight = (b.height + m.top + m.bottom);
34674 b.y = h - totalHeight + m.top;
34675 centerH -= totalHeight;
34676 south.updateBox(this.safeBox(b));
34678 if(west && west.isVisible()){
34679 var b = west.getBox();
34680 var m = west.getMargins();
34681 b.height = centerH - (m.top+m.bottom);
34683 b.y = centerY + m.top;
34684 var totalWidth = (b.width + m.left + m.right);
34685 centerX += totalWidth;
34686 centerW -= totalWidth;
34687 west.updateBox(this.safeBox(b));
34689 if(east && east.isVisible()){
34690 var b = east.getBox();
34691 var m = east.getMargins();
34692 b.height = centerH - (m.top+m.bottom);
34693 var totalWidth = (b.width + m.left + m.right);
34694 b.x = w - totalWidth + m.left;
34695 b.y = centerY + m.top;
34696 centerW -= totalWidth;
34697 east.updateBox(this.safeBox(b));
34700 var m = center.getMargins();
34702 x: centerX + m.left,
34703 y: centerY + m.top,
34704 width: centerW - (m.left+m.right),
34705 height: centerH - (m.top+m.bottom)
34707 //if(this.hideOnLayout){
34708 //center.el.setStyle("display", "block");
34710 center.updateBox(this.safeBox(centerBox));
34713 this.fireEvent("layout", this);
34717 safeBox : function(box){
34718 box.width = Math.max(0, box.width);
34719 box.height = Math.max(0, box.height);
34724 * Adds a ContentPanel (or subclass) to this layout.
34725 * @param {String} target The target region key (north, south, east, west or center).
34726 * @param {Roo.ContentPanel} panel The panel to add
34727 * @return {Roo.ContentPanel} The added panel
34729 add : function(target, panel){
34731 target = target.toLowerCase();
34732 return this.regions[target].add(panel);
34736 * Remove a ContentPanel (or subclass) to this layout.
34737 * @param {String} target The target region key (north, south, east, west or center).
34738 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34739 * @return {Roo.ContentPanel} The removed panel
34741 remove : function(target, panel){
34742 target = target.toLowerCase();
34743 return this.regions[target].remove(panel);
34747 * Searches all regions for a panel with the specified id
34748 * @param {String} panelId
34749 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34751 findPanel : function(panelId){
34752 var rs = this.regions;
34753 for(var target in rs){
34754 if(typeof rs[target] != "function"){
34755 var p = rs[target].getPanel(panelId);
34765 * Searches all regions for a panel with the specified id and activates (shows) it.
34766 * @param {String/ContentPanel} panelId The panels id or the panel itself
34767 * @return {Roo.ContentPanel} The shown panel or null
34769 showPanel : function(panelId) {
34770 var rs = this.regions;
34771 for(var target in rs){
34772 var r = rs[target];
34773 if(typeof r != "function"){
34774 if(r.hasPanel(panelId)){
34775 return r.showPanel(panelId);
34783 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34784 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34787 restoreState : function(provider){
34789 provider = Roo.state.Manager;
34791 var sm = new Roo.LayoutStateManager();
34792 sm.init(this, provider);
34798 * Adds a xtype elements to the layout.
34802 xtype : 'ContentPanel',
34809 xtype : 'NestedLayoutPanel',
34815 items : [ ... list of content panels or nested layout panels.. ]
34819 * @param {Object} cfg Xtype definition of item to add.
34821 addxtype : function(cfg)
34823 // basically accepts a pannel...
34824 // can accept a layout region..!?!?
34825 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34828 // theory? children can only be panels??
34830 //if (!cfg.xtype.match(/Panel$/)) {
34835 if (typeof(cfg.region) == 'undefined') {
34836 Roo.log("Failed to add Panel, region was not set");
34840 var region = cfg.region;
34846 xitems = cfg.items;
34853 case 'Content': // ContentPanel (el, cfg)
34854 case 'Scroll': // ContentPanel (el, cfg)
34856 cfg.autoCreate = true;
34857 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34859 // var el = this.el.createChild();
34860 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34863 this.add(region, ret);
34867 case 'TreePanel': // our new panel!
34868 cfg.el = this.el.createChild();
34869 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34870 this.add(region, ret);
34875 // create a new Layout (which is a Border Layout...
34877 var clayout = cfg.layout;
34878 clayout.el = this.el.createChild();
34879 clayout.items = clayout.items || [];
34883 // replace this exitems with the clayout ones..
34884 xitems = clayout.items;
34886 // force background off if it's in center...
34887 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34888 cfg.background = false;
34890 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34893 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34894 //console.log('adding nested layout panel ' + cfg.toSource());
34895 this.add(region, ret);
34896 nb = {}; /// find first...
34901 // needs grid and region
34903 //var el = this.getRegion(region).el.createChild();
34905 *var el = this.el.createChild();
34906 // create the grid first...
34907 cfg.grid.container = el;
34908 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34911 if (region == 'center' && this.active ) {
34912 cfg.background = false;
34915 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34917 this.add(region, ret);
34919 if (cfg.background) {
34920 // render grid on panel activation (if panel background)
34921 ret.on('activate', function(gp) {
34922 if (!gp.grid.rendered) {
34923 // gp.grid.render(el);
34927 // cfg.grid.render(el);
34933 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34934 // it was the old xcomponent building that caused this before.
34935 // espeically if border is the top element in the tree.
34945 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34947 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34948 this.add(region, ret);
34952 throw "Can not add '" + cfg.xtype + "' to Border";
34958 this.beginUpdate();
34962 Roo.each(xitems, function(i) {
34963 region = nb && i.region ? i.region : false;
34965 var add = ret.addxtype(i);
34968 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34969 if (!i.background) {
34970 abn[region] = nb[region] ;
34977 // make the last non-background panel active..
34978 //if (nb) { Roo.log(abn); }
34981 for(var r in abn) {
34982 region = this.getRegion(r);
34984 // tried using nb[r], but it does not work..
34986 region.showPanel(abn[r]);
34997 factory : function(cfg)
35000 var validRegions = Roo.bootstrap.layout.Border.regions;
35002 var target = cfg.region;
35005 var r = Roo.bootstrap.layout;
35009 return new r.North(cfg);
35011 return new r.South(cfg);
35013 return new r.East(cfg);
35015 return new r.West(cfg);
35017 return new r.Center(cfg);
35019 throw 'Layout region "'+target+'" not supported.';
35026 * Ext JS Library 1.1.1
35027 * Copyright(c) 2006-2007, Ext JS, LLC.
35029 * Originally Released Under LGPL - original licence link has changed is not relivant.
35032 * <script type="text/javascript">
35036 * @class Roo.bootstrap.layout.Basic
35037 * @extends Roo.util.Observable
35038 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35039 * and does not have a titlebar, tabs or any other features. All it does is size and position
35040 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35041 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35042 * @cfg {string} region the region that it inhabits..
35043 * @cfg {bool} skipConfig skip config?
35047 Roo.bootstrap.layout.Basic = function(config){
35049 this.mgr = config.mgr;
35051 this.position = config.region;
35053 var skipConfig = config.skipConfig;
35057 * @scope Roo.BasicLayoutRegion
35061 * @event beforeremove
35062 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35063 * @param {Roo.LayoutRegion} this
35064 * @param {Roo.ContentPanel} panel The panel
35065 * @param {Object} e The cancel event object
35067 "beforeremove" : true,
35069 * @event invalidated
35070 * Fires when the layout for this region is changed.
35071 * @param {Roo.LayoutRegion} this
35073 "invalidated" : true,
35075 * @event visibilitychange
35076 * Fires when this region is shown or hidden
35077 * @param {Roo.LayoutRegion} this
35078 * @param {Boolean} visibility true or false
35080 "visibilitychange" : true,
35082 * @event paneladded
35083 * Fires when a panel is added.
35084 * @param {Roo.LayoutRegion} this
35085 * @param {Roo.ContentPanel} panel The panel
35087 "paneladded" : true,
35089 * @event panelremoved
35090 * Fires when a panel is removed.
35091 * @param {Roo.LayoutRegion} this
35092 * @param {Roo.ContentPanel} panel The panel
35094 "panelremoved" : true,
35096 * @event beforecollapse
35097 * Fires when this region before collapse.
35098 * @param {Roo.LayoutRegion} this
35100 "beforecollapse" : true,
35103 * Fires when this region is collapsed.
35104 * @param {Roo.LayoutRegion} this
35106 "collapsed" : true,
35109 * Fires when this region is expanded.
35110 * @param {Roo.LayoutRegion} this
35115 * Fires when this region is slid into view.
35116 * @param {Roo.LayoutRegion} this
35118 "slideshow" : true,
35121 * Fires when this region slides out of view.
35122 * @param {Roo.LayoutRegion} this
35124 "slidehide" : true,
35126 * @event panelactivated
35127 * Fires when a panel is activated.
35128 * @param {Roo.LayoutRegion} this
35129 * @param {Roo.ContentPanel} panel The activated panel
35131 "panelactivated" : true,
35134 * Fires when the user resizes this region.
35135 * @param {Roo.LayoutRegion} this
35136 * @param {Number} newSize The new size (width for east/west, height for north/south)
35140 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35141 this.panels = new Roo.util.MixedCollection();
35142 this.panels.getKey = this.getPanelId.createDelegate(this);
35144 this.activePanel = null;
35145 // ensure listeners are added...
35147 if (config.listeners || config.events) {
35148 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35149 listeners : config.listeners || {},
35150 events : config.events || {}
35154 if(skipConfig !== true){
35155 this.applyConfig(config);
35159 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35161 getPanelId : function(p){
35165 applyConfig : function(config){
35166 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35167 this.config = config;
35172 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35173 * the width, for horizontal (north, south) the height.
35174 * @param {Number} newSize The new width or height
35176 resizeTo : function(newSize){
35177 var el = this.el ? this.el :
35178 (this.activePanel ? this.activePanel.getEl() : null);
35180 switch(this.position){
35183 el.setWidth(newSize);
35184 this.fireEvent("resized", this, newSize);
35188 el.setHeight(newSize);
35189 this.fireEvent("resized", this, newSize);
35195 getBox : function(){
35196 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35199 getMargins : function(){
35200 return this.margins;
35203 updateBox : function(box){
35205 var el = this.activePanel.getEl();
35206 el.dom.style.left = box.x + "px";
35207 el.dom.style.top = box.y + "px";
35208 this.activePanel.setSize(box.width, box.height);
35212 * Returns the container element for this region.
35213 * @return {Roo.Element}
35215 getEl : function(){
35216 return this.activePanel;
35220 * Returns true if this region is currently visible.
35221 * @return {Boolean}
35223 isVisible : function(){
35224 return this.activePanel ? true : false;
35227 setActivePanel : function(panel){
35228 panel = this.getPanel(panel);
35229 if(this.activePanel && this.activePanel != panel){
35230 this.activePanel.setActiveState(false);
35231 this.activePanel.getEl().setLeftTop(-10000,-10000);
35233 this.activePanel = panel;
35234 panel.setActiveState(true);
35236 panel.setSize(this.box.width, this.box.height);
35238 this.fireEvent("panelactivated", this, panel);
35239 this.fireEvent("invalidated");
35243 * Show the specified panel.
35244 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35245 * @return {Roo.ContentPanel} The shown panel or null
35247 showPanel : function(panel){
35248 panel = this.getPanel(panel);
35250 this.setActivePanel(panel);
35256 * Get the active panel for this region.
35257 * @return {Roo.ContentPanel} The active panel or null
35259 getActivePanel : function(){
35260 return this.activePanel;
35264 * Add the passed ContentPanel(s)
35265 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35266 * @return {Roo.ContentPanel} The panel added (if only one was added)
35268 add : function(panel){
35269 if(arguments.length > 1){
35270 for(var i = 0, len = arguments.length; i < len; i++) {
35271 this.add(arguments[i]);
35275 if(this.hasPanel(panel)){
35276 this.showPanel(panel);
35279 var el = panel.getEl();
35280 if(el.dom.parentNode != this.mgr.el.dom){
35281 this.mgr.el.dom.appendChild(el.dom);
35283 if(panel.setRegion){
35284 panel.setRegion(this);
35286 this.panels.add(panel);
35287 el.setStyle("position", "absolute");
35288 if(!panel.background){
35289 this.setActivePanel(panel);
35290 if(this.config.initialSize && this.panels.getCount()==1){
35291 this.resizeTo(this.config.initialSize);
35294 this.fireEvent("paneladded", this, panel);
35299 * Returns true if the panel is in this region.
35300 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35301 * @return {Boolean}
35303 hasPanel : function(panel){
35304 if(typeof panel == "object"){ // must be panel obj
35305 panel = panel.getId();
35307 return this.getPanel(panel) ? true : false;
35311 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35312 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35313 * @param {Boolean} preservePanel Overrides the config preservePanel option
35314 * @return {Roo.ContentPanel} The panel that was removed
35316 remove : function(panel, preservePanel){
35317 panel = this.getPanel(panel);
35322 this.fireEvent("beforeremove", this, panel, e);
35323 if(e.cancel === true){
35326 var panelId = panel.getId();
35327 this.panels.removeKey(panelId);
35332 * Returns the panel specified or null if it's not in this region.
35333 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35334 * @return {Roo.ContentPanel}
35336 getPanel : function(id){
35337 if(typeof id == "object"){ // must be panel obj
35340 return this.panels.get(id);
35344 * Returns this regions position (north/south/east/west/center).
35347 getPosition: function(){
35348 return this.position;
35352 * Ext JS Library 1.1.1
35353 * Copyright(c) 2006-2007, Ext JS, LLC.
35355 * Originally Released Under LGPL - original licence link has changed is not relivant.
35358 * <script type="text/javascript">
35362 * @class Roo.bootstrap.layout.Region
35363 * @extends Roo.bootstrap.layout.Basic
35364 * This class represents a region in a layout manager.
35366 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35367 * @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})
35368 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35369 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35370 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35371 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35372 * @cfg {String} title The title for the region (overrides panel titles)
35373 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35374 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35375 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35376 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35377 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35378 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35379 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35380 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35381 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35382 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35384 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35385 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35386 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35387 * @cfg {Number} width For East/West panels
35388 * @cfg {Number} height For North/South panels
35389 * @cfg {Boolean} split To show the splitter
35390 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35392 * @cfg {string} cls Extra CSS classes to add to region
35394 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35395 * @cfg {string} region the region that it inhabits..
35398 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35399 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35401 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35402 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35403 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35405 Roo.bootstrap.layout.Region = function(config)
35407 this.applyConfig(config);
35409 var mgr = config.mgr;
35410 var pos = config.region;
35411 config.skipConfig = true;
35412 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35415 this.onRender(mgr.el);
35418 this.visible = true;
35419 this.collapsed = false;
35420 this.unrendered_panels = [];
35423 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35425 position: '', // set by wrapper (eg. north/south etc..)
35426 unrendered_panels : null, // unrendered panels.
35427 createBody : function(){
35428 /** This region's body element
35429 * @type Roo.Element */
35430 this.bodyEl = this.el.createChild({
35432 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35436 onRender: function(ctr, pos)
35438 var dh = Roo.DomHelper;
35439 /** This region's container element
35440 * @type Roo.Element */
35441 this.el = dh.append(ctr.dom, {
35443 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35445 /** This region's title element
35446 * @type Roo.Element */
35448 this.titleEl = dh.append(this.el.dom,
35451 unselectable: "on",
35452 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35454 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35455 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35458 this.titleEl.enableDisplayMode();
35459 /** This region's title text element
35460 * @type HTMLElement */
35461 this.titleTextEl = this.titleEl.dom.firstChild;
35462 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35464 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35465 this.closeBtn.enableDisplayMode();
35466 this.closeBtn.on("click", this.closeClicked, this);
35467 this.closeBtn.hide();
35469 this.createBody(this.config);
35470 if(this.config.hideWhenEmpty){
35472 this.on("paneladded", this.validateVisibility, this);
35473 this.on("panelremoved", this.validateVisibility, this);
35475 if(this.autoScroll){
35476 this.bodyEl.setStyle("overflow", "auto");
35478 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35480 //if(c.titlebar !== false){
35481 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35482 this.titleEl.hide();
35484 this.titleEl.show();
35485 if(this.config.title){
35486 this.titleTextEl.innerHTML = this.config.title;
35490 if(this.config.collapsed){
35491 this.collapse(true);
35493 if(this.config.hidden){
35497 if (this.unrendered_panels && this.unrendered_panels.length) {
35498 for (var i =0;i< this.unrendered_panels.length; i++) {
35499 this.add(this.unrendered_panels[i]);
35501 this.unrendered_panels = null;
35507 applyConfig : function(c)
35510 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35511 var dh = Roo.DomHelper;
35512 if(c.titlebar !== false){
35513 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35514 this.collapseBtn.on("click", this.collapse, this);
35515 this.collapseBtn.enableDisplayMode();
35517 if(c.showPin === true || this.showPin){
35518 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35519 this.stickBtn.enableDisplayMode();
35520 this.stickBtn.on("click", this.expand, this);
35521 this.stickBtn.hide();
35526 /** This region's collapsed element
35527 * @type Roo.Element */
35530 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35531 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35534 if(c.floatable !== false){
35535 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35536 this.collapsedEl.on("click", this.collapseClick, this);
35539 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35540 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35541 id: "message", unselectable: "on", style:{"float":"left"}});
35542 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35544 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35545 this.expandBtn.on("click", this.expand, this);
35549 if(this.collapseBtn){
35550 this.collapseBtn.setVisible(c.collapsible == true);
35553 this.cmargins = c.cmargins || this.cmargins ||
35554 (this.position == "west" || this.position == "east" ?
35555 {top: 0, left: 2, right:2, bottom: 0} :
35556 {top: 2, left: 0, right:0, bottom: 2});
35558 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35561 this.bottomTabs = c.tabPosition != "top";
35563 this.autoScroll = c.autoScroll || false;
35568 this.duration = c.duration || .30;
35569 this.slideDuration = c.slideDuration || .45;
35574 * Returns true if this region is currently visible.
35575 * @return {Boolean}
35577 isVisible : function(){
35578 return this.visible;
35582 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35583 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35585 //setCollapsedTitle : function(title){
35586 // title = title || " ";
35587 // if(this.collapsedTitleTextEl){
35588 // this.collapsedTitleTextEl.innerHTML = title;
35592 getBox : function(){
35594 // if(!this.collapsed){
35595 b = this.el.getBox(false, true);
35597 // b = this.collapsedEl.getBox(false, true);
35602 getMargins : function(){
35603 return this.margins;
35604 //return this.collapsed ? this.cmargins : this.margins;
35607 highlight : function(){
35608 this.el.addClass("x-layout-panel-dragover");
35611 unhighlight : function(){
35612 this.el.removeClass("x-layout-panel-dragover");
35615 updateBox : function(box)
35617 if (!this.bodyEl) {
35618 return; // not rendered yet..
35622 if(!this.collapsed){
35623 this.el.dom.style.left = box.x + "px";
35624 this.el.dom.style.top = box.y + "px";
35625 this.updateBody(box.width, box.height);
35627 this.collapsedEl.dom.style.left = box.x + "px";
35628 this.collapsedEl.dom.style.top = box.y + "px";
35629 this.collapsedEl.setSize(box.width, box.height);
35632 this.tabs.autoSizeTabs();
35636 updateBody : function(w, h)
35639 this.el.setWidth(w);
35640 w -= this.el.getBorderWidth("rl");
35641 if(this.config.adjustments){
35642 w += this.config.adjustments[0];
35645 if(h !== null && h > 0){
35646 this.el.setHeight(h);
35647 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35648 h -= this.el.getBorderWidth("tb");
35649 if(this.config.adjustments){
35650 h += this.config.adjustments[1];
35652 this.bodyEl.setHeight(h);
35654 h = this.tabs.syncHeight(h);
35657 if(this.panelSize){
35658 w = w !== null ? w : this.panelSize.width;
35659 h = h !== null ? h : this.panelSize.height;
35661 if(this.activePanel){
35662 var el = this.activePanel.getEl();
35663 w = w !== null ? w : el.getWidth();
35664 h = h !== null ? h : el.getHeight();
35665 this.panelSize = {width: w, height: h};
35666 this.activePanel.setSize(w, h);
35668 if(Roo.isIE && this.tabs){
35669 this.tabs.el.repaint();
35674 * Returns the container element for this region.
35675 * @return {Roo.Element}
35677 getEl : function(){
35682 * Hides this region.
35685 //if(!this.collapsed){
35686 this.el.dom.style.left = "-2000px";
35689 // this.collapsedEl.dom.style.left = "-2000px";
35690 // this.collapsedEl.hide();
35692 this.visible = false;
35693 this.fireEvent("visibilitychange", this, false);
35697 * Shows this region if it was previously hidden.
35700 //if(!this.collapsed){
35703 // this.collapsedEl.show();
35705 this.visible = true;
35706 this.fireEvent("visibilitychange", this, true);
35709 closeClicked : function(){
35710 if(this.activePanel){
35711 this.remove(this.activePanel);
35715 collapseClick : function(e){
35717 e.stopPropagation();
35720 e.stopPropagation();
35726 * Collapses this region.
35727 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35730 collapse : function(skipAnim, skipCheck = false){
35731 if(this.collapsed) {
35735 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35737 this.collapsed = true;
35739 this.split.el.hide();
35741 if(this.config.animate && skipAnim !== true){
35742 this.fireEvent("invalidated", this);
35743 this.animateCollapse();
35745 this.el.setLocation(-20000,-20000);
35747 this.collapsedEl.show();
35748 this.fireEvent("collapsed", this);
35749 this.fireEvent("invalidated", this);
35755 animateCollapse : function(){
35760 * Expands this region if it was previously collapsed.
35761 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35762 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35765 expand : function(e, skipAnim){
35767 e.stopPropagation();
35769 if(!this.collapsed || this.el.hasActiveFx()) {
35773 this.afterSlideIn();
35776 this.collapsed = false;
35777 if(this.config.animate && skipAnim !== true){
35778 this.animateExpand();
35782 this.split.el.show();
35784 this.collapsedEl.setLocation(-2000,-2000);
35785 this.collapsedEl.hide();
35786 this.fireEvent("invalidated", this);
35787 this.fireEvent("expanded", this);
35791 animateExpand : function(){
35795 initTabs : function()
35797 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35799 var ts = new Roo.bootstrap.panel.Tabs({
35800 el: this.bodyEl.dom,
35801 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35802 disableTooltips: this.config.disableTabTips,
35803 toolbar : this.config.toolbar
35806 if(this.config.hideTabs){
35807 ts.stripWrap.setDisplayed(false);
35810 ts.resizeTabs = this.config.resizeTabs === true;
35811 ts.minTabWidth = this.config.minTabWidth || 40;
35812 ts.maxTabWidth = this.config.maxTabWidth || 250;
35813 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35814 ts.monitorResize = false;
35815 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35816 ts.bodyEl.addClass('roo-layout-tabs-body');
35817 this.panels.each(this.initPanelAsTab, this);
35820 initPanelAsTab : function(panel){
35821 var ti = this.tabs.addTab(
35825 this.config.closeOnTab && panel.isClosable(),
35828 if(panel.tabTip !== undefined){
35829 ti.setTooltip(panel.tabTip);
35831 ti.on("activate", function(){
35832 this.setActivePanel(panel);
35835 if(this.config.closeOnTab){
35836 ti.on("beforeclose", function(t, e){
35838 this.remove(panel);
35842 panel.tabItem = ti;
35847 updatePanelTitle : function(panel, title)
35849 if(this.activePanel == panel){
35850 this.updateTitle(title);
35853 var ti = this.tabs.getTab(panel.getEl().id);
35855 if(panel.tabTip !== undefined){
35856 ti.setTooltip(panel.tabTip);
35861 updateTitle : function(title){
35862 if(this.titleTextEl && !this.config.title){
35863 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35867 setActivePanel : function(panel)
35869 panel = this.getPanel(panel);
35870 if(this.activePanel && this.activePanel != panel){
35871 if(this.activePanel.setActiveState(false) === false){
35875 this.activePanel = panel;
35876 panel.setActiveState(true);
35877 if(this.panelSize){
35878 panel.setSize(this.panelSize.width, this.panelSize.height);
35881 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35883 this.updateTitle(panel.getTitle());
35885 this.fireEvent("invalidated", this);
35887 this.fireEvent("panelactivated", this, panel);
35891 * Shows the specified panel.
35892 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35893 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35895 showPanel : function(panel)
35897 panel = this.getPanel(panel);
35900 var tab = this.tabs.getTab(panel.getEl().id);
35901 if(tab.isHidden()){
35902 this.tabs.unhideTab(tab.id);
35906 this.setActivePanel(panel);
35913 * Get the active panel for this region.
35914 * @return {Roo.ContentPanel} The active panel or null
35916 getActivePanel : function(){
35917 return this.activePanel;
35920 validateVisibility : function(){
35921 if(this.panels.getCount() < 1){
35922 this.updateTitle(" ");
35923 this.closeBtn.hide();
35926 if(!this.isVisible()){
35933 * Adds the passed ContentPanel(s) to this region.
35934 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35935 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35937 add : function(panel)
35939 if(arguments.length > 1){
35940 for(var i = 0, len = arguments.length; i < len; i++) {
35941 this.add(arguments[i]);
35946 // if we have not been rendered yet, then we can not really do much of this..
35947 if (!this.bodyEl) {
35948 this.unrendered_panels.push(panel);
35955 if(this.hasPanel(panel)){
35956 this.showPanel(panel);
35959 panel.setRegion(this);
35960 this.panels.add(panel);
35961 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35962 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35963 // and hide them... ???
35964 this.bodyEl.dom.appendChild(panel.getEl().dom);
35965 if(panel.background !== true){
35966 this.setActivePanel(panel);
35968 this.fireEvent("paneladded", this, panel);
35975 this.initPanelAsTab(panel);
35979 if(panel.background !== true){
35980 this.tabs.activate(panel.getEl().id);
35982 this.fireEvent("paneladded", this, panel);
35987 * Hides the tab for the specified panel.
35988 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35990 hidePanel : function(panel){
35991 if(this.tabs && (panel = this.getPanel(panel))){
35992 this.tabs.hideTab(panel.getEl().id);
35997 * Unhides the tab for a previously hidden panel.
35998 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36000 unhidePanel : function(panel){
36001 if(this.tabs && (panel = this.getPanel(panel))){
36002 this.tabs.unhideTab(panel.getEl().id);
36006 clearPanels : function(){
36007 while(this.panels.getCount() > 0){
36008 this.remove(this.panels.first());
36013 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36014 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36015 * @param {Boolean} preservePanel Overrides the config preservePanel option
36016 * @return {Roo.ContentPanel} The panel that was removed
36018 remove : function(panel, preservePanel)
36020 panel = this.getPanel(panel);
36025 this.fireEvent("beforeremove", this, panel, e);
36026 if(e.cancel === true){
36029 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36030 var panelId = panel.getId();
36031 this.panels.removeKey(panelId);
36033 document.body.appendChild(panel.getEl().dom);
36036 this.tabs.removeTab(panel.getEl().id);
36037 }else if (!preservePanel){
36038 this.bodyEl.dom.removeChild(panel.getEl().dom);
36040 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36041 var p = this.panels.first();
36042 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36043 tempEl.appendChild(p.getEl().dom);
36044 this.bodyEl.update("");
36045 this.bodyEl.dom.appendChild(p.getEl().dom);
36047 this.updateTitle(p.getTitle());
36049 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36050 this.setActivePanel(p);
36052 panel.setRegion(null);
36053 if(this.activePanel == panel){
36054 this.activePanel = null;
36056 if(this.config.autoDestroy !== false && preservePanel !== true){
36057 try{panel.destroy();}catch(e){}
36059 this.fireEvent("panelremoved", this, panel);
36064 * Returns the TabPanel component used by this region
36065 * @return {Roo.TabPanel}
36067 getTabs : function(){
36071 createTool : function(parentEl, className){
36072 var btn = Roo.DomHelper.append(parentEl, {
36074 cls: "x-layout-tools-button",
36077 cls: "roo-layout-tools-button-inner " + className,
36081 btn.addClassOnOver("roo-layout-tools-button-over");
36086 * Ext JS Library 1.1.1
36087 * Copyright(c) 2006-2007, Ext JS, LLC.
36089 * Originally Released Under LGPL - original licence link has changed is not relivant.
36092 * <script type="text/javascript">
36098 * @class Roo.SplitLayoutRegion
36099 * @extends Roo.LayoutRegion
36100 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36102 Roo.bootstrap.layout.Split = function(config){
36103 this.cursor = config.cursor;
36104 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36107 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36109 splitTip : "Drag to resize.",
36110 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36111 useSplitTips : false,
36113 applyConfig : function(config){
36114 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36117 onRender : function(ctr,pos) {
36119 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36120 if(!this.config.split){
36125 var splitEl = Roo.DomHelper.append(ctr.dom, {
36127 id: this.el.id + "-split",
36128 cls: "roo-layout-split roo-layout-split-"+this.position,
36131 /** The SplitBar for this region
36132 * @type Roo.SplitBar */
36133 // does not exist yet...
36134 Roo.log([this.position, this.orientation]);
36136 this.split = new Roo.bootstrap.SplitBar({
36137 dragElement : splitEl,
36138 resizingElement: this.el,
36139 orientation : this.orientation
36142 this.split.on("moved", this.onSplitMove, this);
36143 this.split.useShim = this.config.useShim === true;
36144 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36145 if(this.useSplitTips){
36146 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36148 //if(config.collapsible){
36149 // this.split.el.on("dblclick", this.collapse, this);
36152 if(typeof this.config.minSize != "undefined"){
36153 this.split.minSize = this.config.minSize;
36155 if(typeof this.config.maxSize != "undefined"){
36156 this.split.maxSize = this.config.maxSize;
36158 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36159 this.hideSplitter();
36164 getHMaxSize : function(){
36165 var cmax = this.config.maxSize || 10000;
36166 var center = this.mgr.getRegion("center");
36167 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36170 getVMaxSize : function(){
36171 var cmax = this.config.maxSize || 10000;
36172 var center = this.mgr.getRegion("center");
36173 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36176 onSplitMove : function(split, newSize){
36177 this.fireEvent("resized", this, newSize);
36181 * Returns the {@link Roo.SplitBar} for this region.
36182 * @return {Roo.SplitBar}
36184 getSplitBar : function(){
36189 this.hideSplitter();
36190 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36193 hideSplitter : function(){
36195 this.split.el.setLocation(-2000,-2000);
36196 this.split.el.hide();
36202 this.split.el.show();
36204 Roo.bootstrap.layout.Split.superclass.show.call(this);
36207 beforeSlide: function(){
36208 if(Roo.isGecko){// firefox overflow auto bug workaround
36209 this.bodyEl.clip();
36211 this.tabs.bodyEl.clip();
36213 if(this.activePanel){
36214 this.activePanel.getEl().clip();
36216 if(this.activePanel.beforeSlide){
36217 this.activePanel.beforeSlide();
36223 afterSlide : function(){
36224 if(Roo.isGecko){// firefox overflow auto bug workaround
36225 this.bodyEl.unclip();
36227 this.tabs.bodyEl.unclip();
36229 if(this.activePanel){
36230 this.activePanel.getEl().unclip();
36231 if(this.activePanel.afterSlide){
36232 this.activePanel.afterSlide();
36238 initAutoHide : function(){
36239 if(this.autoHide !== false){
36240 if(!this.autoHideHd){
36241 var st = new Roo.util.DelayedTask(this.slideIn, this);
36242 this.autoHideHd = {
36243 "mouseout": function(e){
36244 if(!e.within(this.el, true)){
36248 "mouseover" : function(e){
36254 this.el.on(this.autoHideHd);
36258 clearAutoHide : function(){
36259 if(this.autoHide !== false){
36260 this.el.un("mouseout", this.autoHideHd.mouseout);
36261 this.el.un("mouseover", this.autoHideHd.mouseover);
36265 clearMonitor : function(){
36266 Roo.get(document).un("click", this.slideInIf, this);
36269 // these names are backwards but not changed for compat
36270 slideOut : function(){
36271 if(this.isSlid || this.el.hasActiveFx()){
36274 this.isSlid = true;
36275 if(this.collapseBtn){
36276 this.collapseBtn.hide();
36278 this.closeBtnState = this.closeBtn.getStyle('display');
36279 this.closeBtn.hide();
36281 this.stickBtn.show();
36284 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36285 this.beforeSlide();
36286 this.el.setStyle("z-index", 10001);
36287 this.el.slideIn(this.getSlideAnchor(), {
36288 callback: function(){
36290 this.initAutoHide();
36291 Roo.get(document).on("click", this.slideInIf, this);
36292 this.fireEvent("slideshow", this);
36299 afterSlideIn : function(){
36300 this.clearAutoHide();
36301 this.isSlid = false;
36302 this.clearMonitor();
36303 this.el.setStyle("z-index", "");
36304 if(this.collapseBtn){
36305 this.collapseBtn.show();
36307 this.closeBtn.setStyle('display', this.closeBtnState);
36309 this.stickBtn.hide();
36311 this.fireEvent("slidehide", this);
36314 slideIn : function(cb){
36315 if(!this.isSlid || this.el.hasActiveFx()){
36319 this.isSlid = false;
36320 this.beforeSlide();
36321 this.el.slideOut(this.getSlideAnchor(), {
36322 callback: function(){
36323 this.el.setLeftTop(-10000, -10000);
36325 this.afterSlideIn();
36333 slideInIf : function(e){
36334 if(!e.within(this.el)){
36339 animateCollapse : function(){
36340 this.beforeSlide();
36341 this.el.setStyle("z-index", 20000);
36342 var anchor = this.getSlideAnchor();
36343 this.el.slideOut(anchor, {
36344 callback : function(){
36345 this.el.setStyle("z-index", "");
36346 this.collapsedEl.slideIn(anchor, {duration:.3});
36348 this.el.setLocation(-10000,-10000);
36350 this.fireEvent("collapsed", this);
36357 animateExpand : function(){
36358 this.beforeSlide();
36359 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36360 this.el.setStyle("z-index", 20000);
36361 this.collapsedEl.hide({
36364 this.el.slideIn(this.getSlideAnchor(), {
36365 callback : function(){
36366 this.el.setStyle("z-index", "");
36369 this.split.el.show();
36371 this.fireEvent("invalidated", this);
36372 this.fireEvent("expanded", this);
36400 getAnchor : function(){
36401 return this.anchors[this.position];
36404 getCollapseAnchor : function(){
36405 return this.canchors[this.position];
36408 getSlideAnchor : function(){
36409 return this.sanchors[this.position];
36412 getAlignAdj : function(){
36413 var cm = this.cmargins;
36414 switch(this.position){
36430 getExpandAdj : function(){
36431 var c = this.collapsedEl, cm = this.cmargins;
36432 switch(this.position){
36434 return [-(cm.right+c.getWidth()+cm.left), 0];
36437 return [cm.right+c.getWidth()+cm.left, 0];
36440 return [0, -(cm.top+cm.bottom+c.getHeight())];
36443 return [0, cm.top+cm.bottom+c.getHeight()];
36449 * Ext JS Library 1.1.1
36450 * Copyright(c) 2006-2007, Ext JS, LLC.
36452 * Originally Released Under LGPL - original licence link has changed is not relivant.
36455 * <script type="text/javascript">
36458 * These classes are private internal classes
36460 Roo.bootstrap.layout.Center = function(config){
36461 config.region = "center";
36462 Roo.bootstrap.layout.Region.call(this, config);
36463 this.visible = true;
36464 this.minWidth = config.minWidth || 20;
36465 this.minHeight = config.minHeight || 20;
36468 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36470 // center panel can't be hidden
36474 // center panel can't be hidden
36477 getMinWidth: function(){
36478 return this.minWidth;
36481 getMinHeight: function(){
36482 return this.minHeight;
36495 Roo.bootstrap.layout.North = function(config)
36497 config.region = 'north';
36498 config.cursor = 'n-resize';
36500 Roo.bootstrap.layout.Split.call(this, config);
36504 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36505 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36506 this.split.el.addClass("roo-layout-split-v");
36508 var size = config.initialSize || config.height;
36509 if(typeof size != "undefined"){
36510 this.el.setHeight(size);
36513 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36515 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36519 getBox : function(){
36520 if(this.collapsed){
36521 return this.collapsedEl.getBox();
36523 var box = this.el.getBox();
36525 box.height += this.split.el.getHeight();
36530 updateBox : function(box){
36531 if(this.split && !this.collapsed){
36532 box.height -= this.split.el.getHeight();
36533 this.split.el.setLeft(box.x);
36534 this.split.el.setTop(box.y+box.height);
36535 this.split.el.setWidth(box.width);
36537 if(this.collapsed){
36538 this.updateBody(box.width, null);
36540 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36548 Roo.bootstrap.layout.South = function(config){
36549 config.region = 'south';
36550 config.cursor = 's-resize';
36551 Roo.bootstrap.layout.Split.call(this, config);
36553 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36554 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36555 this.split.el.addClass("roo-layout-split-v");
36557 var size = config.initialSize || config.height;
36558 if(typeof size != "undefined"){
36559 this.el.setHeight(size);
36563 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36564 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36565 getBox : function(){
36566 if(this.collapsed){
36567 return this.collapsedEl.getBox();
36569 var box = this.el.getBox();
36571 var sh = this.split.el.getHeight();
36578 updateBox : function(box){
36579 if(this.split && !this.collapsed){
36580 var sh = this.split.el.getHeight();
36583 this.split.el.setLeft(box.x);
36584 this.split.el.setTop(box.y-sh);
36585 this.split.el.setWidth(box.width);
36587 if(this.collapsed){
36588 this.updateBody(box.width, null);
36590 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36594 Roo.bootstrap.layout.East = function(config){
36595 config.region = "east";
36596 config.cursor = "e-resize";
36597 Roo.bootstrap.layout.Split.call(this, config);
36599 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36600 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36601 this.split.el.addClass("roo-layout-split-h");
36603 var size = config.initialSize || config.width;
36604 if(typeof size != "undefined"){
36605 this.el.setWidth(size);
36608 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36609 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36610 getBox : function(){
36611 if(this.collapsed){
36612 return this.collapsedEl.getBox();
36614 var box = this.el.getBox();
36616 var sw = this.split.el.getWidth();
36623 updateBox : function(box){
36624 if(this.split && !this.collapsed){
36625 var sw = this.split.el.getWidth();
36627 this.split.el.setLeft(box.x);
36628 this.split.el.setTop(box.y);
36629 this.split.el.setHeight(box.height);
36632 if(this.collapsed){
36633 this.updateBody(null, box.height);
36635 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36639 Roo.bootstrap.layout.West = function(config){
36640 config.region = "west";
36641 config.cursor = "w-resize";
36643 Roo.bootstrap.layout.Split.call(this, config);
36645 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36646 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36647 this.split.el.addClass("roo-layout-split-h");
36651 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36652 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36654 onRender: function(ctr, pos)
36656 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36657 var size = this.config.initialSize || this.config.width;
36658 if(typeof size != "undefined"){
36659 this.el.setWidth(size);
36663 getBox : function(){
36664 if(this.collapsed){
36665 return this.collapsedEl.getBox();
36667 var box = this.el.getBox();
36669 box.width += this.split.el.getWidth();
36674 updateBox : function(box){
36675 if(this.split && !this.collapsed){
36676 var sw = this.split.el.getWidth();
36678 this.split.el.setLeft(box.x+box.width);
36679 this.split.el.setTop(box.y);
36680 this.split.el.setHeight(box.height);
36682 if(this.collapsed){
36683 this.updateBody(null, box.height);
36685 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36688 Roo.namespace("Roo.bootstrap.panel");/*
36690 * Ext JS Library 1.1.1
36691 * Copyright(c) 2006-2007, Ext JS, LLC.
36693 * Originally Released Under LGPL - original licence link has changed is not relivant.
36696 * <script type="text/javascript">
36699 * @class Roo.ContentPanel
36700 * @extends Roo.util.Observable
36701 * A basic ContentPanel element.
36702 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36703 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36704 * @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
36705 * @cfg {Boolean} closable True if the panel can be closed/removed
36706 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36707 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36708 * @cfg {Toolbar} toolbar A toolbar for this panel
36709 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36710 * @cfg {String} title The title for this panel
36711 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36712 * @cfg {String} url Calls {@link #setUrl} with this value
36713 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36714 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36715 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36716 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36717 * @cfg {Boolean} badges render the badges
36720 * Create a new ContentPanel.
36721 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36722 * @param {String/Object} config A string to set only the title or a config object
36723 * @param {String} content (optional) Set the HTML content for this panel
36724 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36726 Roo.bootstrap.panel.Content = function( config){
36728 this.tpl = config.tpl || false;
36730 var el = config.el;
36731 var content = config.content;
36733 if(config.autoCreate){ // xtype is available if this is called from factory
36736 this.el = Roo.get(el);
36737 if(!this.el && config && config.autoCreate){
36738 if(typeof config.autoCreate == "object"){
36739 if(!config.autoCreate.id){
36740 config.autoCreate.id = config.id||el;
36742 this.el = Roo.DomHelper.append(document.body,
36743 config.autoCreate, true);
36745 var elcfg = { tag: "div",
36746 cls: "roo-layout-inactive-content",
36750 elcfg.html = config.html;
36754 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36757 this.closable = false;
36758 this.loaded = false;
36759 this.active = false;
36762 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36764 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36766 this.wrapEl = this.el; //this.el.wrap();
36768 if (config.toolbar.items) {
36769 ti = config.toolbar.items ;
36770 delete config.toolbar.items ;
36774 this.toolbar.render(this.wrapEl, 'before');
36775 for(var i =0;i < ti.length;i++) {
36776 // Roo.log(['add child', items[i]]);
36777 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36779 this.toolbar.items = nitems;
36780 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36781 delete config.toolbar;
36785 // xtype created footer. - not sure if will work as we normally have to render first..
36786 if (this.footer && !this.footer.el && this.footer.xtype) {
36787 if (!this.wrapEl) {
36788 this.wrapEl = this.el.wrap();
36791 this.footer.container = this.wrapEl.createChild();
36793 this.footer = Roo.factory(this.footer, Roo);
36798 if(typeof config == "string"){
36799 this.title = config;
36801 Roo.apply(this, config);
36805 this.resizeEl = Roo.get(this.resizeEl, true);
36807 this.resizeEl = this.el;
36809 // handle view.xtype
36817 * Fires when this panel is activated.
36818 * @param {Roo.ContentPanel} this
36822 * @event deactivate
36823 * Fires when this panel is activated.
36824 * @param {Roo.ContentPanel} this
36826 "deactivate" : true,
36830 * Fires when this panel is resized if fitToFrame is true.
36831 * @param {Roo.ContentPanel} this
36832 * @param {Number} width The width after any component adjustments
36833 * @param {Number} height The height after any component adjustments
36839 * Fires when this tab is created
36840 * @param {Roo.ContentPanel} this
36851 if(this.autoScroll){
36852 this.resizeEl.setStyle("overflow", "auto");
36854 // fix randome scrolling
36855 //this.el.on('scroll', function() {
36856 // Roo.log('fix random scolling');
36857 // this.scrollTo('top',0);
36860 content = content || this.content;
36862 this.setContent(content);
36864 if(config && config.url){
36865 this.setUrl(this.url, this.params, this.loadOnce);
36870 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36872 if (this.view && typeof(this.view.xtype) != 'undefined') {
36873 this.view.el = this.el.appendChild(document.createElement("div"));
36874 this.view = Roo.factory(this.view);
36875 this.view.render && this.view.render(false, '');
36879 this.fireEvent('render', this);
36882 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36886 setRegion : function(region){
36887 this.region = region;
36888 this.setActiveClass(region && !this.background);
36892 setActiveClass: function(state)
36895 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36896 this.el.setStyle('position','relative');
36898 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36899 this.el.setStyle('position', 'absolute');
36904 * Returns the toolbar for this Panel if one was configured.
36905 * @return {Roo.Toolbar}
36907 getToolbar : function(){
36908 return this.toolbar;
36911 setActiveState : function(active)
36913 this.active = active;
36914 this.setActiveClass(active);
36916 if(this.fireEvent("deactivate", this) === false){
36921 this.fireEvent("activate", this);
36925 * Updates this panel's element
36926 * @param {String} content The new content
36927 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36929 setContent : function(content, loadScripts){
36930 this.el.update(content, loadScripts);
36933 ignoreResize : function(w, h){
36934 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36937 this.lastSize = {width: w, height: h};
36942 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36943 * @return {Roo.UpdateManager} The UpdateManager
36945 getUpdateManager : function(){
36946 return this.el.getUpdateManager();
36949 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36950 * @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:
36953 url: "your-url.php",
36954 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36955 callback: yourFunction,
36956 scope: yourObject, //(optional scope)
36959 text: "Loading...",
36964 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36965 * 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.
36966 * @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}
36967 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36968 * @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.
36969 * @return {Roo.ContentPanel} this
36972 var um = this.el.getUpdateManager();
36973 um.update.apply(um, arguments);
36979 * 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.
36980 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36981 * @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)
36982 * @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)
36983 * @return {Roo.UpdateManager} The UpdateManager
36985 setUrl : function(url, params, loadOnce){
36986 if(this.refreshDelegate){
36987 this.removeListener("activate", this.refreshDelegate);
36989 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36990 this.on("activate", this.refreshDelegate);
36991 return this.el.getUpdateManager();
36994 _handleRefresh : function(url, params, loadOnce){
36995 if(!loadOnce || !this.loaded){
36996 var updater = this.el.getUpdateManager();
36997 updater.update(url, params, this._setLoaded.createDelegate(this));
37001 _setLoaded : function(){
37002 this.loaded = true;
37006 * Returns this panel's id
37009 getId : function(){
37014 * Returns this panel's element - used by regiosn to add.
37015 * @return {Roo.Element}
37017 getEl : function(){
37018 return this.wrapEl || this.el;
37023 adjustForComponents : function(width, height)
37025 //Roo.log('adjustForComponents ');
37026 if(this.resizeEl != this.el){
37027 width -= this.el.getFrameWidth('lr');
37028 height -= this.el.getFrameWidth('tb');
37031 var te = this.toolbar.getEl();
37032 te.setWidth(width);
37033 height -= te.getHeight();
37036 var te = this.footer.getEl();
37037 te.setWidth(width);
37038 height -= te.getHeight();
37042 if(this.adjustments){
37043 width += this.adjustments[0];
37044 height += this.adjustments[1];
37046 return {"width": width, "height": height};
37049 setSize : function(width, height){
37050 if(this.fitToFrame && !this.ignoreResize(width, height)){
37051 if(this.fitContainer && this.resizeEl != this.el){
37052 this.el.setSize(width, height);
37054 var size = this.adjustForComponents(width, height);
37055 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37056 this.fireEvent('resize', this, size.width, size.height);
37061 * Returns this panel's title
37064 getTitle : function(){
37066 if (typeof(this.title) != 'object') {
37071 for (var k in this.title) {
37072 if (!this.title.hasOwnProperty(k)) {
37076 if (k.indexOf('-') >= 0) {
37077 var s = k.split('-');
37078 for (var i = 0; i<s.length; i++) {
37079 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37082 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37089 * Set this panel's title
37090 * @param {String} title
37092 setTitle : function(title){
37093 this.title = title;
37095 this.region.updatePanelTitle(this, title);
37100 * Returns true is this panel was configured to be closable
37101 * @return {Boolean}
37103 isClosable : function(){
37104 return this.closable;
37107 beforeSlide : function(){
37109 this.resizeEl.clip();
37112 afterSlide : function(){
37114 this.resizeEl.unclip();
37118 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37119 * Will fail silently if the {@link #setUrl} method has not been called.
37120 * This does not activate the panel, just updates its content.
37122 refresh : function(){
37123 if(this.refreshDelegate){
37124 this.loaded = false;
37125 this.refreshDelegate();
37130 * Destroys this panel
37132 destroy : function(){
37133 this.el.removeAllListeners();
37134 var tempEl = document.createElement("span");
37135 tempEl.appendChild(this.el.dom);
37136 tempEl.innerHTML = "";
37142 * form - if the content panel contains a form - this is a reference to it.
37143 * @type {Roo.form.Form}
37147 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37148 * This contains a reference to it.
37154 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37164 * @param {Object} cfg Xtype definition of item to add.
37168 getChildContainer: function () {
37169 return this.getEl();
37174 var ret = new Roo.factory(cfg);
37179 if (cfg.xtype.match(/^Form$/)) {
37182 //if (this.footer) {
37183 // el = this.footer.container.insertSibling(false, 'before');
37185 el = this.el.createChild();
37188 this.form = new Roo.form.Form(cfg);
37191 if ( this.form.allItems.length) {
37192 this.form.render(el.dom);
37196 // should only have one of theses..
37197 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37198 // views.. should not be just added - used named prop 'view''
37200 cfg.el = this.el.appendChild(document.createElement("div"));
37203 var ret = new Roo.factory(cfg);
37205 ret.render && ret.render(false, ''); // render blank..
37215 * @class Roo.bootstrap.panel.Grid
37216 * @extends Roo.bootstrap.panel.Content
37218 * Create a new GridPanel.
37219 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37220 * @param {Object} config A the config object
37226 Roo.bootstrap.panel.Grid = function(config)
37230 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37231 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37233 config.el = this.wrapper;
37234 //this.el = this.wrapper;
37236 if (config.container) {
37237 // ctor'ed from a Border/panel.grid
37240 this.wrapper.setStyle("overflow", "hidden");
37241 this.wrapper.addClass('roo-grid-container');
37246 if(config.toolbar){
37247 var tool_el = this.wrapper.createChild();
37248 this.toolbar = Roo.factory(config.toolbar);
37250 if (config.toolbar.items) {
37251 ti = config.toolbar.items ;
37252 delete config.toolbar.items ;
37256 this.toolbar.render(tool_el);
37257 for(var i =0;i < ti.length;i++) {
37258 // Roo.log(['add child', items[i]]);
37259 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37261 this.toolbar.items = nitems;
37263 delete config.toolbar;
37266 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37267 config.grid.scrollBody = true;;
37268 config.grid.monitorWindowResize = false; // turn off autosizing
37269 config.grid.autoHeight = false;
37270 config.grid.autoWidth = false;
37272 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37274 if (config.background) {
37275 // render grid on panel activation (if panel background)
37276 this.on('activate', function(gp) {
37277 if (!gp.grid.rendered) {
37278 gp.grid.render(this.wrapper);
37279 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37284 this.grid.render(this.wrapper);
37285 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37288 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37289 // ??? needed ??? config.el = this.wrapper;
37294 // xtype created footer. - not sure if will work as we normally have to render first..
37295 if (this.footer && !this.footer.el && this.footer.xtype) {
37297 var ctr = this.grid.getView().getFooterPanel(true);
37298 this.footer.dataSource = this.grid.dataSource;
37299 this.footer = Roo.factory(this.footer, Roo);
37300 this.footer.render(ctr);
37310 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37311 getId : function(){
37312 return this.grid.id;
37316 * Returns the grid for this panel
37317 * @return {Roo.bootstrap.Table}
37319 getGrid : function(){
37323 setSize : function(width, height){
37324 if(!this.ignoreResize(width, height)){
37325 var grid = this.grid;
37326 var size = this.adjustForComponents(width, height);
37327 var gridel = grid.getGridEl();
37328 gridel.setSize(size.width, size.height);
37330 var thd = grid.getGridEl().select('thead',true).first();
37331 var tbd = grid.getGridEl().select('tbody', true).first();
37333 tbd.setSize(width, height - thd.getHeight());
37342 beforeSlide : function(){
37343 this.grid.getView().scroller.clip();
37346 afterSlide : function(){
37347 this.grid.getView().scroller.unclip();
37350 destroy : function(){
37351 this.grid.destroy();
37353 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37358 * @class Roo.bootstrap.panel.Nest
37359 * @extends Roo.bootstrap.panel.Content
37361 * Create a new Panel, that can contain a layout.Border.
37364 * @param {Roo.BorderLayout} layout The layout for this panel
37365 * @param {String/Object} config A string to set only the title or a config object
37367 Roo.bootstrap.panel.Nest = function(config)
37369 // construct with only one argument..
37370 /* FIXME - implement nicer consturctors
37371 if (layout.layout) {
37373 layout = config.layout;
37374 delete config.layout;
37376 if (layout.xtype && !layout.getEl) {
37377 // then layout needs constructing..
37378 layout = Roo.factory(layout, Roo);
37382 config.el = config.layout.getEl();
37384 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37386 config.layout.monitorWindowResize = false; // turn off autosizing
37387 this.layout = config.layout;
37388 this.layout.getEl().addClass("roo-layout-nested-layout");
37395 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37397 setSize : function(width, height){
37398 if(!this.ignoreResize(width, height)){
37399 var size = this.adjustForComponents(width, height);
37400 var el = this.layout.getEl();
37401 if (size.height < 1) {
37402 el.setWidth(size.width);
37404 el.setSize(size.width, size.height);
37406 var touch = el.dom.offsetWidth;
37407 this.layout.layout();
37408 // ie requires a double layout on the first pass
37409 if(Roo.isIE && !this.initialized){
37410 this.initialized = true;
37411 this.layout.layout();
37416 // activate all subpanels if not currently active..
37418 setActiveState : function(active){
37419 this.active = active;
37420 this.setActiveClass(active);
37423 this.fireEvent("deactivate", this);
37427 this.fireEvent("activate", this);
37428 // not sure if this should happen before or after..
37429 if (!this.layout) {
37430 return; // should not happen..
37433 for (var r in this.layout.regions) {
37434 reg = this.layout.getRegion(r);
37435 if (reg.getActivePanel()) {
37436 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37437 reg.setActivePanel(reg.getActivePanel());
37440 if (!reg.panels.length) {
37443 reg.showPanel(reg.getPanel(0));
37452 * Returns the nested BorderLayout for this panel
37453 * @return {Roo.BorderLayout}
37455 getLayout : function(){
37456 return this.layout;
37460 * Adds a xtype elements to the layout of the nested panel
37464 xtype : 'ContentPanel',
37471 xtype : 'NestedLayoutPanel',
37477 items : [ ... list of content panels or nested layout panels.. ]
37481 * @param {Object} cfg Xtype definition of item to add.
37483 addxtype : function(cfg) {
37484 return this.layout.addxtype(cfg);
37489 * Ext JS Library 1.1.1
37490 * Copyright(c) 2006-2007, Ext JS, LLC.
37492 * Originally Released Under LGPL - original licence link has changed is not relivant.
37495 * <script type="text/javascript">
37498 * @class Roo.TabPanel
37499 * @extends Roo.util.Observable
37500 * A lightweight tab container.
37504 // basic tabs 1, built from existing content
37505 var tabs = new Roo.TabPanel("tabs1");
37506 tabs.addTab("script", "View Script");
37507 tabs.addTab("markup", "View Markup");
37508 tabs.activate("script");
37510 // more advanced tabs, built from javascript
37511 var jtabs = new Roo.TabPanel("jtabs");
37512 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37514 // set up the UpdateManager
37515 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37516 var updater = tab2.getUpdateManager();
37517 updater.setDefaultUrl("ajax1.htm");
37518 tab2.on('activate', updater.refresh, updater, true);
37520 // Use setUrl for Ajax loading
37521 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37522 tab3.setUrl("ajax2.htm", null, true);
37525 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37528 jtabs.activate("jtabs-1");
37531 * Create a new TabPanel.
37532 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37533 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37535 Roo.bootstrap.panel.Tabs = function(config){
37537 * The container element for this TabPanel.
37538 * @type Roo.Element
37540 this.el = Roo.get(config.el);
37543 if(typeof config == "boolean"){
37544 this.tabPosition = config ? "bottom" : "top";
37546 Roo.apply(this, config);
37550 if(this.tabPosition == "bottom"){
37551 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37552 this.el.addClass("roo-tabs-bottom");
37554 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37555 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37556 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37558 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37560 if(this.tabPosition != "bottom"){
37561 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37562 * @type Roo.Element
37564 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37565 this.el.addClass("roo-tabs-top");
37569 this.bodyEl.setStyle("position", "relative");
37571 this.active = null;
37572 this.activateDelegate = this.activate.createDelegate(this);
37577 * Fires when the active tab changes
37578 * @param {Roo.TabPanel} this
37579 * @param {Roo.TabPanelItem} activePanel The new active tab
37583 * @event beforetabchange
37584 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37585 * @param {Roo.TabPanel} this
37586 * @param {Object} e Set cancel to true on this object to cancel the tab change
37587 * @param {Roo.TabPanelItem} tab The tab being changed to
37589 "beforetabchange" : true
37592 Roo.EventManager.onWindowResize(this.onResize, this);
37593 this.cpad = this.el.getPadding("lr");
37594 this.hiddenCount = 0;
37597 // toolbar on the tabbar support...
37598 if (this.toolbar) {
37599 alert("no toolbar support yet");
37600 this.toolbar = false;
37602 var tcfg = this.toolbar;
37603 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37604 this.toolbar = new Roo.Toolbar(tcfg);
37605 if (Roo.isSafari) {
37606 var tbl = tcfg.container.child('table', true);
37607 tbl.setAttribute('width', '100%');
37615 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37618 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37620 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37622 tabPosition : "top",
37624 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37626 currentTabWidth : 0,
37628 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37632 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37636 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37638 preferredTabWidth : 175,
37640 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37642 resizeTabs : false,
37644 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37646 monitorResize : true,
37648 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37653 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37654 * @param {String} id The id of the div to use <b>or create</b>
37655 * @param {String} text The text for the tab
37656 * @param {String} content (optional) Content to put in the TabPanelItem body
37657 * @param {Boolean} closable (optional) True to create a close icon on the tab
37658 * @return {Roo.TabPanelItem} The created TabPanelItem
37660 addTab : function(id, text, content, closable, tpl)
37662 var item = new Roo.bootstrap.panel.TabItem({
37666 closable : closable,
37669 this.addTabItem(item);
37671 item.setContent(content);
37677 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37678 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37679 * @return {Roo.TabPanelItem}
37681 getTab : function(id){
37682 return this.items[id];
37686 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37687 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37689 hideTab : function(id){
37690 var t = this.items[id];
37693 this.hiddenCount++;
37694 this.autoSizeTabs();
37699 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37700 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37702 unhideTab : function(id){
37703 var t = this.items[id];
37705 t.setHidden(false);
37706 this.hiddenCount--;
37707 this.autoSizeTabs();
37712 * Adds an existing {@link Roo.TabPanelItem}.
37713 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37715 addTabItem : function(item){
37716 this.items[item.id] = item;
37717 this.items.push(item);
37718 // if(this.resizeTabs){
37719 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37720 // this.autoSizeTabs();
37722 // item.autoSize();
37727 * Removes a {@link Roo.TabPanelItem}.
37728 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37730 removeTab : function(id){
37731 var items = this.items;
37732 var tab = items[id];
37733 if(!tab) { return; }
37734 var index = items.indexOf(tab);
37735 if(this.active == tab && items.length > 1){
37736 var newTab = this.getNextAvailable(index);
37741 this.stripEl.dom.removeChild(tab.pnode.dom);
37742 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37743 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37745 items.splice(index, 1);
37746 delete this.items[tab.id];
37747 tab.fireEvent("close", tab);
37748 tab.purgeListeners();
37749 this.autoSizeTabs();
37752 getNextAvailable : function(start){
37753 var items = this.items;
37755 // look for a next tab that will slide over to
37756 // replace the one being removed
37757 while(index < items.length){
37758 var item = items[++index];
37759 if(item && !item.isHidden()){
37763 // if one isn't found select the previous tab (on the left)
37766 var item = items[--index];
37767 if(item && !item.isHidden()){
37775 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37776 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37778 disableTab : function(id){
37779 var tab = this.items[id];
37780 if(tab && this.active != tab){
37786 * Enables a {@link Roo.TabPanelItem} that is disabled.
37787 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37789 enableTab : function(id){
37790 var tab = this.items[id];
37795 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37796 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37797 * @return {Roo.TabPanelItem} The TabPanelItem.
37799 activate : function(id){
37800 var tab = this.items[id];
37804 if(tab == this.active || tab.disabled){
37808 this.fireEvent("beforetabchange", this, e, tab);
37809 if(e.cancel !== true && !tab.disabled){
37811 this.active.hide();
37813 this.active = this.items[id];
37814 this.active.show();
37815 this.fireEvent("tabchange", this, this.active);
37821 * Gets the active {@link Roo.TabPanelItem}.
37822 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37824 getActiveTab : function(){
37825 return this.active;
37829 * Updates the tab body element to fit the height of the container element
37830 * for overflow scrolling
37831 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37833 syncHeight : function(targetHeight){
37834 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37835 var bm = this.bodyEl.getMargins();
37836 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37837 this.bodyEl.setHeight(newHeight);
37841 onResize : function(){
37842 if(this.monitorResize){
37843 this.autoSizeTabs();
37848 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37850 beginUpdate : function(){
37851 this.updating = true;
37855 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37857 endUpdate : function(){
37858 this.updating = false;
37859 this.autoSizeTabs();
37863 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37865 autoSizeTabs : function(){
37866 var count = this.items.length;
37867 var vcount = count - this.hiddenCount;
37868 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37871 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37872 var availWidth = Math.floor(w / vcount);
37873 var b = this.stripBody;
37874 if(b.getWidth() > w){
37875 var tabs = this.items;
37876 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37877 if(availWidth < this.minTabWidth){
37878 /*if(!this.sleft){ // incomplete scrolling code
37879 this.createScrollButtons();
37882 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37885 if(this.currentTabWidth < this.preferredTabWidth){
37886 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37892 * Returns the number of tabs in this TabPanel.
37895 getCount : function(){
37896 return this.items.length;
37900 * Resizes all the tabs to the passed width
37901 * @param {Number} The new width
37903 setTabWidth : function(width){
37904 this.currentTabWidth = width;
37905 for(var i = 0, len = this.items.length; i < len; i++) {
37906 if(!this.items[i].isHidden()) {
37907 this.items[i].setWidth(width);
37913 * Destroys this TabPanel
37914 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37916 destroy : function(removeEl){
37917 Roo.EventManager.removeResizeListener(this.onResize, this);
37918 for(var i = 0, len = this.items.length; i < len; i++){
37919 this.items[i].purgeListeners();
37921 if(removeEl === true){
37922 this.el.update("");
37927 createStrip : function(container)
37929 var strip = document.createElement("nav");
37930 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37931 container.appendChild(strip);
37935 createStripList : function(strip)
37937 // div wrapper for retard IE
37938 // returns the "tr" element.
37939 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37940 //'<div class="x-tabs-strip-wrap">'+
37941 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37942 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37943 return strip.firstChild; //.firstChild.firstChild.firstChild;
37945 createBody : function(container)
37947 var body = document.createElement("div");
37948 Roo.id(body, "tab-body");
37949 //Roo.fly(body).addClass("x-tabs-body");
37950 Roo.fly(body).addClass("tab-content");
37951 container.appendChild(body);
37954 createItemBody :function(bodyEl, id){
37955 var body = Roo.getDom(id);
37957 body = document.createElement("div");
37960 //Roo.fly(body).addClass("x-tabs-item-body");
37961 Roo.fly(body).addClass("tab-pane");
37962 bodyEl.insertBefore(body, bodyEl.firstChild);
37966 createStripElements : function(stripEl, text, closable, tpl)
37968 var td = document.createElement("li"); // was td..
37971 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37974 stripEl.appendChild(td);
37976 td.className = "x-tabs-closable";
37977 if(!this.closeTpl){
37978 this.closeTpl = new Roo.Template(
37979 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37980 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37981 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37984 var el = this.closeTpl.overwrite(td, {"text": text});
37985 var close = el.getElementsByTagName("div")[0];
37986 var inner = el.getElementsByTagName("em")[0];
37987 return {"el": el, "close": close, "inner": inner};
37990 // not sure what this is..
37991 // if(!this.tabTpl){
37992 //this.tabTpl = new Roo.Template(
37993 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37994 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37996 // this.tabTpl = new Roo.Template(
37997 // '<a href="#">' +
37998 // '<span unselectable="on"' +
37999 // (this.disableTooltips ? '' : ' title="{text}"') +
38000 // ' >{text}</span></a>'
38006 var template = tpl || this.tabTpl || false;
38010 template = new Roo.Template(
38012 '<span unselectable="on"' +
38013 (this.disableTooltips ? '' : ' title="{text}"') +
38014 ' >{text}</span></a>'
38018 switch (typeof(template)) {
38022 template = new Roo.Template(template);
38028 var el = template.overwrite(td, {"text": text});
38030 var inner = el.getElementsByTagName("span")[0];
38032 return {"el": el, "inner": inner};
38040 * @class Roo.TabPanelItem
38041 * @extends Roo.util.Observable
38042 * Represents an individual item (tab plus body) in a TabPanel.
38043 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38044 * @param {String} id The id of this TabPanelItem
38045 * @param {String} text The text for the tab of this TabPanelItem
38046 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38048 Roo.bootstrap.panel.TabItem = function(config){
38050 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38051 * @type Roo.TabPanel
38053 this.tabPanel = config.panel;
38055 * The id for this TabPanelItem
38058 this.id = config.id;
38060 this.disabled = false;
38062 this.text = config.text;
38064 this.loaded = false;
38065 this.closable = config.closable;
38068 * The body element for this TabPanelItem.
38069 * @type Roo.Element
38071 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38072 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38073 this.bodyEl.setStyle("display", "block");
38074 this.bodyEl.setStyle("zoom", "1");
38075 //this.hideAction();
38077 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38079 this.el = Roo.get(els.el);
38080 this.inner = Roo.get(els.inner, true);
38081 this.textEl = Roo.get(this.el.dom.firstChild, true);
38082 this.pnode = Roo.get(els.el.parentNode, true);
38083 // this.el.on("mousedown", this.onTabMouseDown, this);
38084 this.el.on("click", this.onTabClick, this);
38086 if(config.closable){
38087 var c = Roo.get(els.close, true);
38088 c.dom.title = this.closeText;
38089 c.addClassOnOver("close-over");
38090 c.on("click", this.closeClick, this);
38096 * Fires when this tab becomes the active tab.
38097 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38098 * @param {Roo.TabPanelItem} this
38102 * @event beforeclose
38103 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38104 * @param {Roo.TabPanelItem} this
38105 * @param {Object} e Set cancel to true on this object to cancel the close.
38107 "beforeclose": true,
38110 * Fires when this tab is closed.
38111 * @param {Roo.TabPanelItem} this
38115 * @event deactivate
38116 * Fires when this tab is no longer the active tab.
38117 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38118 * @param {Roo.TabPanelItem} this
38120 "deactivate" : true
38122 this.hidden = false;
38124 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38127 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38129 purgeListeners : function(){
38130 Roo.util.Observable.prototype.purgeListeners.call(this);
38131 this.el.removeAllListeners();
38134 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38137 this.pnode.addClass("active");
38140 this.tabPanel.stripWrap.repaint();
38142 this.fireEvent("activate", this.tabPanel, this);
38146 * Returns true if this tab is the active tab.
38147 * @return {Boolean}
38149 isActive : function(){
38150 return this.tabPanel.getActiveTab() == this;
38154 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38157 this.pnode.removeClass("active");
38159 this.fireEvent("deactivate", this.tabPanel, this);
38162 hideAction : function(){
38163 this.bodyEl.hide();
38164 this.bodyEl.setStyle("position", "absolute");
38165 this.bodyEl.setLeft("-20000px");
38166 this.bodyEl.setTop("-20000px");
38169 showAction : function(){
38170 this.bodyEl.setStyle("position", "relative");
38171 this.bodyEl.setTop("");
38172 this.bodyEl.setLeft("");
38173 this.bodyEl.show();
38177 * Set the tooltip for the tab.
38178 * @param {String} tooltip The tab's tooltip
38180 setTooltip : function(text){
38181 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38182 this.textEl.dom.qtip = text;
38183 this.textEl.dom.removeAttribute('title');
38185 this.textEl.dom.title = text;
38189 onTabClick : function(e){
38190 e.preventDefault();
38191 this.tabPanel.activate(this.id);
38194 onTabMouseDown : function(e){
38195 e.preventDefault();
38196 this.tabPanel.activate(this.id);
38199 getWidth : function(){
38200 return this.inner.getWidth();
38203 setWidth : function(width){
38204 var iwidth = width - this.pnode.getPadding("lr");
38205 this.inner.setWidth(iwidth);
38206 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38207 this.pnode.setWidth(width);
38211 * Show or hide the tab
38212 * @param {Boolean} hidden True to hide or false to show.
38214 setHidden : function(hidden){
38215 this.hidden = hidden;
38216 this.pnode.setStyle("display", hidden ? "none" : "");
38220 * Returns true if this tab is "hidden"
38221 * @return {Boolean}
38223 isHidden : function(){
38224 return this.hidden;
38228 * Returns the text for this tab
38231 getText : function(){
38235 autoSize : function(){
38236 //this.el.beginMeasure();
38237 this.textEl.setWidth(1);
38239 * #2804 [new] Tabs in Roojs
38240 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38242 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38243 //this.el.endMeasure();
38247 * Sets the text for the tab (Note: this also sets the tooltip text)
38248 * @param {String} text The tab's text and tooltip
38250 setText : function(text){
38252 this.textEl.update(text);
38253 this.setTooltip(text);
38254 //if(!this.tabPanel.resizeTabs){
38255 // this.autoSize();
38259 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38261 activate : function(){
38262 this.tabPanel.activate(this.id);
38266 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38268 disable : function(){
38269 if(this.tabPanel.active != this){
38270 this.disabled = true;
38271 this.pnode.addClass("disabled");
38276 * Enables this TabPanelItem if it was previously disabled.
38278 enable : function(){
38279 this.disabled = false;
38280 this.pnode.removeClass("disabled");
38284 * Sets the content for this TabPanelItem.
38285 * @param {String} content The content
38286 * @param {Boolean} loadScripts true to look for and load scripts
38288 setContent : function(content, loadScripts){
38289 this.bodyEl.update(content, loadScripts);
38293 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38294 * @return {Roo.UpdateManager} The UpdateManager
38296 getUpdateManager : function(){
38297 return this.bodyEl.getUpdateManager();
38301 * Set a URL to be used to load the content for this TabPanelItem.
38302 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38303 * @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)
38304 * @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)
38305 * @return {Roo.UpdateManager} The UpdateManager
38307 setUrl : function(url, params, loadOnce){
38308 if(this.refreshDelegate){
38309 this.un('activate', this.refreshDelegate);
38311 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38312 this.on("activate", this.refreshDelegate);
38313 return this.bodyEl.getUpdateManager();
38317 _handleRefresh : function(url, params, loadOnce){
38318 if(!loadOnce || !this.loaded){
38319 var updater = this.bodyEl.getUpdateManager();
38320 updater.update(url, params, this._setLoaded.createDelegate(this));
38325 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38326 * Will fail silently if the setUrl method has not been called.
38327 * This does not activate the panel, just updates its content.
38329 refresh : function(){
38330 if(this.refreshDelegate){
38331 this.loaded = false;
38332 this.refreshDelegate();
38337 _setLoaded : function(){
38338 this.loaded = true;
38342 closeClick : function(e){
38345 this.fireEvent("beforeclose", this, o);
38346 if(o.cancel !== true){
38347 this.tabPanel.removeTab(this.id);
38351 * The text displayed in the tooltip for the close icon.
38354 closeText : "Close this tab"
38357 * This script refer to:
38358 * Title: International Telephone Input
38359 * Author: Jack O'Connor
38360 * Code version: v12.1.12
38361 * Availability: https://github.com/jackocnr/intl-tel-input.git
38364 Roo.bootstrap.PhoneInputData = function() {
38367 "Afghanistan (افغانستان)",
38372 "Albania (Shqipëri)",
38377 "Algeria (الجزائر)",
38402 "Antigua and Barbuda",
38412 "Armenia (Հայաստան)",
38428 "Austria (Österreich)",
38433 "Azerbaijan (Azərbaycan)",
38443 "Bahrain (البحرين)",
38448 "Bangladesh (বাংলাদেশ)",
38458 "Belarus (Беларусь)",
38463 "Belgium (België)",
38493 "Bosnia and Herzegovina (Босна и Херцеговина)",
38508 "British Indian Ocean Territory",
38513 "British Virgin Islands",
38523 "Bulgaria (България)",
38533 "Burundi (Uburundi)",
38538 "Cambodia (កម្ពុជា)",
38543 "Cameroon (Cameroun)",
38552 ["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"]
38555 "Cape Verde (Kabu Verdi)",
38560 "Caribbean Netherlands",
38571 "Central African Republic (République centrafricaine)",
38591 "Christmas Island",
38597 "Cocos (Keeling) Islands",
38608 "Comoros (جزر القمر)",
38613 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38618 "Congo (Republic) (Congo-Brazzaville)",
38638 "Croatia (Hrvatska)",
38659 "Czech Republic (Česká republika)",
38664 "Denmark (Danmark)",
38679 "Dominican Republic (República Dominicana)",
38683 ["809", "829", "849"]
38701 "Equatorial Guinea (Guinea Ecuatorial)",
38721 "Falkland Islands (Islas Malvinas)",
38726 "Faroe Islands (Føroyar)",
38747 "French Guiana (Guyane française)",
38752 "French Polynesia (Polynésie française)",
38767 "Georgia (საქართველო)",
38772 "Germany (Deutschland)",
38792 "Greenland (Kalaallit Nunaat)",
38829 "Guinea-Bissau (Guiné Bissau)",
38854 "Hungary (Magyarország)",
38859 "Iceland (Ísland)",
38879 "Iraq (العراق)",
38895 "Israel (ישראל)",
38922 "Jordan (الأردن)",
38927 "Kazakhstan (Казахстан)",
38948 "Kuwait (الكويت)",
38953 "Kyrgyzstan (Кыргызстан)",
38963 "Latvia (Latvija)",
38968 "Lebanon (لبنان)",
38983 "Libya (ليبيا)",
38993 "Lithuania (Lietuva)",
39008 "Macedonia (FYROM) (Македонија)",
39013 "Madagascar (Madagasikara)",
39043 "Marshall Islands",
39053 "Mauritania (موريتانيا)",
39058 "Mauritius (Moris)",
39079 "Moldova (Republica Moldova)",
39089 "Mongolia (Монгол)",
39094 "Montenegro (Crna Gora)",
39104 "Morocco (المغرب)",
39110 "Mozambique (Moçambique)",
39115 "Myanmar (Burma) (မြန်မာ)",
39120 "Namibia (Namibië)",
39135 "Netherlands (Nederland)",
39140 "New Caledonia (Nouvelle-Calédonie)",
39175 "North Korea (조선 민주주의 인민 공화국)",
39180 "Northern Mariana Islands",
39196 "Pakistan (پاکستان)",
39206 "Palestine (فلسطين)",
39216 "Papua New Guinea",
39258 "Réunion (La Réunion)",
39264 "Romania (România)",
39280 "Saint Barthélemy",
39291 "Saint Kitts and Nevis",
39301 "Saint Martin (Saint-Martin (partie française))",
39307 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39312 "Saint Vincent and the Grenadines",
39327 "São Tomé and Príncipe (São Tomé e Príncipe)",
39332 "Saudi Arabia (المملكة العربية السعودية)",
39337 "Senegal (Sénégal)",
39367 "Slovakia (Slovensko)",
39372 "Slovenia (Slovenija)",
39382 "Somalia (Soomaaliya)",
39392 "South Korea (대한민국)",
39397 "South Sudan (جنوب السودان)",
39407 "Sri Lanka (ශ්රී ලංකාව)",
39412 "Sudan (السودان)",
39422 "Svalbard and Jan Mayen",
39433 "Sweden (Sverige)",
39438 "Switzerland (Schweiz)",
39443 "Syria (سوريا)",
39488 "Trinidad and Tobago",
39493 "Tunisia (تونس)",
39498 "Turkey (Türkiye)",
39508 "Turks and Caicos Islands",
39518 "U.S. Virgin Islands",
39528 "Ukraine (Україна)",
39533 "United Arab Emirates (الإمارات العربية المتحدة)",
39555 "Uzbekistan (Oʻzbekiston)",
39565 "Vatican City (Città del Vaticano)",
39576 "Vietnam (Việt Nam)",
39581 "Wallis and Futuna (Wallis-et-Futuna)",
39586 "Western Sahara (الصحراء الغربية)",
39592 "Yemen (اليمن)",
39616 * This script refer to:
39617 * Title: International Telephone Input
39618 * Author: Jack O'Connor
39619 * Code version: v12.1.12
39620 * Availability: https://github.com/jackocnr/intl-tel-input.git
39624 * @class Roo.bootstrap.PhoneInput
39625 * @extends Roo.bootstrap.TriggerField
39626 * An input with International dial-code selection
39628 * @cfg {String} defaultDialCode default '+852'
39629 * @cfg {Array} preferedCountries default []
39632 * Create a new PhoneInput.
39633 * @param {Object} config Configuration options
39636 Roo.bootstrap.PhoneInput = function(config) {
39637 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39640 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39642 listWidth: undefined,
39644 selectedClass: 'active',
39646 invalidClass : "has-warning",
39648 validClass: 'has-success',
39650 allowed: '0123456789',
39653 * @cfg {String} defaultDialCode The default dial code when initializing the input
39655 defaultDialCode: '+852',
39658 * @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
39660 preferedCountries: false,
39662 getAutoCreate : function()
39664 var data = Roo.bootstrap.PhoneInputData();
39665 var align = this.labelAlign || this.parentLabelAlign();
39668 this.allCountries = [];
39669 this.dialCodeMapping = [];
39671 for (var i = 0; i < data.length; i++) {
39673 this.allCountries[i] = {
39677 priority: c[3] || 0,
39678 areaCodes: c[4] || null
39680 this.dialCodeMapping[c[2]] = {
39683 priority: c[3] || 0,
39684 areaCodes: c[4] || null
39696 cls : 'form-control tel-input',
39697 autocomplete: 'new-password'
39700 var hiddenInput = {
39703 cls: 'hidden-tel-input'
39707 hiddenInput.name = this.name;
39710 if (this.disabled) {
39711 input.disabled = true;
39714 var flag_container = {
39731 cls: this.hasFeedback ? 'has-feedback' : '',
39737 cls: 'dial-code-holder',
39744 cls: 'roo-select2-container input-group',
39751 if (this.fieldLabel.length) {
39754 tooltip: 'This field is required'
39760 cls: 'control-label',
39766 html: this.fieldLabel
39769 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39775 if(this.indicatorpos == 'right') {
39776 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39783 if(align == 'left') {
39791 if(this.labelWidth > 12){
39792 label.style = "width: " + this.labelWidth + 'px';
39794 if(this.labelWidth < 13 && this.labelmd == 0){
39795 this.labelmd = this.labelWidth;
39797 if(this.labellg > 0){
39798 label.cls += ' col-lg-' + this.labellg;
39799 input.cls += ' col-lg-' + (12 - this.labellg);
39801 if(this.labelmd > 0){
39802 label.cls += ' col-md-' + this.labelmd;
39803 container.cls += ' col-md-' + (12 - this.labelmd);
39805 if(this.labelsm > 0){
39806 label.cls += ' col-sm-' + this.labelsm;
39807 container.cls += ' col-sm-' + (12 - this.labelsm);
39809 if(this.labelxs > 0){
39810 label.cls += ' col-xs-' + this.labelxs;
39811 container.cls += ' col-xs-' + (12 - this.labelxs);
39821 var settings = this;
39823 ['xs','sm','md','lg'].map(function(size){
39824 if (settings[size]) {
39825 cfg.cls += ' col-' + size + '-' + settings[size];
39829 this.store = new Roo.data.Store({
39830 proxy : new Roo.data.MemoryProxy({}),
39831 reader : new Roo.data.JsonReader({
39842 'name' : 'dialCode',
39846 'name' : 'priority',
39850 'name' : 'areaCodes',
39857 if(!this.preferedCountries) {
39858 this.preferedCountries = [
39865 var p = this.preferedCountries.reverse();
39868 for (var i = 0; i < p.length; i++) {
39869 for (var j = 0; j < this.allCountries.length; j++) {
39870 if(this.allCountries[j].iso2 == p[i]) {
39871 var t = this.allCountries[j];
39872 this.allCountries.splice(j,1);
39873 this.allCountries.unshift(t);
39879 this.store.proxy.data = {
39881 data: this.allCountries
39887 initEvents : function()
39890 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39892 this.indicator = this.indicatorEl();
39893 this.flag = this.flagEl();
39894 this.dialCodeHolder = this.dialCodeHolderEl();
39896 this.trigger = this.el.select('div.flag-box',true).first();
39897 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39902 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39903 _this.list.setWidth(lw);
39906 this.list.on('mouseover', this.onViewOver, this);
39907 this.list.on('mousemove', this.onViewMove, this);
39908 this.inputEl().on("keyup", this.onKeyUp, this);
39910 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39912 this.view = new Roo.View(this.list, this.tpl, {
39913 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39916 this.view.on('click', this.onViewClick, this);
39917 this.setValue(this.defaultDialCode);
39920 onTriggerClick : function(e)
39922 Roo.log('trigger click');
39927 if(this.isExpanded()){
39929 this.hasFocus = false;
39931 this.store.load({});
39932 this.hasFocus = true;
39937 isExpanded : function()
39939 return this.list.isVisible();
39942 collapse : function()
39944 if(!this.isExpanded()){
39948 Roo.get(document).un('mousedown', this.collapseIf, this);
39949 Roo.get(document).un('mousewheel', this.collapseIf, this);
39950 this.fireEvent('collapse', this);
39954 expand : function()
39958 if(this.isExpanded() || !this.hasFocus){
39962 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39963 this.list.setWidth(lw);
39966 this.restrictHeight();
39968 Roo.get(document).on('mousedown', this.collapseIf, this);
39969 Roo.get(document).on('mousewheel', this.collapseIf, this);
39971 this.fireEvent('expand', this);
39974 restrictHeight : function()
39976 this.list.alignTo(this.inputEl(), this.listAlign);
39977 this.list.alignTo(this.inputEl(), this.listAlign);
39980 onViewOver : function(e, t)
39982 if(this.inKeyMode){
39985 var item = this.view.findItemFromChild(t);
39988 var index = this.view.indexOf(item);
39989 this.select(index, false);
39994 onViewClick : function(view, doFocus, el, e)
39996 var index = this.view.getSelectedIndexes()[0];
39998 var r = this.store.getAt(index);
40001 this.onSelect(r, index);
40003 if(doFocus !== false && !this.blockFocus){
40004 this.inputEl().focus();
40008 onViewMove : function(e, t)
40010 this.inKeyMode = false;
40013 select : function(index, scrollIntoView)
40015 this.selectedIndex = index;
40016 this.view.select(index);
40017 if(scrollIntoView !== false){
40018 var el = this.view.getNode(index);
40020 this.list.scrollChildIntoView(el, false);
40025 createList : function()
40027 this.list = Roo.get(document.body).createChild({
40029 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40030 style: 'display:none'
40032 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40035 collapseIf : function(e)
40037 var in_combo = e.within(this.el);
40038 var in_list = e.within(this.list);
40039 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40041 if (in_combo || in_list || is_list) {
40047 onSelect : function(record, index)
40049 if(this.fireEvent('beforeselect', this, record, index) !== false){
40051 this.setFlagClass(record.data.iso2);
40052 this.setDialCode(record.data.dialCode);
40053 this.hasFocus = false;
40055 this.fireEvent('select', this, record, index);
40059 flagEl : function()
40061 var flag = this.el.select('div.flag',true).first();
40068 dialCodeHolderEl : function()
40070 var d = this.el.select('input.dial-code-holder',true).first();
40077 setDialCode : function(v)
40079 this.dialCodeHolder.dom.value = '+'+v;
40082 setFlagClass : function(n)
40084 this.flag.dom.className = 'flag '+n;
40087 getValue : function()
40089 var v = this.inputEl().getValue();
40090 if(this.dialCodeHolder) {
40091 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40096 setValue : function(v)
40098 var d = this.getDialCode(v);
40100 //invalid dial code
40101 if(v.length == 0 || !d || d.length == 0) {
40103 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40104 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40110 this.setFlagClass(this.dialCodeMapping[d].iso2);
40111 this.setDialCode(d);
40112 this.inputEl().dom.value = v.replace('+'+d,'');
40113 this.hiddenEl().dom.value = this.getValue();
40118 getDialCode : function(v = '')
40120 if (v.length == 0) {
40121 return this.dialCodeHolder.dom.value;
40125 if (v.charAt(0) != "+") {
40128 var numericChars = "";
40129 for (var i = 1; i < v.length; i++) {
40130 var c = v.charAt(i);
40133 if (this.dialCodeMapping[numericChars]) {
40134 dialCode = v.substr(1, i);
40136 if (numericChars.length == 4) {
40146 this.setValue(this.defaultDialCode);
40150 hiddenEl : function()
40152 return this.el.select('input.hidden-tel-input',true).first();
40155 onKeyUp : function(e){
40157 var k = e.getKey();
40158 var c = e.getCharCode();
40161 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40162 this.allowed.indexOf(String.fromCharCode(c)) === -1
40167 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40170 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40174 this.setValue(this.getValue());
40179 * @class Roo.bootstrap.MoneyField
40180 * @extends Roo.bootstrap.ComboBox
40181 * Bootstrap MoneyField class
40184 * Create a new MoneyField.
40185 * @param {Object} config Configuration options
40188 Roo.bootstrap.MoneyField = function(config) {
40190 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40194 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40197 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40199 allowDecimals : true,
40201 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40203 decimalSeparator : ".",
40205 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40207 decimalPrecision : 0,
40209 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40211 allowNegative : true,
40213 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40215 minValue : Number.NEGATIVE_INFINITY,
40217 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40219 maxValue : Number.MAX_VALUE,
40221 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40223 minText : "The minimum value for this field is {0}",
40225 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40227 maxText : "The maximum value for this field is {0}",
40229 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40230 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40232 nanText : "{0} is not a valid number",
40234 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40238 * @cfg {String} defaults currency of the MoneyField
40239 * value should be in lkey
40241 defaultCurrency : false,
40243 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40245 thousandsDelimiter : false,
40255 getAutoCreate : function()
40257 var align = this.labelAlign || this.parentLabelAlign();
40269 cls : 'form-control roo-money-amount-input',
40270 autocomplete: 'new-password'
40273 var hiddenInput = {
40277 cls: 'hidden-number-input'
40281 hiddenInput.name = this.name;
40284 if (this.disabled) {
40285 input.disabled = true;
40288 var clg = 12 - this.inputlg;
40289 var cmd = 12 - this.inputmd;
40290 var csm = 12 - this.inputsm;
40291 var cxs = 12 - this.inputxs;
40295 cls : 'row roo-money-field',
40299 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40303 cls: 'roo-select2-container input-group',
40307 cls : 'form-control roo-money-currency-input',
40308 autocomplete: 'new-password',
40310 name : this.currencyName
40314 cls : 'input-group-addon',
40328 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40332 cls: this.hasFeedback ? 'has-feedback' : '',
40343 if (this.fieldLabel.length) {
40346 tooltip: 'This field is required'
40352 cls: 'control-label',
40358 html: this.fieldLabel
40361 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40367 if(this.indicatorpos == 'right') {
40368 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40375 if(align == 'left') {
40383 if(this.labelWidth > 12){
40384 label.style = "width: " + this.labelWidth + 'px';
40386 if(this.labelWidth < 13 && this.labelmd == 0){
40387 this.labelmd = this.labelWidth;
40389 if(this.labellg > 0){
40390 label.cls += ' col-lg-' + this.labellg;
40391 input.cls += ' col-lg-' + (12 - this.labellg);
40393 if(this.labelmd > 0){
40394 label.cls += ' col-md-' + this.labelmd;
40395 container.cls += ' col-md-' + (12 - this.labelmd);
40397 if(this.labelsm > 0){
40398 label.cls += ' col-sm-' + this.labelsm;
40399 container.cls += ' col-sm-' + (12 - this.labelsm);
40401 if(this.labelxs > 0){
40402 label.cls += ' col-xs-' + this.labelxs;
40403 container.cls += ' col-xs-' + (12 - this.labelxs);
40414 var settings = this;
40416 ['xs','sm','md','lg'].map(function(size){
40417 if (settings[size]) {
40418 cfg.cls += ' col-' + size + '-' + settings[size];
40425 initEvents : function()
40427 this.indicator = this.indicatorEl();
40429 this.initCurrencyEvent();
40431 this.initNumberEvent();
40434 initCurrencyEvent : function()
40437 throw "can not find store for combo";
40440 this.store = Roo.factory(this.store, Roo.data);
40441 this.store.parent = this;
40445 this.triggerEl = this.el.select('.input-group-addon', true).first();
40447 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40452 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40453 _this.list.setWidth(lw);
40456 this.list.on('mouseover', this.onViewOver, this);
40457 this.list.on('mousemove', this.onViewMove, this);
40458 this.list.on('scroll', this.onViewScroll, this);
40461 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40464 this.view = new Roo.View(this.list, this.tpl, {
40465 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40468 this.view.on('click', this.onViewClick, this);
40470 this.store.on('beforeload', this.onBeforeLoad, this);
40471 this.store.on('load', this.onLoad, this);
40472 this.store.on('loadexception', this.onLoadException, this);
40474 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40475 "up" : function(e){
40476 this.inKeyMode = true;
40480 "down" : function(e){
40481 if(!this.isExpanded()){
40482 this.onTriggerClick();
40484 this.inKeyMode = true;
40489 "enter" : function(e){
40492 if(this.fireEvent("specialkey", this, e)){
40493 this.onViewClick(false);
40499 "esc" : function(e){
40503 "tab" : function(e){
40506 if(this.fireEvent("specialkey", this, e)){
40507 this.onViewClick(false);
40515 doRelay : function(foo, bar, hname){
40516 if(hname == 'down' || this.scope.isExpanded()){
40517 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40525 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40529 initNumberEvent : function(e)
40531 this.inputEl().on("keydown" , this.fireKey, this);
40532 this.inputEl().on("focus", this.onFocus, this);
40533 this.inputEl().on("blur", this.onBlur, this);
40535 this.inputEl().relayEvent('keyup', this);
40537 if(this.indicator){
40538 this.indicator.addClass('invisible');
40541 this.originalValue = this.getValue();
40543 if(this.validationEvent == 'keyup'){
40544 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40545 this.inputEl().on('keyup', this.filterValidation, this);
40547 else if(this.validationEvent !== false){
40548 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40551 if(this.selectOnFocus){
40552 this.on("focus", this.preFocus, this);
40555 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40556 this.inputEl().on("keypress", this.filterKeys, this);
40558 this.inputEl().relayEvent('keypress', this);
40561 var allowed = "0123456789";
40563 if(this.allowDecimals){
40564 allowed += this.decimalSeparator;
40567 if(this.allowNegative){
40571 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40573 var keyPress = function(e){
40575 var k = e.getKey();
40577 var c = e.getCharCode();
40580 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40581 allowed.indexOf(String.fromCharCode(c)) === -1
40587 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40591 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40596 this.inputEl().on("keypress", keyPress, this);
40600 onTriggerClick : function(e)
40607 this.loadNext = false;
40609 if(this.isExpanded()){
40614 this.hasFocus = true;
40616 if(this.triggerAction == 'all') {
40617 this.doQuery(this.allQuery, true);
40621 this.doQuery(this.getRawValue());
40624 getCurrency : function()
40626 var v = this.currencyEl().getValue();
40631 restrictHeight : function()
40633 this.list.alignTo(this.currencyEl(), this.listAlign);
40634 this.list.alignTo(this.currencyEl(), this.listAlign);
40637 onViewClick : function(view, doFocus, el, e)
40639 var index = this.view.getSelectedIndexes()[0];
40641 var r = this.store.getAt(index);
40644 this.onSelect(r, index);
40648 onSelect : function(record, index){
40650 if(this.fireEvent('beforeselect', this, record, index) !== false){
40652 this.setFromCurrencyData(index > -1 ? record.data : false);
40656 this.fireEvent('select', this, record, index);
40660 setFromCurrencyData : function(o)
40664 this.lastCurrency = o;
40666 if (this.currencyField) {
40667 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40669 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40672 this.lastSelectionText = currency;
40674 //setting default currency
40675 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40676 this.setCurrency(this.defaultCurrency);
40680 this.setCurrency(currency);
40683 setFromData : function(o)
40687 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40689 this.setFromCurrencyData(c);
40694 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40696 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40699 this.setValue(value);
40703 setCurrency : function(v)
40705 this.currencyValue = v;
40708 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40713 setValue : function(v)
40715 v = this.fixPrecision(v);
40717 v = String(v).replace(".", this.decimalSeparator);
40723 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40725 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40726 this.thousandsDelimiter || ','
40729 if(this.allowBlank && !v) {
40730 this.inputEl().dom.value = '';
40737 getRawValue : function()
40739 var v = this.inputEl().getValue();
40744 getValue : function()
40746 return this.fixPrecision(this.parseValue(this.getRawValue()));
40749 parseValue : function(value)
40751 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40752 return isNaN(value) ? '' : value;
40755 fixPrecision : function(value)
40757 var nan = isNaN(value);
40759 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40760 return nan ? '' : value;
40763 return parseFloat(value).toFixed(this.decimalPrecision);
40766 decimalPrecisionFcn : function(v)
40768 return Math.floor(v);
40771 validateValue : function(value)
40773 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40777 var num = this.parseValue(value);
40780 this.markInvalid(String.format(this.nanText, value));
40784 if(num < this.minValue){
40785 this.markInvalid(String.format(this.minText, this.minValue));
40789 if(num > this.maxValue){
40790 this.markInvalid(String.format(this.maxText, this.maxValue));
40797 validate : function()
40799 if(this.disabled || this.allowBlank){
40804 var currency = this.getCurrency();
40806 if(this.validateValue(this.getRawValue()) && currency.length){
40811 this.markInvalid();
40815 getName: function()
40820 beforeBlur : function()
40826 var v = this.parseValue(this.getRawValue());
40833 onBlur : function()
40837 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40838 //this.el.removeClass(this.focusClass);
40841 this.hasFocus = false;
40843 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40847 var v = this.getValue();
40849 if(String(v) !== String(this.startValue)){
40850 this.fireEvent('change', this, v, this.startValue);
40853 this.fireEvent("blur", this);
40856 inputEl : function()
40858 return this.el.select('.roo-money-amount-input', true).first();
40861 currencyEl : function()
40863 return this.el.select('.roo-money-currency-input', true).first();
40866 hiddenEl : function()
40868 return this.el.select('input.hidden-number-input',true).first();