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;
2758 cls: "modal-dialog " + size,
2761 cls : "modal-content",
2764 cls : 'modal-header',
2769 cls : 'modal-footer',
2773 cls: 'btn-' + this.buttonPosition
2790 modal.cls += ' fade';
2796 getChildContainer : function() {
2801 getButtonContainer : function() {
2802 return this.el.select('.modal-footer div',true).first();
2805 initEvents : function()
2807 if (this.allow_close) {
2808 this.closeEl.on('click', this.hide, this);
2810 Roo.EventManager.onWindowResize(this.resize, this, true);
2817 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2818 if (this.fitwindow) {
2819 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2820 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2825 setSize : function(w,h)
2835 if (!this.rendered) {
2839 //this.el.setStyle('display', 'block');
2840 this.el.addClass('show');
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
2887 this.el.addClass('hideing');
2889 this.el.removeClass('show');
2890 this.el.removeClass('hideing');
2894 this.el.removeClass('show');
2896 this.fireEvent('hide', this);
2899 isVisible : function()
2902 return this.el.hasClass('show') && !this.el.hasClass('hideing');
2906 addButton : function(str, cb)
2910 var b = Roo.apply({}, { html : str } );
2911 b.xns = b.xns || Roo.bootstrap;
2912 b.xtype = b.xtype || 'Button';
2913 if (typeof(b.listeners) == 'undefined') {
2914 b.listeners = { click : cb.createDelegate(this) };
2917 var btn = Roo.factory(b);
2919 btn.render(this.el.select('.modal-footer div').first());
2925 setDefaultButton : function(btn)
2927 //this.el.select('.modal-footer').()
2931 resizeTo: function(w,h)
2935 this.dialogEl.setWidth(w);
2936 if (this.diff === false) {
2937 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2940 this.bodyEl.setHeight(h-this.diff);
2942 this.fireEvent('resize', this);
2945 setContentSize : function(w, h)
2949 onButtonClick: function(btn,e)
2952 this.fireEvent('btnclick', btn.name, e);
2955 * Set the title of the Dialog
2956 * @param {String} str new Title
2958 setTitle: function(str) {
2959 this.titleEl.dom.innerHTML = str;
2962 * Set the body of the Dialog
2963 * @param {String} str new Title
2965 setBody: function(str) {
2966 this.bodyEl.dom.innerHTML = str;
2969 * Set the body of the Dialog using the template
2970 * @param {Obj} data - apply this data to the template and replace the body contents.
2972 applyBody: function(obj)
2975 Roo.log("Error - using apply Body without a template");
2978 this.tmpl.overwrite(this.bodyEl, obj);
2984 Roo.apply(Roo.bootstrap.Modal, {
2986 * Button config that displays a single OK button
2995 * Button config that displays Yes and No buttons
3011 * Button config that displays OK and Cancel buttons
3026 * Button config that displays Yes, No and Cancel buttons
3050 * messagebox - can be used as a replace
3054 * @class Roo.MessageBox
3055 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3059 Roo.Msg.alert('Status', 'Changes saved successfully.');
3061 // Prompt for user data:
3062 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3064 // process text value...
3068 // Show a dialog using config options:
3070 title:'Save Changes?',
3071 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3072 buttons: Roo.Msg.YESNOCANCEL,
3079 Roo.bootstrap.MessageBox = function(){
3080 var dlg, opt, mask, waitTimer;
3081 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3082 var buttons, activeTextEl, bwidth;
3086 var handleButton = function(button){
3088 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3092 var handleHide = function(){
3094 dlg.el.removeClass(opt.cls);
3097 // Roo.TaskMgr.stop(waitTimer);
3098 // waitTimer = null;
3103 var updateButtons = function(b){
3106 buttons["ok"].hide();
3107 buttons["cancel"].hide();
3108 buttons["yes"].hide();
3109 buttons["no"].hide();
3110 //dlg.footer.dom.style.display = 'none';
3113 dlg.footerEl.dom.style.display = '';
3114 for(var k in buttons){
3115 if(typeof buttons[k] != "function"){
3118 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3119 width += buttons[k].el.getWidth()+15;
3129 var handleEsc = function(d, k, e){
3130 if(opt && opt.closable !== false){
3140 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3141 * @return {Roo.BasicDialog} The BasicDialog element
3143 getDialog : function(){
3145 dlg = new Roo.bootstrap.Modal( {
3148 //constraintoviewport:false,
3150 //collapsible : false,
3155 //buttonAlign:"center",
3156 closeClick : function(){
3157 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3160 handleButton("cancel");
3165 dlg.on("hide", handleHide);
3167 //dlg.addKeyListener(27, handleEsc);
3169 this.buttons = buttons;
3170 var bt = this.buttonText;
3171 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3172 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3173 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3174 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3176 bodyEl = dlg.bodyEl.createChild({
3178 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3179 '<textarea class="roo-mb-textarea"></textarea>' +
3180 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3182 msgEl = bodyEl.dom.firstChild;
3183 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3184 textboxEl.enableDisplayMode();
3185 textboxEl.addKeyListener([10,13], function(){
3186 if(dlg.isVisible() && opt && opt.buttons){
3189 }else if(opt.buttons.yes){
3190 handleButton("yes");
3194 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3195 textareaEl.enableDisplayMode();
3196 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3197 progressEl.enableDisplayMode();
3199 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3200 var pf = progressEl.dom.firstChild;
3202 pp = Roo.get(pf.firstChild);
3203 pp.setHeight(pf.offsetHeight);
3211 * Updates the message box body text
3212 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3213 * the XHTML-compliant non-breaking space character '&#160;')
3214 * @return {Roo.MessageBox} This message box
3216 updateText : function(text)
3218 if(!dlg.isVisible() && !opt.width){
3219 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3220 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3222 msgEl.innerHTML = text || ' ';
3224 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3225 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3227 Math.min(opt.width || cw , this.maxWidth),
3228 Math.max(opt.minWidth || this.minWidth, bwidth)
3231 activeTextEl.setWidth(w);
3233 if(dlg.isVisible()){
3234 dlg.fixedcenter = false;
3236 // to big, make it scroll. = But as usual stupid IE does not support
3239 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3240 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3241 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3243 bodyEl.dom.style.height = '';
3244 bodyEl.dom.style.overflowY = '';
3247 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3249 bodyEl.dom.style.overflowX = '';
3252 dlg.setContentSize(w, bodyEl.getHeight());
3253 if(dlg.isVisible()){
3254 dlg.fixedcenter = true;
3260 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3261 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3262 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3263 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3264 * @return {Roo.MessageBox} This message box
3266 updateProgress : function(value, text){
3268 this.updateText(text);
3271 if (pp) { // weird bug on my firefox - for some reason this is not defined
3272 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3273 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3279 * Returns true if the message box is currently displayed
3280 * @return {Boolean} True if the message box is visible, else false
3282 isVisible : function(){
3283 return dlg && dlg.isVisible();
3287 * Hides the message box if it is displayed
3290 if(this.isVisible()){
3296 * Displays a new message box, or reinitializes an existing message box, based on the config options
3297 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3298 * The following config object properties are supported:
3300 Property Type Description
3301 ---------- --------------- ------------------------------------------------------------------------------------
3302 animEl String/Element An id or Element from which the message box should animate as it opens and
3303 closes (defaults to undefined)
3304 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3305 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3306 closable Boolean False to hide the top-right close button (defaults to true). Note that
3307 progress and wait dialogs will ignore this property and always hide the
3308 close button as they can only be closed programmatically.
3309 cls String A custom CSS class to apply to the message box element
3310 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3311 displayed (defaults to 75)
3312 fn Function A callback function to execute after closing the dialog. The arguments to the
3313 function will be btn (the name of the button that was clicked, if applicable,
3314 e.g. "ok"), and text (the value of the active text field, if applicable).
3315 Progress and wait dialogs will ignore this option since they do not respond to
3316 user actions and can only be closed programmatically, so any required function
3317 should be called by the same code after it closes the dialog.
3318 icon String A CSS class that provides a background image to be used as an icon for
3319 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3320 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3321 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3322 modal Boolean False to allow user interaction with the page while the message box is
3323 displayed (defaults to true)
3324 msg String A string that will replace the existing message box body text (defaults
3325 to the XHTML-compliant non-breaking space character ' ')
3326 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3327 progress Boolean True to display a progress bar (defaults to false)
3328 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3329 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3330 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3331 title String The title text
3332 value String The string value to set into the active textbox element if displayed
3333 wait Boolean True to display a progress bar (defaults to false)
3334 width Number The width of the dialog in pixels
3341 msg: 'Please enter your address:',
3343 buttons: Roo.MessageBox.OKCANCEL,
3346 animEl: 'addAddressBtn'
3349 * @param {Object} config Configuration options
3350 * @return {Roo.MessageBox} This message box
3352 show : function(options)
3355 // this causes nightmares if you show one dialog after another
3356 // especially on callbacks..
3358 if(this.isVisible()){
3361 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3362 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3363 Roo.log("New Dialog Message:" + options.msg )
3364 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3365 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3368 var d = this.getDialog();
3370 d.setTitle(opt.title || " ");
3371 d.closeEl.setDisplayed(opt.closable !== false);
3372 activeTextEl = textboxEl;
3373 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3378 textareaEl.setHeight(typeof opt.multiline == "number" ?
3379 opt.multiline : this.defaultTextHeight);
3380 activeTextEl = textareaEl;
3389 progressEl.setDisplayed(opt.progress === true);
3390 this.updateProgress(0);
3391 activeTextEl.dom.value = opt.value || "";
3393 dlg.setDefaultButton(activeTextEl);
3395 var bs = opt.buttons;
3399 }else if(bs && bs.yes){
3400 db = buttons["yes"];
3402 dlg.setDefaultButton(db);
3404 bwidth = updateButtons(opt.buttons);
3405 this.updateText(opt.msg);
3407 d.el.addClass(opt.cls);
3409 d.proxyDrag = opt.proxyDrag === true;
3410 d.modal = opt.modal !== false;
3411 d.mask = opt.modal !== false ? mask : false;
3413 // force it to the end of the z-index stack so it gets a cursor in FF
3414 document.body.appendChild(dlg.el.dom);
3415 d.animateTarget = null;
3416 d.show(options.animEl);
3422 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3423 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3424 * and closing the message box when the process is complete.
3425 * @param {String} title The title bar text
3426 * @param {String} msg The message box body text
3427 * @return {Roo.MessageBox} This message box
3429 progress : function(title, msg){
3436 minWidth: this.minProgressWidth,
3443 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3444 * If a callback function is passed it will be called after the user clicks the button, and the
3445 * id of the button that was clicked will be passed as the only parameter to the callback
3446 * (could also be the top-right close button).
3447 * @param {String} title The title bar text
3448 * @param {String} msg The message box body text
3449 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3450 * @param {Object} scope (optional) The scope of the callback function
3451 * @return {Roo.MessageBox} This message box
3453 alert : function(title, msg, fn, scope)
3468 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3469 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3470 * You are responsible for closing the message box when the process is complete.
3471 * @param {String} msg The message box body text
3472 * @param {String} title (optional) The title bar text
3473 * @return {Roo.MessageBox} This message box
3475 wait : function(msg, title){
3486 waitTimer = Roo.TaskMgr.start({
3488 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3496 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3497 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3498 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3499 * @param {String} title The title bar text
3500 * @param {String} msg The message box body text
3501 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3502 * @param {Object} scope (optional) The scope of the callback function
3503 * @return {Roo.MessageBox} This message box
3505 confirm : function(title, msg, fn, scope){
3509 buttons: this.YESNO,
3518 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3519 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3520 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3521 * (could also be the top-right close button) and the text that was entered will be passed as the two
3522 * parameters to the callback.
3523 * @param {String} title The title bar text
3524 * @param {String} msg The message box body text
3525 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3526 * @param {Object} scope (optional) The scope of the callback function
3527 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3528 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3529 * @return {Roo.MessageBox} This message box
3531 prompt : function(title, msg, fn, scope, multiline){
3535 buttons: this.OKCANCEL,
3540 multiline: multiline,
3547 * Button config that displays a single OK button
3552 * Button config that displays Yes and No buttons
3555 YESNO : {yes:true, no:true},
3557 * Button config that displays OK and Cancel buttons
3560 OKCANCEL : {ok:true, cancel:true},
3562 * Button config that displays Yes, No and Cancel buttons
3565 YESNOCANCEL : {yes:true, no:true, cancel:true},
3568 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3571 defaultTextHeight : 75,
3573 * The maximum width in pixels of the message box (defaults to 600)
3578 * The minimum width in pixels of the message box (defaults to 100)
3583 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3584 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3587 minProgressWidth : 250,
3589 * An object containing the default button text strings that can be overriden for localized language support.
3590 * Supported properties are: ok, cancel, yes and no.
3591 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3604 * Shorthand for {@link Roo.MessageBox}
3606 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3607 Roo.Msg = Roo.Msg || Roo.MessageBox;
3616 * @class Roo.bootstrap.Navbar
3617 * @extends Roo.bootstrap.Component
3618 * Bootstrap Navbar class
3621 * Create a new Navbar
3622 * @param {Object} config The config object
3626 Roo.bootstrap.Navbar = function(config){
3627 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3631 * @event beforetoggle
3632 * Fire before toggle the menu
3633 * @param {Roo.EventObject} e
3635 "beforetoggle" : true
3639 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3648 getAutoCreate : function(){
3651 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3655 initEvents :function ()
3657 //Roo.log(this.el.select('.navbar-toggle',true));
3658 this.el.select('.navbar-toggle',true).on('click', function() {
3659 if(this.fireEvent('beforetoggle', this) !== false){
3660 this.el.select('.navbar-collapse',true).toggleClass('in');
3670 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3672 var size = this.el.getSize();
3673 this.maskEl.setSize(size.width, size.height);
3674 this.maskEl.enableDisplayMode("block");
3683 getChildContainer : function()
3685 if (this.el.select('.collapse').getCount()) {
3686 return this.el.select('.collapse',true).first();
3719 * @class Roo.bootstrap.NavSimplebar
3720 * @extends Roo.bootstrap.Navbar
3721 * Bootstrap Sidebar class
3723 * @cfg {Boolean} inverse is inverted color
3725 * @cfg {String} type (nav | pills | tabs)
3726 * @cfg {Boolean} arrangement stacked | justified
3727 * @cfg {String} align (left | right) alignment
3729 * @cfg {Boolean} main (true|false) main nav bar? default false
3730 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3732 * @cfg {String} tag (header|footer|nav|div) default is nav
3738 * Create a new Sidebar
3739 * @param {Object} config The config object
3743 Roo.bootstrap.NavSimplebar = function(config){
3744 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3747 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3763 getAutoCreate : function(){
3767 tag : this.tag || 'div',
3780 this.type = this.type || 'nav';
3781 if (['tabs','pills'].indexOf(this.type)!==-1) {
3782 cfg.cn[0].cls += ' nav-' + this.type
3786 if (this.type!=='nav') {
3787 Roo.log('nav type must be nav/tabs/pills')
3789 cfg.cn[0].cls += ' navbar-nav'
3795 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3796 cfg.cn[0].cls += ' nav-' + this.arrangement;
3800 if (this.align === 'right') {
3801 cfg.cn[0].cls += ' navbar-right';
3805 cfg.cls += ' navbar-inverse';
3832 * @class Roo.bootstrap.NavHeaderbar
3833 * @extends Roo.bootstrap.NavSimplebar
3834 * Bootstrap Sidebar class
3836 * @cfg {String} brand what is brand
3837 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3838 * @cfg {String} brand_href href of the brand
3839 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3840 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3841 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3842 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3845 * Create a new Sidebar
3846 * @param {Object} config The config object
3850 Roo.bootstrap.NavHeaderbar = function(config){
3851 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3855 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3862 desktopCenter : false,
3865 getAutoCreate : function(){
3868 tag: this.nav || 'nav',
3875 if (this.desktopCenter) {
3876 cn.push({cls : 'container', cn : []});
3883 cls: 'navbar-header',
3888 cls: 'navbar-toggle',
3889 'data-toggle': 'collapse',
3894 html: 'Toggle navigation'
3916 cls: 'collapse navbar-collapse',
3920 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3922 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3923 cfg.cls += ' navbar-' + this.position;
3925 // tag can override this..
3927 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3930 if (this.brand !== '') {
3933 href: this.brand_href ? this.brand_href : '#',
3934 cls: 'navbar-brand',
3942 cfg.cls += ' main-nav';
3950 getHeaderChildContainer : function()
3952 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3953 return this.el.select('.navbar-header',true).first();
3956 return this.getChildContainer();
3960 initEvents : function()
3962 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3964 if (this.autohide) {
3969 Roo.get(document).on('scroll',function(e) {
3970 var ns = Roo.get(document).getScroll().top;
3971 var os = prevScroll;
3975 ft.removeClass('slideDown');
3976 ft.addClass('slideUp');
3979 ft.removeClass('slideUp');
3980 ft.addClass('slideDown');
4001 * @class Roo.bootstrap.NavSidebar
4002 * @extends Roo.bootstrap.Navbar
4003 * Bootstrap Sidebar class
4006 * Create a new Sidebar
4007 * @param {Object} config The config object
4011 Roo.bootstrap.NavSidebar = function(config){
4012 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4015 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4017 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4019 getAutoCreate : function(){
4024 cls: 'sidebar sidebar-nav'
4046 * @class Roo.bootstrap.NavGroup
4047 * @extends Roo.bootstrap.Component
4048 * Bootstrap NavGroup class
4049 * @cfg {String} align (left|right)
4050 * @cfg {Boolean} inverse
4051 * @cfg {String} type (nav|pills|tab) default nav
4052 * @cfg {String} navId - reference Id for navbar.
4056 * Create a new nav group
4057 * @param {Object} config The config object
4060 Roo.bootstrap.NavGroup = function(config){
4061 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4064 Roo.bootstrap.NavGroup.register(this);
4068 * Fires when the active item changes
4069 * @param {Roo.bootstrap.NavGroup} this
4070 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4071 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4078 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4089 getAutoCreate : function()
4091 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4098 if (['tabs','pills'].indexOf(this.type)!==-1) {
4099 cfg.cls += ' nav-' + this.type
4101 if (this.type!=='nav') {
4102 Roo.log('nav type must be nav/tabs/pills')
4104 cfg.cls += ' navbar-nav'
4107 if (this.parent() && this.parent().sidebar) {
4110 cls: 'dashboard-menu sidebar-menu'
4116 if (this.form === true) {
4122 if (this.align === 'right') {
4123 cfg.cls += ' navbar-right';
4125 cfg.cls += ' navbar-left';
4129 if (this.align === 'right') {
4130 cfg.cls += ' navbar-right';
4134 cfg.cls += ' navbar-inverse';
4142 * sets the active Navigation item
4143 * @param {Roo.bootstrap.NavItem} the new current navitem
4145 setActiveItem : function(item)
4148 Roo.each(this.navItems, function(v){
4153 v.setActive(false, true);
4160 item.setActive(true, true);
4161 this.fireEvent('changed', this, item, prev);
4166 * gets the active Navigation item
4167 * @return {Roo.bootstrap.NavItem} the current navitem
4169 getActive : function()
4173 Roo.each(this.navItems, function(v){
4184 indexOfNav : function()
4188 Roo.each(this.navItems, function(v,i){
4199 * adds a Navigation item
4200 * @param {Roo.bootstrap.NavItem} the navitem to add
4202 addItem : function(cfg)
4204 var cn = new Roo.bootstrap.NavItem(cfg);
4206 cn.parentId = this.id;
4207 cn.onRender(this.el, null);
4211 * register a Navigation item
4212 * @param {Roo.bootstrap.NavItem} the navitem to add
4214 register : function(item)
4216 this.navItems.push( item);
4217 item.navId = this.navId;
4222 * clear all the Navigation item
4225 clearAll : function()
4228 this.el.dom.innerHTML = '';
4231 getNavItem: function(tabId)
4234 Roo.each(this.navItems, function(e) {
4235 if (e.tabId == tabId) {
4245 setActiveNext : function()
4247 var i = this.indexOfNav(this.getActive());
4248 if (i > this.navItems.length) {
4251 this.setActiveItem(this.navItems[i+1]);
4253 setActivePrev : function()
4255 var i = this.indexOfNav(this.getActive());
4259 this.setActiveItem(this.navItems[i-1]);
4261 clearWasActive : function(except) {
4262 Roo.each(this.navItems, function(e) {
4263 if (e.tabId != except.tabId && e.was_active) {
4264 e.was_active = false;
4271 getWasActive : function ()
4274 Roo.each(this.navItems, function(e) {
4289 Roo.apply(Roo.bootstrap.NavGroup, {
4293 * register a Navigation Group
4294 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4296 register : function(navgrp)
4298 this.groups[navgrp.navId] = navgrp;
4302 * fetch a Navigation Group based on the navigation ID
4303 * @param {string} the navgroup to add
4304 * @returns {Roo.bootstrap.NavGroup} the navgroup
4306 get: function(navId) {
4307 if (typeof(this.groups[navId]) == 'undefined') {
4309 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4311 return this.groups[navId] ;
4326 * @class Roo.bootstrap.NavItem
4327 * @extends Roo.bootstrap.Component
4328 * Bootstrap Navbar.NavItem class
4329 * @cfg {String} href link to
4330 * @cfg {String} html content of button
4331 * @cfg {String} badge text inside badge
4332 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4333 * @cfg {String} glyphicon name of glyphicon
4334 * @cfg {String} icon name of font awesome icon
4335 * @cfg {Boolean} active Is item active
4336 * @cfg {Boolean} disabled Is item disabled
4338 * @cfg {Boolean} preventDefault (true | false) default false
4339 * @cfg {String} tabId the tab that this item activates.
4340 * @cfg {String} tagtype (a|span) render as a href or span?
4341 * @cfg {Boolean} animateRef (true|false) link to element default false
4344 * Create a new Navbar Item
4345 * @param {Object} config The config object
4347 Roo.bootstrap.NavItem = function(config){
4348 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4353 * The raw click event for the entire grid.
4354 * @param {Roo.EventObject} e
4359 * Fires when the active item active state changes
4360 * @param {Roo.bootstrap.NavItem} this
4361 * @param {boolean} state the new state
4367 * Fires when scroll to element
4368 * @param {Roo.bootstrap.NavItem} this
4369 * @param {Object} options
4370 * @param {Roo.EventObject} e
4378 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4386 preventDefault : false,
4393 getAutoCreate : function(){
4402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4404 if (this.disabled) {
4405 cfg.cls += ' disabled';
4408 if (this.href || this.html || this.glyphicon || this.icon) {
4412 href : this.href || "#",
4413 html: this.html || ''
4418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4421 if(this.glyphicon) {
4422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4427 cfg.cn[0].html += " <span class='caret'></span>";
4431 if (this.badge !== '') {
4433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4441 initEvents: function()
4443 if (typeof (this.menu) != 'undefined') {
4444 this.menu.parentType = this.xtype;
4445 this.menu.triggerEl = this.el;
4446 this.menu = this.addxtype(Roo.apply({}, this.menu));
4449 this.el.select('a',true).on('click', this.onClick, this);
4451 if(this.tagtype == 'span'){
4452 this.el.select('span',true).on('click', this.onClick, this);
4455 // at this point parent should be available..
4456 this.parent().register(this);
4459 onClick : function(e)
4461 if (e.getTarget('.dropdown-menu-item')) {
4462 // did you click on a menu itemm.... - then don't trigger onclick..
4467 this.preventDefault ||
4470 Roo.log("NavItem - prevent Default?");
4474 if (this.disabled) {
4478 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4479 if (tg && tg.transition) {
4480 Roo.log("waiting for the transitionend");
4486 //Roo.log("fire event clicked");
4487 if(this.fireEvent('click', this, e) === false){
4491 if(this.tagtype == 'span'){
4495 //Roo.log(this.href);
4496 var ael = this.el.select('a',true).first();
4499 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4500 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4501 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4502 return; // ignore... - it's a 'hash' to another page.
4504 Roo.log("NavItem - prevent Default?");
4506 this.scrollToElement(e);
4510 var p = this.parent();
4512 if (['tabs','pills'].indexOf(p.type)!==-1) {
4513 if (typeof(p.setActiveItem) !== 'undefined') {
4514 p.setActiveItem(this);
4518 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4519 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4520 // remove the collapsed menu expand...
4521 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4525 isActive: function () {
4528 setActive : function(state, fire, is_was_active)
4530 if (this.active && !state && this.navId) {
4531 this.was_active = true;
4532 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4534 nv.clearWasActive(this);
4538 this.active = state;
4541 this.el.removeClass('active');
4542 } else if (!this.el.hasClass('active')) {
4543 this.el.addClass('active');
4546 this.fireEvent('changed', this, state);
4549 // show a panel if it's registered and related..
4551 if (!this.navId || !this.tabId || !state || is_was_active) {
4555 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4559 var pan = tg.getPanelByName(this.tabId);
4563 // if we can not flip to new panel - go back to old nav highlight..
4564 if (false == tg.showPanel(pan)) {
4565 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4567 var onav = nv.getWasActive();
4569 onav.setActive(true, false, true);
4578 // this should not be here...
4579 setDisabled : function(state)
4581 this.disabled = state;
4583 this.el.removeClass('disabled');
4584 } else if (!this.el.hasClass('disabled')) {
4585 this.el.addClass('disabled');
4591 * Fetch the element to display the tooltip on.
4592 * @return {Roo.Element} defaults to this.el
4594 tooltipEl : function()
4596 return this.el.select('' + this.tagtype + '', true).first();
4599 scrollToElement : function(e)
4601 var c = document.body;
4604 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4606 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4607 c = document.documentElement;
4610 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4616 var o = target.calcOffsetsTo(c);
4623 this.fireEvent('scrollto', this, options, e);
4625 Roo.get(c).scrollTo('top', options.value, true);
4638 * <span> icon </span>
4639 * <span> text </span>
4640 * <span>badge </span>
4644 * @class Roo.bootstrap.NavSidebarItem
4645 * @extends Roo.bootstrap.NavItem
4646 * Bootstrap Navbar.NavSidebarItem class
4647 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4648 * {Boolean} open is the menu open
4649 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4650 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4651 * {String} buttonSize (sm|md|lg)the extra classes for the button
4652 * {Boolean} showArrow show arrow next to the text (default true)
4654 * Create a new Navbar Button
4655 * @param {Object} config The config object
4657 Roo.bootstrap.NavSidebarItem = function(config){
4658 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4663 * The raw click event for the entire grid.
4664 * @param {Roo.EventObject} e
4669 * Fires when the active item active state changes
4670 * @param {Roo.bootstrap.NavSidebarItem} this
4671 * @param {boolean} state the new state
4679 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4681 badgeWeight : 'default',
4687 buttonWeight : 'default',
4693 getAutoCreate : function(){
4698 href : this.href || '#',
4704 if(this.buttonView){
4707 href : this.href || '#',
4708 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4721 cfg.cls += ' active';
4724 if (this.disabled) {
4725 cfg.cls += ' disabled';
4728 cfg.cls += ' open x-open';
4731 if (this.glyphicon || this.icon) {
4732 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4733 a.cn.push({ tag : 'i', cls : c }) ;
4736 if(!this.buttonView){
4739 html : this.html || ''
4746 if (this.badge !== '') {
4747 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4753 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4756 a.cls += ' dropdown-toggle treeview' ;
4762 initEvents : function()
4764 if (typeof (this.menu) != 'undefined') {
4765 this.menu.parentType = this.xtype;
4766 this.menu.triggerEl = this.el;
4767 this.menu = this.addxtype(Roo.apply({}, this.menu));
4770 this.el.on('click', this.onClick, this);
4772 if(this.badge !== ''){
4773 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4778 onClick : function(e)
4785 if(this.preventDefault){
4789 this.fireEvent('click', this);
4792 disable : function()
4794 this.setDisabled(true);
4799 this.setDisabled(false);
4802 setDisabled : function(state)
4804 if(this.disabled == state){
4808 this.disabled = state;
4811 this.el.addClass('disabled');
4815 this.el.removeClass('disabled');
4820 setActive : function(state)
4822 if(this.active == state){
4826 this.active = state;
4829 this.el.addClass('active');
4833 this.el.removeClass('active');
4838 isActive: function ()
4843 setBadge : function(str)
4849 this.badgeEl.dom.innerHTML = str;
4866 * @class Roo.bootstrap.Row
4867 * @extends Roo.bootstrap.Component
4868 * Bootstrap Row class (contains columns...)
4872 * @param {Object} config The config object
4875 Roo.bootstrap.Row = function(config){
4876 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4879 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4881 getAutoCreate : function(){
4900 * @class Roo.bootstrap.Element
4901 * @extends Roo.bootstrap.Component
4902 * Bootstrap Element class
4903 * @cfg {String} html contents of the element
4904 * @cfg {String} tag tag of the element
4905 * @cfg {String} cls class of the element
4906 * @cfg {Boolean} preventDefault (true|false) default false
4907 * @cfg {Boolean} clickable (true|false) default false
4910 * Create a new Element
4911 * @param {Object} config The config object
4914 Roo.bootstrap.Element = function(config){
4915 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4921 * When a element is chick
4922 * @param {Roo.bootstrap.Element} this
4923 * @param {Roo.EventObject} e
4929 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4934 preventDefault: false,
4937 getAutoCreate : function(){
4941 // cls: this.cls, double assign in parent class Component.js :: onRender
4948 initEvents: function()
4950 Roo.bootstrap.Element.superclass.initEvents.call(this);
4953 this.el.on('click', this.onClick, this);
4958 onClick : function(e)
4960 if(this.preventDefault){
4964 this.fireEvent('click', this, e);
4967 getValue : function()
4969 return this.el.dom.innerHTML;
4972 setValue : function(value)
4974 this.el.dom.innerHTML = value;
4989 * @class Roo.bootstrap.Pagination
4990 * @extends Roo.bootstrap.Component
4991 * Bootstrap Pagination class
4992 * @cfg {String} size xs | sm | md | lg
4993 * @cfg {Boolean} inverse false | true
4996 * Create a new Pagination
4997 * @param {Object} config The config object
5000 Roo.bootstrap.Pagination = function(config){
5001 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5004 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5010 getAutoCreate : function(){
5016 cfg.cls += ' inverse';
5022 cfg.cls += " " + this.cls;
5040 * @class Roo.bootstrap.PaginationItem
5041 * @extends Roo.bootstrap.Component
5042 * Bootstrap PaginationItem class
5043 * @cfg {String} html text
5044 * @cfg {String} href the link
5045 * @cfg {Boolean} preventDefault (true | false) default true
5046 * @cfg {Boolean} active (true | false) default false
5047 * @cfg {Boolean} disabled default false
5051 * Create a new PaginationItem
5052 * @param {Object} config The config object
5056 Roo.bootstrap.PaginationItem = function(config){
5057 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5062 * The raw click event for the entire grid.
5063 * @param {Roo.EventObject} e
5069 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5073 preventDefault: true,
5078 getAutoCreate : function(){
5084 href : this.href ? this.href : '#',
5085 html : this.html ? this.html : ''
5095 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5099 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5105 initEvents: function() {
5107 this.el.on('click', this.onClick, this);
5110 onClick : function(e)
5112 Roo.log('PaginationItem on click ');
5113 if(this.preventDefault){
5121 this.fireEvent('click', this, e);
5137 * @class Roo.bootstrap.Slider
5138 * @extends Roo.bootstrap.Component
5139 * Bootstrap Slider class
5142 * Create a new Slider
5143 * @param {Object} config The config object
5146 Roo.bootstrap.Slider = function(config){
5147 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5150 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5152 getAutoCreate : function(){
5156 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5160 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5172 * Ext JS Library 1.1.1
5173 * Copyright(c) 2006-2007, Ext JS, LLC.
5175 * Originally Released Under LGPL - original licence link has changed is not relivant.
5178 * <script type="text/javascript">
5183 * @class Roo.grid.ColumnModel
5184 * @extends Roo.util.Observable
5185 * This is the default implementation of a ColumnModel used by the Grid. It defines
5186 * the columns in the grid.
5189 var colModel = new Roo.grid.ColumnModel([
5190 {header: "Ticker", width: 60, sortable: true, locked: true},
5191 {header: "Company Name", width: 150, sortable: true},
5192 {header: "Market Cap.", width: 100, sortable: true},
5193 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5194 {header: "Employees", width: 100, sortable: true, resizable: false}
5199 * The config options listed for this class are options which may appear in each
5200 * individual column definition.
5201 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5203 * @param {Object} config An Array of column config objects. See this class's
5204 * config objects for details.
5206 Roo.grid.ColumnModel = function(config){
5208 * The config passed into the constructor
5210 this.config = config;
5213 // if no id, create one
5214 // if the column does not have a dataIndex mapping,
5215 // map it to the order it is in the config
5216 for(var i = 0, len = config.length; i < len; i++){
5218 if(typeof c.dataIndex == "undefined"){
5221 if(typeof c.renderer == "string"){
5222 c.renderer = Roo.util.Format[c.renderer];
5224 if(typeof c.id == "undefined"){
5227 if(c.editor && c.editor.xtype){
5228 c.editor = Roo.factory(c.editor, Roo.grid);
5230 if(c.editor && c.editor.isFormField){
5231 c.editor = new Roo.grid.GridEditor(c.editor);
5233 this.lookup[c.id] = c;
5237 * The width of columns which have no width specified (defaults to 100)
5240 this.defaultWidth = 100;
5243 * Default sortable of columns which have no sortable specified (defaults to false)
5246 this.defaultSortable = false;
5250 * @event widthchange
5251 * Fires when the width of a column changes.
5252 * @param {ColumnModel} this
5253 * @param {Number} columnIndex The column index
5254 * @param {Number} newWidth The new width
5256 "widthchange": true,
5258 * @event headerchange
5259 * Fires when the text of a header changes.
5260 * @param {ColumnModel} this
5261 * @param {Number} columnIndex The column index
5262 * @param {Number} newText The new header text
5264 "headerchange": true,
5266 * @event hiddenchange
5267 * Fires when a column is hidden or "unhidden".
5268 * @param {ColumnModel} this
5269 * @param {Number} columnIndex The column index
5270 * @param {Boolean} hidden true if hidden, false otherwise
5272 "hiddenchange": true,
5274 * @event columnmoved
5275 * Fires when a column is moved.
5276 * @param {ColumnModel} this
5277 * @param {Number} oldIndex
5278 * @param {Number} newIndex
5280 "columnmoved" : true,
5282 * @event columlockchange
5283 * Fires when a column's locked state is changed
5284 * @param {ColumnModel} this
5285 * @param {Number} colIndex
5286 * @param {Boolean} locked true if locked
5288 "columnlockchange" : true
5290 Roo.grid.ColumnModel.superclass.constructor.call(this);
5292 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5294 * @cfg {String} header The header text to display in the Grid view.
5297 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5298 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5299 * specified, the column's index is used as an index into the Record's data Array.
5302 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5303 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5306 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5307 * Defaults to the value of the {@link #defaultSortable} property.
5308 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5311 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5314 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5317 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5320 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5323 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5324 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5325 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5326 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5329 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5332 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5335 * @cfg {String} cursor (Optional)
5338 * @cfg {String} tooltip (Optional)
5341 * @cfg {Number} xs (Optional)
5344 * @cfg {Number} sm (Optional)
5347 * @cfg {Number} md (Optional)
5350 * @cfg {Number} lg (Optional)
5353 * Returns the id of the column at the specified index.
5354 * @param {Number} index The column index
5355 * @return {String} the id
5357 getColumnId : function(index){
5358 return this.config[index].id;
5362 * Returns the column for a specified id.
5363 * @param {String} id The column id
5364 * @return {Object} the column
5366 getColumnById : function(id){
5367 return this.lookup[id];
5372 * Returns the column for a specified dataIndex.
5373 * @param {String} dataIndex The column dataIndex
5374 * @return {Object|Boolean} the column or false if not found
5376 getColumnByDataIndex: function(dataIndex){
5377 var index = this.findColumnIndex(dataIndex);
5378 return index > -1 ? this.config[index] : false;
5382 * Returns the index for a specified column id.
5383 * @param {String} id The column id
5384 * @return {Number} the index, or -1 if not found
5386 getIndexById : function(id){
5387 for(var i = 0, len = this.config.length; i < len; i++){
5388 if(this.config[i].id == id){
5396 * Returns the index for a specified column dataIndex.
5397 * @param {String} dataIndex The column dataIndex
5398 * @return {Number} the index, or -1 if not found
5401 findColumnIndex : function(dataIndex){
5402 for(var i = 0, len = this.config.length; i < len; i++){
5403 if(this.config[i].dataIndex == dataIndex){
5411 moveColumn : function(oldIndex, newIndex){
5412 var c = this.config[oldIndex];
5413 this.config.splice(oldIndex, 1);
5414 this.config.splice(newIndex, 0, c);
5415 this.dataMap = null;
5416 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5419 isLocked : function(colIndex){
5420 return this.config[colIndex].locked === true;
5423 setLocked : function(colIndex, value, suppressEvent){
5424 if(this.isLocked(colIndex) == value){
5427 this.config[colIndex].locked = value;
5429 this.fireEvent("columnlockchange", this, colIndex, value);
5433 getTotalLockedWidth : function(){
5435 for(var i = 0; i < this.config.length; i++){
5436 if(this.isLocked(i) && !this.isHidden(i)){
5437 this.totalWidth += this.getColumnWidth(i);
5443 getLockedCount : function(){
5444 for(var i = 0, len = this.config.length; i < len; i++){
5445 if(!this.isLocked(i)){
5450 return this.config.length;
5454 * Returns the number of columns.
5457 getColumnCount : function(visibleOnly){
5458 if(visibleOnly === true){
5460 for(var i = 0, len = this.config.length; i < len; i++){
5461 if(!this.isHidden(i)){
5467 return this.config.length;
5471 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5472 * @param {Function} fn
5473 * @param {Object} scope (optional)
5474 * @return {Array} result
5476 getColumnsBy : function(fn, scope){
5478 for(var i = 0, len = this.config.length; i < len; i++){
5479 var c = this.config[i];
5480 if(fn.call(scope||this, c, i) === true){
5488 * Returns true if the specified column is sortable.
5489 * @param {Number} col The column index
5492 isSortable : function(col){
5493 if(typeof this.config[col].sortable == "undefined"){
5494 return this.defaultSortable;
5496 return this.config[col].sortable;
5500 * Returns the rendering (formatting) function defined for the column.
5501 * @param {Number} col The column index.
5502 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5504 getRenderer : function(col){
5505 if(!this.config[col].renderer){
5506 return Roo.grid.ColumnModel.defaultRenderer;
5508 return this.config[col].renderer;
5512 * Sets the rendering (formatting) function for a column.
5513 * @param {Number} col The column index
5514 * @param {Function} fn The function to use to process the cell's raw data
5515 * to return HTML markup for the grid view. The render function is called with
5516 * the following parameters:<ul>
5517 * <li>Data value.</li>
5518 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5519 * <li>css A CSS style string to apply to the table cell.</li>
5520 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5521 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5522 * <li>Row index</li>
5523 * <li>Column index</li>
5524 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5526 setRenderer : function(col, fn){
5527 this.config[col].renderer = fn;
5531 * Returns the width for the specified column.
5532 * @param {Number} col The column index
5535 getColumnWidth : function(col){
5536 return this.config[col].width * 1 || this.defaultWidth;
5540 * Sets the width for a column.
5541 * @param {Number} col The column index
5542 * @param {Number} width The new width
5544 setColumnWidth : function(col, width, suppressEvent){
5545 this.config[col].width = width;
5546 this.totalWidth = null;
5548 this.fireEvent("widthchange", this, col, width);
5553 * Returns the total width of all columns.
5554 * @param {Boolean} includeHidden True to include hidden column widths
5557 getTotalWidth : function(includeHidden){
5558 if(!this.totalWidth){
5559 this.totalWidth = 0;
5560 for(var i = 0, len = this.config.length; i < len; i++){
5561 if(includeHidden || !this.isHidden(i)){
5562 this.totalWidth += this.getColumnWidth(i);
5566 return this.totalWidth;
5570 * Returns the header for the specified column.
5571 * @param {Number} col The column index
5574 getColumnHeader : function(col){
5575 return this.config[col].header;
5579 * Sets the header for a column.
5580 * @param {Number} col The column index
5581 * @param {String} header The new header
5583 setColumnHeader : function(col, header){
5584 this.config[col].header = header;
5585 this.fireEvent("headerchange", this, col, header);
5589 * Returns the tooltip for the specified column.
5590 * @param {Number} col The column index
5593 getColumnTooltip : function(col){
5594 return this.config[col].tooltip;
5597 * Sets the tooltip for a column.
5598 * @param {Number} col The column index
5599 * @param {String} tooltip The new tooltip
5601 setColumnTooltip : function(col, tooltip){
5602 this.config[col].tooltip = tooltip;
5606 * Returns the dataIndex for the specified column.
5607 * @param {Number} col The column index
5610 getDataIndex : function(col){
5611 return this.config[col].dataIndex;
5615 * Sets the dataIndex for a column.
5616 * @param {Number} col The column index
5617 * @param {Number} dataIndex The new dataIndex
5619 setDataIndex : function(col, dataIndex){
5620 this.config[col].dataIndex = dataIndex;
5626 * Returns true if the cell is editable.
5627 * @param {Number} colIndex The column index
5628 * @param {Number} rowIndex The row index - this is nto actually used..?
5631 isCellEditable : function(colIndex, rowIndex){
5632 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5636 * Returns the editor defined for the cell/column.
5637 * return false or null to disable editing.
5638 * @param {Number} colIndex The column index
5639 * @param {Number} rowIndex The row index
5642 getCellEditor : function(colIndex, rowIndex){
5643 return this.config[colIndex].editor;
5647 * Sets if a column is editable.
5648 * @param {Number} col The column index
5649 * @param {Boolean} editable True if the column is editable
5651 setEditable : function(col, editable){
5652 this.config[col].editable = editable;
5657 * Returns true if the column is hidden.
5658 * @param {Number} colIndex The column index
5661 isHidden : function(colIndex){
5662 return this.config[colIndex].hidden;
5667 * Returns true if the column width cannot be changed
5669 isFixed : function(colIndex){
5670 return this.config[colIndex].fixed;
5674 * Returns true if the column can be resized
5677 isResizable : function(colIndex){
5678 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5681 * Sets if a column is hidden.
5682 * @param {Number} colIndex The column index
5683 * @param {Boolean} hidden True if the column is hidden
5685 setHidden : function(colIndex, hidden){
5686 this.config[colIndex].hidden = hidden;
5687 this.totalWidth = null;
5688 this.fireEvent("hiddenchange", this, colIndex, hidden);
5692 * Sets the editor for a column.
5693 * @param {Number} col The column index
5694 * @param {Object} editor The editor object
5696 setEditor : function(col, editor){
5697 this.config[col].editor = editor;
5701 Roo.grid.ColumnModel.defaultRenderer = function(value)
5703 if(typeof value == "object") {
5706 if(typeof value == "string" && value.length < 1){
5710 return String.format("{0}", value);
5713 // Alias for backwards compatibility
5714 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5717 * Ext JS Library 1.1.1
5718 * Copyright(c) 2006-2007, Ext JS, LLC.
5720 * Originally Released Under LGPL - original licence link has changed is not relivant.
5723 * <script type="text/javascript">
5727 * @class Roo.LoadMask
5728 * A simple utility class for generically masking elements while loading data. If the element being masked has
5729 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5730 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5731 * element's UpdateManager load indicator and will be destroyed after the initial load.
5733 * Create a new LoadMask
5734 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5735 * @param {Object} config The config object
5737 Roo.LoadMask = function(el, config){
5738 this.el = Roo.get(el);
5739 Roo.apply(this, config);
5741 this.store.on('beforeload', this.onBeforeLoad, this);
5742 this.store.on('load', this.onLoad, this);
5743 this.store.on('loadexception', this.onLoadException, this);
5744 this.removeMask = false;
5746 var um = this.el.getUpdateManager();
5747 um.showLoadIndicator = false; // disable the default indicator
5748 um.on('beforeupdate', this.onBeforeLoad, this);
5749 um.on('update', this.onLoad, this);
5750 um.on('failure', this.onLoad, this);
5751 this.removeMask = true;
5755 Roo.LoadMask.prototype = {
5757 * @cfg {Boolean} removeMask
5758 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5759 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5763 * The text to display in a centered loading message box (defaults to 'Loading...')
5767 * @cfg {String} msgCls
5768 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5770 msgCls : 'x-mask-loading',
5773 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5779 * Disables the mask to prevent it from being displayed
5781 disable : function(){
5782 this.disabled = true;
5786 * Enables the mask so that it can be displayed
5788 enable : function(){
5789 this.disabled = false;
5792 onLoadException : function()
5796 if (typeof(arguments[3]) != 'undefined') {
5797 Roo.MessageBox.alert("Error loading",arguments[3]);
5801 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5802 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5809 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5814 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5818 onBeforeLoad : function(){
5820 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5825 destroy : function(){
5827 this.store.un('beforeload', this.onBeforeLoad, this);
5828 this.store.un('load', this.onLoad, this);
5829 this.store.un('loadexception', this.onLoadException, this);
5831 var um = this.el.getUpdateManager();
5832 um.un('beforeupdate', this.onBeforeLoad, this);
5833 um.un('update', this.onLoad, this);
5834 um.un('failure', this.onLoad, this);
5845 * @class Roo.bootstrap.Table
5846 * @extends Roo.bootstrap.Component
5847 * Bootstrap Table class
5848 * @cfg {String} cls table class
5849 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5850 * @cfg {String} bgcolor Specifies the background color for a table
5851 * @cfg {Number} border Specifies whether the table cells should have borders or not
5852 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5853 * @cfg {Number} cellspacing Specifies the space between cells
5854 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5855 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5856 * @cfg {String} sortable Specifies that the table should be sortable
5857 * @cfg {String} summary Specifies a summary of the content of a table
5858 * @cfg {Number} width Specifies the width of a table
5859 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5861 * @cfg {boolean} striped Should the rows be alternative striped
5862 * @cfg {boolean} bordered Add borders to the table
5863 * @cfg {boolean} hover Add hover highlighting
5864 * @cfg {boolean} condensed Format condensed
5865 * @cfg {boolean} responsive Format condensed
5866 * @cfg {Boolean} loadMask (true|false) default false
5867 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5868 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5869 * @cfg {Boolean} rowSelection (true|false) default false
5870 * @cfg {Boolean} cellSelection (true|false) default false
5871 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5872 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5873 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5877 * Create a new Table
5878 * @param {Object} config The config object
5881 Roo.bootstrap.Table = function(config){
5882 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5887 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5888 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5889 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5890 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5892 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5894 this.sm.grid = this;
5895 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5896 this.sm = this.selModel;
5897 this.sm.xmodule = this.xmodule || false;
5900 if (this.cm && typeof(this.cm.config) == 'undefined') {
5901 this.colModel = new Roo.grid.ColumnModel(this.cm);
5902 this.cm = this.colModel;
5903 this.cm.xmodule = this.xmodule || false;
5906 this.store= Roo.factory(this.store, Roo.data);
5907 this.ds = this.store;
5908 this.ds.xmodule = this.xmodule || false;
5911 if (this.footer && this.store) {
5912 this.footer.dataSource = this.ds;
5913 this.footer = Roo.factory(this.footer);
5920 * Fires when a cell is 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
5929 * @event celldblclick
5930 * Fires when a cell is double clicked
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Number} columnIndex
5935 * @param {Roo.EventObject} e
5937 "celldblclick" : true,
5940 * Fires when a row is clicked
5941 * @param {Roo.bootstrap.Table} this
5942 * @param {Roo.Element} el
5943 * @param {Number} rowIndex
5944 * @param {Roo.EventObject} e
5948 * @event rowdblclick
5949 * Fires when a row is double clicked
5950 * @param {Roo.bootstrap.Table} this
5951 * @param {Roo.Element} el
5952 * @param {Number} rowIndex
5953 * @param {Roo.EventObject} e
5955 "rowdblclick" : true,
5958 * Fires when a mouseover 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 mouseout occur
5969 * @param {Roo.bootstrap.Table} this
5970 * @param {Roo.Element} el
5971 * @param {Number} rowIndex
5972 * @param {Number} columnIndex
5973 * @param {Roo.EventObject} e
5978 * Fires when a row is rendered, so you can change add a style to it.
5979 * @param {Roo.bootstrap.Table} this
5980 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5984 * @event rowsrendered
5985 * Fires when all the rows have been rendered
5986 * @param {Roo.bootstrap.Table} this
5988 'rowsrendered' : true,
5990 * @event contextmenu
5991 * The raw contextmenu event for the entire grid.
5992 * @param {Roo.EventObject} e
5994 "contextmenu" : true,
5996 * @event rowcontextmenu
5997 * Fires when a row is right clicked
5998 * @param {Roo.bootstrap.Table} this
5999 * @param {Number} rowIndex
6000 * @param {Roo.EventObject} e
6002 "rowcontextmenu" : true,
6004 * @event cellcontextmenu
6005 * Fires when a cell is right clicked
6006 * @param {Roo.bootstrap.Table} this
6007 * @param {Number} rowIndex
6008 * @param {Number} cellIndex
6009 * @param {Roo.EventObject} e
6011 "cellcontextmenu" : true,
6013 * @event headercontextmenu
6014 * Fires when a header is right clicked
6015 * @param {Roo.bootstrap.Table} this
6016 * @param {Number} columnIndex
6017 * @param {Roo.EventObject} e
6019 "headercontextmenu" : true
6023 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6049 rowSelection : false,
6050 cellSelection : false,
6053 // Roo.Element - the tbody
6055 // Roo.Element - thead element
6058 container: false, // used by gridpanel...
6064 getAutoCreate : function()
6066 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6073 if (this.scrollBody) {
6074 cfg.cls += ' table-body-fixed';
6077 cfg.cls += ' table-striped';
6081 cfg.cls += ' table-hover';
6083 if (this.bordered) {
6084 cfg.cls += ' table-bordered';
6086 if (this.condensed) {
6087 cfg.cls += ' table-condensed';
6089 if (this.responsive) {
6090 cfg.cls += ' table-responsive';
6094 cfg.cls+= ' ' +this.cls;
6097 // this lot should be simplifed...
6100 cfg.align=this.align;
6103 cfg.bgcolor=this.bgcolor;
6106 cfg.border=this.border;
6108 if (this.cellpadding) {
6109 cfg.cellpadding=this.cellpadding;
6111 if (this.cellspacing) {
6112 cfg.cellspacing=this.cellspacing;
6115 cfg.frame=this.frame;
6118 cfg.rules=this.rules;
6120 if (this.sortable) {
6121 cfg.sortable=this.sortable;
6124 cfg.summary=this.summary;
6127 cfg.width=this.width;
6130 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6133 if(this.store || this.cm){
6134 if(this.headerShow){
6135 cfg.cn.push(this.renderHeader());
6138 cfg.cn.push(this.renderBody());
6140 if(this.footerShow){
6141 cfg.cn.push(this.renderFooter());
6143 // where does this come from?
6144 //cfg.cls+= ' TableGrid';
6147 return { cn : [ cfg ] };
6150 initEvents : function()
6152 if(!this.store || !this.cm){
6155 if (this.selModel) {
6156 this.selModel.initEvents();
6160 //Roo.log('initEvents with ds!!!!');
6162 this.mainBody = this.el.select('tbody', true).first();
6163 this.mainHead = this.el.select('thead', true).first();
6170 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6171 e.on('click', _this.sort, _this);
6174 this.mainBody.on("click", this.onClick, this);
6175 this.mainBody.on("dblclick", this.onDblClick, this);
6177 // why is this done????? = it breaks dialogs??
6178 //this.parent().el.setStyle('position', 'relative');
6182 this.footer.parentId = this.id;
6183 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6186 this.el.select('tfoot tr td').first().addClass('hide');
6190 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6192 this.store.on('load', this.onLoad, this);
6193 this.store.on('beforeload', this.onBeforeLoad, this);
6194 this.store.on('update', this.onUpdate, this);
6195 this.store.on('add', this.onAdd, this);
6196 this.store.on("clear", this.clear, this);
6198 this.el.on("contextmenu", this.onContextMenu, this);
6200 this.mainBody.on('scroll', this.onBodyScroll, this);
6202 this.cm.on("headerchange", this.onHeaderChange, this);
6204 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6208 onContextMenu : function(e, t)
6210 this.processEvent("contextmenu", e);
6213 processEvent : function(name, e)
6215 if (name != 'touchstart' ) {
6216 this.fireEvent(name, e);
6219 var t = e.getTarget();
6221 var cell = Roo.get(t);
6227 if(cell.findParent('tfoot', false, true)){
6231 if(cell.findParent('thead', false, true)){
6233 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6234 cell = Roo.get(t).findParent('th', false, true);
6236 Roo.log("failed to find th in thead?");
6237 Roo.log(e.getTarget());
6242 var cellIndex = cell.dom.cellIndex;
6244 var ename = name == 'touchstart' ? 'click' : name;
6245 this.fireEvent("header" + ename, this, cellIndex, e);
6250 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6251 cell = Roo.get(t).findParent('td', false, true);
6253 Roo.log("failed to find th in tbody?");
6254 Roo.log(e.getTarget());
6259 var row = cell.findParent('tr', false, true);
6260 var cellIndex = cell.dom.cellIndex;
6261 var rowIndex = row.dom.rowIndex - 1;
6265 this.fireEvent("row" + name, this, rowIndex, e);
6269 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6275 onMouseover : function(e, el)
6277 var cell = Roo.get(el);
6283 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6284 cell = cell.findParent('td', false, true);
6287 var row = cell.findParent('tr', false, true);
6288 var cellIndex = cell.dom.cellIndex;
6289 var rowIndex = row.dom.rowIndex - 1; // start from 0
6291 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6295 onMouseout : function(e, el)
6297 var cell = Roo.get(el);
6303 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6304 cell = cell.findParent('td', false, true);
6307 var row = cell.findParent('tr', false, true);
6308 var cellIndex = cell.dom.cellIndex;
6309 var rowIndex = row.dom.rowIndex - 1; // start from 0
6311 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6315 onClick : function(e, el)
6317 var cell = Roo.get(el);
6319 if(!cell || (!this.cellSelection && !this.rowSelection)){
6323 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6324 cell = cell.findParent('td', false, true);
6327 if(!cell || typeof(cell) == 'undefined'){
6331 var row = cell.findParent('tr', false, true);
6333 if(!row || typeof(row) == 'undefined'){
6337 var cellIndex = cell.dom.cellIndex;
6338 var rowIndex = this.getRowIndex(row);
6340 // why??? - should these not be based on SelectionModel?
6341 if(this.cellSelection){
6342 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6345 if(this.rowSelection){
6346 this.fireEvent('rowclick', this, row, rowIndex, e);
6352 onDblClick : function(e,el)
6354 var cell = Roo.get(el);
6356 if(!cell || (!this.cellSelection && !this.rowSelection)){
6360 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6361 cell = cell.findParent('td', false, true);
6364 if(!cell || typeof(cell) == 'undefined'){
6368 var row = cell.findParent('tr', false, true);
6370 if(!row || typeof(row) == 'undefined'){
6374 var cellIndex = cell.dom.cellIndex;
6375 var rowIndex = this.getRowIndex(row);
6377 if(this.cellSelection){
6378 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6381 if(this.rowSelection){
6382 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6386 sort : function(e,el)
6388 var col = Roo.get(el);
6390 if(!col.hasClass('sortable')){
6394 var sort = col.attr('sort');
6397 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6401 this.store.sortInfo = {field : sort, direction : dir};
6404 Roo.log("calling footer first");
6405 this.footer.onClick('first');
6408 this.store.load({ params : { start : 0 } });
6412 renderHeader : function()
6420 this.totalWidth = 0;
6422 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6424 var config = cm.config[i];
6428 cls : 'x-hcol-' + i,
6430 html: cm.getColumnHeader(i)
6435 if(typeof(config.sortable) != 'undefined' && config.sortable){
6437 c.html = '<i class="glyphicon"></i>' + c.html;
6440 if(typeof(config.lgHeader) != 'undefined'){
6441 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6444 if(typeof(config.mdHeader) != 'undefined'){
6445 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6448 if(typeof(config.smHeader) != 'undefined'){
6449 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6452 if(typeof(config.xsHeader) != 'undefined'){
6453 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6460 if(typeof(config.tooltip) != 'undefined'){
6461 c.tooltip = config.tooltip;
6464 if(typeof(config.colspan) != 'undefined'){
6465 c.colspan = config.colspan;
6468 if(typeof(config.hidden) != 'undefined' && config.hidden){
6469 c.style += ' display:none;';
6472 if(typeof(config.dataIndex) != 'undefined'){
6473 c.sort = config.dataIndex;
6478 if(typeof(config.align) != 'undefined' && config.align.length){
6479 c.style += ' text-align:' + config.align + ';';
6482 if(typeof(config.width) != 'undefined'){
6483 c.style += ' width:' + config.width + 'px;';
6484 this.totalWidth += config.width;
6486 this.totalWidth += 100; // assume minimum of 100 per column?
6489 if(typeof(config.cls) != 'undefined'){
6490 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6493 ['xs','sm','md','lg'].map(function(size){
6495 if(typeof(config[size]) == 'undefined'){
6499 if (!config[size]) { // 0 = hidden
6500 c.cls += ' hidden-' + size;
6504 c.cls += ' col-' + size + '-' + config[size];
6514 renderBody : function()
6524 colspan : this.cm.getColumnCount()
6534 renderFooter : function()
6544 colspan : this.cm.getColumnCount()
6558 // Roo.log('ds onload');
6563 var ds = this.store;
6565 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6566 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6567 if (_this.store.sortInfo) {
6569 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6570 e.select('i', true).addClass(['glyphicon-arrow-up']);
6573 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6574 e.select('i', true).addClass(['glyphicon-arrow-down']);
6579 var tbody = this.mainBody;
6581 if(ds.getCount() > 0){
6582 ds.data.each(function(d,rowIndex){
6583 var row = this.renderRow(cm, ds, rowIndex);
6585 tbody.createChild(row);
6589 if(row.cellObjects.length){
6590 Roo.each(row.cellObjects, function(r){
6591 _this.renderCellObject(r);
6598 Roo.each(this.el.select('tbody td', true).elements, function(e){
6599 e.on('mouseover', _this.onMouseover, _this);
6602 Roo.each(this.el.select('tbody td', true).elements, function(e){
6603 e.on('mouseout', _this.onMouseout, _this);
6605 this.fireEvent('rowsrendered', this);
6606 //if(this.loadMask){
6607 // this.maskEl.hide();
6614 onUpdate : function(ds,record)
6616 this.refreshRow(record);
6620 onRemove : function(ds, record, index, isUpdate){
6621 if(isUpdate !== true){
6622 this.fireEvent("beforerowremoved", this, index, record);
6624 var bt = this.mainBody.dom;
6626 var rows = this.el.select('tbody > tr', true).elements;
6628 if(typeof(rows[index]) != 'undefined'){
6629 bt.removeChild(rows[index].dom);
6632 // if(bt.rows[index]){
6633 // bt.removeChild(bt.rows[index]);
6636 if(isUpdate !== true){
6637 //this.stripeRows(index);
6638 //this.syncRowHeights(index, index);
6640 this.fireEvent("rowremoved", this, index, record);
6644 onAdd : function(ds, records, rowIndex)
6646 //Roo.log('on Add called');
6647 // - note this does not handle multiple adding very well..
6648 var bt = this.mainBody.dom;
6649 for (var i =0 ; i < records.length;i++) {
6650 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6651 //Roo.log(records[i]);
6652 //Roo.log(this.store.getAt(rowIndex+i));
6653 this.insertRow(this.store, rowIndex + i, false);
6660 refreshRow : function(record){
6661 var ds = this.store, index;
6662 if(typeof record == 'number'){
6664 record = ds.getAt(index);
6666 index = ds.indexOf(record);
6668 this.insertRow(ds, index, true);
6670 this.onRemove(ds, record, index+1, true);
6672 //this.syncRowHeights(index, index);
6674 this.fireEvent("rowupdated", this, index, record);
6677 insertRow : function(dm, rowIndex, isUpdate){
6680 this.fireEvent("beforerowsinserted", this, rowIndex);
6682 //var s = this.getScrollState();
6683 var row = this.renderRow(this.cm, this.store, rowIndex);
6684 // insert before rowIndex..
6685 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6689 if(row.cellObjects.length){
6690 Roo.each(row.cellObjects, function(r){
6691 _this.renderCellObject(r);
6696 this.fireEvent("rowsinserted", this, rowIndex);
6697 //this.syncRowHeights(firstRow, lastRow);
6698 //this.stripeRows(firstRow);
6705 getRowDom : function(rowIndex)
6707 var rows = this.el.select('tbody > tr', true).elements;
6709 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6712 // returns the object tree for a tr..
6715 renderRow : function(cm, ds, rowIndex)
6717 var d = ds.getAt(rowIndex);
6721 cls : 'x-row-' + rowIndex,
6725 var cellObjects = [];
6727 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6728 var config = cm.config[i];
6730 var renderer = cm.getRenderer(i);
6734 if(typeof(renderer) !== 'undefined'){
6735 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6737 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6738 // and are rendered into the cells after the row is rendered - using the id for the element.
6740 if(typeof(value) === 'object'){
6750 rowIndex : rowIndex,
6755 this.fireEvent('rowclass', this, rowcfg);
6759 cls : rowcfg.rowClass + ' x-col-' + i,
6761 html: (typeof(value) === 'object') ? '' : value
6768 if(typeof(config.colspan) != 'undefined'){
6769 td.colspan = config.colspan;
6772 if(typeof(config.hidden) != 'undefined' && config.hidden){
6773 td.style += ' display:none;';
6776 if(typeof(config.align) != 'undefined' && config.align.length){
6777 td.style += ' text-align:' + config.align + ';';
6780 if(typeof(config.width) != 'undefined'){
6781 td.style += ' width:' + config.width + 'px;';
6784 if(typeof(config.cursor) != 'undefined'){
6785 td.style += ' cursor:' + config.cursor + ';';
6788 if(typeof(config.cls) != 'undefined'){
6789 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6792 ['xs','sm','md','lg'].map(function(size){
6794 if(typeof(config[size]) == 'undefined'){
6798 if (!config[size]) { // 0 = hidden
6799 td.cls += ' hidden-' + size;
6803 td.cls += ' col-' + size + '-' + config[size];
6811 row.cellObjects = cellObjects;
6819 onBeforeLoad : function()
6821 //Roo.log('ds onBeforeLoad');
6825 //if(this.loadMask){
6826 // this.maskEl.show();
6834 this.el.select('tbody', true).first().dom.innerHTML = '';
6837 * Show or hide a row.
6838 * @param {Number} rowIndex to show or hide
6839 * @param {Boolean} state hide
6841 setRowVisibility : function(rowIndex, state)
6843 var bt = this.mainBody.dom;
6845 var rows = this.el.select('tbody > tr', true).elements;
6847 if(typeof(rows[rowIndex]) == 'undefined'){
6850 rows[rowIndex].dom.style.display = state ? '' : 'none';
6854 getSelectionModel : function(){
6856 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6858 return this.selModel;
6861 * Render the Roo.bootstrap object from renderder
6863 renderCellObject : function(r)
6867 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6869 var t = r.cfg.render(r.container);
6872 Roo.each(r.cfg.cn, function(c){
6874 container: t.getChildContainer(),
6877 _this.renderCellObject(child);
6882 getRowIndex : function(row)
6886 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6897 * Returns the grid's underlying element = used by panel.Grid
6898 * @return {Element} The element
6900 getGridEl : function(){
6904 * Forces a resize - used by panel.Grid
6905 * @return {Element} The element
6907 autoSize : function()
6909 //var ctr = Roo.get(this.container.dom.parentElement);
6910 var ctr = Roo.get(this.el.dom);
6912 var thd = this.getGridEl().select('thead',true).first();
6913 var tbd = this.getGridEl().select('tbody', true).first();
6914 var tfd = this.getGridEl().select('tfoot', true).first();
6916 var cw = ctr.getWidth();
6920 tbd.setSize(ctr.getWidth(),
6921 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6923 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6926 cw = Math.max(cw, this.totalWidth);
6927 this.getGridEl().select('tr',true).setWidth(cw);
6928 // resize 'expandable coloumn?
6930 return; // we doe not have a view in this design..
6933 onBodyScroll: function()
6935 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6937 this.mainHead.setStyle({
6938 'position' : 'relative',
6939 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6945 var scrollHeight = this.mainBody.dom.scrollHeight;
6947 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6949 var height = this.mainBody.getHeight();
6951 if(scrollHeight - height == scrollTop) {
6953 var total = this.ds.getTotalCount();
6955 if(this.footer.cursor + this.footer.pageSize < total){
6957 this.footer.ds.load({
6959 start : this.footer.cursor + this.footer.pageSize,
6960 limit : this.footer.pageSize
6970 onHeaderChange : function()
6972 var header = this.renderHeader();
6973 var table = this.el.select('table', true).first();
6975 this.mainHead.remove();
6976 this.mainHead = table.createChild(header, this.mainBody, false);
6979 onHiddenChange : function(colModel, colIndex, hidden)
6981 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6982 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6984 this.CSS.updateRule(thSelector, "display", "");
6985 this.CSS.updateRule(tdSelector, "display", "");
6988 this.CSS.updateRule(thSelector, "display", "none");
6989 this.CSS.updateRule(tdSelector, "display", "none");
6992 this.onHeaderChange();
7009 * @class Roo.bootstrap.TableCell
7010 * @extends Roo.bootstrap.Component
7011 * Bootstrap TableCell class
7012 * @cfg {String} html cell contain text
7013 * @cfg {String} cls cell class
7014 * @cfg {String} tag cell tag (td|th) default td
7015 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7016 * @cfg {String} align Aligns the content in a cell
7017 * @cfg {String} axis Categorizes cells
7018 * @cfg {String} bgcolor Specifies the background color of a cell
7019 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7020 * @cfg {Number} colspan Specifies the number of columns a cell should span
7021 * @cfg {String} headers Specifies one or more header cells a cell is related to
7022 * @cfg {Number} height Sets the height of a cell
7023 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7024 * @cfg {Number} rowspan Sets the number of rows a cell should span
7025 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7026 * @cfg {String} valign Vertical aligns the content in a cell
7027 * @cfg {Number} width Specifies the width of a cell
7030 * Create a new TableCell
7031 * @param {Object} config The config object
7034 Roo.bootstrap.TableCell = function(config){
7035 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7038 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7058 getAutoCreate : function(){
7059 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7079 cfg.align=this.align
7085 cfg.bgcolor=this.bgcolor
7088 cfg.charoff=this.charoff
7091 cfg.colspan=this.colspan
7094 cfg.headers=this.headers
7097 cfg.height=this.height
7100 cfg.nowrap=this.nowrap
7103 cfg.rowspan=this.rowspan
7106 cfg.scope=this.scope
7109 cfg.valign=this.valign
7112 cfg.width=this.width
7131 * @class Roo.bootstrap.TableRow
7132 * @extends Roo.bootstrap.Component
7133 * Bootstrap TableRow class
7134 * @cfg {String} cls row class
7135 * @cfg {String} align Aligns the content in a table row
7136 * @cfg {String} bgcolor Specifies a background color for a table row
7137 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7138 * @cfg {String} valign Vertical aligns the content in a table row
7141 * Create a new TableRow
7142 * @param {Object} config The config object
7145 Roo.bootstrap.TableRow = function(config){
7146 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7149 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7157 getAutoCreate : function(){
7158 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7168 cfg.align = this.align;
7171 cfg.bgcolor = this.bgcolor;
7174 cfg.charoff = this.charoff;
7177 cfg.valign = this.valign;
7195 * @class Roo.bootstrap.TableBody
7196 * @extends Roo.bootstrap.Component
7197 * Bootstrap TableBody class
7198 * @cfg {String} cls element class
7199 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7200 * @cfg {String} align Aligns the content inside the element
7201 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7202 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7205 * Create a new TableBody
7206 * @param {Object} config The config object
7209 Roo.bootstrap.TableBody = function(config){
7210 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7213 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7221 getAutoCreate : function(){
7222 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7236 cfg.align = this.align;
7239 cfg.charoff = this.charoff;
7242 cfg.valign = this.valign;
7249 // initEvents : function()
7256 // this.store = Roo.factory(this.store, Roo.data);
7257 // this.store.on('load', this.onLoad, this);
7259 // this.store.load();
7263 // onLoad: function ()
7265 // this.fireEvent('load', this);
7275 * Ext JS Library 1.1.1
7276 * Copyright(c) 2006-2007, Ext JS, LLC.
7278 * Originally Released Under LGPL - original licence link has changed is not relivant.
7281 * <script type="text/javascript">
7284 // as we use this in bootstrap.
7285 Roo.namespace('Roo.form');
7287 * @class Roo.form.Action
7288 * Internal Class used to handle form actions
7290 * @param {Roo.form.BasicForm} el The form element or its id
7291 * @param {Object} config Configuration options
7296 // define the action interface
7297 Roo.form.Action = function(form, options){
7299 this.options = options || {};
7302 * Client Validation Failed
7305 Roo.form.Action.CLIENT_INVALID = 'client';
7307 * Server Validation Failed
7310 Roo.form.Action.SERVER_INVALID = 'server';
7312 * Connect to Server Failed
7315 Roo.form.Action.CONNECT_FAILURE = 'connect';
7317 * Reading Data from Server Failed
7320 Roo.form.Action.LOAD_FAILURE = 'load';
7322 Roo.form.Action.prototype = {
7324 failureType : undefined,
7325 response : undefined,
7329 run : function(options){
7334 success : function(response){
7339 handleResponse : function(response){
7343 // default connection failure
7344 failure : function(response){
7346 this.response = response;
7347 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7348 this.form.afterAction(this, false);
7351 processResponse : function(response){
7352 this.response = response;
7353 if(!response.responseText){
7356 this.result = this.handleResponse(response);
7360 // utility functions used internally
7361 getUrl : function(appendParams){
7362 var url = this.options.url || this.form.url || this.form.el.dom.action;
7364 var p = this.getParams();
7366 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7372 getMethod : function(){
7373 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7376 getParams : function(){
7377 var bp = this.form.baseParams;
7378 var p = this.options.params;
7380 if(typeof p == "object"){
7381 p = Roo.urlEncode(Roo.applyIf(p, bp));
7382 }else if(typeof p == 'string' && bp){
7383 p += '&' + Roo.urlEncode(bp);
7386 p = Roo.urlEncode(bp);
7391 createCallback : function(){
7393 success: this.success,
7394 failure: this.failure,
7396 timeout: (this.form.timeout*1000),
7397 upload: this.form.fileUpload ? this.success : undefined
7402 Roo.form.Action.Submit = function(form, options){
7403 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7406 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7409 haveProgress : false,
7410 uploadComplete : false,
7412 // uploadProgress indicator.
7413 uploadProgress : function()
7415 if (!this.form.progressUrl) {
7419 if (!this.haveProgress) {
7420 Roo.MessageBox.progress("Uploading", "Uploading");
7422 if (this.uploadComplete) {
7423 Roo.MessageBox.hide();
7427 this.haveProgress = true;
7429 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7431 var c = new Roo.data.Connection();
7433 url : this.form.progressUrl,
7438 success : function(req){
7439 //console.log(data);
7443 rdata = Roo.decode(req.responseText)
7445 Roo.log("Invalid data from server..");
7449 if (!rdata || !rdata.success) {
7451 Roo.MessageBox.alert(Roo.encode(rdata));
7454 var data = rdata.data;
7456 if (this.uploadComplete) {
7457 Roo.MessageBox.hide();
7462 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7463 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7466 this.uploadProgress.defer(2000,this);
7469 failure: function(data) {
7470 Roo.log('progress url failed ');
7481 // run get Values on the form, so it syncs any secondary forms.
7482 this.form.getValues();
7484 var o = this.options;
7485 var method = this.getMethod();
7486 var isPost = method == 'POST';
7487 if(o.clientValidation === false || this.form.isValid()){
7489 if (this.form.progressUrl) {
7490 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7491 (new Date() * 1) + '' + Math.random());
7496 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7497 form:this.form.el.dom,
7498 url:this.getUrl(!isPost),
7500 params:isPost ? this.getParams() : null,
7501 isUpload: this.form.fileUpload
7504 this.uploadProgress();
7506 }else if (o.clientValidation !== false){ // client validation failed
7507 this.failureType = Roo.form.Action.CLIENT_INVALID;
7508 this.form.afterAction(this, false);
7512 success : function(response)
7514 this.uploadComplete= true;
7515 if (this.haveProgress) {
7516 Roo.MessageBox.hide();
7520 var result = this.processResponse(response);
7521 if(result === true || result.success){
7522 this.form.afterAction(this, true);
7526 this.form.markInvalid(result.errors);
7527 this.failureType = Roo.form.Action.SERVER_INVALID;
7529 this.form.afterAction(this, false);
7531 failure : function(response)
7533 this.uploadComplete= true;
7534 if (this.haveProgress) {
7535 Roo.MessageBox.hide();
7538 this.response = response;
7539 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7540 this.form.afterAction(this, false);
7543 handleResponse : function(response){
7544 if(this.form.errorReader){
7545 var rs = this.form.errorReader.read(response);
7548 for(var i = 0, len = rs.records.length; i < len; i++) {
7549 var r = rs.records[i];
7553 if(errors.length < 1){
7557 success : rs.success,
7563 ret = Roo.decode(response.responseText);
7567 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7577 Roo.form.Action.Load = function(form, options){
7578 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7579 this.reader = this.form.reader;
7582 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7587 Roo.Ajax.request(Roo.apply(
7588 this.createCallback(), {
7589 method:this.getMethod(),
7590 url:this.getUrl(false),
7591 params:this.getParams()
7595 success : function(response){
7597 var result = this.processResponse(response);
7598 if(result === true || !result.success || !result.data){
7599 this.failureType = Roo.form.Action.LOAD_FAILURE;
7600 this.form.afterAction(this, false);
7603 this.form.clearInvalid();
7604 this.form.setValues(result.data);
7605 this.form.afterAction(this, true);
7608 handleResponse : function(response){
7609 if(this.form.reader){
7610 var rs = this.form.reader.read(response);
7611 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7613 success : rs.success,
7617 return Roo.decode(response.responseText);
7621 Roo.form.Action.ACTION_TYPES = {
7622 'load' : Roo.form.Action.Load,
7623 'submit' : Roo.form.Action.Submit
7632 * @class Roo.bootstrap.Form
7633 * @extends Roo.bootstrap.Component
7634 * Bootstrap Form class
7635 * @cfg {String} method GET | POST (default POST)
7636 * @cfg {String} labelAlign top | left (default top)
7637 * @cfg {String} align left | right - for navbars
7638 * @cfg {Boolean} loadMask load mask when submit (default true)
7643 * @param {Object} config The config object
7647 Roo.bootstrap.Form = function(config){
7649 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7651 Roo.bootstrap.Form.popover.apply();
7655 * @event clientvalidation
7656 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7657 * @param {Form} this
7658 * @param {Boolean} valid true if the form has passed client-side validation
7660 clientvalidation: true,
7662 * @event beforeaction
7663 * Fires before any action is performed. Return false to cancel the action.
7664 * @param {Form} this
7665 * @param {Action} action The action to be performed
7669 * @event actionfailed
7670 * Fires when an action fails.
7671 * @param {Form} this
7672 * @param {Action} action The action that failed
7674 actionfailed : true,
7676 * @event actioncomplete
7677 * Fires when an action is completed.
7678 * @param {Form} this
7679 * @param {Action} action The action that completed
7681 actioncomplete : true
7685 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7688 * @cfg {String} method
7689 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7694 * The URL to use for form actions if one isn't supplied in the action options.
7697 * @cfg {Boolean} fileUpload
7698 * Set to true if this form is a file upload.
7702 * @cfg {Object} baseParams
7703 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7707 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7711 * @cfg {Sting} align (left|right) for navbar forms
7716 activeAction : null,
7719 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7720 * element by passing it or its id or mask the form itself by passing in true.
7723 waitMsgTarget : false,
7728 * @cfg {Boolean} errorMask (true|false) default false
7733 * @cfg {Number} maskOffset Default 100
7738 * @cfg {Boolean} maskBody
7742 getAutoCreate : function(){
7746 method : this.method || 'POST',
7747 id : this.id || Roo.id(),
7750 if (this.parent().xtype.match(/^Nav/)) {
7751 cfg.cls = 'navbar-form navbar-' + this.align;
7755 if (this.labelAlign == 'left' ) {
7756 cfg.cls += ' form-horizontal';
7762 initEvents : function()
7764 this.el.on('submit', this.onSubmit, this);
7765 // this was added as random key presses on the form where triggering form submit.
7766 this.el.on('keypress', function(e) {
7767 if (e.getCharCode() != 13) {
7770 // we might need to allow it for textareas.. and some other items.
7771 // check e.getTarget().
7773 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7777 Roo.log("keypress blocked");
7785 onSubmit : function(e){
7790 * Returns true if client-side validation on the form is successful.
7793 isValid : function(){
7794 var items = this.getItems();
7798 items.each(function(f){
7804 if(!target && f.el.isVisible(true)){
7810 if(this.errorMask && !valid){
7811 Roo.bootstrap.Form.popover.mask(this, target);
7818 * Returns true if any fields in this form have changed since their original load.
7821 isDirty : function(){
7823 var items = this.getItems();
7824 items.each(function(f){
7834 * Performs a predefined action (submit or load) or custom actions you define on this form.
7835 * @param {String} actionName The name of the action type
7836 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7837 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7838 * accept other config options):
7840 Property Type Description
7841 ---------------- --------------- ----------------------------------------------------------------------------------
7842 url String The url for the action (defaults to the form's url)
7843 method String The form method to use (defaults to the form's method, or POST if not defined)
7844 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7845 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7846 validate the form on the client (defaults to false)
7848 * @return {BasicForm} this
7850 doAction : function(action, options){
7851 if(typeof action == 'string'){
7852 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7854 if(this.fireEvent('beforeaction', this, action) !== false){
7855 this.beforeAction(action);
7856 action.run.defer(100, action);
7862 beforeAction : function(action){
7863 var o = action.options;
7868 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7870 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7873 // not really supported yet.. ??
7875 //if(this.waitMsgTarget === true){
7876 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7877 //}else if(this.waitMsgTarget){
7878 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7879 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7881 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7887 afterAction : function(action, success){
7888 this.activeAction = null;
7889 var o = action.options;
7894 Roo.get(document.body).unmask();
7900 //if(this.waitMsgTarget === true){
7901 // this.el.unmask();
7902 //}else if(this.waitMsgTarget){
7903 // this.waitMsgTarget.unmask();
7905 // Roo.MessageBox.updateProgress(1);
7906 // Roo.MessageBox.hide();
7913 Roo.callback(o.success, o.scope, [this, action]);
7914 this.fireEvent('actioncomplete', this, action);
7918 // failure condition..
7919 // we have a scenario where updates need confirming.
7920 // eg. if a locking scenario exists..
7921 // we look for { errors : { needs_confirm : true }} in the response.
7923 (typeof(action.result) != 'undefined') &&
7924 (typeof(action.result.errors) != 'undefined') &&
7925 (typeof(action.result.errors.needs_confirm) != 'undefined')
7928 Roo.log("not supported yet");
7931 Roo.MessageBox.confirm(
7932 "Change requires confirmation",
7933 action.result.errorMsg,
7938 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7948 Roo.callback(o.failure, o.scope, [this, action]);
7949 // show an error message if no failed handler is set..
7950 if (!this.hasListener('actionfailed')) {
7951 Roo.log("need to add dialog support");
7953 Roo.MessageBox.alert("Error",
7954 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7955 action.result.errorMsg :
7956 "Saving Failed, please check your entries or try again"
7961 this.fireEvent('actionfailed', this, action);
7966 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7967 * @param {String} id The value to search for
7970 findField : function(id){
7971 var items = this.getItems();
7972 var field = items.get(id);
7974 items.each(function(f){
7975 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7982 return field || null;
7985 * Mark fields in this form invalid in bulk.
7986 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7987 * @return {BasicForm} this
7989 markInvalid : function(errors){
7990 if(errors instanceof Array){
7991 for(var i = 0, len = errors.length; i < len; i++){
7992 var fieldError = errors[i];
7993 var f = this.findField(fieldError.id);
7995 f.markInvalid(fieldError.msg);
8001 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8002 field.markInvalid(errors[id]);
8006 //Roo.each(this.childForms || [], function (f) {
8007 // f.markInvalid(errors);
8014 * Set values for fields in this form in bulk.
8015 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8016 * @return {BasicForm} this
8018 setValues : function(values){
8019 if(values instanceof Array){ // array of objects
8020 for(var i = 0, len = values.length; i < len; i++){
8022 var f = this.findField(v.id);
8024 f.setValue(v.value);
8025 if(this.trackResetOnLoad){
8026 f.originalValue = f.getValue();
8030 }else{ // object hash
8033 if(typeof values[id] != 'function' && (field = this.findField(id))){
8035 if (field.setFromData &&
8037 field.displayField &&
8038 // combos' with local stores can
8039 // be queried via setValue()
8040 // to set their value..
8041 (field.store && !field.store.isLocal)
8045 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8046 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8047 field.setFromData(sd);
8049 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8051 field.setFromData(values);
8054 field.setValue(values[id]);
8058 if(this.trackResetOnLoad){
8059 field.originalValue = field.getValue();
8065 //Roo.each(this.childForms || [], function (f) {
8066 // f.setValues(values);
8073 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8074 * they are returned as an array.
8075 * @param {Boolean} asString
8078 getValues : function(asString){
8079 //if (this.childForms) {
8080 // copy values from the child forms
8081 // Roo.each(this.childForms, function (f) {
8082 // this.setValues(f.getValues());
8088 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8089 if(asString === true){
8092 return Roo.urlDecode(fs);
8096 * Returns the fields in this form as an object with key/value pairs.
8097 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8100 getFieldValues : function(with_hidden)
8102 var items = this.getItems();
8104 items.each(function(f){
8110 var v = f.getValue();
8112 if (f.inputType =='radio') {
8113 if (typeof(ret[f.getName()]) == 'undefined') {
8114 ret[f.getName()] = ''; // empty..
8117 if (!f.el.dom.checked) {
8125 if(f.xtype == 'MoneyField'){
8126 ret[f.currencyName] = f.getCurrency();
8129 // not sure if this supported any more..
8130 if ((typeof(v) == 'object') && f.getRawValue) {
8131 v = f.getRawValue() ; // dates..
8133 // combo boxes where name != hiddenName...
8134 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8135 ret[f.name] = f.getRawValue();
8137 ret[f.getName()] = v;
8144 * Clears all invalid messages in this form.
8145 * @return {BasicForm} this
8147 clearInvalid : function(){
8148 var items = this.getItems();
8150 items.each(function(f){
8159 * @return {BasicForm} this
8162 var items = this.getItems();
8163 items.each(function(f){
8167 Roo.each(this.childForms || [], function (f) {
8175 getItems : function()
8177 var r=new Roo.util.MixedCollection(false, function(o){
8178 return o.id || (o.id = Roo.id());
8180 var iter = function(el) {
8187 Roo.each(el.items,function(e) {
8196 hideFields : function(items)
8198 Roo.each(items, function(i){
8200 var f = this.findField(i);
8206 if(f.xtype == 'DateField'){
8207 f.setVisible(false);
8216 showFields : function(items)
8218 Roo.each(items, function(i){
8220 var f = this.findField(i);
8226 if(f.xtype == 'DateField'){
8238 Roo.apply(Roo.bootstrap.Form, {
8265 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8266 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8267 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8268 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8271 this.maskEl.top.enableDisplayMode("block");
8272 this.maskEl.left.enableDisplayMode("block");
8273 this.maskEl.bottom.enableDisplayMode("block");
8274 this.maskEl.right.enableDisplayMode("block");
8276 this.toolTip = new Roo.bootstrap.Tooltip({
8277 cls : 'roo-form-error-popover',
8279 'left' : ['r-l', [-2,0], 'right'],
8280 'right' : ['l-r', [2,0], 'left'],
8281 'bottom' : ['tl-bl', [0,2], 'top'],
8282 'top' : [ 'bl-tl', [0,-2], 'bottom']
8286 this.toolTip.render(Roo.get(document.body));
8288 this.toolTip.el.enableDisplayMode("block");
8290 Roo.get(document.body).on('click', function(){
8294 Roo.get(document.body).on('touchstart', function(){
8298 this.isApplied = true
8301 mask : function(form, target)
8305 this.target = target;
8307 if(!this.form.errorMask || !target.el){
8311 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8313 Roo.log(scrollable);
8315 var ot = this.target.el.calcOffsetsTo(scrollable);
8317 var scrollTo = ot[1] - this.form.maskOffset;
8319 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8321 scrollable.scrollTo('top', scrollTo);
8323 var box = this.target.el.getBox();
8325 var zIndex = Roo.bootstrap.Modal.zIndex++;
8328 this.maskEl.top.setStyle('position', 'absolute');
8329 this.maskEl.top.setStyle('z-index', zIndex);
8330 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8331 this.maskEl.top.setLeft(0);
8332 this.maskEl.top.setTop(0);
8333 this.maskEl.top.show();
8335 this.maskEl.left.setStyle('position', 'absolute');
8336 this.maskEl.left.setStyle('z-index', zIndex);
8337 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8338 this.maskEl.left.setLeft(0);
8339 this.maskEl.left.setTop(box.y - this.padding);
8340 this.maskEl.left.show();
8342 this.maskEl.bottom.setStyle('position', 'absolute');
8343 this.maskEl.bottom.setStyle('z-index', zIndex);
8344 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8345 this.maskEl.bottom.setLeft(0);
8346 this.maskEl.bottom.setTop(box.bottom + this.padding);
8347 this.maskEl.bottom.show();
8349 this.maskEl.right.setStyle('position', 'absolute');
8350 this.maskEl.right.setStyle('z-index', zIndex);
8351 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8352 this.maskEl.right.setLeft(box.right + this.padding);
8353 this.maskEl.right.setTop(box.y - this.padding);
8354 this.maskEl.right.show();
8356 this.toolTip.bindEl = this.target.el;
8358 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8360 var tip = this.target.blankText;
8362 if(this.target.getValue() !== '' ) {
8364 if (this.target.invalidText.length) {
8365 tip = this.target.invalidText;
8366 } else if (this.target.regexText.length){
8367 tip = this.target.regexText;
8371 this.toolTip.show(tip);
8373 this.intervalID = window.setInterval(function() {
8374 Roo.bootstrap.Form.popover.unmask();
8377 window.onwheel = function(){ return false;};
8379 (function(){ this.isMasked = true; }).defer(500, this);
8385 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8389 this.maskEl.top.setStyle('position', 'absolute');
8390 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8391 this.maskEl.top.hide();
8393 this.maskEl.left.setStyle('position', 'absolute');
8394 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8395 this.maskEl.left.hide();
8397 this.maskEl.bottom.setStyle('position', 'absolute');
8398 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8399 this.maskEl.bottom.hide();
8401 this.maskEl.right.setStyle('position', 'absolute');
8402 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8403 this.maskEl.right.hide();
8405 this.toolTip.hide();
8407 this.toolTip.el.hide();
8409 window.onwheel = function(){ return true;};
8411 if(this.intervalID){
8412 window.clearInterval(this.intervalID);
8413 this.intervalID = false;
8416 this.isMasked = false;
8426 * Ext JS Library 1.1.1
8427 * Copyright(c) 2006-2007, Ext JS, LLC.
8429 * Originally Released Under LGPL - original licence link has changed is not relivant.
8432 * <script type="text/javascript">
8435 * @class Roo.form.VTypes
8436 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8439 Roo.form.VTypes = function(){
8440 // closure these in so they are only created once.
8441 var alpha = /^[a-zA-Z_]+$/;
8442 var alphanum = /^[a-zA-Z0-9_]+$/;
8443 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8444 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8446 // All these messages and functions are configurable
8449 * The function used to validate email addresses
8450 * @param {String} value The email address
8452 'email' : function(v){
8453 return email.test(v);
8456 * The error text to display when the email validation function returns false
8459 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8461 * The keystroke filter mask to be applied on email input
8464 'emailMask' : /[a-z0-9_\.\-@]/i,
8467 * The function used to validate URLs
8468 * @param {String} value The URL
8470 'url' : function(v){
8474 * The error text to display when the url validation function returns false
8477 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8480 * The function used to validate alpha values
8481 * @param {String} value The value
8483 'alpha' : function(v){
8484 return alpha.test(v);
8487 * The error text to display when the alpha validation function returns false
8490 'alphaText' : 'This field should only contain letters and _',
8492 * The keystroke filter mask to be applied on alpha input
8495 'alphaMask' : /[a-z_]/i,
8498 * The function used to validate alphanumeric values
8499 * @param {String} value The value
8501 'alphanum' : function(v){
8502 return alphanum.test(v);
8505 * The error text to display when the alphanumeric validation function returns false
8508 'alphanumText' : 'This field should only contain letters, numbers and _',
8510 * The keystroke filter mask to be applied on alphanumeric input
8513 'alphanumMask' : /[a-z0-9_]/i
8523 * @class Roo.bootstrap.Input
8524 * @extends Roo.bootstrap.Component
8525 * Bootstrap Input class
8526 * @cfg {Boolean} disabled is it disabled
8527 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8528 * @cfg {String} name name of the input
8529 * @cfg {string} fieldLabel - the label associated
8530 * @cfg {string} placeholder - placeholder to put in text.
8531 * @cfg {string} before - input group add on before
8532 * @cfg {string} after - input group add on after
8533 * @cfg {string} size - (lg|sm) or leave empty..
8534 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8535 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8536 * @cfg {Number} md colspan out of 12 for computer-sized screens
8537 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8538 * @cfg {string} value default value of the input
8539 * @cfg {Number} labelWidth set the width of label
8540 * @cfg {Number} labellg set the width of label (1-12)
8541 * @cfg {Number} labelmd set the width of label (1-12)
8542 * @cfg {Number} labelsm set the width of label (1-12)
8543 * @cfg {Number} labelxs set the width of label (1-12)
8544 * @cfg {String} labelAlign (top|left)
8545 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8546 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8547 * @cfg {String} indicatorpos (left|right) default left
8549 * @cfg {String} align (left|center|right) Default left
8550 * @cfg {Boolean} forceFeedback (true|false) Default false
8553 * Create a new Input
8554 * @param {Object} config The config object
8557 Roo.bootstrap.Input = function(config){
8559 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8564 * Fires when this field receives input focus.
8565 * @param {Roo.form.Field} this
8570 * Fires when this field loses input focus.
8571 * @param {Roo.form.Field} this
8576 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8577 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8578 * @param {Roo.form.Field} this
8579 * @param {Roo.EventObject} e The event object
8584 * Fires just before the field blurs if the field value has changed.
8585 * @param {Roo.form.Field} this
8586 * @param {Mixed} newValue The new value
8587 * @param {Mixed} oldValue The original value
8592 * Fires after the field has been marked as invalid.
8593 * @param {Roo.form.Field} this
8594 * @param {String} msg The validation message
8599 * Fires after the field has been validated with no errors.
8600 * @param {Roo.form.Field} this
8605 * Fires after the key up
8606 * @param {Roo.form.Field} this
8607 * @param {Roo.EventObject} e The event Object
8613 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8615 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8616 automatic validation (defaults to "keyup").
8618 validationEvent : "keyup",
8620 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8622 validateOnBlur : true,
8624 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8626 validationDelay : 250,
8628 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8630 focusClass : "x-form-focus", // not needed???
8634 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8636 invalidClass : "has-warning",
8639 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8641 validClass : "has-success",
8644 * @cfg {Boolean} hasFeedback (true|false) default true
8649 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8651 invalidFeedbackClass : "glyphicon-warning-sign",
8654 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8656 validFeedbackClass : "glyphicon-ok",
8659 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8661 selectOnFocus : false,
8664 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8668 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8673 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8675 disableKeyFilter : false,
8678 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8682 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8686 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8688 blankText : "Please complete this mandatory field",
8691 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8695 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8697 maxLength : Number.MAX_VALUE,
8699 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8701 minLengthText : "The minimum length for this field is {0}",
8703 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8705 maxLengthText : "The maximum length for this field is {0}",
8709 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8710 * If available, this function will be called only after the basic validators all return true, and will be passed the
8711 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8715 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8716 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8717 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8721 * @cfg {String} regexText -- Depricated - use Invalid Text
8726 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8732 autocomplete: false,
8751 formatedValue : false,
8752 forceFeedback : false,
8754 indicatorpos : 'left',
8761 parentLabelAlign : function()
8764 while (parent.parent()) {
8765 parent = parent.parent();
8766 if (typeof(parent.labelAlign) !='undefined') {
8767 return parent.labelAlign;
8774 getAutoCreate : function()
8776 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8782 if(this.inputType != 'hidden'){
8783 cfg.cls = 'form-group' //input-group
8789 type : this.inputType,
8791 cls : 'form-control',
8792 placeholder : this.placeholder || '',
8793 autocomplete : this.autocomplete || 'new-password'
8797 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8800 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8801 input.maxLength = this.maxLength;
8804 if (this.disabled) {
8805 input.disabled=true;
8808 if (this.readOnly) {
8809 input.readonly=true;
8813 input.name = this.name;
8817 input.cls += ' input-' + this.size;
8821 ['xs','sm','md','lg'].map(function(size){
8822 if (settings[size]) {
8823 cfg.cls += ' col-' + size + '-' + settings[size];
8827 var inputblock = input;
8831 cls: 'glyphicon form-control-feedback'
8834 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8837 cls : 'has-feedback',
8845 if (this.before || this.after) {
8848 cls : 'input-group',
8852 if (this.before && typeof(this.before) == 'string') {
8854 inputblock.cn.push({
8856 cls : 'roo-input-before input-group-addon',
8860 if (this.before && typeof(this.before) == 'object') {
8861 this.before = Roo.factory(this.before);
8863 inputblock.cn.push({
8865 cls : 'roo-input-before input-group-' +
8866 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8870 inputblock.cn.push(input);
8872 if (this.after && typeof(this.after) == 'string') {
8873 inputblock.cn.push({
8875 cls : 'roo-input-after input-group-addon',
8879 if (this.after && typeof(this.after) == 'object') {
8880 this.after = Roo.factory(this.after);
8882 inputblock.cn.push({
8884 cls : 'roo-input-after input-group-' +
8885 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8889 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8890 inputblock.cls += ' has-feedback';
8891 inputblock.cn.push(feedback);
8895 if (align ==='left' && this.fieldLabel.length) {
8897 cfg.cls += ' roo-form-group-label-left';
8902 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8903 tooltip : 'This field is required'
8908 cls : 'control-label',
8909 html : this.fieldLabel
8920 var labelCfg = cfg.cn[1];
8921 var contentCfg = cfg.cn[2];
8923 if(this.indicatorpos == 'right'){
8928 cls : 'control-label',
8932 html : this.fieldLabel
8936 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8937 tooltip : 'This field is required'
8950 labelCfg = cfg.cn[0];
8951 contentCfg = cfg.cn[1];
8955 if(this.labelWidth > 12){
8956 labelCfg.style = "width: " + this.labelWidth + 'px';
8959 if(this.labelWidth < 13 && this.labelmd == 0){
8960 this.labelmd = this.labelWidth;
8963 if(this.labellg > 0){
8964 labelCfg.cls += ' col-lg-' + this.labellg;
8965 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8968 if(this.labelmd > 0){
8969 labelCfg.cls += ' col-md-' + this.labelmd;
8970 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8973 if(this.labelsm > 0){
8974 labelCfg.cls += ' col-sm-' + this.labelsm;
8975 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8978 if(this.labelxs > 0){
8979 labelCfg.cls += ' col-xs-' + this.labelxs;
8980 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8984 } else if ( this.fieldLabel.length) {
8989 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8990 tooltip : 'This field is required'
8994 //cls : 'input-group-addon',
8995 html : this.fieldLabel
9003 if(this.indicatorpos == 'right'){
9008 //cls : 'input-group-addon',
9009 html : this.fieldLabel
9014 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9015 tooltip : 'This field is required'
9035 if (this.parentType === 'Navbar' && this.parent().bar) {
9036 cfg.cls += ' navbar-form';
9039 if (this.parentType === 'NavGroup') {
9040 cfg.cls += ' navbar-form';
9048 * return the real input element.
9050 inputEl: function ()
9052 return this.el.select('input.form-control',true).first();
9055 tooltipEl : function()
9057 return this.inputEl();
9060 indicatorEl : function()
9062 var indicator = this.el.select('i.roo-required-indicator',true).first();
9072 setDisabled : function(v)
9074 var i = this.inputEl().dom;
9076 i.removeAttribute('disabled');
9080 i.setAttribute('disabled','true');
9082 initEvents : function()
9085 this.inputEl().on("keydown" , this.fireKey, this);
9086 this.inputEl().on("focus", this.onFocus, this);
9087 this.inputEl().on("blur", this.onBlur, this);
9089 this.inputEl().relayEvent('keyup', this);
9091 this.indicator = this.indicatorEl();
9094 this.indicator.addClass('invisible');
9097 // reference to original value for reset
9098 this.originalValue = this.getValue();
9099 //Roo.form.TextField.superclass.initEvents.call(this);
9100 if(this.validationEvent == 'keyup'){
9101 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9102 this.inputEl().on('keyup', this.filterValidation, this);
9104 else if(this.validationEvent !== false){
9105 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9108 if(this.selectOnFocus){
9109 this.on("focus", this.preFocus, this);
9112 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9113 this.inputEl().on("keypress", this.filterKeys, this);
9115 this.inputEl().relayEvent('keypress', this);
9118 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9119 this.el.on("click", this.autoSize, this);
9122 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9123 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9126 if (typeof(this.before) == 'object') {
9127 this.before.render(this.el.select('.roo-input-before',true).first());
9129 if (typeof(this.after) == 'object') {
9130 this.after.render(this.el.select('.roo-input-after',true).first());
9135 filterValidation : function(e){
9136 if(!e.isNavKeyPress()){
9137 this.validationTask.delay(this.validationDelay);
9141 * Validates the field value
9142 * @return {Boolean} True if the value is valid, else false
9144 validate : function(){
9145 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9146 if(this.disabled || this.validateValue(this.getRawValue())){
9157 * Validates a value according to the field's validation rules and marks the field as invalid
9158 * if the validation fails
9159 * @param {Mixed} value The value to validate
9160 * @return {Boolean} True if the value is valid, else false
9162 validateValue : function(value)
9164 if(this.getVisibilityEl().hasClass('hidden')){
9168 if(value.length < 1) { // if it's blank
9169 if(this.allowBlank){
9175 if(value.length < this.minLength){
9178 if(value.length > this.maxLength){
9182 var vt = Roo.form.VTypes;
9183 if(!vt[this.vtype](value, this)){
9187 if(typeof this.validator == "function"){
9188 var msg = this.validator(value);
9192 if (typeof(msg) == 'string') {
9193 this.invalidText = msg;
9197 if(this.regex && !this.regex.test(value)){
9205 fireKey : function(e){
9206 //Roo.log('field ' + e.getKey());
9207 if(e.isNavKeyPress()){
9208 this.fireEvent("specialkey", this, e);
9211 focus : function (selectText){
9213 this.inputEl().focus();
9214 if(selectText === true){
9215 this.inputEl().dom.select();
9221 onFocus : function(){
9222 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9223 // this.el.addClass(this.focusClass);
9226 this.hasFocus = true;
9227 this.startValue = this.getValue();
9228 this.fireEvent("focus", this);
9232 beforeBlur : Roo.emptyFn,
9236 onBlur : function(){
9238 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9239 //this.el.removeClass(this.focusClass);
9241 this.hasFocus = false;
9242 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9245 var v = this.getValue();
9246 if(String(v) !== String(this.startValue)){
9247 this.fireEvent('change', this, v, this.startValue);
9249 this.fireEvent("blur", this);
9253 * Resets the current field value to the originally loaded value and clears any validation messages
9256 this.setValue(this.originalValue);
9260 * Returns the name of the field
9261 * @return {Mixed} name The name field
9263 getName: function(){
9267 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9268 * @return {Mixed} value The field value
9270 getValue : function(){
9272 var v = this.inputEl().getValue();
9277 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9278 * @return {Mixed} value The field value
9280 getRawValue : function(){
9281 var v = this.inputEl().getValue();
9287 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9288 * @param {Mixed} value The value to set
9290 setRawValue : function(v){
9291 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9294 selectText : function(start, end){
9295 var v = this.getRawValue();
9297 start = start === undefined ? 0 : start;
9298 end = end === undefined ? v.length : end;
9299 var d = this.inputEl().dom;
9300 if(d.setSelectionRange){
9301 d.setSelectionRange(start, end);
9302 }else if(d.createTextRange){
9303 var range = d.createTextRange();
9304 range.moveStart("character", start);
9305 range.moveEnd("character", v.length-end);
9312 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9313 * @param {Mixed} value The value to set
9315 setValue : function(v){
9318 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9324 processValue : function(value){
9325 if(this.stripCharsRe){
9326 var newValue = value.replace(this.stripCharsRe, '');
9327 if(newValue !== value){
9328 this.setRawValue(newValue);
9335 preFocus : function(){
9337 if(this.selectOnFocus){
9338 this.inputEl().dom.select();
9341 filterKeys : function(e){
9343 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9346 var c = e.getCharCode(), cc = String.fromCharCode(c);
9347 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9350 if(!this.maskRe.test(cc)){
9355 * Clear any invalid styles/messages for this field
9357 clearInvalid : function(){
9359 if(!this.el || this.preventMark){ // not rendered
9364 this.el.removeClass(this.invalidClass);
9366 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9368 var feedback = this.el.select('.form-control-feedback', true).first();
9371 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9376 this.fireEvent('valid', this);
9380 * Mark this field as valid
9382 markValid : function()
9384 if(!this.el || this.preventMark){ // not rendered...
9388 this.el.removeClass([this.invalidClass, this.validClass]);
9390 var feedback = this.el.select('.form-control-feedback', true).first();
9393 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9397 this.indicator.removeClass('visible');
9398 this.indicator.addClass('invisible');
9405 if(this.allowBlank && !this.getRawValue().length){
9409 this.el.addClass(this.validClass);
9411 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9413 var feedback = this.el.select('.form-control-feedback', true).first();
9416 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9417 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9422 this.fireEvent('valid', this);
9426 * Mark this field as invalid
9427 * @param {String} msg The validation message
9429 markInvalid : function(msg)
9431 if(!this.el || this.preventMark){ // not rendered
9435 this.el.removeClass([this.invalidClass, this.validClass]);
9437 var feedback = this.el.select('.form-control-feedback', true).first();
9440 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9447 if(this.allowBlank && !this.getRawValue().length){
9452 this.indicator.removeClass('invisible');
9453 this.indicator.addClass('visible');
9456 this.el.addClass(this.invalidClass);
9458 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9460 var feedback = this.el.select('.form-control-feedback', true).first();
9463 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9465 if(this.getValue().length || this.forceFeedback){
9466 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9473 this.fireEvent('invalid', this, msg);
9476 SafariOnKeyDown : function(event)
9478 // this is a workaround for a password hang bug on chrome/ webkit.
9479 if (this.inputEl().dom.type != 'password') {
9483 var isSelectAll = false;
9485 if(this.inputEl().dom.selectionEnd > 0){
9486 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9488 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9489 event.preventDefault();
9494 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9496 event.preventDefault();
9497 // this is very hacky as keydown always get's upper case.
9499 var cc = String.fromCharCode(event.getCharCode());
9500 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9504 adjustWidth : function(tag, w){
9505 tag = tag.toLowerCase();
9506 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9507 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9511 if(tag == 'textarea'){
9514 }else if(Roo.isOpera){
9518 if(tag == 'textarea'){
9526 setFieldLabel : function(v)
9533 var ar = this.el.select('label > span',true);
9535 if (ar.elements.length) {
9536 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9537 this.fieldLabel = v;
9541 var br = this.el.select('label',true);
9543 if(br.elements.length) {
9544 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9545 this.fieldLabel = v;
9549 Roo.log('Cannot Found any of label > span || label in input');
9553 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9554 this.fieldLabel = v;
9569 * @class Roo.bootstrap.TextArea
9570 * @extends Roo.bootstrap.Input
9571 * Bootstrap TextArea class
9572 * @cfg {Number} cols Specifies the visible width of a text area
9573 * @cfg {Number} rows Specifies the visible number of lines in a text area
9574 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9575 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9576 * @cfg {string} html text
9579 * Create a new TextArea
9580 * @param {Object} config The config object
9583 Roo.bootstrap.TextArea = function(config){
9584 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9588 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9598 getAutoCreate : function(){
9600 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9606 if(this.inputType != 'hidden'){
9607 cfg.cls = 'form-group' //input-group
9615 value : this.value || '',
9616 html: this.html || '',
9617 cls : 'form-control',
9618 placeholder : this.placeholder || ''
9622 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9623 input.maxLength = this.maxLength;
9627 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9631 input.cols = this.cols;
9634 if (this.readOnly) {
9635 input.readonly = true;
9639 input.name = this.name;
9643 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9647 ['xs','sm','md','lg'].map(function(size){
9648 if (settings[size]) {
9649 cfg.cls += ' col-' + size + '-' + settings[size];
9653 var inputblock = input;
9655 if(this.hasFeedback && !this.allowBlank){
9659 cls: 'glyphicon form-control-feedback'
9663 cls : 'has-feedback',
9672 if (this.before || this.after) {
9675 cls : 'input-group',
9679 inputblock.cn.push({
9681 cls : 'input-group-addon',
9686 inputblock.cn.push(input);
9688 if(this.hasFeedback && !this.allowBlank){
9689 inputblock.cls += ' has-feedback';
9690 inputblock.cn.push(feedback);
9694 inputblock.cn.push({
9696 cls : 'input-group-addon',
9703 if (align ==='left' && this.fieldLabel.length) {
9708 cls : 'control-label',
9709 html : this.fieldLabel
9720 if(this.labelWidth > 12){
9721 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9724 if(this.labelWidth < 13 && this.labelmd == 0){
9725 this.labelmd = this.labelWidth;
9728 if(this.labellg > 0){
9729 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9730 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9733 if(this.labelmd > 0){
9734 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9735 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9738 if(this.labelsm > 0){
9739 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9740 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9743 if(this.labelxs > 0){
9744 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9745 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9748 } else if ( this.fieldLabel.length) {
9753 //cls : 'input-group-addon',
9754 html : this.fieldLabel
9772 if (this.disabled) {
9773 input.disabled=true;
9780 * return the real textarea element.
9782 inputEl: function ()
9784 return this.el.select('textarea.form-control',true).first();
9788 * Clear any invalid styles/messages for this field
9790 clearInvalid : function()
9793 if(!this.el || this.preventMark){ // not rendered
9797 var label = this.el.select('label', true).first();
9798 var icon = this.el.select('i.fa-star', true).first();
9804 this.el.removeClass(this.invalidClass);
9806 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9808 var feedback = this.el.select('.form-control-feedback', true).first();
9811 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9816 this.fireEvent('valid', this);
9820 * Mark this field as valid
9822 markValid : function()
9824 if(!this.el || this.preventMark){ // not rendered
9828 this.el.removeClass([this.invalidClass, this.validClass]);
9830 var feedback = this.el.select('.form-control-feedback', true).first();
9833 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9836 if(this.disabled || this.allowBlank){
9840 var label = this.el.select('label', true).first();
9841 var icon = this.el.select('i.fa-star', true).first();
9847 this.el.addClass(this.validClass);
9849 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9851 var feedback = this.el.select('.form-control-feedback', true).first();
9854 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9855 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9860 this.fireEvent('valid', this);
9864 * Mark this field as invalid
9865 * @param {String} msg The validation message
9867 markInvalid : function(msg)
9869 if(!this.el || this.preventMark){ // not rendered
9873 this.el.removeClass([this.invalidClass, this.validClass]);
9875 var feedback = this.el.select('.form-control-feedback', true).first();
9878 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9881 if(this.disabled || this.allowBlank){
9885 var label = this.el.select('label', true).first();
9886 var icon = this.el.select('i.fa-star', true).first();
9888 if(!this.getValue().length && label && !icon){
9889 this.el.createChild({
9891 cls : 'text-danger fa fa-lg fa-star',
9892 tooltip : 'This field is required',
9893 style : 'margin-right:5px;'
9897 this.el.addClass(this.invalidClass);
9899 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9901 var feedback = this.el.select('.form-control-feedback', true).first();
9904 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9906 if(this.getValue().length || this.forceFeedback){
9907 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9914 this.fireEvent('invalid', this, msg);
9922 * trigger field - base class for combo..
9927 * @class Roo.bootstrap.TriggerField
9928 * @extends Roo.bootstrap.Input
9929 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9930 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9931 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9932 * for which you can provide a custom implementation. For example:
9934 var trigger = new Roo.bootstrap.TriggerField();
9935 trigger.onTriggerClick = myTriggerFn;
9936 trigger.applyTo('my-field');
9939 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9940 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9941 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9942 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9943 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9946 * Create a new TriggerField.
9947 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9948 * to the base TextField)
9950 Roo.bootstrap.TriggerField = function(config){
9951 this.mimicing = false;
9952 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9955 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9957 * @cfg {String} triggerClass A CSS class to apply to the trigger
9960 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9965 * @cfg {Boolean} removable (true|false) special filter default false
9969 /** @cfg {Boolean} grow @hide */
9970 /** @cfg {Number} growMin @hide */
9971 /** @cfg {Number} growMax @hide */
9977 autoSize: Roo.emptyFn,
9984 actionMode : 'wrap',
9989 getAutoCreate : function(){
9991 var align = this.labelAlign || this.parentLabelAlign();
9996 cls: 'form-group' //input-group
10003 type : this.inputType,
10004 cls : 'form-control',
10005 autocomplete: 'new-password',
10006 placeholder : this.placeholder || ''
10010 input.name = this.name;
10013 input.cls += ' input-' + this.size;
10016 if (this.disabled) {
10017 input.disabled=true;
10020 var inputblock = input;
10022 if(this.hasFeedback && !this.allowBlank){
10026 cls: 'glyphicon form-control-feedback'
10029 if(this.removable && !this.editable && !this.tickable){
10031 cls : 'has-feedback',
10037 cls : 'roo-combo-removable-btn close'
10044 cls : 'has-feedback',
10053 if(this.removable && !this.editable && !this.tickable){
10055 cls : 'roo-removable',
10061 cls : 'roo-combo-removable-btn close'
10068 if (this.before || this.after) {
10071 cls : 'input-group',
10075 inputblock.cn.push({
10077 cls : 'input-group-addon',
10082 inputblock.cn.push(input);
10084 if(this.hasFeedback && !this.allowBlank){
10085 inputblock.cls += ' has-feedback';
10086 inputblock.cn.push(feedback);
10090 inputblock.cn.push({
10092 cls : 'input-group-addon',
10105 cls: 'form-hidden-field'
10119 cls: 'form-hidden-field'
10123 cls: 'roo-select2-choices',
10127 cls: 'roo-select2-search-field',
10140 cls: 'roo-select2-container input-group',
10145 // cls: 'typeahead typeahead-long dropdown-menu',
10146 // style: 'display:none'
10151 if(!this.multiple && this.showToggleBtn){
10157 if (this.caret != false) {
10160 cls: 'fa fa-' + this.caret
10167 cls : 'input-group-addon btn dropdown-toggle',
10172 cls: 'combobox-clear',
10186 combobox.cls += ' roo-select2-container-multi';
10189 if (align ==='left' && this.fieldLabel.length) {
10191 cfg.cls += ' roo-form-group-label-left';
10196 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10197 tooltip : 'This field is required'
10202 cls : 'control-label',
10203 html : this.fieldLabel
10215 var labelCfg = cfg.cn[1];
10216 var contentCfg = cfg.cn[2];
10218 if(this.indicatorpos == 'right'){
10223 cls : 'control-label',
10227 html : this.fieldLabel
10231 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10232 tooltip : 'This field is required'
10245 labelCfg = cfg.cn[0];
10246 contentCfg = cfg.cn[1];
10249 if(this.labelWidth > 12){
10250 labelCfg.style = "width: " + this.labelWidth + 'px';
10253 if(this.labelWidth < 13 && this.labelmd == 0){
10254 this.labelmd = this.labelWidth;
10257 if(this.labellg > 0){
10258 labelCfg.cls += ' col-lg-' + this.labellg;
10259 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10262 if(this.labelmd > 0){
10263 labelCfg.cls += ' col-md-' + this.labelmd;
10264 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10267 if(this.labelsm > 0){
10268 labelCfg.cls += ' col-sm-' + this.labelsm;
10269 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10272 if(this.labelxs > 0){
10273 labelCfg.cls += ' col-xs-' + this.labelxs;
10274 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10277 } else if ( this.fieldLabel.length) {
10278 // Roo.log(" label");
10282 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10283 tooltip : 'This field is required'
10287 //cls : 'input-group-addon',
10288 html : this.fieldLabel
10296 if(this.indicatorpos == 'right'){
10304 html : this.fieldLabel
10308 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10309 tooltip : 'This field is required'
10322 // Roo.log(" no label && no align");
10329 ['xs','sm','md','lg'].map(function(size){
10330 if (settings[size]) {
10331 cfg.cls += ' col-' + size + '-' + settings[size];
10342 onResize : function(w, h){
10343 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10344 // if(typeof w == 'number'){
10345 // var x = w - this.trigger.getWidth();
10346 // this.inputEl().setWidth(this.adjustWidth('input', x));
10347 // this.trigger.setStyle('left', x+'px');
10352 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10355 getResizeEl : function(){
10356 return this.inputEl();
10360 getPositionEl : function(){
10361 return this.inputEl();
10365 alignErrorIcon : function(){
10366 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10370 initEvents : function(){
10374 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10375 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10376 if(!this.multiple && this.showToggleBtn){
10377 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10378 if(this.hideTrigger){
10379 this.trigger.setDisplayed(false);
10381 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10385 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10388 if(this.removable && !this.editable && !this.tickable){
10389 var close = this.closeTriggerEl();
10392 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10393 close.on('click', this.removeBtnClick, this, close);
10397 //this.trigger.addClassOnOver('x-form-trigger-over');
10398 //this.trigger.addClassOnClick('x-form-trigger-click');
10401 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10405 closeTriggerEl : function()
10407 var close = this.el.select('.roo-combo-removable-btn', true).first();
10408 return close ? close : false;
10411 removeBtnClick : function(e, h, el)
10413 e.preventDefault();
10415 if(this.fireEvent("remove", this) !== false){
10417 this.fireEvent("afterremove", this)
10421 createList : function()
10423 this.list = Roo.get(document.body).createChild({
10425 cls: 'typeahead typeahead-long dropdown-menu',
10426 style: 'display:none'
10429 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10434 initTrigger : function(){
10439 onDestroy : function(){
10441 this.trigger.removeAllListeners();
10442 // this.trigger.remove();
10445 // this.wrap.remove();
10447 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10451 onFocus : function(){
10452 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10454 if(!this.mimicing){
10455 this.wrap.addClass('x-trigger-wrap-focus');
10456 this.mimicing = true;
10457 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10458 if(this.monitorTab){
10459 this.el.on("keydown", this.checkTab, this);
10466 checkTab : function(e){
10467 if(e.getKey() == e.TAB){
10468 this.triggerBlur();
10473 onBlur : function(){
10478 mimicBlur : function(e, t){
10480 if(!this.wrap.contains(t) && this.validateBlur()){
10481 this.triggerBlur();
10487 triggerBlur : function(){
10488 this.mimicing = false;
10489 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10490 if(this.monitorTab){
10491 this.el.un("keydown", this.checkTab, this);
10493 //this.wrap.removeClass('x-trigger-wrap-focus');
10494 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10498 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10499 validateBlur : function(e, t){
10504 onDisable : function(){
10505 this.inputEl().dom.disabled = true;
10506 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10508 // this.wrap.addClass('x-item-disabled');
10513 onEnable : function(){
10514 this.inputEl().dom.disabled = false;
10515 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10517 // this.el.removeClass('x-item-disabled');
10522 onShow : function(){
10523 var ae = this.getActionEl();
10526 ae.dom.style.display = '';
10527 ae.dom.style.visibility = 'visible';
10533 onHide : function(){
10534 var ae = this.getActionEl();
10535 ae.dom.style.display = 'none';
10539 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10540 * by an implementing function.
10542 * @param {EventObject} e
10544 onTriggerClick : Roo.emptyFn
10548 * Ext JS Library 1.1.1
10549 * Copyright(c) 2006-2007, Ext JS, LLC.
10551 * Originally Released Under LGPL - original licence link has changed is not relivant.
10554 * <script type="text/javascript">
10559 * @class Roo.data.SortTypes
10561 * Defines the default sorting (casting?) comparison functions used when sorting data.
10563 Roo.data.SortTypes = {
10565 * Default sort that does nothing
10566 * @param {Mixed} s The value being converted
10567 * @return {Mixed} The comparison value
10569 none : function(s){
10574 * The regular expression used to strip tags
10578 stripTagsRE : /<\/?[^>]+>/gi,
10581 * Strips all HTML tags to sort on text only
10582 * @param {Mixed} s The value being converted
10583 * @return {String} The comparison value
10585 asText : function(s){
10586 return String(s).replace(this.stripTagsRE, "");
10590 * Strips all HTML tags to sort on text only - Case insensitive
10591 * @param {Mixed} s The value being converted
10592 * @return {String} The comparison value
10594 asUCText : function(s){
10595 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10599 * Case insensitive string
10600 * @param {Mixed} s The value being converted
10601 * @return {String} The comparison value
10603 asUCString : function(s) {
10604 return String(s).toUpperCase();
10609 * @param {Mixed} s The value being converted
10610 * @return {Number} The comparison value
10612 asDate : function(s) {
10616 if(s instanceof Date){
10617 return s.getTime();
10619 return Date.parse(String(s));
10624 * @param {Mixed} s The value being converted
10625 * @return {Float} The comparison value
10627 asFloat : function(s) {
10628 var val = parseFloat(String(s).replace(/,/g, ""));
10637 * @param {Mixed} s The value being converted
10638 * @return {Number} The comparison value
10640 asInt : function(s) {
10641 var val = parseInt(String(s).replace(/,/g, ""));
10649 * Ext JS Library 1.1.1
10650 * Copyright(c) 2006-2007, Ext JS, LLC.
10652 * Originally Released Under LGPL - original licence link has changed is not relivant.
10655 * <script type="text/javascript">
10659 * @class Roo.data.Record
10660 * Instances of this class encapsulate both record <em>definition</em> information, and record
10661 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10662 * to access Records cached in an {@link Roo.data.Store} object.<br>
10664 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10665 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10668 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10670 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10671 * {@link #create}. The parameters are the same.
10672 * @param {Array} data An associative Array of data values keyed by the field name.
10673 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10674 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10675 * not specified an integer id is generated.
10677 Roo.data.Record = function(data, id){
10678 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10683 * Generate a constructor for a specific record layout.
10684 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10685 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10686 * Each field definition object may contain the following properties: <ul>
10687 * <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,
10688 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10689 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10690 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10691 * is being used, then this is a string containing the javascript expression to reference the data relative to
10692 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10693 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10694 * this may be omitted.</p></li>
10695 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10696 * <ul><li>auto (Default, implies no conversion)</li>
10701 * <li>date</li></ul></p></li>
10702 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10703 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10704 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10705 * by the Reader into an object that will be stored in the Record. It is passed the
10706 * following parameters:<ul>
10707 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10709 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10711 * <br>usage:<br><pre><code>
10712 var TopicRecord = Roo.data.Record.create(
10713 {name: 'title', mapping: 'topic_title'},
10714 {name: 'author', mapping: 'username'},
10715 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10716 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10717 {name: 'lastPoster', mapping: 'user2'},
10718 {name: 'excerpt', mapping: 'post_text'}
10721 var myNewRecord = new TopicRecord({
10722 title: 'Do my job please',
10725 lastPost: new Date(),
10726 lastPoster: 'Animal',
10727 excerpt: 'No way dude!'
10729 myStore.add(myNewRecord);
10734 Roo.data.Record.create = function(o){
10735 var f = function(){
10736 f.superclass.constructor.apply(this, arguments);
10738 Roo.extend(f, Roo.data.Record);
10739 var p = f.prototype;
10740 p.fields = new Roo.util.MixedCollection(false, function(field){
10743 for(var i = 0, len = o.length; i < len; i++){
10744 p.fields.add(new Roo.data.Field(o[i]));
10746 f.getField = function(name){
10747 return p.fields.get(name);
10752 Roo.data.Record.AUTO_ID = 1000;
10753 Roo.data.Record.EDIT = 'edit';
10754 Roo.data.Record.REJECT = 'reject';
10755 Roo.data.Record.COMMIT = 'commit';
10757 Roo.data.Record.prototype = {
10759 * Readonly flag - true if this record has been modified.
10768 join : function(store){
10769 this.store = store;
10773 * Set the named field to the specified value.
10774 * @param {String} name The name of the field to set.
10775 * @param {Object} value The value to set the field to.
10777 set : function(name, value){
10778 if(this.data[name] == value){
10782 if(!this.modified){
10783 this.modified = {};
10785 if(typeof this.modified[name] == 'undefined'){
10786 this.modified[name] = this.data[name];
10788 this.data[name] = value;
10789 if(!this.editing && this.store){
10790 this.store.afterEdit(this);
10795 * Get the value of the named field.
10796 * @param {String} name The name of the field to get the value of.
10797 * @return {Object} The value of the field.
10799 get : function(name){
10800 return this.data[name];
10804 beginEdit : function(){
10805 this.editing = true;
10806 this.modified = {};
10810 cancelEdit : function(){
10811 this.editing = false;
10812 delete this.modified;
10816 endEdit : function(){
10817 this.editing = false;
10818 if(this.dirty && this.store){
10819 this.store.afterEdit(this);
10824 * Usually called by the {@link Roo.data.Store} which owns the Record.
10825 * Rejects all changes made to the Record since either creation, or the last commit operation.
10826 * Modified fields are reverted to their original values.
10828 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10829 * of reject operations.
10831 reject : function(){
10832 var m = this.modified;
10834 if(typeof m[n] != "function"){
10835 this.data[n] = m[n];
10838 this.dirty = false;
10839 delete this.modified;
10840 this.editing = false;
10842 this.store.afterReject(this);
10847 * Usually called by the {@link Roo.data.Store} which owns the Record.
10848 * Commits all changes made to the Record since either creation, or the last commit operation.
10850 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10851 * of commit operations.
10853 commit : function(){
10854 this.dirty = false;
10855 delete this.modified;
10856 this.editing = false;
10858 this.store.afterCommit(this);
10863 hasError : function(){
10864 return this.error != null;
10868 clearError : function(){
10873 * Creates a copy of this record.
10874 * @param {String} id (optional) A new record id if you don't want to use this record's id
10877 copy : function(newId) {
10878 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10882 * Ext JS Library 1.1.1
10883 * Copyright(c) 2006-2007, Ext JS, LLC.
10885 * Originally Released Under LGPL - original licence link has changed is not relivant.
10888 * <script type="text/javascript">
10894 * @class Roo.data.Store
10895 * @extends Roo.util.Observable
10896 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10897 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10899 * 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
10900 * has no knowledge of the format of the data returned by the Proxy.<br>
10902 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10903 * instances from the data object. These records are cached and made available through accessor functions.
10905 * Creates a new Store.
10906 * @param {Object} config A config object containing the objects needed for the Store to access data,
10907 * and read the data into Records.
10909 Roo.data.Store = function(config){
10910 this.data = new Roo.util.MixedCollection(false);
10911 this.data.getKey = function(o){
10914 this.baseParams = {};
10916 this.paramNames = {
10921 "multisort" : "_multisort"
10924 if(config && config.data){
10925 this.inlineData = config.data;
10926 delete config.data;
10929 Roo.apply(this, config);
10931 if(this.reader){ // reader passed
10932 this.reader = Roo.factory(this.reader, Roo.data);
10933 this.reader.xmodule = this.xmodule || false;
10934 if(!this.recordType){
10935 this.recordType = this.reader.recordType;
10937 if(this.reader.onMetaChange){
10938 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10942 if(this.recordType){
10943 this.fields = this.recordType.prototype.fields;
10945 this.modified = [];
10949 * @event datachanged
10950 * Fires when the data cache has changed, and a widget which is using this Store
10951 * as a Record cache should refresh its view.
10952 * @param {Store} this
10954 datachanged : true,
10956 * @event metachange
10957 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10958 * @param {Store} this
10959 * @param {Object} meta The JSON metadata
10964 * Fires when Records have been added to the Store
10965 * @param {Store} this
10966 * @param {Roo.data.Record[]} records The array of Records added
10967 * @param {Number} index The index at which the record(s) were added
10972 * Fires when a Record has been removed from the Store
10973 * @param {Store} this
10974 * @param {Roo.data.Record} record The Record that was removed
10975 * @param {Number} index The index at which the record was removed
10980 * Fires when a Record has been updated
10981 * @param {Store} this
10982 * @param {Roo.data.Record} record The Record that was updated
10983 * @param {String} operation The update operation being performed. Value may be one of:
10985 Roo.data.Record.EDIT
10986 Roo.data.Record.REJECT
10987 Roo.data.Record.COMMIT
10993 * Fires when the data cache has been cleared.
10994 * @param {Store} this
10998 * @event beforeload
10999 * Fires before a request is made for a new data object. If the beforeload handler returns false
11000 * the load action will be canceled.
11001 * @param {Store} this
11002 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11006 * @event beforeloadadd
11007 * Fires after a new set of Records has been loaded.
11008 * @param {Store} this
11009 * @param {Roo.data.Record[]} records The Records that were loaded
11010 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11012 beforeloadadd : true,
11015 * Fires after a new set of Records has been loaded, before they are added to the store.
11016 * @param {Store} this
11017 * @param {Roo.data.Record[]} records The Records that were loaded
11018 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11019 * @params {Object} return from reader
11023 * @event loadexception
11024 * Fires if an exception occurs in the Proxy during loading.
11025 * Called with the signature of the Proxy's "loadexception" event.
11026 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11029 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11030 * @param {Object} load options
11031 * @param {Object} jsonData from your request (normally this contains the Exception)
11033 loadexception : true
11037 this.proxy = Roo.factory(this.proxy, Roo.data);
11038 this.proxy.xmodule = this.xmodule || false;
11039 this.relayEvents(this.proxy, ["loadexception"]);
11041 this.sortToggle = {};
11042 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11044 Roo.data.Store.superclass.constructor.call(this);
11046 if(this.inlineData){
11047 this.loadData(this.inlineData);
11048 delete this.inlineData;
11052 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11054 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11055 * without a remote query - used by combo/forms at present.
11059 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11062 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11065 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11066 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11069 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11070 * on any HTTP request
11073 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11076 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11080 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11081 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11083 remoteSort : false,
11086 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11087 * loaded or when a record is removed. (defaults to false).
11089 pruneModifiedRecords : false,
11092 lastOptions : null,
11095 * Add Records to the Store and fires the add event.
11096 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11098 add : function(records){
11099 records = [].concat(records);
11100 for(var i = 0, len = records.length; i < len; i++){
11101 records[i].join(this);
11103 var index = this.data.length;
11104 this.data.addAll(records);
11105 this.fireEvent("add", this, records, index);
11109 * Remove a Record from the Store and fires the remove event.
11110 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11112 remove : function(record){
11113 var index = this.data.indexOf(record);
11114 this.data.removeAt(index);
11115 if(this.pruneModifiedRecords){
11116 this.modified.remove(record);
11118 this.fireEvent("remove", this, record, index);
11122 * Remove all Records from the Store and fires the clear event.
11124 removeAll : function(){
11126 if(this.pruneModifiedRecords){
11127 this.modified = [];
11129 this.fireEvent("clear", this);
11133 * Inserts Records to the Store at the given index and fires the add event.
11134 * @param {Number} index The start index at which to insert the passed Records.
11135 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11137 insert : function(index, records){
11138 records = [].concat(records);
11139 for(var i = 0, len = records.length; i < len; i++){
11140 this.data.insert(index, records[i]);
11141 records[i].join(this);
11143 this.fireEvent("add", this, records, index);
11147 * Get the index within the cache of the passed Record.
11148 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11149 * @return {Number} The index of the passed Record. Returns -1 if not found.
11151 indexOf : function(record){
11152 return this.data.indexOf(record);
11156 * Get the index within the cache of the Record with the passed id.
11157 * @param {String} id The id of the Record to find.
11158 * @return {Number} The index of the Record. Returns -1 if not found.
11160 indexOfId : function(id){
11161 return this.data.indexOfKey(id);
11165 * Get the Record with the specified id.
11166 * @param {String} id The id of the Record to find.
11167 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11169 getById : function(id){
11170 return this.data.key(id);
11174 * Get the Record at the specified index.
11175 * @param {Number} index The index of the Record to find.
11176 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11178 getAt : function(index){
11179 return this.data.itemAt(index);
11183 * Returns a range of Records between specified indices.
11184 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11185 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11186 * @return {Roo.data.Record[]} An array of Records
11188 getRange : function(start, end){
11189 return this.data.getRange(start, end);
11193 storeOptions : function(o){
11194 o = Roo.apply({}, o);
11197 this.lastOptions = o;
11201 * Loads the Record cache from the configured Proxy using the configured Reader.
11203 * If using remote paging, then the first load call must specify the <em>start</em>
11204 * and <em>limit</em> properties in the options.params property to establish the initial
11205 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11207 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11208 * and this call will return before the new data has been loaded. Perform any post-processing
11209 * in a callback function, or in a "load" event handler.</strong>
11211 * @param {Object} options An object containing properties which control loading options:<ul>
11212 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11213 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11214 * passed the following arguments:<ul>
11215 * <li>r : Roo.data.Record[]</li>
11216 * <li>options: Options object from the load call</li>
11217 * <li>success: Boolean success indicator</li></ul></li>
11218 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11219 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11222 load : function(options){
11223 options = options || {};
11224 if(this.fireEvent("beforeload", this, options) !== false){
11225 this.storeOptions(options);
11226 var p = Roo.apply(options.params || {}, this.baseParams);
11227 // if meta was not loaded from remote source.. try requesting it.
11228 if (!this.reader.metaFromRemote) {
11229 p._requestMeta = 1;
11231 if(this.sortInfo && this.remoteSort){
11232 var pn = this.paramNames;
11233 p[pn["sort"]] = this.sortInfo.field;
11234 p[pn["dir"]] = this.sortInfo.direction;
11236 if (this.multiSort) {
11237 var pn = this.paramNames;
11238 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11241 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11246 * Reloads the Record cache from the configured Proxy using the configured Reader and
11247 * the options from the last load operation performed.
11248 * @param {Object} options (optional) An object containing properties which may override the options
11249 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11250 * the most recently used options are reused).
11252 reload : function(options){
11253 this.load(Roo.applyIf(options||{}, this.lastOptions));
11257 // Called as a callback by the Reader during a load operation.
11258 loadRecords : function(o, options, success){
11259 if(!o || success === false){
11260 if(success !== false){
11261 this.fireEvent("load", this, [], options, o);
11263 if(options.callback){
11264 options.callback.call(options.scope || this, [], options, false);
11268 // if data returned failure - throw an exception.
11269 if (o.success === false) {
11270 // show a message if no listener is registered.
11271 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11272 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11274 // loadmask wil be hooked into this..
11275 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11278 var r = o.records, t = o.totalRecords || r.length;
11280 this.fireEvent("beforeloadadd", this, r, options, o);
11282 if(!options || options.add !== true){
11283 if(this.pruneModifiedRecords){
11284 this.modified = [];
11286 for(var i = 0, len = r.length; i < len; i++){
11290 this.data = this.snapshot;
11291 delete this.snapshot;
11294 this.data.addAll(r);
11295 this.totalLength = t;
11297 this.fireEvent("datachanged", this);
11299 this.totalLength = Math.max(t, this.data.length+r.length);
11303 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11305 var e = new Roo.data.Record({});
11307 e.set(this.parent.displayField, this.parent.emptyTitle);
11308 e.set(this.parent.valueField, '');
11313 this.fireEvent("load", this, r, options, o);
11314 if(options.callback){
11315 options.callback.call(options.scope || this, r, options, true);
11321 * Loads data from a passed data block. A Reader which understands the format of the data
11322 * must have been configured in the constructor.
11323 * @param {Object} data The data block from which to read the Records. The format of the data expected
11324 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11325 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11327 loadData : function(o, append){
11328 var r = this.reader.readRecords(o);
11329 this.loadRecords(r, {add: append}, true);
11333 * Gets the number of cached records.
11335 * <em>If using paging, this may not be the total size of the dataset. If the data object
11336 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11337 * the data set size</em>
11339 getCount : function(){
11340 return this.data.length || 0;
11344 * Gets the total number of records in the dataset as returned by the server.
11346 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11347 * the dataset size</em>
11349 getTotalCount : function(){
11350 return this.totalLength || 0;
11354 * Returns the sort state of the Store as an object with two properties:
11356 field {String} The name of the field by which the Records are sorted
11357 direction {String} The sort order, "ASC" or "DESC"
11360 getSortState : function(){
11361 return this.sortInfo;
11365 applySort : function(){
11366 if(this.sortInfo && !this.remoteSort){
11367 var s = this.sortInfo, f = s.field;
11368 var st = this.fields.get(f).sortType;
11369 var fn = function(r1, r2){
11370 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11371 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11373 this.data.sort(s.direction, fn);
11374 if(this.snapshot && this.snapshot != this.data){
11375 this.snapshot.sort(s.direction, fn);
11381 * Sets the default sort column and order to be used by the next load operation.
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 setDefaultSort : function(field, dir){
11386 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11390 * Sort the Records.
11391 * If remote sorting is used, the sort is performed on the server, and the cache is
11392 * reloaded. If local sorting is used, the cache is sorted internally.
11393 * @param {String} fieldName The name of the field to sort by.
11394 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11396 sort : function(fieldName, dir){
11397 var f = this.fields.get(fieldName);
11399 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11401 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11402 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11407 this.sortToggle[f.name] = dir;
11408 this.sortInfo = {field: f.name, direction: dir};
11409 if(!this.remoteSort){
11411 this.fireEvent("datachanged", this);
11413 this.load(this.lastOptions);
11418 * Calls the specified function for each of the Records in the cache.
11419 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11420 * Returning <em>false</em> aborts and exits the iteration.
11421 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11423 each : function(fn, scope){
11424 this.data.each(fn, scope);
11428 * Gets all records modified since the last commit. Modified records are persisted across load operations
11429 * (e.g., during paging).
11430 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11432 getModifiedRecords : function(){
11433 return this.modified;
11437 createFilterFn : function(property, value, anyMatch){
11438 if(!value.exec){ // not a regex
11439 value = String(value);
11440 if(value.length == 0){
11443 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11445 return function(r){
11446 return value.test(r.data[property]);
11451 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11452 * @param {String} property A field on your records
11453 * @param {Number} start The record index to start at (defaults to 0)
11454 * @param {Number} end The last record index to include (defaults to length - 1)
11455 * @return {Number} The sum
11457 sum : function(property, start, end){
11458 var rs = this.data.items, v = 0;
11459 start = start || 0;
11460 end = (end || end === 0) ? end : rs.length-1;
11462 for(var i = start; i <= end; i++){
11463 v += (rs[i].data[property] || 0);
11469 * Filter the records by a specified property.
11470 * @param {String} field A field on your records
11471 * @param {String/RegExp} value Either a string that the field
11472 * should start with or a RegExp to test against the field
11473 * @param {Boolean} anyMatch True to match any part not just the beginning
11475 filter : function(property, value, anyMatch){
11476 var fn = this.createFilterFn(property, value, anyMatch);
11477 return fn ? this.filterBy(fn) : this.clearFilter();
11481 * Filter by a function. The specified function will be called with each
11482 * record in this data source. If the function returns true the record is included,
11483 * otherwise it is filtered.
11484 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11485 * @param {Object} scope (optional) The scope of the function (defaults to this)
11487 filterBy : function(fn, scope){
11488 this.snapshot = this.snapshot || this.data;
11489 this.data = this.queryBy(fn, scope||this);
11490 this.fireEvent("datachanged", this);
11494 * Query the records by a specified property.
11495 * @param {String} field A field on your records
11496 * @param {String/RegExp} value Either a string that the field
11497 * should start with or a RegExp to test against the field
11498 * @param {Boolean} anyMatch True to match any part not just the beginning
11499 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11501 query : function(property, value, anyMatch){
11502 var fn = this.createFilterFn(property, value, anyMatch);
11503 return fn ? this.queryBy(fn) : this.data.clone();
11507 * Query by a function. The specified function will be called with each
11508 * record in this data source. If the function returns true the record is included
11510 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11511 * @param {Object} scope (optional) The scope of the function (defaults to this)
11512 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11514 queryBy : function(fn, scope){
11515 var data = this.snapshot || this.data;
11516 return data.filterBy(fn, scope||this);
11520 * Collects unique values for a particular dataIndex from this store.
11521 * @param {String} dataIndex The property to collect
11522 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11523 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11524 * @return {Array} An array of the unique values
11526 collect : function(dataIndex, allowNull, bypassFilter){
11527 var d = (bypassFilter === true && this.snapshot) ?
11528 this.snapshot.items : this.data.items;
11529 var v, sv, r = [], l = {};
11530 for(var i = 0, len = d.length; i < len; i++){
11531 v = d[i].data[dataIndex];
11533 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11542 * Revert to a view of the Record cache with no filtering applied.
11543 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11545 clearFilter : function(suppressEvent){
11546 if(this.snapshot && this.snapshot != this.data){
11547 this.data = this.snapshot;
11548 delete this.snapshot;
11549 if(suppressEvent !== true){
11550 this.fireEvent("datachanged", this);
11556 afterEdit : function(record){
11557 if(this.modified.indexOf(record) == -1){
11558 this.modified.push(record);
11560 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11564 afterReject : function(record){
11565 this.modified.remove(record);
11566 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11570 afterCommit : function(record){
11571 this.modified.remove(record);
11572 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11576 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11577 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11579 commitChanges : function(){
11580 var m = this.modified.slice(0);
11581 this.modified = [];
11582 for(var i = 0, len = m.length; i < len; i++){
11588 * Cancel outstanding changes on all changed records.
11590 rejectChanges : function(){
11591 var m = this.modified.slice(0);
11592 this.modified = [];
11593 for(var i = 0, len = m.length; i < len; i++){
11598 onMetaChange : function(meta, rtype, o){
11599 this.recordType = rtype;
11600 this.fields = rtype.prototype.fields;
11601 delete this.snapshot;
11602 this.sortInfo = meta.sortInfo || this.sortInfo;
11603 this.modified = [];
11604 this.fireEvent('metachange', this, this.reader.meta);
11607 moveIndex : function(data, type)
11609 var index = this.indexOf(data);
11611 var newIndex = index + type;
11615 this.insert(newIndex, data);
11620 * Ext JS Library 1.1.1
11621 * Copyright(c) 2006-2007, Ext JS, LLC.
11623 * Originally Released Under LGPL - original licence link has changed is not relivant.
11626 * <script type="text/javascript">
11630 * @class Roo.data.SimpleStore
11631 * @extends Roo.data.Store
11632 * Small helper class to make creating Stores from Array data easier.
11633 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11634 * @cfg {Array} fields An array of field definition objects, or field name strings.
11635 * @cfg {Array} data The multi-dimensional array of data
11637 * @param {Object} config
11639 Roo.data.SimpleStore = function(config){
11640 Roo.data.SimpleStore.superclass.constructor.call(this, {
11642 reader: new Roo.data.ArrayReader({
11645 Roo.data.Record.create(config.fields)
11647 proxy : new Roo.data.MemoryProxy(config.data)
11651 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11653 * Ext JS Library 1.1.1
11654 * Copyright(c) 2006-2007, Ext JS, LLC.
11656 * Originally Released Under LGPL - original licence link has changed is not relivant.
11659 * <script type="text/javascript">
11664 * @extends Roo.data.Store
11665 * @class Roo.data.JsonStore
11666 * Small helper class to make creating Stores for JSON data easier. <br/>
11668 var store = new Roo.data.JsonStore({
11669 url: 'get-images.php',
11671 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11674 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11675 * JsonReader and HttpProxy (unless inline data is provided).</b>
11676 * @cfg {Array} fields An array of field definition objects, or field name strings.
11678 * @param {Object} config
11680 Roo.data.JsonStore = function(c){
11681 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11682 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11683 reader: new Roo.data.JsonReader(c, c.fields)
11686 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11688 * Ext JS Library 1.1.1
11689 * Copyright(c) 2006-2007, Ext JS, LLC.
11691 * Originally Released Under LGPL - original licence link has changed is not relivant.
11694 * <script type="text/javascript">
11698 Roo.data.Field = function(config){
11699 if(typeof config == "string"){
11700 config = {name: config};
11702 Roo.apply(this, config);
11705 this.type = "auto";
11708 var st = Roo.data.SortTypes;
11709 // named sortTypes are supported, here we look them up
11710 if(typeof this.sortType == "string"){
11711 this.sortType = st[this.sortType];
11714 // set default sortType for strings and dates
11715 if(!this.sortType){
11718 this.sortType = st.asUCString;
11721 this.sortType = st.asDate;
11724 this.sortType = st.none;
11729 var stripRe = /[\$,%]/g;
11731 // prebuilt conversion function for this field, instead of
11732 // switching every time we're reading a value
11734 var cv, dateFormat = this.dateFormat;
11739 cv = function(v){ return v; };
11742 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11746 return v !== undefined && v !== null && v !== '' ?
11747 parseInt(String(v).replace(stripRe, ""), 10) : '';
11752 return v !== undefined && v !== null && v !== '' ?
11753 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11758 cv = function(v){ return v === true || v === "true" || v == 1; };
11765 if(v instanceof Date){
11769 if(dateFormat == "timestamp"){
11770 return new Date(v*1000);
11772 return Date.parseDate(v, dateFormat);
11774 var parsed = Date.parse(v);
11775 return parsed ? new Date(parsed) : null;
11784 Roo.data.Field.prototype = {
11792 * Ext JS Library 1.1.1
11793 * Copyright(c) 2006-2007, Ext JS, LLC.
11795 * Originally Released Under LGPL - original licence link has changed is not relivant.
11798 * <script type="text/javascript">
11801 // Base class for reading structured data from a data source. This class is intended to be
11802 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11805 * @class Roo.data.DataReader
11806 * Base class for reading structured data from a data source. This class is intended to be
11807 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11810 Roo.data.DataReader = function(meta, recordType){
11814 this.recordType = recordType instanceof Array ?
11815 Roo.data.Record.create(recordType) : recordType;
11818 Roo.data.DataReader.prototype = {
11820 * Create an empty record
11821 * @param {Object} data (optional) - overlay some values
11822 * @return {Roo.data.Record} record created.
11824 newRow : function(d) {
11826 this.recordType.prototype.fields.each(function(c) {
11828 case 'int' : da[c.name] = 0; break;
11829 case 'date' : da[c.name] = new Date(); break;
11830 case 'float' : da[c.name] = 0.0; break;
11831 case 'boolean' : da[c.name] = false; break;
11832 default : da[c.name] = ""; break;
11836 return new this.recordType(Roo.apply(da, d));
11841 * Ext JS Library 1.1.1
11842 * Copyright(c) 2006-2007, Ext JS, LLC.
11844 * Originally Released Under LGPL - original licence link has changed is not relivant.
11847 * <script type="text/javascript">
11851 * @class Roo.data.DataProxy
11852 * @extends Roo.data.Observable
11853 * This class is an abstract base class for implementations which provide retrieval of
11854 * unformatted data objects.<br>
11856 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11857 * (of the appropriate type which knows how to parse the data object) to provide a block of
11858 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11860 * Custom implementations must implement the load method as described in
11861 * {@link Roo.data.HttpProxy#load}.
11863 Roo.data.DataProxy = function(){
11866 * @event beforeload
11867 * Fires before a network request is made to retrieve a data object.
11868 * @param {Object} This DataProxy object.
11869 * @param {Object} params The params parameter to the load function.
11874 * Fires before the load method's callback is called.
11875 * @param {Object} This DataProxy object.
11876 * @param {Object} o The data object.
11877 * @param {Object} arg The callback argument object passed to the load function.
11881 * @event loadexception
11882 * Fires if an Exception occurs during data retrieval.
11883 * @param {Object} This DataProxy object.
11884 * @param {Object} o The data object.
11885 * @param {Object} arg The callback argument object passed to the load function.
11886 * @param {Object} e The Exception.
11888 loadexception : true
11890 Roo.data.DataProxy.superclass.constructor.call(this);
11893 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11896 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11900 * Ext JS Library 1.1.1
11901 * Copyright(c) 2006-2007, Ext JS, LLC.
11903 * Originally Released Under LGPL - original licence link has changed is not relivant.
11906 * <script type="text/javascript">
11909 * @class Roo.data.MemoryProxy
11910 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11911 * to the Reader when its load method is called.
11913 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11915 Roo.data.MemoryProxy = function(data){
11919 Roo.data.MemoryProxy.superclass.constructor.call(this);
11923 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11926 * Load data from the requested source (in this case an in-memory
11927 * data object passed to the constructor), read the data object into
11928 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11929 * process that block using the passed callback.
11930 * @param {Object} params This parameter is not used by the MemoryProxy class.
11931 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11932 * object into a block of Roo.data.Records.
11933 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11934 * The function must be passed <ul>
11935 * <li>The Record block object</li>
11936 * <li>The "arg" argument from the load function</li>
11937 * <li>A boolean success indicator</li>
11939 * @param {Object} scope The scope in which to call the callback
11940 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11942 load : function(params, reader, callback, scope, arg){
11943 params = params || {};
11946 result = reader.readRecords(this.data);
11948 this.fireEvent("loadexception", this, arg, null, e);
11949 callback.call(scope, null, arg, false);
11952 callback.call(scope, result, arg, true);
11956 update : function(params, records){
11961 * Ext JS Library 1.1.1
11962 * Copyright(c) 2006-2007, Ext JS, LLC.
11964 * Originally Released Under LGPL - original licence link has changed is not relivant.
11967 * <script type="text/javascript">
11970 * @class Roo.data.HttpProxy
11971 * @extends Roo.data.DataProxy
11972 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11973 * configured to reference a certain URL.<br><br>
11975 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11976 * from which the running page was served.<br><br>
11978 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11980 * Be aware that to enable the browser to parse an XML document, the server must set
11981 * the Content-Type header in the HTTP response to "text/xml".
11983 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11984 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11985 * will be used to make the request.
11987 Roo.data.HttpProxy = function(conn){
11988 Roo.data.HttpProxy.superclass.constructor.call(this);
11989 // is conn a conn config or a real conn?
11991 this.useAjax = !conn || !conn.events;
11995 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11996 // thse are take from connection...
11999 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12002 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12003 * extra parameters to each request made by this object. (defaults to undefined)
12006 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12007 * to each request made by this object. (defaults to undefined)
12010 * @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)
12013 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12016 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12022 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12026 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12027 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12028 * a finer-grained basis than the DataProxy events.
12030 getConnection : function(){
12031 return this.useAjax ? Roo.Ajax : this.conn;
12035 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12036 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12037 * process that block using the passed callback.
12038 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12039 * for the request to the remote server.
12040 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12041 * object into a block of Roo.data.Records.
12042 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12043 * The function must be passed <ul>
12044 * <li>The Record block object</li>
12045 * <li>The "arg" argument from the load function</li>
12046 * <li>A boolean success indicator</li>
12048 * @param {Object} scope The scope in which to call the callback
12049 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12051 load : function(params, reader, callback, scope, arg){
12052 if(this.fireEvent("beforeload", this, params) !== false){
12054 params : params || {},
12056 callback : callback,
12061 callback : this.loadResponse,
12065 Roo.applyIf(o, this.conn);
12066 if(this.activeRequest){
12067 Roo.Ajax.abort(this.activeRequest);
12069 this.activeRequest = Roo.Ajax.request(o);
12071 this.conn.request(o);
12074 callback.call(scope||this, null, arg, false);
12079 loadResponse : function(o, success, response){
12080 delete this.activeRequest;
12082 this.fireEvent("loadexception", this, o, response);
12083 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12088 result = o.reader.read(response);
12090 this.fireEvent("loadexception", this, o, response, e);
12091 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12095 this.fireEvent("load", this, o, o.request.arg);
12096 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12100 update : function(dataSet){
12105 updateResponse : function(dataSet){
12110 * Ext JS Library 1.1.1
12111 * Copyright(c) 2006-2007, Ext JS, LLC.
12113 * Originally Released Under LGPL - original licence link has changed is not relivant.
12116 * <script type="text/javascript">
12120 * @class Roo.data.ScriptTagProxy
12121 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12122 * other than the originating domain of the running page.<br><br>
12124 * <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
12125 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12127 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12128 * source code that is used as the source inside a <script> tag.<br><br>
12130 * In order for the browser to process the returned data, the server must wrap the data object
12131 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12132 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12133 * depending on whether the callback name was passed:
12136 boolean scriptTag = false;
12137 String cb = request.getParameter("callback");
12140 response.setContentType("text/javascript");
12142 response.setContentType("application/x-json");
12144 Writer out = response.getWriter();
12146 out.write(cb + "(");
12148 out.print(dataBlock.toJsonString());
12155 * @param {Object} config A configuration object.
12157 Roo.data.ScriptTagProxy = function(config){
12158 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12159 Roo.apply(this, config);
12160 this.head = document.getElementsByTagName("head")[0];
12163 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12165 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12167 * @cfg {String} url The URL from which to request the data object.
12170 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12174 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12175 * the server the name of the callback function set up by the load call to process the returned data object.
12176 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12177 * javascript output which calls this named function passing the data object as its only parameter.
12179 callbackParam : "callback",
12181 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12182 * name to the request.
12187 * Load data from the configured URL, read the data object into
12188 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12189 * process that block using the passed callback.
12190 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12191 * for the request to the remote server.
12192 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12193 * object into a block of Roo.data.Records.
12194 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12195 * The function must be passed <ul>
12196 * <li>The Record block object</li>
12197 * <li>The "arg" argument from the load function</li>
12198 * <li>A boolean success indicator</li>
12200 * @param {Object} scope The scope in which to call the callback
12201 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12203 load : function(params, reader, callback, scope, arg){
12204 if(this.fireEvent("beforeload", this, params) !== false){
12206 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12208 var url = this.url;
12209 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12211 url += "&_dc=" + (new Date().getTime());
12213 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12216 cb : "stcCallback"+transId,
12217 scriptId : "stcScript"+transId,
12221 callback : callback,
12227 window[trans.cb] = function(o){
12228 conn.handleResponse(o, trans);
12231 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12233 if(this.autoAbort !== false){
12237 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12239 var script = document.createElement("script");
12240 script.setAttribute("src", url);
12241 script.setAttribute("type", "text/javascript");
12242 script.setAttribute("id", trans.scriptId);
12243 this.head.appendChild(script);
12245 this.trans = trans;
12247 callback.call(scope||this, null, arg, false);
12252 isLoading : function(){
12253 return this.trans ? true : false;
12257 * Abort the current server request.
12259 abort : function(){
12260 if(this.isLoading()){
12261 this.destroyTrans(this.trans);
12266 destroyTrans : function(trans, isLoaded){
12267 this.head.removeChild(document.getElementById(trans.scriptId));
12268 clearTimeout(trans.timeoutId);
12270 window[trans.cb] = undefined;
12272 delete window[trans.cb];
12275 // if hasn't been loaded, wait for load to remove it to prevent script error
12276 window[trans.cb] = function(){
12277 window[trans.cb] = undefined;
12279 delete window[trans.cb];
12286 handleResponse : function(o, trans){
12287 this.trans = false;
12288 this.destroyTrans(trans, true);
12291 result = trans.reader.readRecords(o);
12293 this.fireEvent("loadexception", this, o, trans.arg, e);
12294 trans.callback.call(trans.scope||window, null, trans.arg, false);
12297 this.fireEvent("load", this, o, trans.arg);
12298 trans.callback.call(trans.scope||window, result, trans.arg, true);
12302 handleFailure : function(trans){
12303 this.trans = false;
12304 this.destroyTrans(trans, false);
12305 this.fireEvent("loadexception", this, null, trans.arg);
12306 trans.callback.call(trans.scope||window, null, trans.arg, false);
12310 * Ext JS Library 1.1.1
12311 * Copyright(c) 2006-2007, Ext JS, LLC.
12313 * Originally Released Under LGPL - original licence link has changed is not relivant.
12316 * <script type="text/javascript">
12320 * @class Roo.data.JsonReader
12321 * @extends Roo.data.DataReader
12322 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12323 * based on mappings in a provided Roo.data.Record constructor.
12325 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12326 * in the reply previously.
12331 var RecordDef = Roo.data.Record.create([
12332 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12333 {name: 'occupation'} // This field will use "occupation" as the mapping.
12335 var myReader = new Roo.data.JsonReader({
12336 totalProperty: "results", // The property which contains the total dataset size (optional)
12337 root: "rows", // The property which contains an Array of row objects
12338 id: "id" // The property within each row object that provides an ID for the record (optional)
12342 * This would consume a JSON file like this:
12344 { 'results': 2, 'rows': [
12345 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12346 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12349 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12350 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12351 * paged from the remote server.
12352 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12353 * @cfg {String} root name of the property which contains the Array of row objects.
12354 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12355 * @cfg {Array} fields Array of field definition objects
12357 * Create a new JsonReader
12358 * @param {Object} meta Metadata configuration options
12359 * @param {Object} recordType Either an Array of field definition objects,
12360 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12362 Roo.data.JsonReader = function(meta, recordType){
12365 // set some defaults:
12366 Roo.applyIf(meta, {
12367 totalProperty: 'total',
12368 successProperty : 'success',
12373 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12375 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12378 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12379 * Used by Store query builder to append _requestMeta to params.
12382 metaFromRemote : false,
12384 * This method is only used by a DataProxy which has retrieved data from a remote server.
12385 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12386 * @return {Object} data A data block which is used by an Roo.data.Store object as
12387 * a cache of Roo.data.Records.
12389 read : function(response){
12390 var json = response.responseText;
12392 var o = /* eval:var:o */ eval("("+json+")");
12394 throw {message: "JsonReader.read: Json object not found"};
12400 this.metaFromRemote = true;
12401 this.meta = o.metaData;
12402 this.recordType = Roo.data.Record.create(o.metaData.fields);
12403 this.onMetaChange(this.meta, this.recordType, o);
12405 return this.readRecords(o);
12408 // private function a store will implement
12409 onMetaChange : function(meta, recordType, o){
12416 simpleAccess: function(obj, subsc) {
12423 getJsonAccessor: function(){
12425 return function(expr) {
12427 return(re.test(expr))
12428 ? new Function("obj", "return obj." + expr)
12433 return Roo.emptyFn;
12438 * Create a data block containing Roo.data.Records from an XML document.
12439 * @param {Object} o An object which contains an Array of row objects in the property specified
12440 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12441 * which contains the total size of the dataset.
12442 * @return {Object} data A data block which is used by an Roo.data.Store object as
12443 * a cache of Roo.data.Records.
12445 readRecords : function(o){
12447 * After any data loads, the raw JSON data is available for further custom processing.
12451 var s = this.meta, Record = this.recordType,
12452 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12454 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12456 if(s.totalProperty) {
12457 this.getTotal = this.getJsonAccessor(s.totalProperty);
12459 if(s.successProperty) {
12460 this.getSuccess = this.getJsonAccessor(s.successProperty);
12462 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12464 var g = this.getJsonAccessor(s.id);
12465 this.getId = function(rec) {
12467 return (r === undefined || r === "") ? null : r;
12470 this.getId = function(){return null;};
12473 for(var jj = 0; jj < fl; jj++){
12475 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12476 this.ef[jj] = this.getJsonAccessor(map);
12480 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12481 if(s.totalProperty){
12482 var vt = parseInt(this.getTotal(o), 10);
12487 if(s.successProperty){
12488 var vs = this.getSuccess(o);
12489 if(vs === false || vs === 'false'){
12494 for(var i = 0; i < c; i++){
12497 var id = this.getId(n);
12498 for(var j = 0; j < fl; j++){
12500 var v = this.ef[j](n);
12502 Roo.log('missing convert for ' + f.name);
12506 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12508 var record = new Record(values, id);
12510 records[i] = record;
12516 totalRecords : totalRecords
12521 * Ext JS Library 1.1.1
12522 * Copyright(c) 2006-2007, Ext JS, LLC.
12524 * Originally Released Under LGPL - original licence link has changed is not relivant.
12527 * <script type="text/javascript">
12531 * @class Roo.data.ArrayReader
12532 * @extends Roo.data.DataReader
12533 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12534 * Each element of that Array represents a row of data fields. The
12535 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12536 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12540 var RecordDef = Roo.data.Record.create([
12541 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12542 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12544 var myReader = new Roo.data.ArrayReader({
12545 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12549 * This would consume an Array like this:
12551 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12553 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12555 * Create a new JsonReader
12556 * @param {Object} meta Metadata configuration options.
12557 * @param {Object} recordType Either an Array of field definition objects
12558 * as specified to {@link Roo.data.Record#create},
12559 * or an {@link Roo.data.Record} object
12560 * created using {@link Roo.data.Record#create}.
12562 Roo.data.ArrayReader = function(meta, recordType){
12563 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12566 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12568 * Create a data block containing Roo.data.Records from an XML document.
12569 * @param {Object} o An Array of row objects which represents the dataset.
12570 * @return {Object} data A data block which is used by an Roo.data.Store object as
12571 * a cache of Roo.data.Records.
12573 readRecords : function(o){
12574 var sid = this.meta ? this.meta.id : null;
12575 var recordType = this.recordType, fields = recordType.prototype.fields;
12578 for(var i = 0; i < root.length; i++){
12581 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12582 for(var j = 0, jlen = fields.length; j < jlen; j++){
12583 var f = fields.items[j];
12584 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12585 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12587 values[f.name] = v;
12589 var record = new recordType(values, id);
12591 records[records.length] = record;
12595 totalRecords : records.length
12604 * @class Roo.bootstrap.ComboBox
12605 * @extends Roo.bootstrap.TriggerField
12606 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12607 * @cfg {Boolean} append (true|false) default false
12608 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12609 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12610 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12611 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12612 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12613 * @cfg {Boolean} animate default true
12614 * @cfg {Boolean} emptyResultText only for touch device
12615 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12616 * @cfg {String} emptyTitle default ''
12618 * Create a new ComboBox.
12619 * @param {Object} config Configuration options
12621 Roo.bootstrap.ComboBox = function(config){
12622 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12626 * Fires when the dropdown list is expanded
12627 * @param {Roo.bootstrap.ComboBox} combo This combo box
12632 * Fires when the dropdown list is collapsed
12633 * @param {Roo.bootstrap.ComboBox} combo This combo box
12637 * @event beforeselect
12638 * Fires before a list item is selected. Return false to cancel the selection.
12639 * @param {Roo.bootstrap.ComboBox} combo This combo box
12640 * @param {Roo.data.Record} record The data record returned from the underlying store
12641 * @param {Number} index The index of the selected item in the dropdown list
12643 'beforeselect' : true,
12646 * Fires when a list item is selected
12647 * @param {Roo.bootstrap.ComboBox} combo This combo box
12648 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12649 * @param {Number} index The index of the selected item in the dropdown list
12653 * @event beforequery
12654 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12655 * The event object passed has these properties:
12656 * @param {Roo.bootstrap.ComboBox} combo This combo box
12657 * @param {String} query The query
12658 * @param {Boolean} forceAll true to force "all" query
12659 * @param {Boolean} cancel true to cancel the query
12660 * @param {Object} e The query event object
12662 'beforequery': true,
12665 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12666 * @param {Roo.bootstrap.ComboBox} combo This combo box
12671 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12672 * @param {Roo.bootstrap.ComboBox} combo This combo box
12673 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12678 * Fires when the remove value from the combobox array
12679 * @param {Roo.bootstrap.ComboBox} combo This combo box
12683 * @event afterremove
12684 * Fires when the remove value from the combobox array
12685 * @param {Roo.bootstrap.ComboBox} combo This combo box
12687 'afterremove' : true,
12689 * @event specialfilter
12690 * Fires when specialfilter
12691 * @param {Roo.bootstrap.ComboBox} combo This combo box
12693 'specialfilter' : true,
12696 * Fires when tick the element
12697 * @param {Roo.bootstrap.ComboBox} combo This combo box
12701 * @event touchviewdisplay
12702 * Fires when touch view require special display (default is using displayField)
12703 * @param {Roo.bootstrap.ComboBox} combo This combo box
12704 * @param {Object} cfg set html .
12706 'touchviewdisplay' : true
12711 this.tickItems = [];
12713 this.selectedIndex = -1;
12714 if(this.mode == 'local'){
12715 if(config.queryDelay === undefined){
12716 this.queryDelay = 10;
12718 if(config.minChars === undefined){
12724 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12727 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12728 * rendering into an Roo.Editor, defaults to false)
12731 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12732 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12735 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12738 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12739 * the dropdown list (defaults to undefined, with no header element)
12743 * @cfg {String/Roo.Template} tpl The template to use to render the output
12747 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12749 listWidth: undefined,
12751 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12752 * mode = 'remote' or 'text' if mode = 'local')
12754 displayField: undefined,
12757 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12758 * mode = 'remote' or 'value' if mode = 'local').
12759 * Note: use of a valueField requires the user make a selection
12760 * in order for a value to be mapped.
12762 valueField: undefined,
12764 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12769 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12770 * field's data value (defaults to the underlying DOM element's name)
12772 hiddenName: undefined,
12774 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12778 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12780 selectedClass: 'active',
12783 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12787 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12788 * anchor positions (defaults to 'tl-bl')
12790 listAlign: 'tl-bl?',
12792 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12796 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12797 * query specified by the allQuery config option (defaults to 'query')
12799 triggerAction: 'query',
12801 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12802 * (defaults to 4, does not apply if editable = false)
12806 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12807 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12811 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12812 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12816 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12817 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12821 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12822 * when editable = true (defaults to false)
12824 selectOnFocus:false,
12826 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12828 queryParam: 'query',
12830 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12831 * when mode = 'remote' (defaults to 'Loading...')
12833 loadingText: 'Loading...',
12835 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12839 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12843 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12844 * traditional select (defaults to true)
12848 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12852 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12856 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12857 * listWidth has a higher value)
12861 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12862 * allow the user to set arbitrary text into the field (defaults to false)
12864 forceSelection:false,
12866 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12867 * if typeAhead = true (defaults to 250)
12869 typeAheadDelay : 250,
12871 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12872 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12874 valueNotFoundText : undefined,
12876 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12878 blockFocus : false,
12881 * @cfg {Boolean} disableClear Disable showing of clear button.
12883 disableClear : false,
12885 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12887 alwaysQuery : false,
12890 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12895 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12897 invalidClass : "has-warning",
12900 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12902 validClass : "has-success",
12905 * @cfg {Boolean} specialFilter (true|false) special filter default false
12907 specialFilter : false,
12910 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12912 mobileTouchView : true,
12915 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12917 useNativeIOS : false,
12919 ios_options : false,
12931 btnPosition : 'right',
12932 triggerList : true,
12933 showToggleBtn : true,
12935 emptyResultText: 'Empty',
12936 triggerText : 'Select',
12939 // element that contains real text value.. (when hidden is used..)
12941 getAutoCreate : function()
12946 * Render classic select for iso
12949 if(Roo.isIOS && this.useNativeIOS){
12950 cfg = this.getAutoCreateNativeIOS();
12958 if(Roo.isTouch && this.mobileTouchView){
12959 cfg = this.getAutoCreateTouchView();
12966 if(!this.tickable){
12967 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12972 * ComboBox with tickable selections
12975 var align = this.labelAlign || this.parentLabelAlign();
12978 cls : 'form-group roo-combobox-tickable' //input-group
12981 var btn_text_select = '';
12982 var btn_text_done = '';
12983 var btn_text_cancel = '';
12985 if (this.btn_text_show) {
12986 btn_text_select = 'Select';
12987 btn_text_done = 'Done';
12988 btn_text_cancel = 'Cancel';
12993 cls : 'tickable-buttons',
12998 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12999 //html : this.triggerText
13000 html: btn_text_select
13006 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13008 html: btn_text_done
13014 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13016 html: btn_text_cancel
13022 buttons.cn.unshift({
13024 cls: 'roo-select2-search-field-input'
13030 Roo.each(buttons.cn, function(c){
13032 c.cls += ' btn-' + _this.size;
13035 if (_this.disabled) {
13046 cls: 'form-hidden-field'
13050 cls: 'roo-select2-choices',
13054 cls: 'roo-select2-search-field',
13065 cls: 'roo-select2-container input-group roo-select2-container-multi',
13070 // cls: 'typeahead typeahead-long dropdown-menu',
13071 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13076 if(this.hasFeedback && !this.allowBlank){
13080 cls: 'glyphicon form-control-feedback'
13083 combobox.cn.push(feedback);
13087 if (align ==='left' && this.fieldLabel.length) {
13089 cfg.cls += ' roo-form-group-label-left';
13094 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13095 tooltip : 'This field is required'
13100 cls : 'control-label',
13101 html : this.fieldLabel
13113 var labelCfg = cfg.cn[1];
13114 var contentCfg = cfg.cn[2];
13117 if(this.indicatorpos == 'right'){
13123 cls : 'control-label',
13127 html : this.fieldLabel
13131 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13132 tooltip : 'This field is required'
13147 labelCfg = cfg.cn[0];
13148 contentCfg = cfg.cn[1];
13152 if(this.labelWidth > 12){
13153 labelCfg.style = "width: " + this.labelWidth + 'px';
13156 if(this.labelWidth < 13 && this.labelmd == 0){
13157 this.labelmd = this.labelWidth;
13160 if(this.labellg > 0){
13161 labelCfg.cls += ' col-lg-' + this.labellg;
13162 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13165 if(this.labelmd > 0){
13166 labelCfg.cls += ' col-md-' + this.labelmd;
13167 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13170 if(this.labelsm > 0){
13171 labelCfg.cls += ' col-sm-' + this.labelsm;
13172 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13175 if(this.labelxs > 0){
13176 labelCfg.cls += ' col-xs-' + this.labelxs;
13177 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13181 } else if ( this.fieldLabel.length) {
13182 // Roo.log(" label");
13186 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13187 tooltip : 'This field is required'
13191 //cls : 'input-group-addon',
13192 html : this.fieldLabel
13197 if(this.indicatorpos == 'right'){
13201 //cls : 'input-group-addon',
13202 html : this.fieldLabel
13206 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13207 tooltip : 'This field is required'
13216 // Roo.log(" no label && no align");
13223 ['xs','sm','md','lg'].map(function(size){
13224 if (settings[size]) {
13225 cfg.cls += ' col-' + size + '-' + settings[size];
13233 _initEventsCalled : false,
13236 initEvents: function()
13238 if (this._initEventsCalled) { // as we call render... prevent looping...
13241 this._initEventsCalled = true;
13244 throw "can not find store for combo";
13247 this.indicator = this.indicatorEl();
13249 this.store = Roo.factory(this.store, Roo.data);
13250 this.store.parent = this;
13252 // if we are building from html. then this element is so complex, that we can not really
13253 // use the rendered HTML.
13254 // so we have to trash and replace the previous code.
13255 if (Roo.XComponent.build_from_html) {
13256 // remove this element....
13257 var e = this.el.dom, k=0;
13258 while (e ) { e = e.previousSibling; ++k;}
13263 this.rendered = false;
13265 this.render(this.parent().getChildContainer(true), k);
13268 if(Roo.isIOS && this.useNativeIOS){
13269 this.initIOSView();
13277 if(Roo.isTouch && this.mobileTouchView){
13278 this.initTouchView();
13283 this.initTickableEvents();
13287 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13289 if(this.hiddenName){
13291 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13293 this.hiddenField.dom.value =
13294 this.hiddenValue !== undefined ? this.hiddenValue :
13295 this.value !== undefined ? this.value : '';
13297 // prevent input submission
13298 this.el.dom.removeAttribute('name');
13299 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13304 // this.el.dom.setAttribute('autocomplete', 'off');
13307 var cls = 'x-combo-list';
13309 //this.list = new Roo.Layer({
13310 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13316 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13317 _this.list.setWidth(lw);
13320 this.list.on('mouseover', this.onViewOver, this);
13321 this.list.on('mousemove', this.onViewMove, this);
13322 this.list.on('scroll', this.onViewScroll, this);
13325 this.list.swallowEvent('mousewheel');
13326 this.assetHeight = 0;
13329 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13330 this.assetHeight += this.header.getHeight();
13333 this.innerList = this.list.createChild({cls:cls+'-inner'});
13334 this.innerList.on('mouseover', this.onViewOver, this);
13335 this.innerList.on('mousemove', this.onViewMove, this);
13336 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13338 if(this.allowBlank && !this.pageSize && !this.disableClear){
13339 this.footer = this.list.createChild({cls:cls+'-ft'});
13340 this.pageTb = new Roo.Toolbar(this.footer);
13344 this.footer = this.list.createChild({cls:cls+'-ft'});
13345 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13346 {pageSize: this.pageSize});
13350 if (this.pageTb && this.allowBlank && !this.disableClear) {
13352 this.pageTb.add(new Roo.Toolbar.Fill(), {
13353 cls: 'x-btn-icon x-btn-clear',
13355 handler: function()
13358 _this.clearValue();
13359 _this.onSelect(false, -1);
13364 this.assetHeight += this.footer.getHeight();
13369 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13372 this.view = new Roo.View(this.list, this.tpl, {
13373 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13375 //this.view.wrapEl.setDisplayed(false);
13376 this.view.on('click', this.onViewClick, this);
13379 this.store.on('beforeload', this.onBeforeLoad, this);
13380 this.store.on('load', this.onLoad, this);
13381 this.store.on('loadexception', this.onLoadException, this);
13383 if(this.resizable){
13384 this.resizer = new Roo.Resizable(this.list, {
13385 pinned:true, handles:'se'
13387 this.resizer.on('resize', function(r, w, h){
13388 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13389 this.listWidth = w;
13390 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13391 this.restrictHeight();
13393 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13396 if(!this.editable){
13397 this.editable = true;
13398 this.setEditable(false);
13403 if (typeof(this.events.add.listeners) != 'undefined') {
13405 this.addicon = this.wrap.createChild(
13406 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13408 this.addicon.on('click', function(e) {
13409 this.fireEvent('add', this);
13412 if (typeof(this.events.edit.listeners) != 'undefined') {
13414 this.editicon = this.wrap.createChild(
13415 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13416 if (this.addicon) {
13417 this.editicon.setStyle('margin-left', '40px');
13419 this.editicon.on('click', function(e) {
13421 // we fire even if inothing is selected..
13422 this.fireEvent('edit', this, this.lastData );
13428 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13429 "up" : function(e){
13430 this.inKeyMode = true;
13434 "down" : function(e){
13435 if(!this.isExpanded()){
13436 this.onTriggerClick();
13438 this.inKeyMode = true;
13443 "enter" : function(e){
13444 // this.onViewClick();
13448 if(this.fireEvent("specialkey", this, e)){
13449 this.onViewClick(false);
13455 "esc" : function(e){
13459 "tab" : function(e){
13462 if(this.fireEvent("specialkey", this, e)){
13463 this.onViewClick(false);
13471 doRelay : function(foo, bar, hname){
13472 if(hname == 'down' || this.scope.isExpanded()){
13473 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13482 this.queryDelay = Math.max(this.queryDelay || 10,
13483 this.mode == 'local' ? 10 : 250);
13486 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13488 if(this.typeAhead){
13489 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13491 if(this.editable !== false){
13492 this.inputEl().on("keyup", this.onKeyUp, this);
13494 if(this.forceSelection){
13495 this.inputEl().on('blur', this.doForce, this);
13499 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13500 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13504 initTickableEvents: function()
13508 if(this.hiddenName){
13510 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13512 this.hiddenField.dom.value =
13513 this.hiddenValue !== undefined ? this.hiddenValue :
13514 this.value !== undefined ? this.value : '';
13516 // prevent input submission
13517 this.el.dom.removeAttribute('name');
13518 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13523 // this.list = this.el.select('ul.dropdown-menu',true).first();
13525 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13526 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13527 if(this.triggerList){
13528 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13531 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13532 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13534 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13535 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13537 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13538 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13540 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13541 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13542 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13545 this.cancelBtn.hide();
13550 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13551 _this.list.setWidth(lw);
13554 this.list.on('mouseover', this.onViewOver, this);
13555 this.list.on('mousemove', this.onViewMove, this);
13557 this.list.on('scroll', this.onViewScroll, this);
13560 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>';
13563 this.view = new Roo.View(this.list, this.tpl, {
13564 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13567 //this.view.wrapEl.setDisplayed(false);
13568 this.view.on('click', this.onViewClick, this);
13572 this.store.on('beforeload', this.onBeforeLoad, this);
13573 this.store.on('load', this.onLoad, this);
13574 this.store.on('loadexception', this.onLoadException, this);
13577 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13578 "up" : function(e){
13579 this.inKeyMode = true;
13583 "down" : function(e){
13584 this.inKeyMode = true;
13588 "enter" : function(e){
13589 if(this.fireEvent("specialkey", this, e)){
13590 this.onViewClick(false);
13596 "esc" : function(e){
13597 this.onTickableFooterButtonClick(e, false, false);
13600 "tab" : function(e){
13601 this.fireEvent("specialkey", this, e);
13603 this.onTickableFooterButtonClick(e, false, false);
13610 doRelay : function(e, fn, key){
13611 if(this.scope.isExpanded()){
13612 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13621 this.queryDelay = Math.max(this.queryDelay || 10,
13622 this.mode == 'local' ? 10 : 250);
13625 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13627 if(this.typeAhead){
13628 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13631 if(this.editable !== false){
13632 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13635 this.indicator = this.indicatorEl();
13637 if(this.indicator){
13638 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13639 this.indicator.hide();
13644 onDestroy : function(){
13646 this.view.setStore(null);
13647 this.view.el.removeAllListeners();
13648 this.view.el.remove();
13649 this.view.purgeListeners();
13652 this.list.dom.innerHTML = '';
13656 this.store.un('beforeload', this.onBeforeLoad, this);
13657 this.store.un('load', this.onLoad, this);
13658 this.store.un('loadexception', this.onLoadException, this);
13660 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13664 fireKey : function(e){
13665 if(e.isNavKeyPress() && !this.list.isVisible()){
13666 this.fireEvent("specialkey", this, e);
13671 onResize: function(w, h){
13672 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13674 // if(typeof w != 'number'){
13675 // // we do not handle it!?!?
13678 // var tw = this.trigger.getWidth();
13679 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13680 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13682 // this.inputEl().setWidth( this.adjustWidth('input', x));
13684 // //this.trigger.setStyle('left', x+'px');
13686 // if(this.list && this.listWidth === undefined){
13687 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13688 // this.list.setWidth(lw);
13689 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13697 * Allow or prevent the user from directly editing the field text. If false is passed,
13698 * the user will only be able to select from the items defined in the dropdown list. This method
13699 * is the runtime equivalent of setting the 'editable' config option at config time.
13700 * @param {Boolean} value True to allow the user to directly edit the field text
13702 setEditable : function(value){
13703 if(value == this.editable){
13706 this.editable = value;
13708 this.inputEl().dom.setAttribute('readOnly', true);
13709 this.inputEl().on('mousedown', this.onTriggerClick, this);
13710 this.inputEl().addClass('x-combo-noedit');
13712 this.inputEl().dom.setAttribute('readOnly', false);
13713 this.inputEl().un('mousedown', this.onTriggerClick, this);
13714 this.inputEl().removeClass('x-combo-noedit');
13720 onBeforeLoad : function(combo,opts){
13721 if(!this.hasFocus){
13725 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13727 this.restrictHeight();
13728 this.selectedIndex = -1;
13732 onLoad : function(){
13734 this.hasQuery = false;
13736 if(!this.hasFocus){
13740 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13741 this.loading.hide();
13744 if(this.store.getCount() > 0){
13747 this.restrictHeight();
13748 if(this.lastQuery == this.allQuery){
13749 if(this.editable && !this.tickable){
13750 this.inputEl().dom.select();
13754 !this.selectByValue(this.value, true) &&
13757 !this.store.lastOptions ||
13758 typeof(this.store.lastOptions.add) == 'undefined' ||
13759 this.store.lastOptions.add != true
13762 this.select(0, true);
13765 if(this.autoFocus){
13768 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13769 this.taTask.delay(this.typeAheadDelay);
13773 this.onEmptyResults();
13779 onLoadException : function()
13781 this.hasQuery = false;
13783 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13784 this.loading.hide();
13787 if(this.tickable && this.editable){
13792 // only causes errors at present
13793 //Roo.log(this.store.reader.jsonData);
13794 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13796 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13802 onTypeAhead : function(){
13803 if(this.store.getCount() > 0){
13804 var r = this.store.getAt(0);
13805 var newValue = r.data[this.displayField];
13806 var len = newValue.length;
13807 var selStart = this.getRawValue().length;
13809 if(selStart != len){
13810 this.setRawValue(newValue);
13811 this.selectText(selStart, newValue.length);
13817 onSelect : function(record, index){
13819 if(this.fireEvent('beforeselect', this, record, index) !== false){
13821 this.setFromData(index > -1 ? record.data : false);
13824 this.fireEvent('select', this, record, index);
13829 * Returns the currently selected field value or empty string if no value is set.
13830 * @return {String} value The selected value
13832 getValue : function()
13834 if(Roo.isIOS && this.useNativeIOS){
13835 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13839 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13842 if(this.valueField){
13843 return typeof this.value != 'undefined' ? this.value : '';
13845 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13849 getRawValue : function()
13851 if(Roo.isIOS && this.useNativeIOS){
13852 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13855 var v = this.inputEl().getValue();
13861 * Clears any text/value currently set in the field
13863 clearValue : function(){
13865 if(this.hiddenField){
13866 this.hiddenField.dom.value = '';
13869 this.setRawValue('');
13870 this.lastSelectionText = '';
13871 this.lastData = false;
13873 var close = this.closeTriggerEl();
13884 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13885 * will be displayed in the field. If the value does not match the data value of an existing item,
13886 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13887 * Otherwise the field will be blank (although the value will still be set).
13888 * @param {String} value The value to match
13890 setValue : function(v)
13892 if(Roo.isIOS && this.useNativeIOS){
13893 this.setIOSValue(v);
13903 if(this.valueField){
13904 var r = this.findRecord(this.valueField, v);
13906 text = r.data[this.displayField];
13907 }else if(this.valueNotFoundText !== undefined){
13908 text = this.valueNotFoundText;
13911 this.lastSelectionText = text;
13912 if(this.hiddenField){
13913 this.hiddenField.dom.value = v;
13915 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13918 var close = this.closeTriggerEl();
13921 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13927 * @property {Object} the last set data for the element
13932 * Sets the value of the field based on a object which is related to the record format for the store.
13933 * @param {Object} value the value to set as. or false on reset?
13935 setFromData : function(o){
13942 var dv = ''; // display value
13943 var vv = ''; // value value..
13945 if (this.displayField) {
13946 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13948 // this is an error condition!!!
13949 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13952 if(this.valueField){
13953 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13956 var close = this.closeTriggerEl();
13959 if(dv.length || vv * 1 > 0){
13961 this.blockFocus=true;
13967 if(this.hiddenField){
13968 this.hiddenField.dom.value = vv;
13970 this.lastSelectionText = dv;
13971 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13975 // no hidden field.. - we store the value in 'value', but still display
13976 // display field!!!!
13977 this.lastSelectionText = dv;
13978 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13985 reset : function(){
13986 // overridden so that last data is reset..
13993 this.setValue(this.originalValue);
13994 //this.clearInvalid();
13995 this.lastData = false;
13997 this.view.clearSelections();
14003 findRecord : function(prop, value){
14005 if(this.store.getCount() > 0){
14006 this.store.each(function(r){
14007 if(r.data[prop] == value){
14017 getName: function()
14019 // returns hidden if it's set..
14020 if (!this.rendered) {return ''};
14021 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14025 onViewMove : function(e, t){
14026 this.inKeyMode = false;
14030 onViewOver : function(e, t){
14031 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14034 var item = this.view.findItemFromChild(t);
14037 var index = this.view.indexOf(item);
14038 this.select(index, false);
14043 onViewClick : function(view, doFocus, el, e)
14045 var index = this.view.getSelectedIndexes()[0];
14047 var r = this.store.getAt(index);
14051 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14058 Roo.each(this.tickItems, function(v,k){
14060 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14062 _this.tickItems.splice(k, 1);
14064 if(typeof(e) == 'undefined' && view == false){
14065 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14077 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14078 this.tickItems.push(r.data);
14081 if(typeof(e) == 'undefined' && view == false){
14082 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14089 this.onSelect(r, index);
14091 if(doFocus !== false && !this.blockFocus){
14092 this.inputEl().focus();
14097 restrictHeight : function(){
14098 //this.innerList.dom.style.height = '';
14099 //var inner = this.innerList.dom;
14100 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14101 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14102 //this.list.beginUpdate();
14103 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14104 this.list.alignTo(this.inputEl(), this.listAlign);
14105 this.list.alignTo(this.inputEl(), this.listAlign);
14106 //this.list.endUpdate();
14110 onEmptyResults : function(){
14112 if(this.tickable && this.editable){
14113 this.hasFocus = false;
14114 this.restrictHeight();
14122 * Returns true if the dropdown list is expanded, else false.
14124 isExpanded : function(){
14125 return this.list.isVisible();
14129 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14130 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14131 * @param {String} value The data value of the item to select
14132 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14133 * selected item if it is not currently in view (defaults to true)
14134 * @return {Boolean} True if the value matched an item in the list, else false
14136 selectByValue : function(v, scrollIntoView){
14137 if(v !== undefined && v !== null){
14138 var r = this.findRecord(this.valueField || this.displayField, v);
14140 this.select(this.store.indexOf(r), scrollIntoView);
14148 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14149 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14150 * @param {Number} index The zero-based index of the list item to select
14151 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14152 * selected item if it is not currently in view (defaults to true)
14154 select : function(index, scrollIntoView){
14155 this.selectedIndex = index;
14156 this.view.select(index);
14157 if(scrollIntoView !== false){
14158 var el = this.view.getNode(index);
14160 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14163 this.list.scrollChildIntoView(el, false);
14169 selectNext : function(){
14170 var ct = this.store.getCount();
14172 if(this.selectedIndex == -1){
14174 }else if(this.selectedIndex < ct-1){
14175 this.select(this.selectedIndex+1);
14181 selectPrev : function(){
14182 var ct = this.store.getCount();
14184 if(this.selectedIndex == -1){
14186 }else if(this.selectedIndex != 0){
14187 this.select(this.selectedIndex-1);
14193 onKeyUp : function(e){
14194 if(this.editable !== false && !e.isSpecialKey()){
14195 this.lastKey = e.getKey();
14196 this.dqTask.delay(this.queryDelay);
14201 validateBlur : function(){
14202 return !this.list || !this.list.isVisible();
14206 initQuery : function(){
14208 var v = this.getRawValue();
14210 if(this.tickable && this.editable){
14211 v = this.tickableInputEl().getValue();
14218 doForce : function(){
14219 if(this.inputEl().dom.value.length > 0){
14220 this.inputEl().dom.value =
14221 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14227 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14228 * query allowing the query action to be canceled if needed.
14229 * @param {String} query The SQL query to execute
14230 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14231 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14232 * saved in the current store (defaults to false)
14234 doQuery : function(q, forceAll){
14236 if(q === undefined || q === null){
14241 forceAll: forceAll,
14245 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14250 forceAll = qe.forceAll;
14251 if(forceAll === true || (q.length >= this.minChars)){
14253 this.hasQuery = true;
14255 if(this.lastQuery != q || this.alwaysQuery){
14256 this.lastQuery = q;
14257 if(this.mode == 'local'){
14258 this.selectedIndex = -1;
14260 this.store.clearFilter();
14263 if(this.specialFilter){
14264 this.fireEvent('specialfilter', this);
14269 this.store.filter(this.displayField, q);
14272 this.store.fireEvent("datachanged", this.store);
14279 this.store.baseParams[this.queryParam] = q;
14281 var options = {params : this.getParams(q)};
14284 options.add = true;
14285 options.params.start = this.page * this.pageSize;
14288 this.store.load(options);
14291 * this code will make the page width larger, at the beginning, the list not align correctly,
14292 * we should expand the list on onLoad
14293 * so command out it
14298 this.selectedIndex = -1;
14303 this.loadNext = false;
14307 getParams : function(q){
14309 //p[this.queryParam] = q;
14313 p.limit = this.pageSize;
14319 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14321 collapse : function(){
14322 if(!this.isExpanded()){
14328 this.hasFocus = false;
14332 this.cancelBtn.hide();
14333 this.trigger.show();
14336 this.tickableInputEl().dom.value = '';
14337 this.tickableInputEl().blur();
14342 Roo.get(document).un('mousedown', this.collapseIf, this);
14343 Roo.get(document).un('mousewheel', this.collapseIf, this);
14344 if (!this.editable) {
14345 Roo.get(document).un('keydown', this.listKeyPress, this);
14347 this.fireEvent('collapse', this);
14353 collapseIf : function(e){
14354 var in_combo = e.within(this.el);
14355 var in_list = e.within(this.list);
14356 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14358 if (in_combo || in_list || is_list) {
14359 //e.stopPropagation();
14364 this.onTickableFooterButtonClick(e, false, false);
14372 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14374 expand : function(){
14376 if(this.isExpanded() || !this.hasFocus){
14380 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14381 this.list.setWidth(lw);
14387 this.restrictHeight();
14391 this.tickItems = Roo.apply([], this.item);
14394 this.cancelBtn.show();
14395 this.trigger.hide();
14398 this.tickableInputEl().focus();
14403 Roo.get(document).on('mousedown', this.collapseIf, this);
14404 Roo.get(document).on('mousewheel', this.collapseIf, this);
14405 if (!this.editable) {
14406 Roo.get(document).on('keydown', this.listKeyPress, this);
14409 this.fireEvent('expand', this);
14413 // Implements the default empty TriggerField.onTriggerClick function
14414 onTriggerClick : function(e)
14416 Roo.log('trigger click');
14418 if(this.disabled || !this.triggerList){
14423 this.loadNext = false;
14425 if(this.isExpanded()){
14427 if (!this.blockFocus) {
14428 this.inputEl().focus();
14432 this.hasFocus = true;
14433 if(this.triggerAction == 'all') {
14434 this.doQuery(this.allQuery, true);
14436 this.doQuery(this.getRawValue());
14438 if (!this.blockFocus) {
14439 this.inputEl().focus();
14444 onTickableTriggerClick : function(e)
14451 this.loadNext = false;
14452 this.hasFocus = true;
14454 if(this.triggerAction == 'all') {
14455 this.doQuery(this.allQuery, true);
14457 this.doQuery(this.getRawValue());
14461 onSearchFieldClick : function(e)
14463 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14464 this.onTickableFooterButtonClick(e, false, false);
14468 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14473 this.loadNext = false;
14474 this.hasFocus = true;
14476 if(this.triggerAction == 'all') {
14477 this.doQuery(this.allQuery, true);
14479 this.doQuery(this.getRawValue());
14483 listKeyPress : function(e)
14485 //Roo.log('listkeypress');
14486 // scroll to first matching element based on key pres..
14487 if (e.isSpecialKey()) {
14490 var k = String.fromCharCode(e.getKey()).toUpperCase();
14493 var csel = this.view.getSelectedNodes();
14494 var cselitem = false;
14496 var ix = this.view.indexOf(csel[0]);
14497 cselitem = this.store.getAt(ix);
14498 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14504 this.store.each(function(v) {
14506 // start at existing selection.
14507 if (cselitem.id == v.id) {
14513 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14514 match = this.store.indexOf(v);
14520 if (match === false) {
14521 return true; // no more action?
14524 this.view.select(match);
14525 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14526 sn.scrollIntoView(sn.dom.parentNode, false);
14529 onViewScroll : function(e, t){
14531 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){
14535 this.hasQuery = true;
14537 this.loading = this.list.select('.loading', true).first();
14539 if(this.loading === null){
14540 this.list.createChild({
14542 cls: 'loading roo-select2-more-results roo-select2-active',
14543 html: 'Loading more results...'
14546 this.loading = this.list.select('.loading', true).first();
14548 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14550 this.loading.hide();
14553 this.loading.show();
14558 this.loadNext = true;
14560 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14565 addItem : function(o)
14567 var dv = ''; // display value
14569 if (this.displayField) {
14570 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14572 // this is an error condition!!!
14573 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14580 var choice = this.choices.createChild({
14582 cls: 'roo-select2-search-choice',
14591 cls: 'roo-select2-search-choice-close fa fa-times',
14596 }, this.searchField);
14598 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14600 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14608 this.inputEl().dom.value = '';
14613 onRemoveItem : function(e, _self, o)
14615 e.preventDefault();
14617 this.lastItem = Roo.apply([], this.item);
14619 var index = this.item.indexOf(o.data) * 1;
14622 Roo.log('not this item?!');
14626 this.item.splice(index, 1);
14631 this.fireEvent('remove', this, e);
14637 syncValue : function()
14639 if(!this.item.length){
14646 Roo.each(this.item, function(i){
14647 if(_this.valueField){
14648 value.push(i[_this.valueField]);
14655 this.value = value.join(',');
14657 if(this.hiddenField){
14658 this.hiddenField.dom.value = this.value;
14661 this.store.fireEvent("datachanged", this.store);
14666 clearItem : function()
14668 if(!this.multiple){
14674 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14682 if(this.tickable && !Roo.isTouch){
14683 this.view.refresh();
14687 inputEl: function ()
14689 if(Roo.isIOS && this.useNativeIOS){
14690 return this.el.select('select.roo-ios-select', true).first();
14693 if(Roo.isTouch && this.mobileTouchView){
14694 return this.el.select('input.form-control',true).first();
14698 return this.searchField;
14701 return this.el.select('input.form-control',true).first();
14704 onTickableFooterButtonClick : function(e, btn, el)
14706 e.preventDefault();
14708 this.lastItem = Roo.apply([], this.item);
14710 if(btn && btn.name == 'cancel'){
14711 this.tickItems = Roo.apply([], this.item);
14720 Roo.each(this.tickItems, function(o){
14728 validate : function()
14730 if(this.getVisibilityEl().hasClass('hidden')){
14734 var v = this.getRawValue();
14737 v = this.getValue();
14740 if(this.disabled || this.allowBlank || v.length){
14745 this.markInvalid();
14749 tickableInputEl : function()
14751 if(!this.tickable || !this.editable){
14752 return this.inputEl();
14755 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14759 getAutoCreateTouchView : function()
14764 cls: 'form-group' //input-group
14770 type : this.inputType,
14771 cls : 'form-control x-combo-noedit',
14772 autocomplete: 'new-password',
14773 placeholder : this.placeholder || '',
14778 input.name = this.name;
14782 input.cls += ' input-' + this.size;
14785 if (this.disabled) {
14786 input.disabled = true;
14797 inputblock.cls += ' input-group';
14799 inputblock.cn.unshift({
14801 cls : 'input-group-addon',
14806 if(this.removable && !this.multiple){
14807 inputblock.cls += ' roo-removable';
14809 inputblock.cn.push({
14812 cls : 'roo-combo-removable-btn close'
14816 if(this.hasFeedback && !this.allowBlank){
14818 inputblock.cls += ' has-feedback';
14820 inputblock.cn.push({
14822 cls: 'glyphicon form-control-feedback'
14829 inputblock.cls += (this.before) ? '' : ' input-group';
14831 inputblock.cn.push({
14833 cls : 'input-group-addon',
14844 cls: 'form-hidden-field'
14858 cls: 'form-hidden-field'
14862 cls: 'roo-select2-choices',
14866 cls: 'roo-select2-search-field',
14879 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14885 if(!this.multiple && this.showToggleBtn){
14892 if (this.caret != false) {
14895 cls: 'fa fa-' + this.caret
14902 cls : 'input-group-addon btn dropdown-toggle',
14907 cls: 'combobox-clear',
14921 combobox.cls += ' roo-select2-container-multi';
14924 var align = this.labelAlign || this.parentLabelAlign();
14926 if (align ==='left' && this.fieldLabel.length) {
14931 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14932 tooltip : 'This field is required'
14936 cls : 'control-label',
14937 html : this.fieldLabel
14948 var labelCfg = cfg.cn[1];
14949 var contentCfg = cfg.cn[2];
14952 if(this.indicatorpos == 'right'){
14957 cls : 'control-label',
14961 html : this.fieldLabel
14965 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14966 tooltip : 'This field is required'
14979 labelCfg = cfg.cn[0];
14980 contentCfg = cfg.cn[1];
14985 if(this.labelWidth > 12){
14986 labelCfg.style = "width: " + this.labelWidth + 'px';
14989 if(this.labelWidth < 13 && this.labelmd == 0){
14990 this.labelmd = this.labelWidth;
14993 if(this.labellg > 0){
14994 labelCfg.cls += ' col-lg-' + this.labellg;
14995 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14998 if(this.labelmd > 0){
14999 labelCfg.cls += ' col-md-' + this.labelmd;
15000 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15003 if(this.labelsm > 0){
15004 labelCfg.cls += ' col-sm-' + this.labelsm;
15005 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15008 if(this.labelxs > 0){
15009 labelCfg.cls += ' col-xs-' + this.labelxs;
15010 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15014 } else if ( this.fieldLabel.length) {
15018 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15019 tooltip : 'This field is required'
15023 cls : 'control-label',
15024 html : this.fieldLabel
15035 if(this.indicatorpos == 'right'){
15039 cls : 'control-label',
15040 html : this.fieldLabel,
15044 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15045 tooltip : 'This field is required'
15062 var settings = this;
15064 ['xs','sm','md','lg'].map(function(size){
15065 if (settings[size]) {
15066 cfg.cls += ' col-' + size + '-' + settings[size];
15073 initTouchView : function()
15075 this.renderTouchView();
15077 this.touchViewEl.on('scroll', function(){
15078 this.el.dom.scrollTop = 0;
15081 this.originalValue = this.getValue();
15083 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15085 this.inputEl().on("click", this.showTouchView, this);
15086 if (this.triggerEl) {
15087 this.triggerEl.on("click", this.showTouchView, this);
15091 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15092 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15094 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15096 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15097 this.store.on('load', this.onTouchViewLoad, this);
15098 this.store.on('loadexception', this.onTouchViewLoadException, this);
15100 if(this.hiddenName){
15102 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15104 this.hiddenField.dom.value =
15105 this.hiddenValue !== undefined ? this.hiddenValue :
15106 this.value !== undefined ? this.value : '';
15108 this.el.dom.removeAttribute('name');
15109 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15113 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15114 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15117 if(this.removable && !this.multiple){
15118 var close = this.closeTriggerEl();
15120 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15121 close.on('click', this.removeBtnClick, this, close);
15125 * fix the bug in Safari iOS8
15127 this.inputEl().on("focus", function(e){
15128 document.activeElement.blur();
15136 renderTouchView : function()
15138 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15139 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15141 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15142 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15144 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15145 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15146 this.touchViewBodyEl.setStyle('overflow', 'auto');
15148 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15149 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15151 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15152 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15156 showTouchView : function()
15162 this.touchViewHeaderEl.hide();
15164 if(this.modalTitle.length){
15165 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15166 this.touchViewHeaderEl.show();
15169 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15170 this.touchViewEl.show();
15172 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15174 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15175 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15177 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15179 if(this.modalTitle.length){
15180 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15183 this.touchViewBodyEl.setHeight(bodyHeight);
15187 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15189 this.touchViewEl.addClass('in');
15192 this.doTouchViewQuery();
15196 hideTouchView : function()
15198 this.touchViewEl.removeClass('in');
15202 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15204 this.touchViewEl.setStyle('display', 'none');
15209 setTouchViewValue : function()
15216 Roo.each(this.tickItems, function(o){
15221 this.hideTouchView();
15224 doTouchViewQuery : function()
15233 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15237 if(!this.alwaysQuery || this.mode == 'local'){
15238 this.onTouchViewLoad();
15245 onTouchViewBeforeLoad : function(combo,opts)
15251 onTouchViewLoad : function()
15253 if(this.store.getCount() < 1){
15254 this.onTouchViewEmptyResults();
15258 this.clearTouchView();
15260 var rawValue = this.getRawValue();
15262 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15264 this.tickItems = [];
15266 this.store.data.each(function(d, rowIndex){
15267 var row = this.touchViewListGroup.createChild(template);
15269 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15270 row.addClass(d.data.cls);
15273 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15276 html : d.data[this.displayField]
15279 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15280 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15283 row.removeClass('selected');
15284 if(!this.multiple && this.valueField &&
15285 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15288 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15289 row.addClass('selected');
15292 if(this.multiple && this.valueField &&
15293 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15297 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15298 this.tickItems.push(d.data);
15301 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15305 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15307 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15309 if(this.modalTitle.length){
15310 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15313 var listHeight = this.touchViewListGroup.getHeight();
15317 if(firstChecked && listHeight > bodyHeight){
15318 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15323 onTouchViewLoadException : function()
15325 this.hideTouchView();
15328 onTouchViewEmptyResults : function()
15330 this.clearTouchView();
15332 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15334 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15338 clearTouchView : function()
15340 this.touchViewListGroup.dom.innerHTML = '';
15343 onTouchViewClick : function(e, el, o)
15345 e.preventDefault();
15348 var rowIndex = o.rowIndex;
15350 var r = this.store.getAt(rowIndex);
15352 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15354 if(!this.multiple){
15355 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15356 c.dom.removeAttribute('checked');
15359 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15361 this.setFromData(r.data);
15363 var close = this.closeTriggerEl();
15369 this.hideTouchView();
15371 this.fireEvent('select', this, r, rowIndex);
15376 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15377 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15378 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15382 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15383 this.addItem(r.data);
15384 this.tickItems.push(r.data);
15388 getAutoCreateNativeIOS : function()
15391 cls: 'form-group' //input-group,
15396 cls : 'roo-ios-select'
15400 combobox.name = this.name;
15403 if (this.disabled) {
15404 combobox.disabled = true;
15407 var settings = this;
15409 ['xs','sm','md','lg'].map(function(size){
15410 if (settings[size]) {
15411 cfg.cls += ' col-' + size + '-' + settings[size];
15421 initIOSView : function()
15423 this.store.on('load', this.onIOSViewLoad, this);
15428 onIOSViewLoad : function()
15430 if(this.store.getCount() < 1){
15434 this.clearIOSView();
15436 if(this.allowBlank) {
15438 var default_text = '-- SELECT --';
15440 if(this.placeholder.length){
15441 default_text = this.placeholder;
15444 if(this.emptyTitle.length){
15445 default_text += ' - ' + this.emptyTitle + ' -';
15448 var opt = this.inputEl().createChild({
15451 html : default_text
15455 o[this.valueField] = 0;
15456 o[this.displayField] = default_text;
15458 this.ios_options.push({
15465 this.store.data.each(function(d, rowIndex){
15469 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15470 html = d.data[this.displayField];
15475 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15476 value = d.data[this.valueField];
15485 if(this.value == d.data[this.valueField]){
15486 option['selected'] = true;
15489 var opt = this.inputEl().createChild(option);
15491 this.ios_options.push({
15498 this.inputEl().on('change', function(){
15499 this.fireEvent('select', this);
15504 clearIOSView: function()
15506 this.inputEl().dom.innerHTML = '';
15508 this.ios_options = [];
15511 setIOSValue: function(v)
15515 if(!this.ios_options){
15519 Roo.each(this.ios_options, function(opts){
15521 opts.el.dom.removeAttribute('selected');
15523 if(opts.data[this.valueField] != v){
15527 opts.el.dom.setAttribute('selected', true);
15533 * @cfg {Boolean} grow
15537 * @cfg {Number} growMin
15541 * @cfg {Number} growMax
15550 Roo.apply(Roo.bootstrap.ComboBox, {
15554 cls: 'modal-header',
15576 cls: 'list-group-item',
15580 cls: 'roo-combobox-list-group-item-value'
15584 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15598 listItemCheckbox : {
15600 cls: 'list-group-item',
15604 cls: 'roo-combobox-list-group-item-value'
15608 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15624 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15629 cls: 'modal-footer',
15637 cls: 'col-xs-6 text-left',
15640 cls: 'btn btn-danger roo-touch-view-cancel',
15646 cls: 'col-xs-6 text-right',
15649 cls: 'btn btn-success roo-touch-view-ok',
15660 Roo.apply(Roo.bootstrap.ComboBox, {
15662 touchViewTemplate : {
15664 cls: 'modal fade roo-combobox-touch-view',
15668 cls: 'modal-dialog',
15669 style : 'position:fixed', // we have to fix position....
15673 cls: 'modal-content',
15675 Roo.bootstrap.ComboBox.header,
15676 Roo.bootstrap.ComboBox.body,
15677 Roo.bootstrap.ComboBox.footer
15686 * Ext JS Library 1.1.1
15687 * Copyright(c) 2006-2007, Ext JS, LLC.
15689 * Originally Released Under LGPL - original licence link has changed is not relivant.
15692 * <script type="text/javascript">
15697 * @extends Roo.util.Observable
15698 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15699 * This class also supports single and multi selection modes. <br>
15700 * Create a data model bound view:
15702 var store = new Roo.data.Store(...);
15704 var view = new Roo.View({
15706 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15708 singleSelect: true,
15709 selectedClass: "ydataview-selected",
15713 // listen for node click?
15714 view.on("click", function(vw, index, node, e){
15715 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15719 dataModel.load("foobar.xml");
15721 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15723 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15724 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15726 * Note: old style constructor is still suported (container, template, config)
15729 * Create a new View
15730 * @param {Object} config The config object
15733 Roo.View = function(config, depreciated_tpl, depreciated_config){
15735 this.parent = false;
15737 if (typeof(depreciated_tpl) == 'undefined') {
15738 // new way.. - universal constructor.
15739 Roo.apply(this, config);
15740 this.el = Roo.get(this.el);
15743 this.el = Roo.get(config);
15744 this.tpl = depreciated_tpl;
15745 Roo.apply(this, depreciated_config);
15747 this.wrapEl = this.el.wrap().wrap();
15748 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15751 if(typeof(this.tpl) == "string"){
15752 this.tpl = new Roo.Template(this.tpl);
15754 // support xtype ctors..
15755 this.tpl = new Roo.factory(this.tpl, Roo);
15759 this.tpl.compile();
15764 * @event beforeclick
15765 * Fires before a click is processed. Returns false to cancel the default action.
15766 * @param {Roo.View} this
15767 * @param {Number} index The index of the target node
15768 * @param {HTMLElement} node The target node
15769 * @param {Roo.EventObject} e The raw event object
15771 "beforeclick" : true,
15774 * Fires when a template node is clicked.
15775 * @param {Roo.View} this
15776 * @param {Number} index The index of the target node
15777 * @param {HTMLElement} node The target node
15778 * @param {Roo.EventObject} e The raw event object
15783 * Fires when a template node is double clicked.
15784 * @param {Roo.View} this
15785 * @param {Number} index The index of the target node
15786 * @param {HTMLElement} node The target node
15787 * @param {Roo.EventObject} e The raw event object
15791 * @event contextmenu
15792 * Fires when a template node is right clicked.
15793 * @param {Roo.View} this
15794 * @param {Number} index The index of the target node
15795 * @param {HTMLElement} node The target node
15796 * @param {Roo.EventObject} e The raw event object
15798 "contextmenu" : true,
15800 * @event selectionchange
15801 * Fires when the selected nodes change.
15802 * @param {Roo.View} this
15803 * @param {Array} selections Array of the selected nodes
15805 "selectionchange" : true,
15808 * @event beforeselect
15809 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15810 * @param {Roo.View} this
15811 * @param {HTMLElement} node The node to be selected
15812 * @param {Array} selections Array of currently selected nodes
15814 "beforeselect" : true,
15816 * @event preparedata
15817 * Fires on every row to render, to allow you to change the data.
15818 * @param {Roo.View} this
15819 * @param {Object} data to be rendered (change this)
15821 "preparedata" : true
15829 "click": this.onClick,
15830 "dblclick": this.onDblClick,
15831 "contextmenu": this.onContextMenu,
15835 this.selections = [];
15837 this.cmp = new Roo.CompositeElementLite([]);
15839 this.store = Roo.factory(this.store, Roo.data);
15840 this.setStore(this.store, true);
15843 if ( this.footer && this.footer.xtype) {
15845 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15847 this.footer.dataSource = this.store;
15848 this.footer.container = fctr;
15849 this.footer = Roo.factory(this.footer, Roo);
15850 fctr.insertFirst(this.el);
15852 // this is a bit insane - as the paging toolbar seems to detach the el..
15853 // dom.parentNode.parentNode.parentNode
15854 // they get detached?
15858 Roo.View.superclass.constructor.call(this);
15863 Roo.extend(Roo.View, Roo.util.Observable, {
15866 * @cfg {Roo.data.Store} store Data store to load data from.
15871 * @cfg {String|Roo.Element} el The container element.
15876 * @cfg {String|Roo.Template} tpl The template used by this View
15880 * @cfg {String} dataName the named area of the template to use as the data area
15881 * Works with domtemplates roo-name="name"
15885 * @cfg {String} selectedClass The css class to add to selected nodes
15887 selectedClass : "x-view-selected",
15889 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15894 * @cfg {String} text to display on mask (default Loading)
15898 * @cfg {Boolean} multiSelect Allow multiple selection
15900 multiSelect : false,
15902 * @cfg {Boolean} singleSelect Allow single selection
15904 singleSelect: false,
15907 * @cfg {Boolean} toggleSelect - selecting
15909 toggleSelect : false,
15912 * @cfg {Boolean} tickable - selecting
15917 * Returns the element this view is bound to.
15918 * @return {Roo.Element}
15920 getEl : function(){
15921 return this.wrapEl;
15927 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15929 refresh : function(){
15930 //Roo.log('refresh');
15933 // if we are using something like 'domtemplate', then
15934 // the what gets used is:
15935 // t.applySubtemplate(NAME, data, wrapping data..)
15936 // the outer template then get' applied with
15937 // the store 'extra data'
15938 // and the body get's added to the
15939 // roo-name="data" node?
15940 // <span class='roo-tpl-{name}'></span> ?????
15944 this.clearSelections();
15945 this.el.update("");
15947 var records = this.store.getRange();
15948 if(records.length < 1) {
15950 // is this valid?? = should it render a template??
15952 this.el.update(this.emptyText);
15956 if (this.dataName) {
15957 this.el.update(t.apply(this.store.meta)); //????
15958 el = this.el.child('.roo-tpl-' + this.dataName);
15961 for(var i = 0, len = records.length; i < len; i++){
15962 var data = this.prepareData(records[i].data, i, records[i]);
15963 this.fireEvent("preparedata", this, data, i, records[i]);
15965 var d = Roo.apply({}, data);
15968 Roo.apply(d, {'roo-id' : Roo.id()});
15972 Roo.each(this.parent.item, function(item){
15973 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15976 Roo.apply(d, {'roo-data-checked' : 'checked'});
15980 html[html.length] = Roo.util.Format.trim(
15982 t.applySubtemplate(this.dataName, d, this.store.meta) :
15989 el.update(html.join(""));
15990 this.nodes = el.dom.childNodes;
15991 this.updateIndexes(0);
15996 * Function to override to reformat the data that is sent to
15997 * the template for each node.
15998 * DEPRICATED - use the preparedata event handler.
15999 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16000 * a JSON object for an UpdateManager bound view).
16002 prepareData : function(data, index, record)
16004 this.fireEvent("preparedata", this, data, index, record);
16008 onUpdate : function(ds, record){
16009 // Roo.log('on update');
16010 this.clearSelections();
16011 var index = this.store.indexOf(record);
16012 var n = this.nodes[index];
16013 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16014 n.parentNode.removeChild(n);
16015 this.updateIndexes(index, index);
16021 onAdd : function(ds, records, index)
16023 //Roo.log(['on Add', ds, records, index] );
16024 this.clearSelections();
16025 if(this.nodes.length == 0){
16029 var n = this.nodes[index];
16030 for(var i = 0, len = records.length; i < len; i++){
16031 var d = this.prepareData(records[i].data, i, records[i]);
16033 this.tpl.insertBefore(n, d);
16036 this.tpl.append(this.el, d);
16039 this.updateIndexes(index);
16042 onRemove : function(ds, record, index){
16043 // Roo.log('onRemove');
16044 this.clearSelections();
16045 var el = this.dataName ?
16046 this.el.child('.roo-tpl-' + this.dataName) :
16049 el.dom.removeChild(this.nodes[index]);
16050 this.updateIndexes(index);
16054 * Refresh an individual node.
16055 * @param {Number} index
16057 refreshNode : function(index){
16058 this.onUpdate(this.store, this.store.getAt(index));
16061 updateIndexes : function(startIndex, endIndex){
16062 var ns = this.nodes;
16063 startIndex = startIndex || 0;
16064 endIndex = endIndex || ns.length - 1;
16065 for(var i = startIndex; i <= endIndex; i++){
16066 ns[i].nodeIndex = i;
16071 * Changes the data store this view uses and refresh the view.
16072 * @param {Store} store
16074 setStore : function(store, initial){
16075 if(!initial && this.store){
16076 this.store.un("datachanged", this.refresh);
16077 this.store.un("add", this.onAdd);
16078 this.store.un("remove", this.onRemove);
16079 this.store.un("update", this.onUpdate);
16080 this.store.un("clear", this.refresh);
16081 this.store.un("beforeload", this.onBeforeLoad);
16082 this.store.un("load", this.onLoad);
16083 this.store.un("loadexception", this.onLoad);
16087 store.on("datachanged", this.refresh, this);
16088 store.on("add", this.onAdd, this);
16089 store.on("remove", this.onRemove, this);
16090 store.on("update", this.onUpdate, this);
16091 store.on("clear", this.refresh, this);
16092 store.on("beforeload", this.onBeforeLoad, this);
16093 store.on("load", this.onLoad, this);
16094 store.on("loadexception", this.onLoad, this);
16102 * onbeforeLoad - masks the loading area.
16105 onBeforeLoad : function(store,opts)
16107 //Roo.log('onBeforeLoad');
16109 this.el.update("");
16111 this.el.mask(this.mask ? this.mask : "Loading" );
16113 onLoad : function ()
16120 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16121 * @param {HTMLElement} node
16122 * @return {HTMLElement} The template node
16124 findItemFromChild : function(node){
16125 var el = this.dataName ?
16126 this.el.child('.roo-tpl-' + this.dataName,true) :
16129 if(!node || node.parentNode == el){
16132 var p = node.parentNode;
16133 while(p && p != el){
16134 if(p.parentNode == el){
16143 onClick : function(e){
16144 var item = this.findItemFromChild(e.getTarget());
16146 var index = this.indexOf(item);
16147 if(this.onItemClick(item, index, e) !== false){
16148 this.fireEvent("click", this, index, item, e);
16151 this.clearSelections();
16156 onContextMenu : function(e){
16157 var item = this.findItemFromChild(e.getTarget());
16159 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16164 onDblClick : function(e){
16165 var item = this.findItemFromChild(e.getTarget());
16167 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16171 onItemClick : function(item, index, e)
16173 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16176 if (this.toggleSelect) {
16177 var m = this.isSelected(item) ? 'unselect' : 'select';
16180 _t[m](item, true, false);
16183 if(this.multiSelect || this.singleSelect){
16184 if(this.multiSelect && e.shiftKey && this.lastSelection){
16185 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16187 this.select(item, this.multiSelect && e.ctrlKey);
16188 this.lastSelection = item;
16191 if(!this.tickable){
16192 e.preventDefault();
16200 * Get the number of selected nodes.
16203 getSelectionCount : function(){
16204 return this.selections.length;
16208 * Get the currently selected nodes.
16209 * @return {Array} An array of HTMLElements
16211 getSelectedNodes : function(){
16212 return this.selections;
16216 * Get the indexes of the selected nodes.
16219 getSelectedIndexes : function(){
16220 var indexes = [], s = this.selections;
16221 for(var i = 0, len = s.length; i < len; i++){
16222 indexes.push(s[i].nodeIndex);
16228 * Clear all selections
16229 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16231 clearSelections : function(suppressEvent){
16232 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16233 this.cmp.elements = this.selections;
16234 this.cmp.removeClass(this.selectedClass);
16235 this.selections = [];
16236 if(!suppressEvent){
16237 this.fireEvent("selectionchange", this, this.selections);
16243 * Returns true if the passed node is selected
16244 * @param {HTMLElement/Number} node The node or node index
16245 * @return {Boolean}
16247 isSelected : function(node){
16248 var s = this.selections;
16252 node = this.getNode(node);
16253 return s.indexOf(node) !== -1;
16258 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16259 * @param {Boolean} keepExisting (optional) true to keep existing selections
16260 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16262 select : function(nodeInfo, keepExisting, suppressEvent){
16263 if(nodeInfo instanceof Array){
16265 this.clearSelections(true);
16267 for(var i = 0, len = nodeInfo.length; i < len; i++){
16268 this.select(nodeInfo[i], true, true);
16272 var node = this.getNode(nodeInfo);
16273 if(!node || this.isSelected(node)){
16274 return; // already selected.
16277 this.clearSelections(true);
16280 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16281 Roo.fly(node).addClass(this.selectedClass);
16282 this.selections.push(node);
16283 if(!suppressEvent){
16284 this.fireEvent("selectionchange", this, this.selections);
16292 * @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
16293 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16294 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16296 unselect : function(nodeInfo, keepExisting, suppressEvent)
16298 if(nodeInfo instanceof Array){
16299 Roo.each(this.selections, function(s) {
16300 this.unselect(s, nodeInfo);
16304 var node = this.getNode(nodeInfo);
16305 if(!node || !this.isSelected(node)){
16306 //Roo.log("not selected");
16307 return; // not selected.
16311 Roo.each(this.selections, function(s) {
16313 Roo.fly(node).removeClass(this.selectedClass);
16320 this.selections= ns;
16321 this.fireEvent("selectionchange", this, this.selections);
16325 * Gets a template node.
16326 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16327 * @return {HTMLElement} The node or null if it wasn't found
16329 getNode : function(nodeInfo){
16330 if(typeof nodeInfo == "string"){
16331 return document.getElementById(nodeInfo);
16332 }else if(typeof nodeInfo == "number"){
16333 return this.nodes[nodeInfo];
16339 * Gets a range template nodes.
16340 * @param {Number} startIndex
16341 * @param {Number} endIndex
16342 * @return {Array} An array of nodes
16344 getNodes : function(start, end){
16345 var ns = this.nodes;
16346 start = start || 0;
16347 end = typeof end == "undefined" ? ns.length - 1 : end;
16350 for(var i = start; i <= end; i++){
16354 for(var i = start; i >= end; i--){
16362 * Finds the index of the passed node
16363 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16364 * @return {Number} The index of the node or -1
16366 indexOf : function(node){
16367 node = this.getNode(node);
16368 if(typeof node.nodeIndex == "number"){
16369 return node.nodeIndex;
16371 var ns = this.nodes;
16372 for(var i = 0, len = ns.length; i < len; i++){
16383 * based on jquery fullcalendar
16387 Roo.bootstrap = Roo.bootstrap || {};
16389 * @class Roo.bootstrap.Calendar
16390 * @extends Roo.bootstrap.Component
16391 * Bootstrap Calendar class
16392 * @cfg {Boolean} loadMask (true|false) default false
16393 * @cfg {Object} header generate the user specific header of the calendar, default false
16396 * Create a new Container
16397 * @param {Object} config The config object
16402 Roo.bootstrap.Calendar = function(config){
16403 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16407 * Fires when a date is selected
16408 * @param {DatePicker} this
16409 * @param {Date} date The selected date
16413 * @event monthchange
16414 * Fires when the displayed month changes
16415 * @param {DatePicker} this
16416 * @param {Date} date The selected month
16418 'monthchange': true,
16420 * @event evententer
16421 * Fires when mouse over an event
16422 * @param {Calendar} this
16423 * @param {event} Event
16425 'evententer': true,
16427 * @event eventleave
16428 * Fires when the mouse leaves an
16429 * @param {Calendar} this
16432 'eventleave': true,
16434 * @event eventclick
16435 * Fires when the mouse click an
16436 * @param {Calendar} this
16445 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16448 * @cfg {Number} startDay
16449 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16457 getAutoCreate : function(){
16460 var fc_button = function(name, corner, style, content ) {
16461 return Roo.apply({},{
16463 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16465 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16468 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16479 style : 'width:100%',
16486 cls : 'fc-header-left',
16488 fc_button('prev', 'left', 'arrow', '‹' ),
16489 fc_button('next', 'right', 'arrow', '›' ),
16490 { tag: 'span', cls: 'fc-header-space' },
16491 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16499 cls : 'fc-header-center',
16503 cls: 'fc-header-title',
16506 html : 'month / year'
16514 cls : 'fc-header-right',
16516 /* fc_button('month', 'left', '', 'month' ),
16517 fc_button('week', '', '', 'week' ),
16518 fc_button('day', 'right', '', 'day' )
16530 header = this.header;
16533 var cal_heads = function() {
16535 // fixme - handle this.
16537 for (var i =0; i < Date.dayNames.length; i++) {
16538 var d = Date.dayNames[i];
16541 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16542 html : d.substring(0,3)
16546 ret[0].cls += ' fc-first';
16547 ret[6].cls += ' fc-last';
16550 var cal_cell = function(n) {
16553 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16558 cls: 'fc-day-number',
16562 cls: 'fc-day-content',
16566 style: 'position: relative;' // height: 17px;
16578 var cal_rows = function() {
16581 for (var r = 0; r < 6; r++) {
16588 for (var i =0; i < Date.dayNames.length; i++) {
16589 var d = Date.dayNames[i];
16590 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16593 row.cn[0].cls+=' fc-first';
16594 row.cn[0].cn[0].style = 'min-height:90px';
16595 row.cn[6].cls+=' fc-last';
16599 ret[0].cls += ' fc-first';
16600 ret[4].cls += ' fc-prev-last';
16601 ret[5].cls += ' fc-last';
16608 cls: 'fc-border-separate',
16609 style : 'width:100%',
16617 cls : 'fc-first fc-last',
16635 cls : 'fc-content',
16636 style : "position: relative;",
16639 cls : 'fc-view fc-view-month fc-grid',
16640 style : 'position: relative',
16641 unselectable : 'on',
16644 cls : 'fc-event-container',
16645 style : 'position:absolute;z-index:8;top:0;left:0;'
16663 initEvents : function()
16666 throw "can not find store for calendar";
16672 style: "text-align:center",
16676 style: "background-color:white;width:50%;margin:250 auto",
16680 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16691 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16693 var size = this.el.select('.fc-content', true).first().getSize();
16694 this.maskEl.setSize(size.width, size.height);
16695 this.maskEl.enableDisplayMode("block");
16696 if(!this.loadMask){
16697 this.maskEl.hide();
16700 this.store = Roo.factory(this.store, Roo.data);
16701 this.store.on('load', this.onLoad, this);
16702 this.store.on('beforeload', this.onBeforeLoad, this);
16706 this.cells = this.el.select('.fc-day',true);
16707 //Roo.log(this.cells);
16708 this.textNodes = this.el.query('.fc-day-number');
16709 this.cells.addClassOnOver('fc-state-hover');
16711 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16712 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16713 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16714 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16716 this.on('monthchange', this.onMonthChange, this);
16718 this.update(new Date().clearTime());
16721 resize : function() {
16722 var sz = this.el.getSize();
16724 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16725 this.el.select('.fc-day-content div',true).setHeight(34);
16730 showPrevMonth : function(e){
16731 this.update(this.activeDate.add("mo", -1));
16733 showToday : function(e){
16734 this.update(new Date().clearTime());
16737 showNextMonth : function(e){
16738 this.update(this.activeDate.add("mo", 1));
16742 showPrevYear : function(){
16743 this.update(this.activeDate.add("y", -1));
16747 showNextYear : function(){
16748 this.update(this.activeDate.add("y", 1));
16753 update : function(date)
16755 var vd = this.activeDate;
16756 this.activeDate = date;
16757 // if(vd && this.el){
16758 // var t = date.getTime();
16759 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16760 // Roo.log('using add remove');
16762 // this.fireEvent('monthchange', this, date);
16764 // this.cells.removeClass("fc-state-highlight");
16765 // this.cells.each(function(c){
16766 // if(c.dateValue == t){
16767 // c.addClass("fc-state-highlight");
16768 // setTimeout(function(){
16769 // try{c.dom.firstChild.focus();}catch(e){}
16779 var days = date.getDaysInMonth();
16781 var firstOfMonth = date.getFirstDateOfMonth();
16782 var startingPos = firstOfMonth.getDay()-this.startDay;
16784 if(startingPos < this.startDay){
16788 var pm = date.add(Date.MONTH, -1);
16789 var prevStart = pm.getDaysInMonth()-startingPos;
16791 this.cells = this.el.select('.fc-day',true);
16792 this.textNodes = this.el.query('.fc-day-number');
16793 this.cells.addClassOnOver('fc-state-hover');
16795 var cells = this.cells.elements;
16796 var textEls = this.textNodes;
16798 Roo.each(cells, function(cell){
16799 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16802 days += startingPos;
16804 // convert everything to numbers so it's fast
16805 var day = 86400000;
16806 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16809 //Roo.log(prevStart);
16811 var today = new Date().clearTime().getTime();
16812 var sel = date.clearTime().getTime();
16813 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16814 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16815 var ddMatch = this.disabledDatesRE;
16816 var ddText = this.disabledDatesText;
16817 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16818 var ddaysText = this.disabledDaysText;
16819 var format = this.format;
16821 var setCellClass = function(cal, cell){
16825 //Roo.log('set Cell Class');
16827 var t = d.getTime();
16831 cell.dateValue = t;
16833 cell.className += " fc-today";
16834 cell.className += " fc-state-highlight";
16835 cell.title = cal.todayText;
16838 // disable highlight in other month..
16839 //cell.className += " fc-state-highlight";
16844 cell.className = " fc-state-disabled";
16845 cell.title = cal.minText;
16849 cell.className = " fc-state-disabled";
16850 cell.title = cal.maxText;
16854 if(ddays.indexOf(d.getDay()) != -1){
16855 cell.title = ddaysText;
16856 cell.className = " fc-state-disabled";
16859 if(ddMatch && format){
16860 var fvalue = d.dateFormat(format);
16861 if(ddMatch.test(fvalue)){
16862 cell.title = ddText.replace("%0", fvalue);
16863 cell.className = " fc-state-disabled";
16867 if (!cell.initialClassName) {
16868 cell.initialClassName = cell.dom.className;
16871 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16876 for(; i < startingPos; i++) {
16877 textEls[i].innerHTML = (++prevStart);
16878 d.setDate(d.getDate()+1);
16880 cells[i].className = "fc-past fc-other-month";
16881 setCellClass(this, cells[i]);
16886 for(; i < days; i++){
16887 intDay = i - startingPos + 1;
16888 textEls[i].innerHTML = (intDay);
16889 d.setDate(d.getDate()+1);
16891 cells[i].className = ''; // "x-date-active";
16892 setCellClass(this, cells[i]);
16896 for(; i < 42; i++) {
16897 textEls[i].innerHTML = (++extraDays);
16898 d.setDate(d.getDate()+1);
16900 cells[i].className = "fc-future fc-other-month";
16901 setCellClass(this, cells[i]);
16904 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16906 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16908 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16909 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16911 if(totalRows != 6){
16912 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16913 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16916 this.fireEvent('monthchange', this, date);
16920 if(!this.internalRender){
16921 var main = this.el.dom.firstChild;
16922 var w = main.offsetWidth;
16923 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16924 Roo.fly(main).setWidth(w);
16925 this.internalRender = true;
16926 // opera does not respect the auto grow header center column
16927 // then, after it gets a width opera refuses to recalculate
16928 // without a second pass
16929 if(Roo.isOpera && !this.secondPass){
16930 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16931 this.secondPass = true;
16932 this.update.defer(10, this, [date]);
16939 findCell : function(dt) {
16940 dt = dt.clearTime().getTime();
16942 this.cells.each(function(c){
16943 //Roo.log("check " +c.dateValue + '?=' + dt);
16944 if(c.dateValue == dt){
16954 findCells : function(ev) {
16955 var s = ev.start.clone().clearTime().getTime();
16957 var e= ev.end.clone().clearTime().getTime();
16960 this.cells.each(function(c){
16961 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16963 if(c.dateValue > e){
16966 if(c.dateValue < s){
16975 // findBestRow: function(cells)
16979 // for (var i =0 ; i < cells.length;i++) {
16980 // ret = Math.max(cells[i].rows || 0,ret);
16987 addItem : function(ev)
16989 // look for vertical location slot in
16990 var cells = this.findCells(ev);
16992 // ev.row = this.findBestRow(cells);
16994 // work out the location.
16998 for(var i =0; i < cells.length; i++) {
17000 cells[i].row = cells[0].row;
17003 cells[i].row = cells[i].row + 1;
17013 if (crow.start.getY() == cells[i].getY()) {
17015 crow.end = cells[i];
17032 cells[0].events.push(ev);
17034 this.calevents.push(ev);
17037 clearEvents: function() {
17039 if(!this.calevents){
17043 Roo.each(this.cells.elements, function(c){
17049 Roo.each(this.calevents, function(e) {
17050 Roo.each(e.els, function(el) {
17051 el.un('mouseenter' ,this.onEventEnter, this);
17052 el.un('mouseleave' ,this.onEventLeave, this);
17057 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17063 renderEvents: function()
17067 this.cells.each(function(c) {
17076 if(c.row != c.events.length){
17077 r = 4 - (4 - (c.row - c.events.length));
17080 c.events = ev.slice(0, r);
17081 c.more = ev.slice(r);
17083 if(c.more.length && c.more.length == 1){
17084 c.events.push(c.more.pop());
17087 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17091 this.cells.each(function(c) {
17093 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17096 for (var e = 0; e < c.events.length; e++){
17097 var ev = c.events[e];
17098 var rows = ev.rows;
17100 for(var i = 0; i < rows.length; i++) {
17102 // how many rows should it span..
17105 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17106 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17108 unselectable : "on",
17111 cls: 'fc-event-inner',
17115 // cls: 'fc-event-time',
17116 // html : cells.length > 1 ? '' : ev.time
17120 cls: 'fc-event-title',
17121 html : String.format('{0}', ev.title)
17128 cls: 'ui-resizable-handle ui-resizable-e',
17129 html : '  '
17136 cfg.cls += ' fc-event-start';
17138 if ((i+1) == rows.length) {
17139 cfg.cls += ' fc-event-end';
17142 var ctr = _this.el.select('.fc-event-container',true).first();
17143 var cg = ctr.createChild(cfg);
17145 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17146 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17148 var r = (c.more.length) ? 1 : 0;
17149 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17150 cg.setWidth(ebox.right - sbox.x -2);
17152 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17153 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17154 cg.on('click', _this.onEventClick, _this, ev);
17165 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17166 style : 'position: absolute',
17167 unselectable : "on",
17170 cls: 'fc-event-inner',
17174 cls: 'fc-event-title',
17182 cls: 'ui-resizable-handle ui-resizable-e',
17183 html : '  '
17189 var ctr = _this.el.select('.fc-event-container',true).first();
17190 var cg = ctr.createChild(cfg);
17192 var sbox = c.select('.fc-day-content',true).first().getBox();
17193 var ebox = c.select('.fc-day-content',true).first().getBox();
17195 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17196 cg.setWidth(ebox.right - sbox.x -2);
17198 cg.on('click', _this.onMoreEventClick, _this, c.more);
17208 onEventEnter: function (e, el,event,d) {
17209 this.fireEvent('evententer', this, el, event);
17212 onEventLeave: function (e, el,event,d) {
17213 this.fireEvent('eventleave', this, el, event);
17216 onEventClick: function (e, el,event,d) {
17217 this.fireEvent('eventclick', this, el, event);
17220 onMonthChange: function () {
17224 onMoreEventClick: function(e, el, more)
17228 this.calpopover.placement = 'right';
17229 this.calpopover.setTitle('More');
17231 this.calpopover.setContent('');
17233 var ctr = this.calpopover.el.select('.popover-content', true).first();
17235 Roo.each(more, function(m){
17237 cls : 'fc-event-hori fc-event-draggable',
17240 var cg = ctr.createChild(cfg);
17242 cg.on('click', _this.onEventClick, _this, m);
17245 this.calpopover.show(el);
17250 onLoad: function ()
17252 this.calevents = [];
17255 if(this.store.getCount() > 0){
17256 this.store.data.each(function(d){
17259 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17260 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17261 time : d.data.start_time,
17262 title : d.data.title,
17263 description : d.data.description,
17264 venue : d.data.venue
17269 this.renderEvents();
17271 if(this.calevents.length && this.loadMask){
17272 this.maskEl.hide();
17276 onBeforeLoad: function()
17278 this.clearEvents();
17280 this.maskEl.show();
17294 * @class Roo.bootstrap.Popover
17295 * @extends Roo.bootstrap.Component
17296 * Bootstrap Popover class
17297 * @cfg {String} html contents of the popover (or false to use children..)
17298 * @cfg {String} title of popover (or false to hide)
17299 * @cfg {String} placement how it is placed
17300 * @cfg {String} trigger click || hover (or false to trigger manually)
17301 * @cfg {String} over what (parent or false to trigger manually.)
17302 * @cfg {Number} delay - delay before showing
17305 * Create a new Popover
17306 * @param {Object} config The config object
17309 Roo.bootstrap.Popover = function(config){
17310 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17316 * After the popover show
17318 * @param {Roo.bootstrap.Popover} this
17323 * After the popover hide
17325 * @param {Roo.bootstrap.Popover} this
17331 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17333 title: 'Fill in a title',
17336 placement : 'right',
17337 trigger : 'hover', // hover
17343 can_build_overlaid : false,
17345 getChildContainer : function()
17347 return this.el.select('.popover-content',true).first();
17350 getAutoCreate : function(){
17353 cls : 'popover roo-dynamic',
17354 style: 'display:block',
17360 cls : 'popover-inner',
17364 cls: 'popover-title',
17368 cls : 'popover-content',
17379 setTitle: function(str)
17382 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17384 setContent: function(str)
17387 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17389 // as it get's added to the bottom of the page.
17390 onRender : function(ct, position)
17392 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17394 var cfg = Roo.apply({}, this.getAutoCreate());
17398 cfg.cls += ' ' + this.cls;
17401 cfg.style = this.style;
17403 //Roo.log("adding to ");
17404 this.el = Roo.get(document.body).createChild(cfg, position);
17405 // Roo.log(this.el);
17410 initEvents : function()
17412 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17413 this.el.enableDisplayMode('block');
17415 if (this.over === false) {
17418 if (this.triggers === false) {
17421 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17422 var triggers = this.trigger ? this.trigger.split(' ') : [];
17423 Roo.each(triggers, function(trigger) {
17425 if (trigger == 'click') {
17426 on_el.on('click', this.toggle, this);
17427 } else if (trigger != 'manual') {
17428 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17429 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17431 on_el.on(eventIn ,this.enter, this);
17432 on_el.on(eventOut, this.leave, this);
17443 toggle : function () {
17444 this.hoverState == 'in' ? this.leave() : this.enter();
17447 enter : function () {
17449 clearTimeout(this.timeout);
17451 this.hoverState = 'in';
17453 if (!this.delay || !this.delay.show) {
17458 this.timeout = setTimeout(function () {
17459 if (_t.hoverState == 'in') {
17462 }, this.delay.show)
17465 leave : function() {
17466 clearTimeout(this.timeout);
17468 this.hoverState = 'out';
17470 if (!this.delay || !this.delay.hide) {
17475 this.timeout = setTimeout(function () {
17476 if (_t.hoverState == 'out') {
17479 }, this.delay.hide)
17482 show : function (on_el)
17485 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17489 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17490 if (this.html !== false) {
17491 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17493 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17494 if (!this.title.length) {
17495 this.el.select('.popover-title',true).hide();
17498 var placement = typeof this.placement == 'function' ?
17499 this.placement.call(this, this.el, on_el) :
17502 var autoToken = /\s?auto?\s?/i;
17503 var autoPlace = autoToken.test(placement);
17505 placement = placement.replace(autoToken, '') || 'top';
17509 //this.el.setXY([0,0]);
17511 this.el.dom.style.display='block';
17512 this.el.addClass(placement);
17514 //this.el.appendTo(on_el);
17516 var p = this.getPosition();
17517 var box = this.el.getBox();
17522 var align = Roo.bootstrap.Popover.alignment[placement];
17525 this.el.alignTo(on_el, align[0],align[1]);
17526 //var arrow = this.el.select('.arrow',true).first();
17527 //arrow.set(align[2],
17529 this.el.addClass('in');
17532 if (this.el.hasClass('fade')) {
17536 this.hoverState = 'in';
17538 this.fireEvent('show', this);
17543 this.el.setXY([0,0]);
17544 this.el.removeClass('in');
17546 this.hoverState = null;
17548 this.fireEvent('hide', this);
17553 Roo.bootstrap.Popover.alignment = {
17554 'left' : ['r-l', [-10,0], 'right'],
17555 'right' : ['l-r', [10,0], 'left'],
17556 'bottom' : ['t-b', [0,10], 'top'],
17557 'top' : [ 'b-t', [0,-10], 'bottom']
17568 * @class Roo.bootstrap.Progress
17569 * @extends Roo.bootstrap.Component
17570 * Bootstrap Progress class
17571 * @cfg {Boolean} striped striped of the progress bar
17572 * @cfg {Boolean} active animated of the progress bar
17576 * Create a new Progress
17577 * @param {Object} config The config object
17580 Roo.bootstrap.Progress = function(config){
17581 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17584 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17589 getAutoCreate : function(){
17597 cfg.cls += ' progress-striped';
17601 cfg.cls += ' active';
17620 * @class Roo.bootstrap.ProgressBar
17621 * @extends Roo.bootstrap.Component
17622 * Bootstrap ProgressBar class
17623 * @cfg {Number} aria_valuenow aria-value now
17624 * @cfg {Number} aria_valuemin aria-value min
17625 * @cfg {Number} aria_valuemax aria-value max
17626 * @cfg {String} label label for the progress bar
17627 * @cfg {String} panel (success | info | warning | danger )
17628 * @cfg {String} role role of the progress bar
17629 * @cfg {String} sr_only text
17633 * Create a new ProgressBar
17634 * @param {Object} config The config object
17637 Roo.bootstrap.ProgressBar = function(config){
17638 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17641 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17645 aria_valuemax : 100,
17651 getAutoCreate : function()
17656 cls: 'progress-bar',
17657 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17669 cfg.role = this.role;
17672 if(this.aria_valuenow){
17673 cfg['aria-valuenow'] = this.aria_valuenow;
17676 if(this.aria_valuemin){
17677 cfg['aria-valuemin'] = this.aria_valuemin;
17680 if(this.aria_valuemax){
17681 cfg['aria-valuemax'] = this.aria_valuemax;
17684 if(this.label && !this.sr_only){
17685 cfg.html = this.label;
17689 cfg.cls += ' progress-bar-' + this.panel;
17695 update : function(aria_valuenow)
17697 this.aria_valuenow = aria_valuenow;
17699 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17714 * @class Roo.bootstrap.TabGroup
17715 * @extends Roo.bootstrap.Column
17716 * Bootstrap Column class
17717 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17718 * @cfg {Boolean} carousel true to make the group behave like a carousel
17719 * @cfg {Boolean} bullets show bullets for the panels
17720 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17721 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17722 * @cfg {Boolean} showarrow (true|false) show arrow default true
17725 * Create a new TabGroup
17726 * @param {Object} config The config object
17729 Roo.bootstrap.TabGroup = function(config){
17730 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17732 this.navId = Roo.id();
17735 Roo.bootstrap.TabGroup.register(this);
17739 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17742 transition : false,
17747 slideOnTouch : false,
17750 getAutoCreate : function()
17752 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17754 cfg.cls += ' tab-content';
17756 if (this.carousel) {
17757 cfg.cls += ' carousel slide';
17760 cls : 'carousel-inner',
17764 if(this.bullets && !Roo.isTouch){
17767 cls : 'carousel-bullets',
17771 if(this.bullets_cls){
17772 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17779 cfg.cn[0].cn.push(bullets);
17782 if(this.showarrow){
17783 cfg.cn[0].cn.push({
17785 class : 'carousel-arrow',
17789 class : 'carousel-prev',
17793 class : 'fa fa-chevron-left'
17799 class : 'carousel-next',
17803 class : 'fa fa-chevron-right'
17816 initEvents: function()
17818 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17819 // this.el.on("touchstart", this.onTouchStart, this);
17822 if(this.autoslide){
17825 this.slideFn = window.setInterval(function() {
17826 _this.showPanelNext();
17830 if(this.showarrow){
17831 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17832 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17838 // onTouchStart : function(e, el, o)
17840 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17844 // this.showPanelNext();
17848 getChildContainer : function()
17850 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17854 * register a Navigation item
17855 * @param {Roo.bootstrap.NavItem} the navitem to add
17857 register : function(item)
17859 this.tabs.push( item);
17860 item.navId = this.navId; // not really needed..
17865 getActivePanel : function()
17868 Roo.each(this.tabs, function(t) {
17878 getPanelByName : function(n)
17881 Roo.each(this.tabs, function(t) {
17882 if (t.tabId == n) {
17890 indexOfPanel : function(p)
17893 Roo.each(this.tabs, function(t,i) {
17894 if (t.tabId == p.tabId) {
17903 * show a specific panel
17904 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17905 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17907 showPanel : function (pan)
17909 if(this.transition || typeof(pan) == 'undefined'){
17910 Roo.log("waiting for the transitionend");
17914 if (typeof(pan) == 'number') {
17915 pan = this.tabs[pan];
17918 if (typeof(pan) == 'string') {
17919 pan = this.getPanelByName(pan);
17922 var cur = this.getActivePanel();
17925 Roo.log('pan or acitve pan is undefined');
17929 if (pan.tabId == this.getActivePanel().tabId) {
17933 if (false === cur.fireEvent('beforedeactivate')) {
17937 if(this.bullets > 0 && !Roo.isTouch){
17938 this.setActiveBullet(this.indexOfPanel(pan));
17941 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17943 this.transition = true;
17944 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17945 var lr = dir == 'next' ? 'left' : 'right';
17946 pan.el.addClass(dir); // or prev
17947 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17948 cur.el.addClass(lr); // or right
17949 pan.el.addClass(lr);
17952 cur.el.on('transitionend', function() {
17953 Roo.log("trans end?");
17955 pan.el.removeClass([lr,dir]);
17956 pan.setActive(true);
17958 cur.el.removeClass([lr]);
17959 cur.setActive(false);
17961 _this.transition = false;
17963 }, this, { single: true } );
17968 cur.setActive(false);
17969 pan.setActive(true);
17974 showPanelNext : function()
17976 var i = this.indexOfPanel(this.getActivePanel());
17978 if (i >= this.tabs.length - 1 && !this.autoslide) {
17982 if (i >= this.tabs.length - 1 && this.autoslide) {
17986 this.showPanel(this.tabs[i+1]);
17989 showPanelPrev : function()
17991 var i = this.indexOfPanel(this.getActivePanel());
17993 if (i < 1 && !this.autoslide) {
17997 if (i < 1 && this.autoslide) {
17998 i = this.tabs.length;
18001 this.showPanel(this.tabs[i-1]);
18005 addBullet: function()
18007 if(!this.bullets || Roo.isTouch){
18010 var ctr = this.el.select('.carousel-bullets',true).first();
18011 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18012 var bullet = ctr.createChild({
18013 cls : 'bullet bullet-' + i
18014 },ctr.dom.lastChild);
18019 bullet.on('click', (function(e, el, o, ii, t){
18021 e.preventDefault();
18023 this.showPanel(ii);
18025 if(this.autoslide && this.slideFn){
18026 clearInterval(this.slideFn);
18027 this.slideFn = window.setInterval(function() {
18028 _this.showPanelNext();
18032 }).createDelegate(this, [i, bullet], true));
18037 setActiveBullet : function(i)
18043 Roo.each(this.el.select('.bullet', true).elements, function(el){
18044 el.removeClass('selected');
18047 var bullet = this.el.select('.bullet-' + i, true).first();
18053 bullet.addClass('selected');
18064 Roo.apply(Roo.bootstrap.TabGroup, {
18068 * register a Navigation Group
18069 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18071 register : function(navgrp)
18073 this.groups[navgrp.navId] = navgrp;
18077 * fetch a Navigation Group based on the navigation ID
18078 * if one does not exist , it will get created.
18079 * @param {string} the navgroup to add
18080 * @returns {Roo.bootstrap.NavGroup} the navgroup
18082 get: function(navId) {
18083 if (typeof(this.groups[navId]) == 'undefined') {
18084 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18086 return this.groups[navId] ;
18101 * @class Roo.bootstrap.TabPanel
18102 * @extends Roo.bootstrap.Component
18103 * Bootstrap TabPanel class
18104 * @cfg {Boolean} active panel active
18105 * @cfg {String} html panel content
18106 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18107 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18108 * @cfg {String} href click to link..
18112 * Create a new TabPanel
18113 * @param {Object} config The config object
18116 Roo.bootstrap.TabPanel = function(config){
18117 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18121 * Fires when the active status changes
18122 * @param {Roo.bootstrap.TabPanel} this
18123 * @param {Boolean} state the new state
18128 * @event beforedeactivate
18129 * Fires before a tab is de-activated - can be used to do validation on a form.
18130 * @param {Roo.bootstrap.TabPanel} this
18131 * @return {Boolean} false if there is an error
18134 'beforedeactivate': true
18137 this.tabId = this.tabId || Roo.id();
18141 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18149 getAutoCreate : function(){
18152 // item is needed for carousel - not sure if it has any effect otherwise
18153 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18154 html: this.html || ''
18158 cfg.cls += ' active';
18162 cfg.tabId = this.tabId;
18169 initEvents: function()
18171 var p = this.parent();
18173 this.navId = this.navId || p.navId;
18175 if (typeof(this.navId) != 'undefined') {
18176 // not really needed.. but just in case.. parent should be a NavGroup.
18177 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18181 var i = tg.tabs.length - 1;
18183 if(this.active && tg.bullets > 0 && i < tg.bullets){
18184 tg.setActiveBullet(i);
18188 this.el.on('click', this.onClick, this);
18191 this.el.on("touchstart", this.onTouchStart, this);
18192 this.el.on("touchmove", this.onTouchMove, this);
18193 this.el.on("touchend", this.onTouchEnd, this);
18198 onRender : function(ct, position)
18200 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18203 setActive : function(state)
18205 Roo.log("panel - set active " + this.tabId + "=" + state);
18207 this.active = state;
18209 this.el.removeClass('active');
18211 } else if (!this.el.hasClass('active')) {
18212 this.el.addClass('active');
18215 this.fireEvent('changed', this, state);
18218 onClick : function(e)
18220 e.preventDefault();
18222 if(!this.href.length){
18226 window.location.href = this.href;
18235 onTouchStart : function(e)
18237 this.swiping = false;
18239 this.startX = e.browserEvent.touches[0].clientX;
18240 this.startY = e.browserEvent.touches[0].clientY;
18243 onTouchMove : function(e)
18245 this.swiping = true;
18247 this.endX = e.browserEvent.touches[0].clientX;
18248 this.endY = e.browserEvent.touches[0].clientY;
18251 onTouchEnd : function(e)
18258 var tabGroup = this.parent();
18260 if(this.endX > this.startX){ // swiping right
18261 tabGroup.showPanelPrev();
18265 if(this.startX > this.endX){ // swiping left
18266 tabGroup.showPanelNext();
18285 * @class Roo.bootstrap.DateField
18286 * @extends Roo.bootstrap.Input
18287 * Bootstrap DateField class
18288 * @cfg {Number} weekStart default 0
18289 * @cfg {String} viewMode default empty, (months|years)
18290 * @cfg {String} minViewMode default empty, (months|years)
18291 * @cfg {Number} startDate default -Infinity
18292 * @cfg {Number} endDate default Infinity
18293 * @cfg {Boolean} todayHighlight default false
18294 * @cfg {Boolean} todayBtn default false
18295 * @cfg {Boolean} calendarWeeks default false
18296 * @cfg {Object} daysOfWeekDisabled default empty
18297 * @cfg {Boolean} singleMode default false (true | false)
18299 * @cfg {Boolean} keyboardNavigation default true
18300 * @cfg {String} language default en
18303 * Create a new DateField
18304 * @param {Object} config The config object
18307 Roo.bootstrap.DateField = function(config){
18308 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18312 * Fires when this field show.
18313 * @param {Roo.bootstrap.DateField} this
18314 * @param {Mixed} date The date value
18319 * Fires when this field hide.
18320 * @param {Roo.bootstrap.DateField} this
18321 * @param {Mixed} date The date value
18326 * Fires when select a date.
18327 * @param {Roo.bootstrap.DateField} this
18328 * @param {Mixed} date The date value
18332 * @event beforeselect
18333 * Fires when before select a date.
18334 * @param {Roo.bootstrap.DateField} this
18335 * @param {Mixed} date The date value
18337 beforeselect : true
18341 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18344 * @cfg {String} format
18345 * The default date format string which can be overriden for localization support. The format must be
18346 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18350 * @cfg {String} altFormats
18351 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18352 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18354 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18362 todayHighlight : false,
18368 keyboardNavigation: true,
18370 calendarWeeks: false,
18372 startDate: -Infinity,
18376 daysOfWeekDisabled: [],
18380 singleMode : false,
18382 UTCDate: function()
18384 return new Date(Date.UTC.apply(Date, arguments));
18387 UTCToday: function()
18389 var today = new Date();
18390 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18393 getDate: function() {
18394 var d = this.getUTCDate();
18395 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18398 getUTCDate: function() {
18402 setDate: function(d) {
18403 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18406 setUTCDate: function(d) {
18408 this.setValue(this.formatDate(this.date));
18411 onRender: function(ct, position)
18414 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18416 this.language = this.language || 'en';
18417 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18418 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18420 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18421 this.format = this.format || 'm/d/y';
18422 this.isInline = false;
18423 this.isInput = true;
18424 this.component = this.el.select('.add-on', true).first() || false;
18425 this.component = (this.component && this.component.length === 0) ? false : this.component;
18426 this.hasInput = this.component && this.inputEl().length;
18428 if (typeof(this.minViewMode === 'string')) {
18429 switch (this.minViewMode) {
18431 this.minViewMode = 1;
18434 this.minViewMode = 2;
18437 this.minViewMode = 0;
18442 if (typeof(this.viewMode === 'string')) {
18443 switch (this.viewMode) {
18456 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18458 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18460 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18462 this.picker().on('mousedown', this.onMousedown, this);
18463 this.picker().on('click', this.onClick, this);
18465 this.picker().addClass('datepicker-dropdown');
18467 this.startViewMode = this.viewMode;
18469 if(this.singleMode){
18470 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18471 v.setVisibilityMode(Roo.Element.DISPLAY);
18475 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18476 v.setStyle('width', '189px');
18480 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18481 if(!this.calendarWeeks){
18486 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18487 v.attr('colspan', function(i, val){
18488 return parseInt(val) + 1;
18493 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18495 this.setStartDate(this.startDate);
18496 this.setEndDate(this.endDate);
18498 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18505 if(this.isInline) {
18510 picker : function()
18512 return this.pickerEl;
18513 // return this.el.select('.datepicker', true).first();
18516 fillDow: function()
18518 var dowCnt = this.weekStart;
18527 if(this.calendarWeeks){
18535 while (dowCnt < this.weekStart + 7) {
18539 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18543 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18546 fillMonths: function()
18549 var months = this.picker().select('>.datepicker-months td', true).first();
18551 months.dom.innerHTML = '';
18557 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18560 months.createChild(month);
18567 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;
18569 if (this.date < this.startDate) {
18570 this.viewDate = new Date(this.startDate);
18571 } else if (this.date > this.endDate) {
18572 this.viewDate = new Date(this.endDate);
18574 this.viewDate = new Date(this.date);
18582 var d = new Date(this.viewDate),
18583 year = d.getUTCFullYear(),
18584 month = d.getUTCMonth(),
18585 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18586 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18587 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18588 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18589 currentDate = this.date && this.date.valueOf(),
18590 today = this.UTCToday();
18592 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18594 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18596 // this.picker.select('>tfoot th.today').
18597 // .text(dates[this.language].today)
18598 // .toggle(this.todayBtn !== false);
18600 this.updateNavArrows();
18603 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18605 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18607 prevMonth.setUTCDate(day);
18609 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18611 var nextMonth = new Date(prevMonth);
18613 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18615 nextMonth = nextMonth.valueOf();
18617 var fillMonths = false;
18619 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18621 while(prevMonth.valueOf() < nextMonth) {
18624 if (prevMonth.getUTCDay() === this.weekStart) {
18626 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18634 if(this.calendarWeeks){
18635 // ISO 8601: First week contains first thursday.
18636 // ISO also states week starts on Monday, but we can be more abstract here.
18638 // Start of current week: based on weekstart/current date
18639 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18640 // Thursday of this week
18641 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18642 // First Thursday of year, year from thursday
18643 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18644 // Calendar week: ms between thursdays, div ms per day, div 7 days
18645 calWeek = (th - yth) / 864e5 / 7 + 1;
18647 fillMonths.cn.push({
18655 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18657 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18660 if (this.todayHighlight &&
18661 prevMonth.getUTCFullYear() == today.getFullYear() &&
18662 prevMonth.getUTCMonth() == today.getMonth() &&
18663 prevMonth.getUTCDate() == today.getDate()) {
18664 clsName += ' today';
18667 if (currentDate && prevMonth.valueOf() === currentDate) {
18668 clsName += ' active';
18671 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18672 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18673 clsName += ' disabled';
18676 fillMonths.cn.push({
18678 cls: 'day ' + clsName,
18679 html: prevMonth.getDate()
18682 prevMonth.setDate(prevMonth.getDate()+1);
18685 var currentYear = this.date && this.date.getUTCFullYear();
18686 var currentMonth = this.date && this.date.getUTCMonth();
18688 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18690 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18691 v.removeClass('active');
18693 if(currentYear === year && k === currentMonth){
18694 v.addClass('active');
18697 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18698 v.addClass('disabled');
18704 year = parseInt(year/10, 10) * 10;
18706 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18708 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18711 for (var i = -1; i < 11; i++) {
18712 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18714 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18722 showMode: function(dir)
18725 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18728 Roo.each(this.picker().select('>div',true).elements, function(v){
18729 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18732 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18737 if(this.isInline) {
18741 this.picker().removeClass(['bottom', 'top']);
18743 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18745 * place to the top of element!
18749 this.picker().addClass('top');
18750 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18755 this.picker().addClass('bottom');
18757 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18760 parseDate : function(value)
18762 if(!value || value instanceof Date){
18765 var v = Date.parseDate(value, this.format);
18766 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18767 v = Date.parseDate(value, 'Y-m-d');
18769 if(!v && this.altFormats){
18770 if(!this.altFormatsArray){
18771 this.altFormatsArray = this.altFormats.split("|");
18773 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18774 v = Date.parseDate(value, this.altFormatsArray[i]);
18780 formatDate : function(date, fmt)
18782 return (!date || !(date instanceof Date)) ?
18783 date : date.dateFormat(fmt || this.format);
18786 onFocus : function()
18788 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18792 onBlur : function()
18794 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18796 var d = this.inputEl().getValue();
18805 this.picker().show();
18809 this.fireEvent('show', this, this.date);
18814 if(this.isInline) {
18817 this.picker().hide();
18818 this.viewMode = this.startViewMode;
18821 this.fireEvent('hide', this, this.date);
18825 onMousedown: function(e)
18827 e.stopPropagation();
18828 e.preventDefault();
18833 Roo.bootstrap.DateField.superclass.keyup.call(this);
18837 setValue: function(v)
18839 if(this.fireEvent('beforeselect', this, v) !== false){
18840 var d = new Date(this.parseDate(v) ).clearTime();
18842 if(isNaN(d.getTime())){
18843 this.date = this.viewDate = '';
18844 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18848 v = this.formatDate(d);
18850 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18852 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18856 this.fireEvent('select', this, this.date);
18860 getValue: function()
18862 return this.formatDate(this.date);
18865 fireKey: function(e)
18867 if (!this.picker().isVisible()){
18868 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18874 var dateChanged = false,
18876 newDate, newViewDate;
18881 e.preventDefault();
18885 if (!this.keyboardNavigation) {
18888 dir = e.keyCode == 37 ? -1 : 1;
18891 newDate = this.moveYear(this.date, dir);
18892 newViewDate = this.moveYear(this.viewDate, dir);
18893 } else if (e.shiftKey){
18894 newDate = this.moveMonth(this.date, dir);
18895 newViewDate = this.moveMonth(this.viewDate, dir);
18897 newDate = new Date(this.date);
18898 newDate.setUTCDate(this.date.getUTCDate() + dir);
18899 newViewDate = new Date(this.viewDate);
18900 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18902 if (this.dateWithinRange(newDate)){
18903 this.date = newDate;
18904 this.viewDate = newViewDate;
18905 this.setValue(this.formatDate(this.date));
18907 e.preventDefault();
18908 dateChanged = true;
18913 if (!this.keyboardNavigation) {
18916 dir = e.keyCode == 38 ? -1 : 1;
18918 newDate = this.moveYear(this.date, dir);
18919 newViewDate = this.moveYear(this.viewDate, dir);
18920 } else if (e.shiftKey){
18921 newDate = this.moveMonth(this.date, dir);
18922 newViewDate = this.moveMonth(this.viewDate, dir);
18924 newDate = new Date(this.date);
18925 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18926 newViewDate = new Date(this.viewDate);
18927 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18929 if (this.dateWithinRange(newDate)){
18930 this.date = newDate;
18931 this.viewDate = newViewDate;
18932 this.setValue(this.formatDate(this.date));
18934 e.preventDefault();
18935 dateChanged = true;
18939 this.setValue(this.formatDate(this.date));
18941 e.preventDefault();
18944 this.setValue(this.formatDate(this.date));
18958 onClick: function(e)
18960 e.stopPropagation();
18961 e.preventDefault();
18963 var target = e.getTarget();
18965 if(target.nodeName.toLowerCase() === 'i'){
18966 target = Roo.get(target).dom.parentNode;
18969 var nodeName = target.nodeName;
18970 var className = target.className;
18971 var html = target.innerHTML;
18972 //Roo.log(nodeName);
18974 switch(nodeName.toLowerCase()) {
18976 switch(className) {
18982 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18983 switch(this.viewMode){
18985 this.viewDate = this.moveMonth(this.viewDate, dir);
18989 this.viewDate = this.moveYear(this.viewDate, dir);
18995 var date = new Date();
18996 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18998 this.setValue(this.formatDate(this.date));
19005 if (className.indexOf('disabled') < 0) {
19006 this.viewDate.setUTCDate(1);
19007 if (className.indexOf('month') > -1) {
19008 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19010 var year = parseInt(html, 10) || 0;
19011 this.viewDate.setUTCFullYear(year);
19015 if(this.singleMode){
19016 this.setValue(this.formatDate(this.viewDate));
19027 //Roo.log(className);
19028 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19029 var day = parseInt(html, 10) || 1;
19030 var year = this.viewDate.getUTCFullYear(),
19031 month = this.viewDate.getUTCMonth();
19033 if (className.indexOf('old') > -1) {
19040 } else if (className.indexOf('new') > -1) {
19048 //Roo.log([year,month,day]);
19049 this.date = this.UTCDate(year, month, day,0,0,0,0);
19050 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19052 //Roo.log(this.formatDate(this.date));
19053 this.setValue(this.formatDate(this.date));
19060 setStartDate: function(startDate)
19062 this.startDate = startDate || -Infinity;
19063 if (this.startDate !== -Infinity) {
19064 this.startDate = this.parseDate(this.startDate);
19067 this.updateNavArrows();
19070 setEndDate: function(endDate)
19072 this.endDate = endDate || Infinity;
19073 if (this.endDate !== Infinity) {
19074 this.endDate = this.parseDate(this.endDate);
19077 this.updateNavArrows();
19080 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19082 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19083 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19084 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19086 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19087 return parseInt(d, 10);
19090 this.updateNavArrows();
19093 updateNavArrows: function()
19095 if(this.singleMode){
19099 var d = new Date(this.viewDate),
19100 year = d.getUTCFullYear(),
19101 month = d.getUTCMonth();
19103 Roo.each(this.picker().select('.prev', true).elements, function(v){
19105 switch (this.viewMode) {
19108 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19114 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19121 Roo.each(this.picker().select('.next', true).elements, function(v){
19123 switch (this.viewMode) {
19126 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19132 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19140 moveMonth: function(date, dir)
19145 var new_date = new Date(date.valueOf()),
19146 day = new_date.getUTCDate(),
19147 month = new_date.getUTCMonth(),
19148 mag = Math.abs(dir),
19150 dir = dir > 0 ? 1 : -1;
19153 // If going back one month, make sure month is not current month
19154 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19156 return new_date.getUTCMonth() == month;
19158 // If going forward one month, make sure month is as expected
19159 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19161 return new_date.getUTCMonth() != new_month;
19163 new_month = month + dir;
19164 new_date.setUTCMonth(new_month);
19165 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19166 if (new_month < 0 || new_month > 11) {
19167 new_month = (new_month + 12) % 12;
19170 // For magnitudes >1, move one month at a time...
19171 for (var i=0; i<mag; i++) {
19172 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19173 new_date = this.moveMonth(new_date, dir);
19175 // ...then reset the day, keeping it in the new month
19176 new_month = new_date.getUTCMonth();
19177 new_date.setUTCDate(day);
19179 return new_month != new_date.getUTCMonth();
19182 // Common date-resetting loop -- if date is beyond end of month, make it
19185 new_date.setUTCDate(--day);
19186 new_date.setUTCMonth(new_month);
19191 moveYear: function(date, dir)
19193 return this.moveMonth(date, dir*12);
19196 dateWithinRange: function(date)
19198 return date >= this.startDate && date <= this.endDate;
19204 this.picker().remove();
19207 validateValue : function(value)
19209 if(this.getVisibilityEl().hasClass('hidden')){
19213 if(value.length < 1) {
19214 if(this.allowBlank){
19220 if(value.length < this.minLength){
19223 if(value.length > this.maxLength){
19227 var vt = Roo.form.VTypes;
19228 if(!vt[this.vtype](value, this)){
19232 if(typeof this.validator == "function"){
19233 var msg = this.validator(value);
19239 if(this.regex && !this.regex.test(value)){
19243 if(typeof(this.parseDate(value)) == 'undefined'){
19247 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19251 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19259 setVisible : function(visible)
19265 this.getEl().removeClass('hidden');
19271 this.getEl().addClass('hidden');
19276 Roo.apply(Roo.bootstrap.DateField, {
19287 html: '<i class="fa fa-arrow-left"/>'
19297 html: '<i class="fa fa-arrow-right"/>'
19339 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19340 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19341 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19342 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19343 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19356 navFnc: 'FullYear',
19361 navFnc: 'FullYear',
19366 Roo.apply(Roo.bootstrap.DateField, {
19370 cls: 'datepicker dropdown-menu roo-dynamic',
19374 cls: 'datepicker-days',
19378 cls: 'table-condensed',
19380 Roo.bootstrap.DateField.head,
19384 Roo.bootstrap.DateField.footer
19391 cls: 'datepicker-months',
19395 cls: 'table-condensed',
19397 Roo.bootstrap.DateField.head,
19398 Roo.bootstrap.DateField.content,
19399 Roo.bootstrap.DateField.footer
19406 cls: 'datepicker-years',
19410 cls: 'table-condensed',
19412 Roo.bootstrap.DateField.head,
19413 Roo.bootstrap.DateField.content,
19414 Roo.bootstrap.DateField.footer
19433 * @class Roo.bootstrap.TimeField
19434 * @extends Roo.bootstrap.Input
19435 * Bootstrap DateField class
19439 * Create a new TimeField
19440 * @param {Object} config The config object
19443 Roo.bootstrap.TimeField = function(config){
19444 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19448 * Fires when this field show.
19449 * @param {Roo.bootstrap.DateField} thisthis
19450 * @param {Mixed} date The date value
19455 * Fires when this field hide.
19456 * @param {Roo.bootstrap.DateField} this
19457 * @param {Mixed} date The date value
19462 * Fires when select a date.
19463 * @param {Roo.bootstrap.DateField} this
19464 * @param {Mixed} date The date value
19470 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19473 * @cfg {String} format
19474 * The default time format string which can be overriden for localization support. The format must be
19475 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19479 onRender: function(ct, position)
19482 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19484 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19486 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19488 this.pop = this.picker().select('>.datepicker-time',true).first();
19489 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19491 this.picker().on('mousedown', this.onMousedown, this);
19492 this.picker().on('click', this.onClick, this);
19494 this.picker().addClass('datepicker-dropdown');
19499 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19500 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19501 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19502 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19503 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19504 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19508 fireKey: function(e){
19509 if (!this.picker().isVisible()){
19510 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19516 e.preventDefault();
19524 this.onTogglePeriod();
19527 this.onIncrementMinutes();
19530 this.onDecrementMinutes();
19539 onClick: function(e) {
19540 e.stopPropagation();
19541 e.preventDefault();
19544 picker : function()
19546 return this.el.select('.datepicker', true).first();
19549 fillTime: function()
19551 var time = this.pop.select('tbody', true).first();
19553 time.dom.innerHTML = '';
19568 cls: 'hours-up glyphicon glyphicon-chevron-up'
19588 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19609 cls: 'timepicker-hour',
19624 cls: 'timepicker-minute',
19639 cls: 'btn btn-primary period',
19661 cls: 'hours-down glyphicon glyphicon-chevron-down'
19681 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19699 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19706 var hours = this.time.getHours();
19707 var minutes = this.time.getMinutes();
19720 hours = hours - 12;
19724 hours = '0' + hours;
19728 minutes = '0' + minutes;
19731 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19732 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19733 this.pop.select('button', true).first().dom.innerHTML = period;
19739 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19741 var cls = ['bottom'];
19743 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19750 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19755 this.picker().addClass(cls.join('-'));
19759 Roo.each(cls, function(c){
19761 _this.picker().setTop(_this.inputEl().getHeight());
19765 _this.picker().setTop(0 - _this.picker().getHeight());
19770 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19774 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19781 onFocus : function()
19783 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19787 onBlur : function()
19789 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19795 this.picker().show();
19800 this.fireEvent('show', this, this.date);
19805 this.picker().hide();
19808 this.fireEvent('hide', this, this.date);
19811 setTime : function()
19814 this.setValue(this.time.format(this.format));
19816 this.fireEvent('select', this, this.date);
19821 onMousedown: function(e){
19822 e.stopPropagation();
19823 e.preventDefault();
19826 onIncrementHours: function()
19828 Roo.log('onIncrementHours');
19829 this.time = this.time.add(Date.HOUR, 1);
19834 onDecrementHours: function()
19836 Roo.log('onDecrementHours');
19837 this.time = this.time.add(Date.HOUR, -1);
19841 onIncrementMinutes: function()
19843 Roo.log('onIncrementMinutes');
19844 this.time = this.time.add(Date.MINUTE, 1);
19848 onDecrementMinutes: function()
19850 Roo.log('onDecrementMinutes');
19851 this.time = this.time.add(Date.MINUTE, -1);
19855 onTogglePeriod: function()
19857 Roo.log('onTogglePeriod');
19858 this.time = this.time.add(Date.HOUR, 12);
19865 Roo.apply(Roo.bootstrap.TimeField, {
19895 cls: 'btn btn-info ok',
19907 Roo.apply(Roo.bootstrap.TimeField, {
19911 cls: 'datepicker dropdown-menu',
19915 cls: 'datepicker-time',
19919 cls: 'table-condensed',
19921 Roo.bootstrap.TimeField.content,
19922 Roo.bootstrap.TimeField.footer
19941 * @class Roo.bootstrap.MonthField
19942 * @extends Roo.bootstrap.Input
19943 * Bootstrap MonthField class
19945 * @cfg {String} language default en
19948 * Create a new MonthField
19949 * @param {Object} config The config object
19952 Roo.bootstrap.MonthField = function(config){
19953 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19958 * Fires when this field show.
19959 * @param {Roo.bootstrap.MonthField} this
19960 * @param {Mixed} date The date value
19965 * Fires when this field hide.
19966 * @param {Roo.bootstrap.MonthField} this
19967 * @param {Mixed} date The date value
19972 * Fires when select a date.
19973 * @param {Roo.bootstrap.MonthField} this
19974 * @param {String} oldvalue The old value
19975 * @param {String} newvalue The new value
19981 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19983 onRender: function(ct, position)
19986 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19988 this.language = this.language || 'en';
19989 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19990 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19992 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19993 this.isInline = false;
19994 this.isInput = true;
19995 this.component = this.el.select('.add-on', true).first() || false;
19996 this.component = (this.component && this.component.length === 0) ? false : this.component;
19997 this.hasInput = this.component && this.inputEL().length;
19999 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20001 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20003 this.picker().on('mousedown', this.onMousedown, this);
20004 this.picker().on('click', this.onClick, this);
20006 this.picker().addClass('datepicker-dropdown');
20008 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20009 v.setStyle('width', '189px');
20016 if(this.isInline) {
20022 setValue: function(v, suppressEvent)
20024 var o = this.getValue();
20026 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20030 if(suppressEvent !== true){
20031 this.fireEvent('select', this, o, v);
20036 getValue: function()
20041 onClick: function(e)
20043 e.stopPropagation();
20044 e.preventDefault();
20046 var target = e.getTarget();
20048 if(target.nodeName.toLowerCase() === 'i'){
20049 target = Roo.get(target).dom.parentNode;
20052 var nodeName = target.nodeName;
20053 var className = target.className;
20054 var html = target.innerHTML;
20056 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20060 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20062 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20068 picker : function()
20070 return this.pickerEl;
20073 fillMonths: function()
20076 var months = this.picker().select('>.datepicker-months td', true).first();
20078 months.dom.innerHTML = '';
20084 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20087 months.createChild(month);
20096 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20097 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20100 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20101 e.removeClass('active');
20103 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20104 e.addClass('active');
20111 if(this.isInline) {
20115 this.picker().removeClass(['bottom', 'top']);
20117 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20119 * place to the top of element!
20123 this.picker().addClass('top');
20124 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20129 this.picker().addClass('bottom');
20131 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20134 onFocus : function()
20136 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20140 onBlur : function()
20142 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20144 var d = this.inputEl().getValue();
20153 this.picker().show();
20154 this.picker().select('>.datepicker-months', true).first().show();
20158 this.fireEvent('show', this, this.date);
20163 if(this.isInline) {
20166 this.picker().hide();
20167 this.fireEvent('hide', this, this.date);
20171 onMousedown: function(e)
20173 e.stopPropagation();
20174 e.preventDefault();
20179 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20183 fireKey: function(e)
20185 if (!this.picker().isVisible()){
20186 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20197 e.preventDefault();
20201 dir = e.keyCode == 37 ? -1 : 1;
20203 this.vIndex = this.vIndex + dir;
20205 if(this.vIndex < 0){
20209 if(this.vIndex > 11){
20213 if(isNaN(this.vIndex)){
20217 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20223 dir = e.keyCode == 38 ? -1 : 1;
20225 this.vIndex = this.vIndex + dir * 4;
20227 if(this.vIndex < 0){
20231 if(this.vIndex > 11){
20235 if(isNaN(this.vIndex)){
20239 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20244 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20245 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20249 e.preventDefault();
20252 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20253 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20269 this.picker().remove();
20274 Roo.apply(Roo.bootstrap.MonthField, {
20293 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20294 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20299 Roo.apply(Roo.bootstrap.MonthField, {
20303 cls: 'datepicker dropdown-menu roo-dynamic',
20307 cls: 'datepicker-months',
20311 cls: 'table-condensed',
20313 Roo.bootstrap.DateField.content
20333 * @class Roo.bootstrap.CheckBox
20334 * @extends Roo.bootstrap.Input
20335 * Bootstrap CheckBox class
20337 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20338 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20339 * @cfg {String} boxLabel The text that appears beside the checkbox
20340 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20341 * @cfg {Boolean} checked initnal the element
20342 * @cfg {Boolean} inline inline the element (default false)
20343 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20344 * @cfg {String} tooltip label tooltip
20347 * Create a new CheckBox
20348 * @param {Object} config The config object
20351 Roo.bootstrap.CheckBox = function(config){
20352 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20357 * Fires when the element is checked or unchecked.
20358 * @param {Roo.bootstrap.CheckBox} this This input
20359 * @param {Boolean} checked The new checked value
20364 * Fires when the element is click.
20365 * @param {Roo.bootstrap.CheckBox} this This input
20372 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20374 inputType: 'checkbox',
20383 getAutoCreate : function()
20385 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20391 cfg.cls = 'form-group ' + this.inputType; //input-group
20394 cfg.cls += ' ' + this.inputType + '-inline';
20400 type : this.inputType,
20401 value : this.inputValue,
20402 cls : 'roo-' + this.inputType, //'form-box',
20403 placeholder : this.placeholder || ''
20407 if(this.inputType != 'radio'){
20411 cls : 'roo-hidden-value',
20412 value : this.checked ? this.inputValue : this.valueOff
20417 if (this.weight) { // Validity check?
20418 cfg.cls += " " + this.inputType + "-" + this.weight;
20421 if (this.disabled) {
20422 input.disabled=true;
20426 input.checked = this.checked;
20431 input.name = this.name;
20433 if(this.inputType != 'radio'){
20434 hidden.name = this.name;
20435 input.name = '_hidden_' + this.name;
20440 input.cls += ' input-' + this.size;
20445 ['xs','sm','md','lg'].map(function(size){
20446 if (settings[size]) {
20447 cfg.cls += ' col-' + size + '-' + settings[size];
20451 var inputblock = input;
20453 if (this.before || this.after) {
20456 cls : 'input-group',
20461 inputblock.cn.push({
20463 cls : 'input-group-addon',
20468 inputblock.cn.push(input);
20470 if(this.inputType != 'radio'){
20471 inputblock.cn.push(hidden);
20475 inputblock.cn.push({
20477 cls : 'input-group-addon',
20484 if (align ==='left' && this.fieldLabel.length) {
20485 // Roo.log("left and has label");
20490 cls : 'control-label',
20491 html : this.fieldLabel
20501 if(this.labelWidth > 12){
20502 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20505 if(this.labelWidth < 13 && this.labelmd == 0){
20506 this.labelmd = this.labelWidth;
20509 if(this.labellg > 0){
20510 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20511 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20514 if(this.labelmd > 0){
20515 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20516 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20519 if(this.labelsm > 0){
20520 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20521 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20524 if(this.labelxs > 0){
20525 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20526 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20529 } else if ( this.fieldLabel.length) {
20530 // Roo.log(" label");
20534 tag: this.boxLabel ? 'span' : 'label',
20536 cls: 'control-label box-input-label',
20537 //cls : 'input-group-addon',
20538 html : this.fieldLabel
20547 // Roo.log(" no label && no align");
20548 cfg.cn = [ inputblock ] ;
20554 var boxLabelCfg = {
20556 //'for': id, // box label is handled by onclick - so no for...
20558 html: this.boxLabel
20562 boxLabelCfg.tooltip = this.tooltip;
20565 cfg.cn.push(boxLabelCfg);
20568 if(this.inputType != 'radio'){
20569 cfg.cn.push(hidden);
20577 * return the real input element.
20579 inputEl: function ()
20581 return this.el.select('input.roo-' + this.inputType,true).first();
20583 hiddenEl: function ()
20585 return this.el.select('input.roo-hidden-value',true).first();
20588 labelEl: function()
20590 return this.el.select('label.control-label',true).first();
20592 /* depricated... */
20596 return this.labelEl();
20599 boxLabelEl: function()
20601 return this.el.select('label.box-label',true).first();
20604 initEvents : function()
20606 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20608 this.inputEl().on('click', this.onClick, this);
20610 if (this.boxLabel) {
20611 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20614 this.startValue = this.getValue();
20617 Roo.bootstrap.CheckBox.register(this);
20621 onClick : function(e)
20623 if(this.fireEvent('click', this, e) !== false){
20624 this.setChecked(!this.checked);
20629 setChecked : function(state,suppressEvent)
20631 this.startValue = this.getValue();
20633 if(this.inputType == 'radio'){
20635 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20636 e.dom.checked = false;
20639 this.inputEl().dom.checked = true;
20641 this.inputEl().dom.value = this.inputValue;
20643 if(suppressEvent !== true){
20644 this.fireEvent('check', this, true);
20652 this.checked = state;
20654 this.inputEl().dom.checked = state;
20657 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20659 if(suppressEvent !== true){
20660 this.fireEvent('check', this, state);
20666 getValue : function()
20668 if(this.inputType == 'radio'){
20669 return this.getGroupValue();
20672 return this.hiddenEl().dom.value;
20676 getGroupValue : function()
20678 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20682 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20685 setValue : function(v,suppressEvent)
20687 if(this.inputType == 'radio'){
20688 this.setGroupValue(v, suppressEvent);
20692 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20697 setGroupValue : function(v, suppressEvent)
20699 this.startValue = this.getValue();
20701 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20702 e.dom.checked = false;
20704 if(e.dom.value == v){
20705 e.dom.checked = true;
20709 if(suppressEvent !== true){
20710 this.fireEvent('check', this, true);
20718 validate : function()
20720 if(this.getVisibilityEl().hasClass('hidden')){
20726 (this.inputType == 'radio' && this.validateRadio()) ||
20727 (this.inputType == 'checkbox' && this.validateCheckbox())
20733 this.markInvalid();
20737 validateRadio : function()
20739 if(this.getVisibilityEl().hasClass('hidden')){
20743 if(this.allowBlank){
20749 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20750 if(!e.dom.checked){
20762 validateCheckbox : function()
20765 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20766 //return (this.getValue() == this.inputValue) ? true : false;
20769 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20777 for(var i in group){
20778 if(group[i].el.isVisible(true)){
20786 for(var i in group){
20791 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20798 * Mark this field as valid
20800 markValid : function()
20804 this.fireEvent('valid', this);
20806 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20809 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20816 if(this.inputType == 'radio'){
20817 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20818 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20819 e.findParent('.form-group', false, true).addClass(_this.validClass);
20826 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20827 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20831 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20837 for(var i in group){
20838 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20839 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20844 * Mark this field as invalid
20845 * @param {String} msg The validation message
20847 markInvalid : function(msg)
20849 if(this.allowBlank){
20855 this.fireEvent('invalid', this, msg);
20857 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20860 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20864 label.markInvalid();
20867 if(this.inputType == 'radio'){
20868 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20869 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20870 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20877 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20878 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20882 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20888 for(var i in group){
20889 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20890 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20895 clearInvalid : function()
20897 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20899 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20901 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20903 if (label && label.iconEl) {
20904 label.iconEl.removeClass(label.validClass);
20905 label.iconEl.removeClass(label.invalidClass);
20909 disable : function()
20911 if(this.inputType != 'radio'){
20912 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20919 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20920 _this.getActionEl().addClass(this.disabledClass);
20921 e.dom.disabled = true;
20925 this.disabled = true;
20926 this.fireEvent("disable", this);
20930 enable : function()
20932 if(this.inputType != 'radio'){
20933 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20940 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20941 _this.getActionEl().removeClass(this.disabledClass);
20942 e.dom.disabled = false;
20946 this.disabled = false;
20947 this.fireEvent("enable", this);
20951 setBoxLabel : function(v)
20956 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20962 Roo.apply(Roo.bootstrap.CheckBox, {
20967 * register a CheckBox Group
20968 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20970 register : function(checkbox)
20972 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20973 this.groups[checkbox.groupId] = {};
20976 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20980 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20984 * fetch a CheckBox Group based on the group ID
20985 * @param {string} the group ID
20986 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20988 get: function(groupId) {
20989 if (typeof(this.groups[groupId]) == 'undefined') {
20993 return this.groups[groupId] ;
21006 * @class Roo.bootstrap.Radio
21007 * @extends Roo.bootstrap.Component
21008 * Bootstrap Radio class
21009 * @cfg {String} boxLabel - the label associated
21010 * @cfg {String} value - the value of radio
21013 * Create a new Radio
21014 * @param {Object} config The config object
21016 Roo.bootstrap.Radio = function(config){
21017 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21021 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21027 getAutoCreate : function()
21031 cls : 'form-group radio',
21036 html : this.boxLabel
21044 initEvents : function()
21046 this.parent().register(this);
21048 this.el.on('click', this.onClick, this);
21052 onClick : function(e)
21054 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21055 this.setChecked(true);
21059 setChecked : function(state, suppressEvent)
21061 this.parent().setValue(this.value, suppressEvent);
21065 setBoxLabel : function(v)
21070 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21085 * @class Roo.bootstrap.SecurePass
21086 * @extends Roo.bootstrap.Input
21087 * Bootstrap SecurePass class
21091 * Create a new SecurePass
21092 * @param {Object} config The config object
21095 Roo.bootstrap.SecurePass = function (config) {
21096 // these go here, so the translation tool can replace them..
21098 PwdEmpty: "Please type a password, and then retype it to confirm.",
21099 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21100 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21101 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21102 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21103 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21104 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21105 TooWeak: "Your password is Too Weak."
21107 this.meterLabel = "Password strength:";
21108 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21109 this.meterClass = [
21110 "roo-password-meter-tooweak",
21111 "roo-password-meter-weak",
21112 "roo-password-meter-medium",
21113 "roo-password-meter-strong",
21114 "roo-password-meter-grey"
21119 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21122 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21124 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21126 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21127 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21128 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21129 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21130 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21131 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21132 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21142 * @cfg {String/Object} Label for the strength meter (defaults to
21143 * 'Password strength:')
21148 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21149 * ['Weak', 'Medium', 'Strong'])
21152 pwdStrengths: false,
21165 initEvents: function ()
21167 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21169 if (this.el.is('input[type=password]') && Roo.isSafari) {
21170 this.el.on('keydown', this.SafariOnKeyDown, this);
21173 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21176 onRender: function (ct, position)
21178 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21179 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21180 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21182 this.trigger.createChild({
21187 cls: 'roo-password-meter-grey col-xs-12',
21190 //width: this.meterWidth + 'px'
21194 cls: 'roo-password-meter-text'
21200 if (this.hideTrigger) {
21201 this.trigger.setDisplayed(false);
21203 this.setSize(this.width || '', this.height || '');
21206 onDestroy: function ()
21208 if (this.trigger) {
21209 this.trigger.removeAllListeners();
21210 this.trigger.remove();
21213 this.wrap.remove();
21215 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21218 checkStrength: function ()
21220 var pwd = this.inputEl().getValue();
21221 if (pwd == this._lastPwd) {
21226 if (this.ClientSideStrongPassword(pwd)) {
21228 } else if (this.ClientSideMediumPassword(pwd)) {
21230 } else if (this.ClientSideWeakPassword(pwd)) {
21236 Roo.log('strength1: ' + strength);
21238 //var pm = this.trigger.child('div/div/div').dom;
21239 var pm = this.trigger.child('div/div');
21240 pm.removeClass(this.meterClass);
21241 pm.addClass(this.meterClass[strength]);
21244 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21246 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21248 this._lastPwd = pwd;
21252 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21254 this._lastPwd = '';
21256 var pm = this.trigger.child('div/div');
21257 pm.removeClass(this.meterClass);
21258 pm.addClass('roo-password-meter-grey');
21261 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21264 this.inputEl().dom.type='password';
21267 validateValue: function (value)
21270 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21273 if (value.length == 0) {
21274 if (this.allowBlank) {
21275 this.clearInvalid();
21279 this.markInvalid(this.errors.PwdEmpty);
21280 this.errorMsg = this.errors.PwdEmpty;
21288 if ('[\x21-\x7e]*'.match(value)) {
21289 this.markInvalid(this.errors.PwdBadChar);
21290 this.errorMsg = this.errors.PwdBadChar;
21293 if (value.length < 6) {
21294 this.markInvalid(this.errors.PwdShort);
21295 this.errorMsg = this.errors.PwdShort;
21298 if (value.length > 16) {
21299 this.markInvalid(this.errors.PwdLong);
21300 this.errorMsg = this.errors.PwdLong;
21304 if (this.ClientSideStrongPassword(value)) {
21306 } else if (this.ClientSideMediumPassword(value)) {
21308 } else if (this.ClientSideWeakPassword(value)) {
21315 if (strength < 2) {
21316 //this.markInvalid(this.errors.TooWeak);
21317 this.errorMsg = this.errors.TooWeak;
21322 console.log('strength2: ' + strength);
21324 //var pm = this.trigger.child('div/div/div').dom;
21326 var pm = this.trigger.child('div/div');
21327 pm.removeClass(this.meterClass);
21328 pm.addClass(this.meterClass[strength]);
21330 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21332 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21334 this.errorMsg = '';
21338 CharacterSetChecks: function (type)
21341 this.fResult = false;
21344 isctype: function (character, type)
21347 case this.kCapitalLetter:
21348 if (character >= 'A' && character <= 'Z') {
21353 case this.kSmallLetter:
21354 if (character >= 'a' && character <= 'z') {
21360 if (character >= '0' && character <= '9') {
21365 case this.kPunctuation:
21366 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21377 IsLongEnough: function (pwd, size)
21379 return !(pwd == null || isNaN(size) || pwd.length < size);
21382 SpansEnoughCharacterSets: function (word, nb)
21384 if (!this.IsLongEnough(word, nb))
21389 var characterSetChecks = new Array(
21390 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21391 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21394 for (var index = 0; index < word.length; ++index) {
21395 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21396 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21397 characterSetChecks[nCharSet].fResult = true;
21404 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21405 if (characterSetChecks[nCharSet].fResult) {
21410 if (nCharSets < nb) {
21416 ClientSideStrongPassword: function (pwd)
21418 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21421 ClientSideMediumPassword: function (pwd)
21423 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21426 ClientSideWeakPassword: function (pwd)
21428 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21431 })//<script type="text/javascript">
21434 * Based Ext JS Library 1.1.1
21435 * Copyright(c) 2006-2007, Ext JS, LLC.
21441 * @class Roo.HtmlEditorCore
21442 * @extends Roo.Component
21443 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21445 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21448 Roo.HtmlEditorCore = function(config){
21451 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21456 * @event initialize
21457 * Fires when the editor is fully initialized (including the iframe)
21458 * @param {Roo.HtmlEditorCore} this
21463 * Fires when the editor is first receives the focus. Any insertion must wait
21464 * until after this event.
21465 * @param {Roo.HtmlEditorCore} this
21469 * @event beforesync
21470 * Fires before the textarea is updated with content from the editor iframe. Return false
21471 * to cancel the sync.
21472 * @param {Roo.HtmlEditorCore} this
21473 * @param {String} html
21477 * @event beforepush
21478 * Fires before the iframe editor is updated with content from the textarea. Return false
21479 * to cancel the push.
21480 * @param {Roo.HtmlEditorCore} this
21481 * @param {String} html
21486 * Fires when the textarea is updated with content from the editor iframe.
21487 * @param {Roo.HtmlEditorCore} this
21488 * @param {String} html
21493 * Fires when the iframe editor is updated with content from the textarea.
21494 * @param {Roo.HtmlEditorCore} this
21495 * @param {String} html
21500 * @event editorevent
21501 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21502 * @param {Roo.HtmlEditorCore} this
21508 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21510 // defaults : white / black...
21511 this.applyBlacklists();
21518 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21522 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21528 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21533 * @cfg {Number} height (in pixels)
21537 * @cfg {Number} width (in pixels)
21542 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21545 stylesheets: false,
21550 // private properties
21551 validationEvent : false,
21553 initialized : false,
21555 sourceEditMode : false,
21556 onFocus : Roo.emptyFn,
21558 hideMode:'offsets',
21562 // blacklist + whitelisted elements..
21569 * Protected method that will not generally be called directly. It
21570 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21571 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21573 getDocMarkup : function(){
21577 // inherit styels from page...??
21578 if (this.stylesheets === false) {
21580 Roo.get(document.head).select('style').each(function(node) {
21581 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21584 Roo.get(document.head).select('link').each(function(node) {
21585 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21588 } else if (!this.stylesheets.length) {
21590 st = '<style type="text/css">' +
21591 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21594 st = '<style type="text/css">' +
21599 st += '<style type="text/css">' +
21600 'IMG { cursor: pointer } ' +
21603 var cls = 'roo-htmleditor-body';
21605 if(this.bodyCls.length){
21606 cls += ' ' + this.bodyCls;
21609 return '<html><head>' + st +
21610 //<style type="text/css">' +
21611 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21613 ' </head><body class="' + cls + '"></body></html>';
21617 onRender : function(ct, position)
21620 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21621 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21624 this.el.dom.style.border = '0 none';
21625 this.el.dom.setAttribute('tabIndex', -1);
21626 this.el.addClass('x-hidden hide');
21630 if(Roo.isIE){ // fix IE 1px bogus margin
21631 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21635 this.frameId = Roo.id();
21639 var iframe = this.owner.wrap.createChild({
21641 cls: 'form-control', // bootstrap..
21643 name: this.frameId,
21644 frameBorder : 'no',
21645 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21650 this.iframe = iframe.dom;
21652 this.assignDocWin();
21654 this.doc.designMode = 'on';
21657 this.doc.write(this.getDocMarkup());
21661 var task = { // must defer to wait for browser to be ready
21663 //console.log("run task?" + this.doc.readyState);
21664 this.assignDocWin();
21665 if(this.doc.body || this.doc.readyState == 'complete'){
21667 this.doc.designMode="on";
21671 Roo.TaskMgr.stop(task);
21672 this.initEditor.defer(10, this);
21679 Roo.TaskMgr.start(task);
21684 onResize : function(w, h)
21686 Roo.log('resize: ' +w + ',' + h );
21687 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21691 if(typeof w == 'number'){
21693 this.iframe.style.width = w + 'px';
21695 if(typeof h == 'number'){
21697 this.iframe.style.height = h + 'px';
21699 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21706 * Toggles the editor between standard and source edit mode.
21707 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21709 toggleSourceEdit : function(sourceEditMode){
21711 this.sourceEditMode = sourceEditMode === true;
21713 if(this.sourceEditMode){
21715 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21718 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21719 //this.iframe.className = '';
21722 //this.setSize(this.owner.wrap.getSize());
21723 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21730 * Protected method that will not generally be called directly. If you need/want
21731 * custom HTML cleanup, this is the method you should override.
21732 * @param {String} html The HTML to be cleaned
21733 * return {String} The cleaned HTML
21735 cleanHtml : function(html){
21736 html = String(html);
21737 if(html.length > 5){
21738 if(Roo.isSafari){ // strip safari nonsense
21739 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21742 if(html == ' '){
21749 * HTML Editor -> Textarea
21750 * Protected method that will not generally be called directly. Syncs the contents
21751 * of the editor iframe with the textarea.
21753 syncValue : function(){
21754 if(this.initialized){
21755 var bd = (this.doc.body || this.doc.documentElement);
21756 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21757 var html = bd.innerHTML;
21759 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21760 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21762 html = '<div style="'+m[0]+'">' + html + '</div>';
21765 html = this.cleanHtml(html);
21766 // fix up the special chars.. normaly like back quotes in word...
21767 // however we do not want to do this with chinese..
21768 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21769 var cc = b.charCodeAt();
21771 (cc >= 0x4E00 && cc < 0xA000 ) ||
21772 (cc >= 0x3400 && cc < 0x4E00 ) ||
21773 (cc >= 0xf900 && cc < 0xfb00 )
21779 if(this.owner.fireEvent('beforesync', this, html) !== false){
21780 this.el.dom.value = html;
21781 this.owner.fireEvent('sync', this, html);
21787 * Protected method that will not generally be called directly. Pushes the value of the textarea
21788 * into the iframe editor.
21790 pushValue : function(){
21791 if(this.initialized){
21792 var v = this.el.dom.value.trim();
21794 // if(v.length < 1){
21798 if(this.owner.fireEvent('beforepush', this, v) !== false){
21799 var d = (this.doc.body || this.doc.documentElement);
21801 this.cleanUpPaste();
21802 this.el.dom.value = d.innerHTML;
21803 this.owner.fireEvent('push', this, v);
21809 deferFocus : function(){
21810 this.focus.defer(10, this);
21814 focus : function(){
21815 if(this.win && !this.sourceEditMode){
21822 assignDocWin: function()
21824 var iframe = this.iframe;
21827 this.doc = iframe.contentWindow.document;
21828 this.win = iframe.contentWindow;
21830 // if (!Roo.get(this.frameId)) {
21833 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21834 // this.win = Roo.get(this.frameId).dom.contentWindow;
21836 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21840 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21841 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21846 initEditor : function(){
21847 //console.log("INIT EDITOR");
21848 this.assignDocWin();
21852 this.doc.designMode="on";
21854 this.doc.write(this.getDocMarkup());
21857 var dbody = (this.doc.body || this.doc.documentElement);
21858 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21859 // this copies styles from the containing element into thsi one..
21860 // not sure why we need all of this..
21861 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21863 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21864 //ss['background-attachment'] = 'fixed'; // w3c
21865 dbody.bgProperties = 'fixed'; // ie
21866 //Roo.DomHelper.applyStyles(dbody, ss);
21867 Roo.EventManager.on(this.doc, {
21868 //'mousedown': this.onEditorEvent,
21869 'mouseup': this.onEditorEvent,
21870 'dblclick': this.onEditorEvent,
21871 'click': this.onEditorEvent,
21872 'keyup': this.onEditorEvent,
21877 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21879 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21880 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21882 this.initialized = true;
21884 this.owner.fireEvent('initialize', this);
21889 onDestroy : function(){
21895 //for (var i =0; i < this.toolbars.length;i++) {
21896 // // fixme - ask toolbars for heights?
21897 // this.toolbars[i].onDestroy();
21900 //this.wrap.dom.innerHTML = '';
21901 //this.wrap.remove();
21906 onFirstFocus : function(){
21908 this.assignDocWin();
21911 this.activated = true;
21914 if(Roo.isGecko){ // prevent silly gecko errors
21916 var s = this.win.getSelection();
21917 if(!s.focusNode || s.focusNode.nodeType != 3){
21918 var r = s.getRangeAt(0);
21919 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21924 this.execCmd('useCSS', true);
21925 this.execCmd('styleWithCSS', false);
21928 this.owner.fireEvent('activate', this);
21932 adjustFont: function(btn){
21933 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21934 //if(Roo.isSafari){ // safari
21937 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21938 if(Roo.isSafari){ // safari
21939 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21940 v = (v < 10) ? 10 : v;
21941 v = (v > 48) ? 48 : v;
21942 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21947 v = Math.max(1, v+adjust);
21949 this.execCmd('FontSize', v );
21952 onEditorEvent : function(e)
21954 this.owner.fireEvent('editorevent', this, e);
21955 // this.updateToolbar();
21956 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21959 insertTag : function(tg)
21961 // could be a bit smarter... -> wrap the current selected tRoo..
21962 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21964 range = this.createRange(this.getSelection());
21965 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21966 wrappingNode.appendChild(range.extractContents());
21967 range.insertNode(wrappingNode);
21974 this.execCmd("formatblock", tg);
21978 insertText : function(txt)
21982 var range = this.createRange();
21983 range.deleteContents();
21984 //alert(Sender.getAttribute('label'));
21986 range.insertNode(this.doc.createTextNode(txt));
21992 * Executes a Midas editor command on the editor document and performs necessary focus and
21993 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21994 * @param {String} cmd The Midas command
21995 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21997 relayCmd : function(cmd, value){
21999 this.execCmd(cmd, value);
22000 this.owner.fireEvent('editorevent', this);
22001 //this.updateToolbar();
22002 this.owner.deferFocus();
22006 * Executes a Midas editor command directly on the editor document.
22007 * For visual commands, you should use {@link #relayCmd} instead.
22008 * <b>This should only be called after the editor is initialized.</b>
22009 * @param {String} cmd The Midas command
22010 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22012 execCmd : function(cmd, value){
22013 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22020 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22022 * @param {String} text | dom node..
22024 insertAtCursor : function(text)
22027 if(!this.activated){
22033 var r = this.doc.selection.createRange();
22044 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22048 // from jquery ui (MIT licenced)
22050 var win = this.win;
22052 if (win.getSelection && win.getSelection().getRangeAt) {
22053 range = win.getSelection().getRangeAt(0);
22054 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22055 range.insertNode(node);
22056 } else if (win.document.selection && win.document.selection.createRange) {
22057 // no firefox support
22058 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22059 win.document.selection.createRange().pasteHTML(txt);
22061 // no firefox support
22062 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22063 this.execCmd('InsertHTML', txt);
22072 mozKeyPress : function(e){
22074 var c = e.getCharCode(), cmd;
22077 c = String.fromCharCode(c).toLowerCase();
22091 this.cleanUpPaste.defer(100, this);
22099 e.preventDefault();
22107 fixKeys : function(){ // load time branching for fastest keydown performance
22109 return function(e){
22110 var k = e.getKey(), r;
22113 r = this.doc.selection.createRange();
22116 r.pasteHTML('    ');
22123 r = this.doc.selection.createRange();
22125 var target = r.parentElement();
22126 if(!target || target.tagName.toLowerCase() != 'li'){
22128 r.pasteHTML('<br />');
22134 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22135 this.cleanUpPaste.defer(100, this);
22141 }else if(Roo.isOpera){
22142 return function(e){
22143 var k = e.getKey();
22147 this.execCmd('InsertHTML','    ');
22150 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22151 this.cleanUpPaste.defer(100, this);
22156 }else if(Roo.isSafari){
22157 return function(e){
22158 var k = e.getKey();
22162 this.execCmd('InsertText','\t');
22166 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22167 this.cleanUpPaste.defer(100, this);
22175 getAllAncestors: function()
22177 var p = this.getSelectedNode();
22180 a.push(p); // push blank onto stack..
22181 p = this.getParentElement();
22185 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22189 a.push(this.doc.body);
22193 lastSelNode : false,
22196 getSelection : function()
22198 this.assignDocWin();
22199 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22202 getSelectedNode: function()
22204 // this may only work on Gecko!!!
22206 // should we cache this!!!!
22211 var range = this.createRange(this.getSelection()).cloneRange();
22214 var parent = range.parentElement();
22216 var testRange = range.duplicate();
22217 testRange.moveToElementText(parent);
22218 if (testRange.inRange(range)) {
22221 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22224 parent = parent.parentElement;
22229 // is ancestor a text element.
22230 var ac = range.commonAncestorContainer;
22231 if (ac.nodeType == 3) {
22232 ac = ac.parentNode;
22235 var ar = ac.childNodes;
22238 var other_nodes = [];
22239 var has_other_nodes = false;
22240 for (var i=0;i<ar.length;i++) {
22241 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22244 // fullly contained node.
22246 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22251 // probably selected..
22252 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22253 other_nodes.push(ar[i]);
22257 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22262 has_other_nodes = true;
22264 if (!nodes.length && other_nodes.length) {
22265 nodes= other_nodes;
22267 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22273 createRange: function(sel)
22275 // this has strange effects when using with
22276 // top toolbar - not sure if it's a great idea.
22277 //this.editor.contentWindow.focus();
22278 if (typeof sel != "undefined") {
22280 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22282 return this.doc.createRange();
22285 return this.doc.createRange();
22288 getParentElement: function()
22291 this.assignDocWin();
22292 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22294 var range = this.createRange(sel);
22297 var p = range.commonAncestorContainer;
22298 while (p.nodeType == 3) { // text node
22309 * Range intersection.. the hard stuff...
22313 * [ -- selected range --- ]
22317 * if end is before start or hits it. fail.
22318 * if start is after end or hits it fail.
22320 * if either hits (but other is outside. - then it's not
22326 // @see http://www.thismuchiknow.co.uk/?p=64.
22327 rangeIntersectsNode : function(range, node)
22329 var nodeRange = node.ownerDocument.createRange();
22331 nodeRange.selectNode(node);
22333 nodeRange.selectNodeContents(node);
22336 var rangeStartRange = range.cloneRange();
22337 rangeStartRange.collapse(true);
22339 var rangeEndRange = range.cloneRange();
22340 rangeEndRange.collapse(false);
22342 var nodeStartRange = nodeRange.cloneRange();
22343 nodeStartRange.collapse(true);
22345 var nodeEndRange = nodeRange.cloneRange();
22346 nodeEndRange.collapse(false);
22348 return rangeStartRange.compareBoundaryPoints(
22349 Range.START_TO_START, nodeEndRange) == -1 &&
22350 rangeEndRange.compareBoundaryPoints(
22351 Range.START_TO_START, nodeStartRange) == 1;
22355 rangeCompareNode : function(range, node)
22357 var nodeRange = node.ownerDocument.createRange();
22359 nodeRange.selectNode(node);
22361 nodeRange.selectNodeContents(node);
22365 range.collapse(true);
22367 nodeRange.collapse(true);
22369 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22370 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22372 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22374 var nodeIsBefore = ss == 1;
22375 var nodeIsAfter = ee == -1;
22377 if (nodeIsBefore && nodeIsAfter) {
22380 if (!nodeIsBefore && nodeIsAfter) {
22381 return 1; //right trailed.
22384 if (nodeIsBefore && !nodeIsAfter) {
22385 return 2; // left trailed.
22391 // private? - in a new class?
22392 cleanUpPaste : function()
22394 // cleans up the whole document..
22395 Roo.log('cleanuppaste');
22397 this.cleanUpChildren(this.doc.body);
22398 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22399 if (clean != this.doc.body.innerHTML) {
22400 this.doc.body.innerHTML = clean;
22405 cleanWordChars : function(input) {// change the chars to hex code
22406 var he = Roo.HtmlEditorCore;
22408 var output = input;
22409 Roo.each(he.swapCodes, function(sw) {
22410 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22412 output = output.replace(swapper, sw[1]);
22419 cleanUpChildren : function (n)
22421 if (!n.childNodes.length) {
22424 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22425 this.cleanUpChild(n.childNodes[i]);
22432 cleanUpChild : function (node)
22435 //console.log(node);
22436 if (node.nodeName == "#text") {
22437 // clean up silly Windows -- stuff?
22440 if (node.nodeName == "#comment") {
22441 node.parentNode.removeChild(node);
22442 // clean up silly Windows -- stuff?
22445 var lcname = node.tagName.toLowerCase();
22446 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22447 // whitelist of tags..
22449 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22451 node.parentNode.removeChild(node);
22456 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22458 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22459 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22461 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22462 // remove_keep_children = true;
22465 if (remove_keep_children) {
22466 this.cleanUpChildren(node);
22467 // inserts everything just before this node...
22468 while (node.childNodes.length) {
22469 var cn = node.childNodes[0];
22470 node.removeChild(cn);
22471 node.parentNode.insertBefore(cn, node);
22473 node.parentNode.removeChild(node);
22477 if (!node.attributes || !node.attributes.length) {
22478 this.cleanUpChildren(node);
22482 function cleanAttr(n,v)
22485 if (v.match(/^\./) || v.match(/^\//)) {
22488 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22491 if (v.match(/^#/)) {
22494 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22495 node.removeAttribute(n);
22499 var cwhite = this.cwhite;
22500 var cblack = this.cblack;
22502 function cleanStyle(n,v)
22504 if (v.match(/expression/)) { //XSS?? should we even bother..
22505 node.removeAttribute(n);
22509 var parts = v.split(/;/);
22512 Roo.each(parts, function(p) {
22513 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22517 var l = p.split(':').shift().replace(/\s+/g,'');
22518 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22520 if ( cwhite.length && cblack.indexOf(l) > -1) {
22521 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22522 //node.removeAttribute(n);
22526 // only allow 'c whitelisted system attributes'
22527 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22528 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22529 //node.removeAttribute(n);
22539 if (clean.length) {
22540 node.setAttribute(n, clean.join(';'));
22542 node.removeAttribute(n);
22548 for (var i = node.attributes.length-1; i > -1 ; i--) {
22549 var a = node.attributes[i];
22552 if (a.name.toLowerCase().substr(0,2)=='on') {
22553 node.removeAttribute(a.name);
22556 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22557 node.removeAttribute(a.name);
22560 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22561 cleanAttr(a.name,a.value); // fixme..
22564 if (a.name == 'style') {
22565 cleanStyle(a.name,a.value);
22568 /// clean up MS crap..
22569 // tecnically this should be a list of valid class'es..
22572 if (a.name == 'class') {
22573 if (a.value.match(/^Mso/)) {
22574 node.className = '';
22577 if (a.value.match(/^body$/)) {
22578 node.className = '';
22589 this.cleanUpChildren(node);
22595 * Clean up MS wordisms...
22597 cleanWord : function(node)
22602 this.cleanWord(this.doc.body);
22605 if (node.nodeName == "#text") {
22606 // clean up silly Windows -- stuff?
22609 if (node.nodeName == "#comment") {
22610 node.parentNode.removeChild(node);
22611 // clean up silly Windows -- stuff?
22615 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22616 node.parentNode.removeChild(node);
22620 // remove - but keep children..
22621 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22622 while (node.childNodes.length) {
22623 var cn = node.childNodes[0];
22624 node.removeChild(cn);
22625 node.parentNode.insertBefore(cn, node);
22627 node.parentNode.removeChild(node);
22628 this.iterateChildren(node, this.cleanWord);
22632 if (node.className.length) {
22634 var cn = node.className.split(/\W+/);
22636 Roo.each(cn, function(cls) {
22637 if (cls.match(/Mso[a-zA-Z]+/)) {
22642 node.className = cna.length ? cna.join(' ') : '';
22644 node.removeAttribute("class");
22648 if (node.hasAttribute("lang")) {
22649 node.removeAttribute("lang");
22652 if (node.hasAttribute("style")) {
22654 var styles = node.getAttribute("style").split(";");
22656 Roo.each(styles, function(s) {
22657 if (!s.match(/:/)) {
22660 var kv = s.split(":");
22661 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22664 // what ever is left... we allow.
22667 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22668 if (!nstyle.length) {
22669 node.removeAttribute('style');
22672 this.iterateChildren(node, this.cleanWord);
22678 * iterateChildren of a Node, calling fn each time, using this as the scole..
22679 * @param {DomNode} node node to iterate children of.
22680 * @param {Function} fn method of this class to call on each item.
22682 iterateChildren : function(node, fn)
22684 if (!node.childNodes.length) {
22687 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22688 fn.call(this, node.childNodes[i])
22694 * cleanTableWidths.
22696 * Quite often pasting from word etc.. results in tables with column and widths.
22697 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22700 cleanTableWidths : function(node)
22705 this.cleanTableWidths(this.doc.body);
22710 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22713 Roo.log(node.tagName);
22714 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22715 this.iterateChildren(node, this.cleanTableWidths);
22718 if (node.hasAttribute('width')) {
22719 node.removeAttribute('width');
22723 if (node.hasAttribute("style")) {
22726 var styles = node.getAttribute("style").split(";");
22728 Roo.each(styles, function(s) {
22729 if (!s.match(/:/)) {
22732 var kv = s.split(":");
22733 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22736 // what ever is left... we allow.
22739 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22740 if (!nstyle.length) {
22741 node.removeAttribute('style');
22745 this.iterateChildren(node, this.cleanTableWidths);
22753 domToHTML : function(currentElement, depth, nopadtext) {
22755 depth = depth || 0;
22756 nopadtext = nopadtext || false;
22758 if (!currentElement) {
22759 return this.domToHTML(this.doc.body);
22762 //Roo.log(currentElement);
22764 var allText = false;
22765 var nodeName = currentElement.nodeName;
22766 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22768 if (nodeName == '#text') {
22770 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22775 if (nodeName != 'BODY') {
22778 // Prints the node tagName, such as <A>, <IMG>, etc
22781 for(i = 0; i < currentElement.attributes.length;i++) {
22783 var aname = currentElement.attributes.item(i).name;
22784 if (!currentElement.attributes.item(i).value.length) {
22787 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22790 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22799 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22802 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22807 // Traverse the tree
22809 var currentElementChild = currentElement.childNodes.item(i);
22810 var allText = true;
22811 var innerHTML = '';
22813 while (currentElementChild) {
22814 // Formatting code (indent the tree so it looks nice on the screen)
22815 var nopad = nopadtext;
22816 if (lastnode == 'SPAN') {
22820 if (currentElementChild.nodeName == '#text') {
22821 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22822 toadd = nopadtext ? toadd : toadd.trim();
22823 if (!nopad && toadd.length > 80) {
22824 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22826 innerHTML += toadd;
22829 currentElementChild = currentElement.childNodes.item(i);
22835 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22837 // Recursively traverse the tree structure of the child node
22838 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22839 lastnode = currentElementChild.nodeName;
22841 currentElementChild=currentElement.childNodes.item(i);
22847 // The remaining code is mostly for formatting the tree
22848 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22853 ret+= "</"+tagName+">";
22859 applyBlacklists : function()
22861 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22862 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22866 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22867 if (b.indexOf(tag) > -1) {
22870 this.white.push(tag);
22874 Roo.each(w, function(tag) {
22875 if (b.indexOf(tag) > -1) {
22878 if (this.white.indexOf(tag) > -1) {
22881 this.white.push(tag);
22886 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22887 if (w.indexOf(tag) > -1) {
22890 this.black.push(tag);
22894 Roo.each(b, function(tag) {
22895 if (w.indexOf(tag) > -1) {
22898 if (this.black.indexOf(tag) > -1) {
22901 this.black.push(tag);
22906 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22907 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22911 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22912 if (b.indexOf(tag) > -1) {
22915 this.cwhite.push(tag);
22919 Roo.each(w, function(tag) {
22920 if (b.indexOf(tag) > -1) {
22923 if (this.cwhite.indexOf(tag) > -1) {
22926 this.cwhite.push(tag);
22931 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22932 if (w.indexOf(tag) > -1) {
22935 this.cblack.push(tag);
22939 Roo.each(b, function(tag) {
22940 if (w.indexOf(tag) > -1) {
22943 if (this.cblack.indexOf(tag) > -1) {
22946 this.cblack.push(tag);
22951 setStylesheets : function(stylesheets)
22953 if(typeof(stylesheets) == 'string'){
22954 Roo.get(this.iframe.contentDocument.head).createChild({
22956 rel : 'stylesheet',
22965 Roo.each(stylesheets, function(s) {
22970 Roo.get(_this.iframe.contentDocument.head).createChild({
22972 rel : 'stylesheet',
22981 removeStylesheets : function()
22985 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22990 setStyle : function(style)
22992 Roo.get(this.iframe.contentDocument.head).createChild({
23001 // hide stuff that is not compatible
23015 * @event specialkey
23019 * @cfg {String} fieldClass @hide
23022 * @cfg {String} focusClass @hide
23025 * @cfg {String} autoCreate @hide
23028 * @cfg {String} inputType @hide
23031 * @cfg {String} invalidClass @hide
23034 * @cfg {String} invalidText @hide
23037 * @cfg {String} msgFx @hide
23040 * @cfg {String} validateOnBlur @hide
23044 Roo.HtmlEditorCore.white = [
23045 'area', 'br', 'img', 'input', 'hr', 'wbr',
23047 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23048 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23049 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23050 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23051 'table', 'ul', 'xmp',
23053 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23056 'dir', 'menu', 'ol', 'ul', 'dl',
23062 Roo.HtmlEditorCore.black = [
23063 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23065 'base', 'basefont', 'bgsound', 'blink', 'body',
23066 'frame', 'frameset', 'head', 'html', 'ilayer',
23067 'iframe', 'layer', 'link', 'meta', 'object',
23068 'script', 'style' ,'title', 'xml' // clean later..
23070 Roo.HtmlEditorCore.clean = [
23071 'script', 'style', 'title', 'xml'
23073 Roo.HtmlEditorCore.remove = [
23078 Roo.HtmlEditorCore.ablack = [
23082 Roo.HtmlEditorCore.aclean = [
23083 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23087 Roo.HtmlEditorCore.pwhite= [
23088 'http', 'https', 'mailto'
23091 // white listed style attributes.
23092 Roo.HtmlEditorCore.cwhite= [
23093 // 'text-align', /// default is to allow most things..
23099 // black listed style attributes.
23100 Roo.HtmlEditorCore.cblack= [
23101 // 'font-size' -- this can be set by the project
23105 Roo.HtmlEditorCore.swapCodes =[
23124 * @class Roo.bootstrap.HtmlEditor
23125 * @extends Roo.bootstrap.TextArea
23126 * Bootstrap HtmlEditor class
23129 * Create a new HtmlEditor
23130 * @param {Object} config The config object
23133 Roo.bootstrap.HtmlEditor = function(config){
23134 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23135 if (!this.toolbars) {
23136 this.toolbars = [];
23139 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23142 * @event initialize
23143 * Fires when the editor is fully initialized (including the iframe)
23144 * @param {HtmlEditor} this
23149 * Fires when the editor is first receives the focus. Any insertion must wait
23150 * until after this event.
23151 * @param {HtmlEditor} this
23155 * @event beforesync
23156 * Fires before the textarea is updated with content from the editor iframe. Return false
23157 * to cancel the sync.
23158 * @param {HtmlEditor} this
23159 * @param {String} html
23163 * @event beforepush
23164 * Fires before the iframe editor is updated with content from the textarea. Return false
23165 * to cancel the push.
23166 * @param {HtmlEditor} this
23167 * @param {String} html
23172 * Fires when the textarea is updated with content from the editor iframe.
23173 * @param {HtmlEditor} this
23174 * @param {String} html
23179 * Fires when the iframe editor is updated with content from the textarea.
23180 * @param {HtmlEditor} this
23181 * @param {String} html
23185 * @event editmodechange
23186 * Fires when the editor switches edit modes
23187 * @param {HtmlEditor} this
23188 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23190 editmodechange: true,
23192 * @event editorevent
23193 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23194 * @param {HtmlEditor} this
23198 * @event firstfocus
23199 * Fires when on first focus - needed by toolbars..
23200 * @param {HtmlEditor} this
23205 * Auto save the htmlEditor value as a file into Events
23206 * @param {HtmlEditor} this
23210 * @event savedpreview
23211 * preview the saved version of htmlEditor
23212 * @param {HtmlEditor} this
23219 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23223 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23228 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23233 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23238 * @cfg {Number} height (in pixels)
23242 * @cfg {Number} width (in pixels)
23247 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23250 stylesheets: false,
23255 // private properties
23256 validationEvent : false,
23258 initialized : false,
23261 onFocus : Roo.emptyFn,
23263 hideMode:'offsets',
23265 tbContainer : false,
23269 toolbarContainer :function() {
23270 return this.wrap.select('.x-html-editor-tb',true).first();
23274 * Protected method that will not generally be called directly. It
23275 * is called when the editor creates its toolbar. Override this method if you need to
23276 * add custom toolbar buttons.
23277 * @param {HtmlEditor} editor
23279 createToolbar : function(){
23280 Roo.log('renewing');
23281 Roo.log("create toolbars");
23283 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23284 this.toolbars[0].render(this.toolbarContainer());
23288 // if (!editor.toolbars || !editor.toolbars.length) {
23289 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23292 // for (var i =0 ; i < editor.toolbars.length;i++) {
23293 // editor.toolbars[i] = Roo.factory(
23294 // typeof(editor.toolbars[i]) == 'string' ?
23295 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23296 // Roo.bootstrap.HtmlEditor);
23297 // editor.toolbars[i].init(editor);
23303 onRender : function(ct, position)
23305 // Roo.log("Call onRender: " + this.xtype);
23307 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23309 this.wrap = this.inputEl().wrap({
23310 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23313 this.editorcore.onRender(ct, position);
23315 if (this.resizable) {
23316 this.resizeEl = new Roo.Resizable(this.wrap, {
23320 minHeight : this.height,
23321 height: this.height,
23322 handles : this.resizable,
23325 resize : function(r, w, h) {
23326 _t.onResize(w,h); // -something
23332 this.createToolbar(this);
23335 if(!this.width && this.resizable){
23336 this.setSize(this.wrap.getSize());
23338 if (this.resizeEl) {
23339 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23340 // should trigger onReize..
23346 onResize : function(w, h)
23348 Roo.log('resize: ' +w + ',' + h );
23349 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23353 if(this.inputEl() ){
23354 if(typeof w == 'number'){
23355 var aw = w - this.wrap.getFrameWidth('lr');
23356 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23359 if(typeof h == 'number'){
23360 var tbh = -11; // fixme it needs to tool bar size!
23361 for (var i =0; i < this.toolbars.length;i++) {
23362 // fixme - ask toolbars for heights?
23363 tbh += this.toolbars[i].el.getHeight();
23364 //if (this.toolbars[i].footer) {
23365 // tbh += this.toolbars[i].footer.el.getHeight();
23373 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23374 ah -= 5; // knock a few pixes off for look..
23375 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23379 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23380 this.editorcore.onResize(ew,eh);
23385 * Toggles the editor between standard and source edit mode.
23386 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23388 toggleSourceEdit : function(sourceEditMode)
23390 this.editorcore.toggleSourceEdit(sourceEditMode);
23392 if(this.editorcore.sourceEditMode){
23393 Roo.log('editor - showing textarea');
23396 // Roo.log(this.syncValue());
23398 this.inputEl().removeClass(['hide', 'x-hidden']);
23399 this.inputEl().dom.removeAttribute('tabIndex');
23400 this.inputEl().focus();
23402 Roo.log('editor - hiding textarea');
23404 // Roo.log(this.pushValue());
23407 this.inputEl().addClass(['hide', 'x-hidden']);
23408 this.inputEl().dom.setAttribute('tabIndex', -1);
23409 //this.deferFocus();
23412 if(this.resizable){
23413 this.setSize(this.wrap.getSize());
23416 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23419 // private (for BoxComponent)
23420 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23422 // private (for BoxComponent)
23423 getResizeEl : function(){
23427 // private (for BoxComponent)
23428 getPositionEl : function(){
23433 initEvents : function(){
23434 this.originalValue = this.getValue();
23438 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23441 // markInvalid : Roo.emptyFn,
23443 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23446 // clearInvalid : Roo.emptyFn,
23448 setValue : function(v){
23449 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23450 this.editorcore.pushValue();
23455 deferFocus : function(){
23456 this.focus.defer(10, this);
23460 focus : function(){
23461 this.editorcore.focus();
23467 onDestroy : function(){
23473 for (var i =0; i < this.toolbars.length;i++) {
23474 // fixme - ask toolbars for heights?
23475 this.toolbars[i].onDestroy();
23478 this.wrap.dom.innerHTML = '';
23479 this.wrap.remove();
23484 onFirstFocus : function(){
23485 //Roo.log("onFirstFocus");
23486 this.editorcore.onFirstFocus();
23487 for (var i =0; i < this.toolbars.length;i++) {
23488 this.toolbars[i].onFirstFocus();
23494 syncValue : function()
23496 this.editorcore.syncValue();
23499 pushValue : function()
23501 this.editorcore.pushValue();
23505 // hide stuff that is not compatible
23519 * @event specialkey
23523 * @cfg {String} fieldClass @hide
23526 * @cfg {String} focusClass @hide
23529 * @cfg {String} autoCreate @hide
23532 * @cfg {String} inputType @hide
23535 * @cfg {String} invalidClass @hide
23538 * @cfg {String} invalidText @hide
23541 * @cfg {String} msgFx @hide
23544 * @cfg {String} validateOnBlur @hide
23553 Roo.namespace('Roo.bootstrap.htmleditor');
23555 * @class Roo.bootstrap.HtmlEditorToolbar1
23560 new Roo.bootstrap.HtmlEditor({
23563 new Roo.bootstrap.HtmlEditorToolbar1({
23564 disable : { fonts: 1 , format: 1, ..., ... , ...],
23570 * @cfg {Object} disable List of elements to disable..
23571 * @cfg {Array} btns List of additional buttons.
23575 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23578 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23581 Roo.apply(this, config);
23583 // default disabled, based on 'good practice'..
23584 this.disable = this.disable || {};
23585 Roo.applyIf(this.disable, {
23588 specialElements : true
23590 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23592 this.editor = config.editor;
23593 this.editorcore = config.editor.editorcore;
23595 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23597 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23598 // dont call parent... till later.
23600 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23605 editorcore : false,
23610 "h1","h2","h3","h4","h5","h6",
23612 "abbr", "acronym", "address", "cite", "samp", "var",
23616 onRender : function(ct, position)
23618 // Roo.log("Call onRender: " + this.xtype);
23620 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23622 this.el.dom.style.marginBottom = '0';
23624 var editorcore = this.editorcore;
23625 var editor= this.editor;
23628 var btn = function(id,cmd , toggle, handler, html){
23630 var event = toggle ? 'toggle' : 'click';
23635 xns: Roo.bootstrap,
23638 enableToggle:toggle !== false,
23640 pressed : toggle ? false : null,
23643 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23644 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23650 // var cb_box = function...
23655 xns: Roo.bootstrap,
23656 glyphicon : 'font',
23660 xns: Roo.bootstrap,
23664 Roo.each(this.formats, function(f) {
23665 style.menu.items.push({
23667 xns: Roo.bootstrap,
23668 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23673 editorcore.insertTag(this.tagname);
23680 children.push(style);
23682 btn('bold',false,true);
23683 btn('italic',false,true);
23684 btn('align-left', 'justifyleft',true);
23685 btn('align-center', 'justifycenter',true);
23686 btn('align-right' , 'justifyright',true);
23687 btn('link', false, false, function(btn) {
23688 //Roo.log("create link?");
23689 var url = prompt(this.createLinkText, this.defaultLinkValue);
23690 if(url && url != 'http:/'+'/'){
23691 this.editorcore.relayCmd('createlink', url);
23694 btn('list','insertunorderedlist',true);
23695 btn('pencil', false,true, function(btn){
23697 this.toggleSourceEdit(btn.pressed);
23700 if (this.editor.btns.length > 0) {
23701 for (var i = 0; i<this.editor.btns.length; i++) {
23702 children.push(this.editor.btns[i]);
23710 xns: Roo.bootstrap,
23715 xns: Roo.bootstrap,
23720 cog.menu.items.push({
23722 xns: Roo.bootstrap,
23723 html : Clean styles,
23728 editorcore.insertTag(this.tagname);
23737 this.xtype = 'NavSimplebar';
23739 for(var i=0;i< children.length;i++) {
23741 this.buttons.add(this.addxtypeChild(children[i]));
23745 editor.on('editorevent', this.updateToolbar, this);
23747 onBtnClick : function(id)
23749 this.editorcore.relayCmd(id);
23750 this.editorcore.focus();
23754 * Protected method that will not generally be called directly. It triggers
23755 * a toolbar update by reading the markup state of the current selection in the editor.
23757 updateToolbar: function(){
23759 if(!this.editorcore.activated){
23760 this.editor.onFirstFocus(); // is this neeed?
23764 var btns = this.buttons;
23765 var doc = this.editorcore.doc;
23766 btns.get('bold').setActive(doc.queryCommandState('bold'));
23767 btns.get('italic').setActive(doc.queryCommandState('italic'));
23768 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23770 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23771 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23772 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23774 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23775 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23778 var ans = this.editorcore.getAllAncestors();
23779 if (this.formatCombo) {
23782 var store = this.formatCombo.store;
23783 this.formatCombo.setValue("");
23784 for (var i =0; i < ans.length;i++) {
23785 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23787 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23795 // hides menus... - so this cant be on a menu...
23796 Roo.bootstrap.MenuMgr.hideAll();
23798 Roo.bootstrap.MenuMgr.hideAll();
23799 //this.editorsyncValue();
23801 onFirstFocus: function() {
23802 this.buttons.each(function(item){
23806 toggleSourceEdit : function(sourceEditMode){
23809 if(sourceEditMode){
23810 Roo.log("disabling buttons");
23811 this.buttons.each( function(item){
23812 if(item.cmd != 'pencil'){
23818 Roo.log("enabling buttons");
23819 if(this.editorcore.initialized){
23820 this.buttons.each( function(item){
23826 Roo.log("calling toggole on editor");
23827 // tell the editor that it's been pressed..
23828 this.editor.toggleSourceEdit(sourceEditMode);
23838 * @class Roo.bootstrap.Table.AbstractSelectionModel
23839 * @extends Roo.util.Observable
23840 * Abstract base class for grid SelectionModels. It provides the interface that should be
23841 * implemented by descendant classes. This class should not be directly instantiated.
23844 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23845 this.locked = false;
23846 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23850 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23851 /** @ignore Called by the grid automatically. Do not call directly. */
23852 init : function(grid){
23858 * Locks the selections.
23861 this.locked = true;
23865 * Unlocks the selections.
23867 unlock : function(){
23868 this.locked = false;
23872 * Returns true if the selections are locked.
23873 * @return {Boolean}
23875 isLocked : function(){
23876 return this.locked;
23880 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23881 * @class Roo.bootstrap.Table.RowSelectionModel
23882 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23883 * It supports multiple selections and keyboard selection/navigation.
23885 * @param {Object} config
23888 Roo.bootstrap.Table.RowSelectionModel = function(config){
23889 Roo.apply(this, config);
23890 this.selections = new Roo.util.MixedCollection(false, function(o){
23895 this.lastActive = false;
23899 * @event selectionchange
23900 * Fires when the selection changes
23901 * @param {SelectionModel} this
23903 "selectionchange" : true,
23905 * @event afterselectionchange
23906 * Fires after the selection changes (eg. by key press or clicking)
23907 * @param {SelectionModel} this
23909 "afterselectionchange" : true,
23911 * @event beforerowselect
23912 * Fires when a row is selected being selected, return false to cancel.
23913 * @param {SelectionModel} this
23914 * @param {Number} rowIndex The selected index
23915 * @param {Boolean} keepExisting False if other selections will be cleared
23917 "beforerowselect" : true,
23920 * Fires when a row is selected.
23921 * @param {SelectionModel} this
23922 * @param {Number} rowIndex The selected index
23923 * @param {Roo.data.Record} r The record
23925 "rowselect" : true,
23927 * @event rowdeselect
23928 * Fires when a row is deselected.
23929 * @param {SelectionModel} this
23930 * @param {Number} rowIndex The selected index
23932 "rowdeselect" : true
23934 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23935 this.locked = false;
23938 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23940 * @cfg {Boolean} singleSelect
23941 * True to allow selection of only one row at a time (defaults to false)
23943 singleSelect : false,
23946 initEvents : function()
23949 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23950 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23951 //}else{ // allow click to work like normal
23952 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23954 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23955 this.grid.on("rowclick", this.handleMouseDown, this);
23957 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23958 "up" : function(e){
23960 this.selectPrevious(e.shiftKey);
23961 }else if(this.last !== false && this.lastActive !== false){
23962 var last = this.last;
23963 this.selectRange(this.last, this.lastActive-1);
23964 this.grid.getView().focusRow(this.lastActive);
23965 if(last !== false){
23969 this.selectFirstRow();
23971 this.fireEvent("afterselectionchange", this);
23973 "down" : function(e){
23975 this.selectNext(e.shiftKey);
23976 }else if(this.last !== false && this.lastActive !== false){
23977 var last = this.last;
23978 this.selectRange(this.last, this.lastActive+1);
23979 this.grid.getView().focusRow(this.lastActive);
23980 if(last !== false){
23984 this.selectFirstRow();
23986 this.fireEvent("afterselectionchange", this);
23990 this.grid.store.on('load', function(){
23991 this.selections.clear();
23994 var view = this.grid.view;
23995 view.on("refresh", this.onRefresh, this);
23996 view.on("rowupdated", this.onRowUpdated, this);
23997 view.on("rowremoved", this.onRemove, this);
24002 onRefresh : function()
24004 var ds = this.grid.store, i, v = this.grid.view;
24005 var s = this.selections;
24006 s.each(function(r){
24007 if((i = ds.indexOfId(r.id)) != -1){
24016 onRemove : function(v, index, r){
24017 this.selections.remove(r);
24021 onRowUpdated : function(v, index, r){
24022 if(this.isSelected(r)){
24023 v.onRowSelect(index);
24029 * @param {Array} records The records to select
24030 * @param {Boolean} keepExisting (optional) True to keep existing selections
24032 selectRecords : function(records, keepExisting)
24035 this.clearSelections();
24037 var ds = this.grid.store;
24038 for(var i = 0, len = records.length; i < len; i++){
24039 this.selectRow(ds.indexOf(records[i]), true);
24044 * Gets the number of selected rows.
24047 getCount : function(){
24048 return this.selections.length;
24052 * Selects the first row in the grid.
24054 selectFirstRow : function(){
24059 * Select the last row.
24060 * @param {Boolean} keepExisting (optional) True to keep existing selections
24062 selectLastRow : function(keepExisting){
24063 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24064 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24068 * Selects the row immediately following the last selected row.
24069 * @param {Boolean} keepExisting (optional) True to keep existing selections
24071 selectNext : function(keepExisting)
24073 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24074 this.selectRow(this.last+1, keepExisting);
24075 this.grid.getView().focusRow(this.last);
24080 * Selects the row that precedes the last selected row.
24081 * @param {Boolean} keepExisting (optional) True to keep existing selections
24083 selectPrevious : function(keepExisting){
24085 this.selectRow(this.last-1, keepExisting);
24086 this.grid.getView().focusRow(this.last);
24091 * Returns the selected records
24092 * @return {Array} Array of selected records
24094 getSelections : function(){
24095 return [].concat(this.selections.items);
24099 * Returns the first selected record.
24102 getSelected : function(){
24103 return this.selections.itemAt(0);
24108 * Clears all selections.
24110 clearSelections : function(fast)
24116 var ds = this.grid.store;
24117 var s = this.selections;
24118 s.each(function(r){
24119 this.deselectRow(ds.indexOfId(r.id));
24123 this.selections.clear();
24130 * Selects all rows.
24132 selectAll : function(){
24136 this.selections.clear();
24137 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24138 this.selectRow(i, true);
24143 * Returns True if there is a selection.
24144 * @return {Boolean}
24146 hasSelection : function(){
24147 return this.selections.length > 0;
24151 * Returns True if the specified row is selected.
24152 * @param {Number/Record} record The record or index of the record to check
24153 * @return {Boolean}
24155 isSelected : function(index){
24156 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24157 return (r && this.selections.key(r.id) ? true : false);
24161 * Returns True if the specified record id is selected.
24162 * @param {String} id The id of record to check
24163 * @return {Boolean}
24165 isIdSelected : function(id){
24166 return (this.selections.key(id) ? true : false);
24171 handleMouseDBClick : function(e, t){
24175 handleMouseDown : function(e, t)
24177 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24178 if(this.isLocked() || rowIndex < 0 ){
24181 if(e.shiftKey && this.last !== false){
24182 var last = this.last;
24183 this.selectRange(last, rowIndex, e.ctrlKey);
24184 this.last = last; // reset the last
24188 var isSelected = this.isSelected(rowIndex);
24189 //Roo.log("select row:" + rowIndex);
24191 this.deselectRow(rowIndex);
24193 this.selectRow(rowIndex, true);
24197 if(e.button !== 0 && isSelected){
24198 alert('rowIndex 2: ' + rowIndex);
24199 view.focusRow(rowIndex);
24200 }else if(e.ctrlKey && isSelected){
24201 this.deselectRow(rowIndex);
24202 }else if(!isSelected){
24203 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24204 view.focusRow(rowIndex);
24208 this.fireEvent("afterselectionchange", this);
24211 handleDragableRowClick : function(grid, rowIndex, e)
24213 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24214 this.selectRow(rowIndex, false);
24215 grid.view.focusRow(rowIndex);
24216 this.fireEvent("afterselectionchange", this);
24221 * Selects multiple rows.
24222 * @param {Array} rows Array of the indexes of the row to select
24223 * @param {Boolean} keepExisting (optional) True to keep existing selections
24225 selectRows : function(rows, keepExisting){
24227 this.clearSelections();
24229 for(var i = 0, len = rows.length; i < len; i++){
24230 this.selectRow(rows[i], true);
24235 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24236 * @param {Number} startRow The index of the first row in the range
24237 * @param {Number} endRow The index of the last row in the range
24238 * @param {Boolean} keepExisting (optional) True to retain existing selections
24240 selectRange : function(startRow, endRow, keepExisting){
24245 this.clearSelections();
24247 if(startRow <= endRow){
24248 for(var i = startRow; i <= endRow; i++){
24249 this.selectRow(i, true);
24252 for(var i = startRow; i >= endRow; i--){
24253 this.selectRow(i, true);
24259 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24260 * @param {Number} startRow The index of the first row in the range
24261 * @param {Number} endRow The index of the last row in the range
24263 deselectRange : function(startRow, endRow, preventViewNotify){
24267 for(var i = startRow; i <= endRow; i++){
24268 this.deselectRow(i, preventViewNotify);
24274 * @param {Number} row The index of the row to select
24275 * @param {Boolean} keepExisting (optional) True to keep existing selections
24277 selectRow : function(index, keepExisting, preventViewNotify)
24279 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24282 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24283 if(!keepExisting || this.singleSelect){
24284 this.clearSelections();
24287 var r = this.grid.store.getAt(index);
24288 //console.log('selectRow - record id :' + r.id);
24290 this.selections.add(r);
24291 this.last = this.lastActive = index;
24292 if(!preventViewNotify){
24293 var proxy = new Roo.Element(
24294 this.grid.getRowDom(index)
24296 proxy.addClass('bg-info info');
24298 this.fireEvent("rowselect", this, index, r);
24299 this.fireEvent("selectionchange", this);
24305 * @param {Number} row The index of the row to deselect
24307 deselectRow : function(index, preventViewNotify)
24312 if(this.last == index){
24315 if(this.lastActive == index){
24316 this.lastActive = false;
24319 var r = this.grid.store.getAt(index);
24324 this.selections.remove(r);
24325 //.console.log('deselectRow - record id :' + r.id);
24326 if(!preventViewNotify){
24328 var proxy = new Roo.Element(
24329 this.grid.getRowDom(index)
24331 proxy.removeClass('bg-info info');
24333 this.fireEvent("rowdeselect", this, index);
24334 this.fireEvent("selectionchange", this);
24338 restoreLast : function(){
24340 this.last = this._last;
24345 acceptsNav : function(row, col, cm){
24346 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24350 onEditorKey : function(field, e){
24351 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24356 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24358 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24360 }else if(k == e.ENTER && !e.ctrlKey){
24364 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24366 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24368 }else if(k == e.ESC){
24372 g.startEditing(newCell[0], newCell[1]);
24378 * Ext JS Library 1.1.1
24379 * Copyright(c) 2006-2007, Ext JS, LLC.
24381 * Originally Released Under LGPL - original licence link has changed is not relivant.
24384 * <script type="text/javascript">
24388 * @class Roo.bootstrap.PagingToolbar
24389 * @extends Roo.bootstrap.NavSimplebar
24390 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24392 * Create a new PagingToolbar
24393 * @param {Object} config The config object
24394 * @param {Roo.data.Store} store
24396 Roo.bootstrap.PagingToolbar = function(config)
24398 // old args format still supported... - xtype is prefered..
24399 // created from xtype...
24401 this.ds = config.dataSource;
24403 if (config.store && !this.ds) {
24404 this.store= Roo.factory(config.store, Roo.data);
24405 this.ds = this.store;
24406 this.ds.xmodule = this.xmodule || false;
24409 this.toolbarItems = [];
24410 if (config.items) {
24411 this.toolbarItems = config.items;
24414 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24419 this.bind(this.ds);
24422 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24426 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24428 * @cfg {Roo.data.Store} dataSource
24429 * The underlying data store providing the paged data
24432 * @cfg {String/HTMLElement/Element} container
24433 * container The id or element that will contain the toolbar
24436 * @cfg {Boolean} displayInfo
24437 * True to display the displayMsg (defaults to false)
24440 * @cfg {Number} pageSize
24441 * The number of records to display per page (defaults to 20)
24445 * @cfg {String} displayMsg
24446 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24448 displayMsg : 'Displaying {0} - {1} of {2}',
24450 * @cfg {String} emptyMsg
24451 * The message to display when no records are found (defaults to "No data to display")
24453 emptyMsg : 'No data to display',
24455 * Customizable piece of the default paging text (defaults to "Page")
24458 beforePageText : "Page",
24460 * Customizable piece of the default paging text (defaults to "of %0")
24463 afterPageText : "of {0}",
24465 * Customizable piece of the default paging text (defaults to "First Page")
24468 firstText : "First Page",
24470 * Customizable piece of the default paging text (defaults to "Previous Page")
24473 prevText : "Previous Page",
24475 * Customizable piece of the default paging text (defaults to "Next Page")
24478 nextText : "Next Page",
24480 * Customizable piece of the default paging text (defaults to "Last Page")
24483 lastText : "Last Page",
24485 * Customizable piece of the default paging text (defaults to "Refresh")
24488 refreshText : "Refresh",
24492 onRender : function(ct, position)
24494 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24495 this.navgroup.parentId = this.id;
24496 this.navgroup.onRender(this.el, null);
24497 // add the buttons to the navgroup
24499 if(this.displayInfo){
24500 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24501 this.displayEl = this.el.select('.x-paging-info', true).first();
24502 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24503 // this.displayEl = navel.el.select('span',true).first();
24509 Roo.each(_this.buttons, function(e){ // this might need to use render????
24510 Roo.factory(e).onRender(_this.el, null);
24514 Roo.each(_this.toolbarItems, function(e) {
24515 _this.navgroup.addItem(e);
24519 this.first = this.navgroup.addItem({
24520 tooltip: this.firstText,
24522 icon : 'fa fa-backward',
24524 preventDefault: true,
24525 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24528 this.prev = this.navgroup.addItem({
24529 tooltip: this.prevText,
24531 icon : 'fa fa-step-backward',
24533 preventDefault: true,
24534 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24536 //this.addSeparator();
24539 var field = this.navgroup.addItem( {
24541 cls : 'x-paging-position',
24543 html : this.beforePageText +
24544 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24545 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24548 this.field = field.el.select('input', true).first();
24549 this.field.on("keydown", this.onPagingKeydown, this);
24550 this.field.on("focus", function(){this.dom.select();});
24553 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24554 //this.field.setHeight(18);
24555 //this.addSeparator();
24556 this.next = this.navgroup.addItem({
24557 tooltip: this.nextText,
24559 html : ' <i class="fa fa-step-forward">',
24561 preventDefault: true,
24562 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24564 this.last = this.navgroup.addItem({
24565 tooltip: this.lastText,
24566 icon : 'fa fa-forward',
24569 preventDefault: true,
24570 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24572 //this.addSeparator();
24573 this.loading = this.navgroup.addItem({
24574 tooltip: this.refreshText,
24575 icon: 'fa fa-refresh',
24576 preventDefault: true,
24577 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24583 updateInfo : function(){
24584 if(this.displayEl){
24585 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24586 var msg = count == 0 ?
24590 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24592 this.displayEl.update(msg);
24597 onLoad : function(ds, r, o)
24599 this.cursor = o.params.start ? o.params.start : 0;
24601 var d = this.getPageData(),
24606 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24607 this.field.dom.value = ap;
24608 this.first.setDisabled(ap == 1);
24609 this.prev.setDisabled(ap == 1);
24610 this.next.setDisabled(ap == ps);
24611 this.last.setDisabled(ap == ps);
24612 this.loading.enable();
24617 getPageData : function(){
24618 var total = this.ds.getTotalCount();
24621 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24622 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24627 onLoadError : function(){
24628 this.loading.enable();
24632 onPagingKeydown : function(e){
24633 var k = e.getKey();
24634 var d = this.getPageData();
24636 var v = this.field.dom.value, pageNum;
24637 if(!v || isNaN(pageNum = parseInt(v, 10))){
24638 this.field.dom.value = d.activePage;
24641 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24642 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24645 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))
24647 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24648 this.field.dom.value = pageNum;
24649 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24652 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24654 var v = this.field.dom.value, pageNum;
24655 var increment = (e.shiftKey) ? 10 : 1;
24656 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24659 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24660 this.field.dom.value = d.activePage;
24663 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24665 this.field.dom.value = parseInt(v, 10) + increment;
24666 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24667 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24674 beforeLoad : function(){
24676 this.loading.disable();
24681 onClick : function(which){
24690 ds.load({params:{start: 0, limit: this.pageSize}});
24693 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24696 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24699 var total = ds.getTotalCount();
24700 var extra = total % this.pageSize;
24701 var lastStart = extra ? (total - extra) : total-this.pageSize;
24702 ds.load({params:{start: lastStart, limit: this.pageSize}});
24705 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24711 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24712 * @param {Roo.data.Store} store The data store to unbind
24714 unbind : function(ds){
24715 ds.un("beforeload", this.beforeLoad, this);
24716 ds.un("load", this.onLoad, this);
24717 ds.un("loadexception", this.onLoadError, this);
24718 ds.un("remove", this.updateInfo, this);
24719 ds.un("add", this.updateInfo, this);
24720 this.ds = undefined;
24724 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24725 * @param {Roo.data.Store} store The data store to bind
24727 bind : function(ds){
24728 ds.on("beforeload", this.beforeLoad, this);
24729 ds.on("load", this.onLoad, this);
24730 ds.on("loadexception", this.onLoadError, this);
24731 ds.on("remove", this.updateInfo, this);
24732 ds.on("add", this.updateInfo, this);
24743 * @class Roo.bootstrap.MessageBar
24744 * @extends Roo.bootstrap.Component
24745 * Bootstrap MessageBar class
24746 * @cfg {String} html contents of the MessageBar
24747 * @cfg {String} weight (info | success | warning | danger) default info
24748 * @cfg {String} beforeClass insert the bar before the given class
24749 * @cfg {Boolean} closable (true | false) default false
24750 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24753 * Create a new Element
24754 * @param {Object} config The config object
24757 Roo.bootstrap.MessageBar = function(config){
24758 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24761 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24767 beforeClass: 'bootstrap-sticky-wrap',
24769 getAutoCreate : function(){
24773 cls: 'alert alert-dismissable alert-' + this.weight,
24778 html: this.html || ''
24784 cfg.cls += ' alert-messages-fixed';
24798 onRender : function(ct, position)
24800 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24803 var cfg = Roo.apply({}, this.getAutoCreate());
24807 cfg.cls += ' ' + this.cls;
24810 cfg.style = this.style;
24812 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24814 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24817 this.el.select('>button.close').on('click', this.hide, this);
24823 if (!this.rendered) {
24829 this.fireEvent('show', this);
24835 if (!this.rendered) {
24841 this.fireEvent('hide', this);
24844 update : function()
24846 // var e = this.el.dom.firstChild;
24848 // if(this.closable){
24849 // e = e.nextSibling;
24852 // e.data = this.html || '';
24854 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24870 * @class Roo.bootstrap.Graph
24871 * @extends Roo.bootstrap.Component
24872 * Bootstrap Graph class
24876 @cfg {String} graphtype bar | vbar | pie
24877 @cfg {number} g_x coodinator | centre x (pie)
24878 @cfg {number} g_y coodinator | centre y (pie)
24879 @cfg {number} g_r radius (pie)
24880 @cfg {number} g_height height of the chart (respected by all elements in the set)
24881 @cfg {number} g_width width of the chart (respected by all elements in the set)
24882 @cfg {Object} title The title of the chart
24885 -opts (object) options for the chart
24887 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24888 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24890 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.
24891 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24893 o stretch (boolean)
24895 -opts (object) options for the pie
24898 o startAngle (number)
24899 o endAngle (number)
24903 * Create a new Input
24904 * @param {Object} config The config object
24907 Roo.bootstrap.Graph = function(config){
24908 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24914 * The img click event for the img.
24915 * @param {Roo.EventObject} e
24921 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24932 //g_colors: this.colors,
24939 getAutoCreate : function(){
24950 onRender : function(ct,position){
24953 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24955 if (typeof(Raphael) == 'undefined') {
24956 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24960 this.raphael = Raphael(this.el.dom);
24962 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24963 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24964 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24965 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24967 r.text(160, 10, "Single Series Chart").attr(txtattr);
24968 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24969 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24970 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24972 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24973 r.barchart(330, 10, 300, 220, data1);
24974 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24975 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24978 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24979 // r.barchart(30, 30, 560, 250, xdata, {
24980 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24981 // axis : "0 0 1 1",
24982 // axisxlabels : xdata
24983 // //yvalues : cols,
24986 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24988 // this.load(null,xdata,{
24989 // axis : "0 0 1 1",
24990 // axisxlabels : xdata
24995 load : function(graphtype,xdata,opts)
24997 this.raphael.clear();
24999 graphtype = this.graphtype;
25004 var r = this.raphael,
25005 fin = function () {
25006 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25008 fout = function () {
25009 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25011 pfin = function() {
25012 this.sector.stop();
25013 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25016 this.label[0].stop();
25017 this.label[0].attr({ r: 7.5 });
25018 this.label[1].attr({ "font-weight": 800 });
25021 pfout = function() {
25022 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25025 this.label[0].animate({ r: 5 }, 500, "bounce");
25026 this.label[1].attr({ "font-weight": 400 });
25032 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25035 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25038 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25039 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25041 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25048 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25053 setTitle: function(o)
25058 initEvents: function() {
25061 this.el.on('click', this.onClick, this);
25065 onClick : function(e)
25067 Roo.log('img onclick');
25068 this.fireEvent('click', this, e);
25080 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25083 * @class Roo.bootstrap.dash.NumberBox
25084 * @extends Roo.bootstrap.Component
25085 * Bootstrap NumberBox class
25086 * @cfg {String} headline Box headline
25087 * @cfg {String} content Box content
25088 * @cfg {String} icon Box icon
25089 * @cfg {String} footer Footer text
25090 * @cfg {String} fhref Footer href
25093 * Create a new NumberBox
25094 * @param {Object} config The config object
25098 Roo.bootstrap.dash.NumberBox = function(config){
25099 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25103 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25112 getAutoCreate : function(){
25116 cls : 'small-box ',
25124 cls : 'roo-headline',
25125 html : this.headline
25129 cls : 'roo-content',
25130 html : this.content
25144 cls : 'ion ' + this.icon
25153 cls : 'small-box-footer',
25154 href : this.fhref || '#',
25158 cfg.cn.push(footer);
25165 onRender : function(ct,position){
25166 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25173 setHeadline: function (value)
25175 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25178 setFooter: function (value, href)
25180 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25183 this.el.select('a.small-box-footer',true).first().attr('href', href);
25188 setContent: function (value)
25190 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25193 initEvents: function()
25207 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25210 * @class Roo.bootstrap.dash.TabBox
25211 * @extends Roo.bootstrap.Component
25212 * Bootstrap TabBox class
25213 * @cfg {String} title Title of the TabBox
25214 * @cfg {String} icon Icon of the TabBox
25215 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25216 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25219 * Create a new TabBox
25220 * @param {Object} config The config object
25224 Roo.bootstrap.dash.TabBox = function(config){
25225 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25230 * When a pane is added
25231 * @param {Roo.bootstrap.dash.TabPane} pane
25235 * @event activatepane
25236 * When a pane is activated
25237 * @param {Roo.bootstrap.dash.TabPane} pane
25239 "activatepane" : true
25247 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25252 tabScrollable : false,
25254 getChildContainer : function()
25256 return this.el.select('.tab-content', true).first();
25259 getAutoCreate : function(){
25263 cls: 'pull-left header',
25271 cls: 'fa ' + this.icon
25277 cls: 'nav nav-tabs pull-right',
25283 if(this.tabScrollable){
25290 cls: 'nav nav-tabs pull-right',
25301 cls: 'nav-tabs-custom',
25306 cls: 'tab-content no-padding',
25314 initEvents : function()
25316 //Roo.log('add add pane handler');
25317 this.on('addpane', this.onAddPane, this);
25320 * Updates the box title
25321 * @param {String} html to set the title to.
25323 setTitle : function(value)
25325 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25327 onAddPane : function(pane)
25329 this.panes.push(pane);
25330 //Roo.log('addpane');
25332 // tabs are rendere left to right..
25333 if(!this.showtabs){
25337 var ctr = this.el.select('.nav-tabs', true).first();
25340 var existing = ctr.select('.nav-tab',true);
25341 var qty = existing.getCount();;
25344 var tab = ctr.createChild({
25346 cls : 'nav-tab' + (qty ? '' : ' active'),
25354 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25357 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25359 pane.el.addClass('active');
25364 onTabClick : function(ev,un,ob,pane)
25366 //Roo.log('tab - prev default');
25367 ev.preventDefault();
25370 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25371 pane.tab.addClass('active');
25372 //Roo.log(pane.title);
25373 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25374 // technically we should have a deactivate event.. but maybe add later.
25375 // and it should not de-activate the selected tab...
25376 this.fireEvent('activatepane', pane);
25377 pane.el.addClass('active');
25378 pane.fireEvent('activate');
25383 getActivePane : function()
25386 Roo.each(this.panes, function(p) {
25387 if(p.el.hasClass('active')){
25408 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25410 * @class Roo.bootstrap.TabPane
25411 * @extends Roo.bootstrap.Component
25412 * Bootstrap TabPane class
25413 * @cfg {Boolean} active (false | true) Default false
25414 * @cfg {String} title title of panel
25418 * Create a new TabPane
25419 * @param {Object} config The config object
25422 Roo.bootstrap.dash.TabPane = function(config){
25423 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25429 * When a pane is activated
25430 * @param {Roo.bootstrap.dash.TabPane} pane
25437 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25442 // the tabBox that this is attached to.
25445 getAutoCreate : function()
25453 cfg.cls += ' active';
25458 initEvents : function()
25460 //Roo.log('trigger add pane handler');
25461 this.parent().fireEvent('addpane', this)
25465 * Updates the tab title
25466 * @param {String} html to set the title to.
25468 setTitle: function(str)
25474 this.tab.select('a', true).first().dom.innerHTML = str;
25491 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25494 * @class Roo.bootstrap.menu.Menu
25495 * @extends Roo.bootstrap.Component
25496 * Bootstrap Menu class - container for Menu
25497 * @cfg {String} html Text of the menu
25498 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25499 * @cfg {String} icon Font awesome icon
25500 * @cfg {String} pos Menu align to (top | bottom) default bottom
25504 * Create a new Menu
25505 * @param {Object} config The config object
25509 Roo.bootstrap.menu.Menu = function(config){
25510 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25514 * @event beforeshow
25515 * Fires before this menu is displayed
25516 * @param {Roo.bootstrap.menu.Menu} this
25520 * @event beforehide
25521 * Fires before this menu is hidden
25522 * @param {Roo.bootstrap.menu.Menu} this
25527 * Fires after this menu is displayed
25528 * @param {Roo.bootstrap.menu.Menu} this
25533 * Fires after this menu is hidden
25534 * @param {Roo.bootstrap.menu.Menu} this
25539 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25540 * @param {Roo.bootstrap.menu.Menu} this
25541 * @param {Roo.EventObject} e
25548 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25552 weight : 'default',
25557 getChildContainer : function() {
25558 if(this.isSubMenu){
25562 return this.el.select('ul.dropdown-menu', true).first();
25565 getAutoCreate : function()
25570 cls : 'roo-menu-text',
25578 cls : 'fa ' + this.icon
25589 cls : 'dropdown-button btn btn-' + this.weight,
25594 cls : 'dropdown-toggle btn btn-' + this.weight,
25604 cls : 'dropdown-menu'
25610 if(this.pos == 'top'){
25611 cfg.cls += ' dropup';
25614 if(this.isSubMenu){
25617 cls : 'dropdown-menu'
25624 onRender : function(ct, position)
25626 this.isSubMenu = ct.hasClass('dropdown-submenu');
25628 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25631 initEvents : function()
25633 if(this.isSubMenu){
25637 this.hidden = true;
25639 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25640 this.triggerEl.on('click', this.onTriggerPress, this);
25642 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25643 this.buttonEl.on('click', this.onClick, this);
25649 if(this.isSubMenu){
25653 return this.el.select('ul.dropdown-menu', true).first();
25656 onClick : function(e)
25658 this.fireEvent("click", this, e);
25661 onTriggerPress : function(e)
25663 if (this.isVisible()) {
25670 isVisible : function(){
25671 return !this.hidden;
25676 this.fireEvent("beforeshow", this);
25678 this.hidden = false;
25679 this.el.addClass('open');
25681 Roo.get(document).on("mouseup", this.onMouseUp, this);
25683 this.fireEvent("show", this);
25690 this.fireEvent("beforehide", this);
25692 this.hidden = true;
25693 this.el.removeClass('open');
25695 Roo.get(document).un("mouseup", this.onMouseUp);
25697 this.fireEvent("hide", this);
25700 onMouseUp : function()
25714 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25717 * @class Roo.bootstrap.menu.Item
25718 * @extends Roo.bootstrap.Component
25719 * Bootstrap MenuItem class
25720 * @cfg {Boolean} submenu (true | false) default false
25721 * @cfg {String} html text of the item
25722 * @cfg {String} href the link
25723 * @cfg {Boolean} disable (true | false) default false
25724 * @cfg {Boolean} preventDefault (true | false) default true
25725 * @cfg {String} icon Font awesome icon
25726 * @cfg {String} pos Submenu align to (left | right) default right
25730 * Create a new Item
25731 * @param {Object} config The config object
25735 Roo.bootstrap.menu.Item = function(config){
25736 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25740 * Fires when the mouse is hovering over this menu
25741 * @param {Roo.bootstrap.menu.Item} this
25742 * @param {Roo.EventObject} e
25747 * Fires when the mouse exits this menu
25748 * @param {Roo.bootstrap.menu.Item} this
25749 * @param {Roo.EventObject} e
25755 * The raw click event for the entire grid.
25756 * @param {Roo.EventObject} e
25762 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25767 preventDefault: true,
25772 getAutoCreate : function()
25777 cls : 'roo-menu-item-text',
25785 cls : 'fa ' + this.icon
25794 href : this.href || '#',
25801 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25805 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25807 if(this.pos == 'left'){
25808 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25815 initEvents : function()
25817 this.el.on('mouseover', this.onMouseOver, this);
25818 this.el.on('mouseout', this.onMouseOut, this);
25820 this.el.select('a', true).first().on('click', this.onClick, this);
25824 onClick : function(e)
25826 if(this.preventDefault){
25827 e.preventDefault();
25830 this.fireEvent("click", this, e);
25833 onMouseOver : function(e)
25835 if(this.submenu && this.pos == 'left'){
25836 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25839 this.fireEvent("mouseover", this, e);
25842 onMouseOut : function(e)
25844 this.fireEvent("mouseout", this, e);
25856 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25859 * @class Roo.bootstrap.menu.Separator
25860 * @extends Roo.bootstrap.Component
25861 * Bootstrap Separator class
25864 * Create a new Separator
25865 * @param {Object} config The config object
25869 Roo.bootstrap.menu.Separator = function(config){
25870 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25873 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25875 getAutoCreate : function(){
25896 * @class Roo.bootstrap.Tooltip
25897 * Bootstrap Tooltip class
25898 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25899 * to determine which dom element triggers the tooltip.
25901 * It needs to add support for additional attributes like tooltip-position
25904 * Create a new Toolti
25905 * @param {Object} config The config object
25908 Roo.bootstrap.Tooltip = function(config){
25909 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25911 this.alignment = Roo.bootstrap.Tooltip.alignment;
25913 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25914 this.alignment = config.alignment;
25919 Roo.apply(Roo.bootstrap.Tooltip, {
25921 * @function init initialize tooltip monitoring.
25925 currentTip : false,
25926 currentRegion : false,
25932 Roo.get(document).on('mouseover', this.enter ,this);
25933 Roo.get(document).on('mouseout', this.leave, this);
25936 this.currentTip = new Roo.bootstrap.Tooltip();
25939 enter : function(ev)
25941 var dom = ev.getTarget();
25943 //Roo.log(['enter',dom]);
25944 var el = Roo.fly(dom);
25945 if (this.currentEl) {
25947 //Roo.log(this.currentEl);
25948 //Roo.log(this.currentEl.contains(dom));
25949 if (this.currentEl == el) {
25952 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25958 if (this.currentTip.el) {
25959 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25963 if(!el || el.dom == document){
25969 // you can not look for children, as if el is the body.. then everythign is the child..
25970 if (!el.attr('tooltip')) { //
25971 if (!el.select("[tooltip]").elements.length) {
25974 // is the mouse over this child...?
25975 bindEl = el.select("[tooltip]").first();
25976 var xy = ev.getXY();
25977 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25978 //Roo.log("not in region.");
25981 //Roo.log("child element over..");
25984 this.currentEl = bindEl;
25985 this.currentTip.bind(bindEl);
25986 this.currentRegion = Roo.lib.Region.getRegion(dom);
25987 this.currentTip.enter();
25990 leave : function(ev)
25992 var dom = ev.getTarget();
25993 //Roo.log(['leave',dom]);
25994 if (!this.currentEl) {
25999 if (dom != this.currentEl.dom) {
26002 var xy = ev.getXY();
26003 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26006 // only activate leave if mouse cursor is outside... bounding box..
26011 if (this.currentTip) {
26012 this.currentTip.leave();
26014 //Roo.log('clear currentEl');
26015 this.currentEl = false;
26020 'left' : ['r-l', [-2,0], 'right'],
26021 'right' : ['l-r', [2,0], 'left'],
26022 'bottom' : ['t-b', [0,2], 'top'],
26023 'top' : [ 'b-t', [0,-2], 'bottom']
26029 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26034 delay : null, // can be { show : 300 , hide: 500}
26038 hoverState : null, //???
26040 placement : 'bottom',
26044 getAutoCreate : function(){
26051 cls : 'tooltip-arrow'
26054 cls : 'tooltip-inner'
26061 bind : function(el)
26067 enter : function () {
26069 if (this.timeout != null) {
26070 clearTimeout(this.timeout);
26073 this.hoverState = 'in';
26074 //Roo.log("enter - show");
26075 if (!this.delay || !this.delay.show) {
26080 this.timeout = setTimeout(function () {
26081 if (_t.hoverState == 'in') {
26084 }, this.delay.show);
26088 clearTimeout(this.timeout);
26090 this.hoverState = 'out';
26091 if (!this.delay || !this.delay.hide) {
26097 this.timeout = setTimeout(function () {
26098 //Roo.log("leave - timeout");
26100 if (_t.hoverState == 'out') {
26102 Roo.bootstrap.Tooltip.currentEl = false;
26107 show : function (msg)
26110 this.render(document.body);
26113 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26115 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26117 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26119 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26121 var placement = typeof this.placement == 'function' ?
26122 this.placement.call(this, this.el, on_el) :
26125 var autoToken = /\s?auto?\s?/i;
26126 var autoPlace = autoToken.test(placement);
26128 placement = placement.replace(autoToken, '') || 'top';
26132 //this.el.setXY([0,0]);
26134 //this.el.dom.style.display='block';
26136 //this.el.appendTo(on_el);
26138 var p = this.getPosition();
26139 var box = this.el.getBox();
26145 var align = this.alignment[placement];
26147 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26149 if(placement == 'top' || placement == 'bottom'){
26151 placement = 'right';
26154 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26155 placement = 'left';
26158 var scroll = Roo.select('body', true).first().getScroll();
26160 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26166 this.el.alignTo(this.bindEl, align[0],align[1]);
26167 //var arrow = this.el.select('.arrow',true).first();
26168 //arrow.set(align[2],
26170 this.el.addClass(placement);
26172 this.el.addClass('in fade');
26174 this.hoverState = null;
26176 if (this.el.hasClass('fade')) {
26187 //this.el.setXY([0,0]);
26188 this.el.removeClass('in');
26204 * @class Roo.bootstrap.LocationPicker
26205 * @extends Roo.bootstrap.Component
26206 * Bootstrap LocationPicker class
26207 * @cfg {Number} latitude Position when init default 0
26208 * @cfg {Number} longitude Position when init default 0
26209 * @cfg {Number} zoom default 15
26210 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26211 * @cfg {Boolean} mapTypeControl default false
26212 * @cfg {Boolean} disableDoubleClickZoom default false
26213 * @cfg {Boolean} scrollwheel default true
26214 * @cfg {Boolean} streetViewControl default false
26215 * @cfg {Number} radius default 0
26216 * @cfg {String} locationName
26217 * @cfg {Boolean} draggable default true
26218 * @cfg {Boolean} enableAutocomplete default false
26219 * @cfg {Boolean} enableReverseGeocode default true
26220 * @cfg {String} markerTitle
26223 * Create a new LocationPicker
26224 * @param {Object} config The config object
26228 Roo.bootstrap.LocationPicker = function(config){
26230 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26235 * Fires when the picker initialized.
26236 * @param {Roo.bootstrap.LocationPicker} this
26237 * @param {Google Location} location
26241 * @event positionchanged
26242 * Fires when the picker position changed.
26243 * @param {Roo.bootstrap.LocationPicker} this
26244 * @param {Google Location} location
26246 positionchanged : true,
26249 * Fires when the map resize.
26250 * @param {Roo.bootstrap.LocationPicker} this
26255 * Fires when the map show.
26256 * @param {Roo.bootstrap.LocationPicker} this
26261 * Fires when the map hide.
26262 * @param {Roo.bootstrap.LocationPicker} this
26267 * Fires when click the map.
26268 * @param {Roo.bootstrap.LocationPicker} this
26269 * @param {Map event} e
26273 * @event mapRightClick
26274 * Fires when right click the map.
26275 * @param {Roo.bootstrap.LocationPicker} this
26276 * @param {Map event} e
26278 mapRightClick : true,
26280 * @event markerClick
26281 * Fires when click the marker.
26282 * @param {Roo.bootstrap.LocationPicker} this
26283 * @param {Map event} e
26285 markerClick : true,
26287 * @event markerRightClick
26288 * Fires when right click the marker.
26289 * @param {Roo.bootstrap.LocationPicker} this
26290 * @param {Map event} e
26292 markerRightClick : true,
26294 * @event OverlayViewDraw
26295 * Fires when OverlayView Draw
26296 * @param {Roo.bootstrap.LocationPicker} this
26298 OverlayViewDraw : true,
26300 * @event OverlayViewOnAdd
26301 * Fires when OverlayView Draw
26302 * @param {Roo.bootstrap.LocationPicker} this
26304 OverlayViewOnAdd : true,
26306 * @event OverlayViewOnRemove
26307 * Fires when OverlayView Draw
26308 * @param {Roo.bootstrap.LocationPicker} this
26310 OverlayViewOnRemove : true,
26312 * @event OverlayViewShow
26313 * Fires when OverlayView Draw
26314 * @param {Roo.bootstrap.LocationPicker} this
26315 * @param {Pixel} cpx
26317 OverlayViewShow : true,
26319 * @event OverlayViewHide
26320 * Fires when OverlayView Draw
26321 * @param {Roo.bootstrap.LocationPicker} this
26323 OverlayViewHide : true,
26325 * @event loadexception
26326 * Fires when load google lib failed.
26327 * @param {Roo.bootstrap.LocationPicker} this
26329 loadexception : true
26334 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26336 gMapContext: false,
26342 mapTypeControl: false,
26343 disableDoubleClickZoom: false,
26345 streetViewControl: false,
26349 enableAutocomplete: false,
26350 enableReverseGeocode: true,
26353 getAutoCreate: function()
26358 cls: 'roo-location-picker'
26364 initEvents: function(ct, position)
26366 if(!this.el.getWidth() || this.isApplied()){
26370 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26375 initial: function()
26377 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26378 this.fireEvent('loadexception', this);
26382 if(!this.mapTypeId){
26383 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26386 this.gMapContext = this.GMapContext();
26388 this.initOverlayView();
26390 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26394 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26395 _this.setPosition(_this.gMapContext.marker.position);
26398 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26399 _this.fireEvent('mapClick', this, event);
26403 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26404 _this.fireEvent('mapRightClick', this, event);
26408 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26409 _this.fireEvent('markerClick', this, event);
26413 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26414 _this.fireEvent('markerRightClick', this, event);
26418 this.setPosition(this.gMapContext.location);
26420 this.fireEvent('initial', this, this.gMapContext.location);
26423 initOverlayView: function()
26427 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26431 _this.fireEvent('OverlayViewDraw', _this);
26436 _this.fireEvent('OverlayViewOnAdd', _this);
26439 onRemove: function()
26441 _this.fireEvent('OverlayViewOnRemove', _this);
26444 show: function(cpx)
26446 _this.fireEvent('OverlayViewShow', _this, cpx);
26451 _this.fireEvent('OverlayViewHide', _this);
26457 fromLatLngToContainerPixel: function(event)
26459 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26462 isApplied: function()
26464 return this.getGmapContext() == false ? false : true;
26467 getGmapContext: function()
26469 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26472 GMapContext: function()
26474 var position = new google.maps.LatLng(this.latitude, this.longitude);
26476 var _map = new google.maps.Map(this.el.dom, {
26479 mapTypeId: this.mapTypeId,
26480 mapTypeControl: this.mapTypeControl,
26481 disableDoubleClickZoom: this.disableDoubleClickZoom,
26482 scrollwheel: this.scrollwheel,
26483 streetViewControl: this.streetViewControl,
26484 locationName: this.locationName,
26485 draggable: this.draggable,
26486 enableAutocomplete: this.enableAutocomplete,
26487 enableReverseGeocode: this.enableReverseGeocode
26490 var _marker = new google.maps.Marker({
26491 position: position,
26493 title: this.markerTitle,
26494 draggable: this.draggable
26501 location: position,
26502 radius: this.radius,
26503 locationName: this.locationName,
26504 addressComponents: {
26505 formatted_address: null,
26506 addressLine1: null,
26507 addressLine2: null,
26509 streetNumber: null,
26513 stateOrProvince: null
26516 domContainer: this.el.dom,
26517 geodecoder: new google.maps.Geocoder()
26521 drawCircle: function(center, radius, options)
26523 if (this.gMapContext.circle != null) {
26524 this.gMapContext.circle.setMap(null);
26528 options = Roo.apply({}, options, {
26529 strokeColor: "#0000FF",
26530 strokeOpacity: .35,
26532 fillColor: "#0000FF",
26536 options.map = this.gMapContext.map;
26537 options.radius = radius;
26538 options.center = center;
26539 this.gMapContext.circle = new google.maps.Circle(options);
26540 return this.gMapContext.circle;
26546 setPosition: function(location)
26548 this.gMapContext.location = location;
26549 this.gMapContext.marker.setPosition(location);
26550 this.gMapContext.map.panTo(location);
26551 this.drawCircle(location, this.gMapContext.radius, {});
26555 if (this.gMapContext.settings.enableReverseGeocode) {
26556 this.gMapContext.geodecoder.geocode({
26557 latLng: this.gMapContext.location
26558 }, function(results, status) {
26560 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26561 _this.gMapContext.locationName = results[0].formatted_address;
26562 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26564 _this.fireEvent('positionchanged', this, location);
26571 this.fireEvent('positionchanged', this, location);
26576 google.maps.event.trigger(this.gMapContext.map, "resize");
26578 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26580 this.fireEvent('resize', this);
26583 setPositionByLatLng: function(latitude, longitude)
26585 this.setPosition(new google.maps.LatLng(latitude, longitude));
26588 getCurrentPosition: function()
26591 latitude: this.gMapContext.location.lat(),
26592 longitude: this.gMapContext.location.lng()
26596 getAddressName: function()
26598 return this.gMapContext.locationName;
26601 getAddressComponents: function()
26603 return this.gMapContext.addressComponents;
26606 address_component_from_google_geocode: function(address_components)
26610 for (var i = 0; i < address_components.length; i++) {
26611 var component = address_components[i];
26612 if (component.types.indexOf("postal_code") >= 0) {
26613 result.postalCode = component.short_name;
26614 } else if (component.types.indexOf("street_number") >= 0) {
26615 result.streetNumber = component.short_name;
26616 } else if (component.types.indexOf("route") >= 0) {
26617 result.streetName = component.short_name;
26618 } else if (component.types.indexOf("neighborhood") >= 0) {
26619 result.city = component.short_name;
26620 } else if (component.types.indexOf("locality") >= 0) {
26621 result.city = component.short_name;
26622 } else if (component.types.indexOf("sublocality") >= 0) {
26623 result.district = component.short_name;
26624 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26625 result.stateOrProvince = component.short_name;
26626 } else if (component.types.indexOf("country") >= 0) {
26627 result.country = component.short_name;
26631 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26632 result.addressLine2 = "";
26636 setZoomLevel: function(zoom)
26638 this.gMapContext.map.setZoom(zoom);
26651 this.fireEvent('show', this);
26662 this.fireEvent('hide', this);
26667 Roo.apply(Roo.bootstrap.LocationPicker, {
26669 OverlayView : function(map, options)
26671 options = options || {};
26685 * @class Roo.bootstrap.Alert
26686 * @extends Roo.bootstrap.Component
26687 * Bootstrap Alert class
26688 * @cfg {String} title The title of alert
26689 * @cfg {String} html The content of alert
26690 * @cfg {String} weight ( success | info | warning | danger )
26691 * @cfg {String} faicon font-awesomeicon
26694 * Create a new alert
26695 * @param {Object} config The config object
26699 Roo.bootstrap.Alert = function(config){
26700 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26704 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26711 getAutoCreate : function()
26720 cls : 'roo-alert-icon'
26725 cls : 'roo-alert-title',
26730 cls : 'roo-alert-text',
26737 cfg.cn[0].cls += ' fa ' + this.faicon;
26741 cfg.cls += ' alert-' + this.weight;
26747 initEvents: function()
26749 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26752 setTitle : function(str)
26754 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26757 setText : function(str)
26759 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26762 setWeight : function(weight)
26765 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26768 this.weight = weight;
26770 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26773 setIcon : function(icon)
26776 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26779 this.faicon = icon;
26781 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26802 * @class Roo.bootstrap.UploadCropbox
26803 * @extends Roo.bootstrap.Component
26804 * Bootstrap UploadCropbox class
26805 * @cfg {String} emptyText show when image has been loaded
26806 * @cfg {String} rotateNotify show when image too small to rotate
26807 * @cfg {Number} errorTimeout default 3000
26808 * @cfg {Number} minWidth default 300
26809 * @cfg {Number} minHeight default 300
26810 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26811 * @cfg {Boolean} isDocument (true|false) default false
26812 * @cfg {String} url action url
26813 * @cfg {String} paramName default 'imageUpload'
26814 * @cfg {String} method default POST
26815 * @cfg {Boolean} loadMask (true|false) default true
26816 * @cfg {Boolean} loadingText default 'Loading...'
26819 * Create a new UploadCropbox
26820 * @param {Object} config The config object
26823 Roo.bootstrap.UploadCropbox = function(config){
26824 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26828 * @event beforeselectfile
26829 * Fire before select file
26830 * @param {Roo.bootstrap.UploadCropbox} this
26832 "beforeselectfile" : true,
26835 * Fire after initEvent
26836 * @param {Roo.bootstrap.UploadCropbox} this
26841 * Fire after initEvent
26842 * @param {Roo.bootstrap.UploadCropbox} this
26843 * @param {String} data
26848 * Fire when preparing the file data
26849 * @param {Roo.bootstrap.UploadCropbox} this
26850 * @param {Object} file
26855 * Fire when get exception
26856 * @param {Roo.bootstrap.UploadCropbox} this
26857 * @param {XMLHttpRequest} xhr
26859 "exception" : true,
26861 * @event beforeloadcanvas
26862 * Fire before load the canvas
26863 * @param {Roo.bootstrap.UploadCropbox} this
26864 * @param {String} src
26866 "beforeloadcanvas" : true,
26869 * Fire when trash image
26870 * @param {Roo.bootstrap.UploadCropbox} this
26875 * Fire when download the image
26876 * @param {Roo.bootstrap.UploadCropbox} this
26880 * @event footerbuttonclick
26881 * Fire when footerbuttonclick
26882 * @param {Roo.bootstrap.UploadCropbox} this
26883 * @param {String} type
26885 "footerbuttonclick" : true,
26889 * @param {Roo.bootstrap.UploadCropbox} this
26894 * Fire when rotate the image
26895 * @param {Roo.bootstrap.UploadCropbox} this
26896 * @param {String} pos
26901 * Fire when inspect the file
26902 * @param {Roo.bootstrap.UploadCropbox} this
26903 * @param {Object} file
26908 * Fire when xhr upload the file
26909 * @param {Roo.bootstrap.UploadCropbox} this
26910 * @param {Object} data
26915 * Fire when arrange the file data
26916 * @param {Roo.bootstrap.UploadCropbox} this
26917 * @param {Object} formData
26922 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26925 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26927 emptyText : 'Click to upload image',
26928 rotateNotify : 'Image is too small to rotate',
26929 errorTimeout : 3000,
26943 cropType : 'image/jpeg',
26945 canvasLoaded : false,
26946 isDocument : false,
26948 paramName : 'imageUpload',
26950 loadingText : 'Loading...',
26953 getAutoCreate : function()
26957 cls : 'roo-upload-cropbox',
26961 cls : 'roo-upload-cropbox-selector',
26966 cls : 'roo-upload-cropbox-body',
26967 style : 'cursor:pointer',
26971 cls : 'roo-upload-cropbox-preview'
26975 cls : 'roo-upload-cropbox-thumb'
26979 cls : 'roo-upload-cropbox-empty-notify',
26980 html : this.emptyText
26984 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26985 html : this.rotateNotify
26991 cls : 'roo-upload-cropbox-footer',
26994 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27004 onRender : function(ct, position)
27006 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27008 if (this.buttons.length) {
27010 Roo.each(this.buttons, function(bb) {
27012 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27014 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27020 this.maskEl = this.el;
27024 initEvents : function()
27026 this.urlAPI = (window.createObjectURL && window) ||
27027 (window.URL && URL.revokeObjectURL && URL) ||
27028 (window.webkitURL && webkitURL);
27030 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27031 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27033 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27034 this.selectorEl.hide();
27036 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27037 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27039 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27040 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27041 this.thumbEl.hide();
27043 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27044 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27046 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27047 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27048 this.errorEl.hide();
27050 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27051 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27052 this.footerEl.hide();
27054 this.setThumbBoxSize();
27060 this.fireEvent('initial', this);
27067 window.addEventListener("resize", function() { _this.resize(); } );
27069 this.bodyEl.on('click', this.beforeSelectFile, this);
27072 this.bodyEl.on('touchstart', this.onTouchStart, this);
27073 this.bodyEl.on('touchmove', this.onTouchMove, this);
27074 this.bodyEl.on('touchend', this.onTouchEnd, this);
27078 this.bodyEl.on('mousedown', this.onMouseDown, this);
27079 this.bodyEl.on('mousemove', this.onMouseMove, this);
27080 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27081 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27082 Roo.get(document).on('mouseup', this.onMouseUp, this);
27085 this.selectorEl.on('change', this.onFileSelected, this);
27091 this.baseScale = 1;
27093 this.baseRotate = 1;
27094 this.dragable = false;
27095 this.pinching = false;
27098 this.cropData = false;
27099 this.notifyEl.dom.innerHTML = this.emptyText;
27101 this.selectorEl.dom.value = '';
27105 resize : function()
27107 if(this.fireEvent('resize', this) != false){
27108 this.setThumbBoxPosition();
27109 this.setCanvasPosition();
27113 onFooterButtonClick : function(e, el, o, type)
27116 case 'rotate-left' :
27117 this.onRotateLeft(e);
27119 case 'rotate-right' :
27120 this.onRotateRight(e);
27123 this.beforeSelectFile(e);
27138 this.fireEvent('footerbuttonclick', this, type);
27141 beforeSelectFile : function(e)
27143 e.preventDefault();
27145 if(this.fireEvent('beforeselectfile', this) != false){
27146 this.selectorEl.dom.click();
27150 onFileSelected : function(e)
27152 e.preventDefault();
27154 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27158 var file = this.selectorEl.dom.files[0];
27160 if(this.fireEvent('inspect', this, file) != false){
27161 this.prepare(file);
27166 trash : function(e)
27168 this.fireEvent('trash', this);
27171 download : function(e)
27173 this.fireEvent('download', this);
27176 loadCanvas : function(src)
27178 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27182 this.imageEl = document.createElement('img');
27186 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27188 this.imageEl.src = src;
27192 onLoadCanvas : function()
27194 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27195 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27197 this.bodyEl.un('click', this.beforeSelectFile, this);
27199 this.notifyEl.hide();
27200 this.thumbEl.show();
27201 this.footerEl.show();
27203 this.baseRotateLevel();
27205 if(this.isDocument){
27206 this.setThumbBoxSize();
27209 this.setThumbBoxPosition();
27211 this.baseScaleLevel();
27217 this.canvasLoaded = true;
27220 this.maskEl.unmask();
27225 setCanvasPosition : function()
27227 if(!this.canvasEl){
27231 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27232 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27234 this.previewEl.setLeft(pw);
27235 this.previewEl.setTop(ph);
27239 onMouseDown : function(e)
27243 this.dragable = true;
27244 this.pinching = false;
27246 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27247 this.dragable = false;
27251 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27252 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27256 onMouseMove : function(e)
27260 if(!this.canvasLoaded){
27264 if (!this.dragable){
27268 var minX = Math.ceil(this.thumbEl.getLeft(true));
27269 var minY = Math.ceil(this.thumbEl.getTop(true));
27271 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27272 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27274 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27275 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27277 x = x - this.mouseX;
27278 y = y - this.mouseY;
27280 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27281 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27283 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27284 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27286 this.previewEl.setLeft(bgX);
27287 this.previewEl.setTop(bgY);
27289 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27290 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27293 onMouseUp : function(e)
27297 this.dragable = false;
27300 onMouseWheel : function(e)
27304 this.startScale = this.scale;
27306 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27308 if(!this.zoomable()){
27309 this.scale = this.startScale;
27318 zoomable : function()
27320 var minScale = this.thumbEl.getWidth() / this.minWidth;
27322 if(this.minWidth < this.minHeight){
27323 minScale = this.thumbEl.getHeight() / this.minHeight;
27326 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27327 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27331 (this.rotate == 0 || this.rotate == 180) &&
27333 width > this.imageEl.OriginWidth ||
27334 height > this.imageEl.OriginHeight ||
27335 (width < this.minWidth && height < this.minHeight)
27343 (this.rotate == 90 || this.rotate == 270) &&
27345 width > this.imageEl.OriginWidth ||
27346 height > this.imageEl.OriginHeight ||
27347 (width < this.minHeight && height < this.minWidth)
27354 !this.isDocument &&
27355 (this.rotate == 0 || this.rotate == 180) &&
27357 width < this.minWidth ||
27358 width > this.imageEl.OriginWidth ||
27359 height < this.minHeight ||
27360 height > this.imageEl.OriginHeight
27367 !this.isDocument &&
27368 (this.rotate == 90 || this.rotate == 270) &&
27370 width < this.minHeight ||
27371 width > this.imageEl.OriginWidth ||
27372 height < this.minWidth ||
27373 height > this.imageEl.OriginHeight
27383 onRotateLeft : function(e)
27385 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27387 var minScale = this.thumbEl.getWidth() / this.minWidth;
27389 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27390 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27392 this.startScale = this.scale;
27394 while (this.getScaleLevel() < minScale){
27396 this.scale = this.scale + 1;
27398 if(!this.zoomable()){
27403 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27404 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27409 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27416 this.scale = this.startScale;
27418 this.onRotateFail();
27423 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27425 if(this.isDocument){
27426 this.setThumbBoxSize();
27427 this.setThumbBoxPosition();
27428 this.setCanvasPosition();
27433 this.fireEvent('rotate', this, 'left');
27437 onRotateRight : function(e)
27439 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27441 var minScale = this.thumbEl.getWidth() / this.minWidth;
27443 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27444 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27446 this.startScale = this.scale;
27448 while (this.getScaleLevel() < minScale){
27450 this.scale = this.scale + 1;
27452 if(!this.zoomable()){
27457 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27458 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27463 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27470 this.scale = this.startScale;
27472 this.onRotateFail();
27477 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27479 if(this.isDocument){
27480 this.setThumbBoxSize();
27481 this.setThumbBoxPosition();
27482 this.setCanvasPosition();
27487 this.fireEvent('rotate', this, 'right');
27490 onRotateFail : function()
27492 this.errorEl.show(true);
27496 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27501 this.previewEl.dom.innerHTML = '';
27503 var canvasEl = document.createElement("canvas");
27505 var contextEl = canvasEl.getContext("2d");
27507 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27508 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27509 var center = this.imageEl.OriginWidth / 2;
27511 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27512 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27513 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27514 center = this.imageEl.OriginHeight / 2;
27517 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27519 contextEl.translate(center, center);
27520 contextEl.rotate(this.rotate * Math.PI / 180);
27522 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27524 this.canvasEl = document.createElement("canvas");
27526 this.contextEl = this.canvasEl.getContext("2d");
27528 switch (this.rotate) {
27531 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27532 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27534 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27539 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27540 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27542 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27543 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);
27547 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27552 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27553 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27555 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27556 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);
27560 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);
27565 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27566 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27568 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27569 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27573 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);
27580 this.previewEl.appendChild(this.canvasEl);
27582 this.setCanvasPosition();
27587 if(!this.canvasLoaded){
27591 var imageCanvas = document.createElement("canvas");
27593 var imageContext = imageCanvas.getContext("2d");
27595 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27596 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27598 var center = imageCanvas.width / 2;
27600 imageContext.translate(center, center);
27602 imageContext.rotate(this.rotate * Math.PI / 180);
27604 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27606 var canvas = document.createElement("canvas");
27608 var context = canvas.getContext("2d");
27610 canvas.width = this.minWidth;
27611 canvas.height = this.minHeight;
27613 switch (this.rotate) {
27616 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27617 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27619 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27620 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27622 var targetWidth = this.minWidth - 2 * x;
27623 var targetHeight = this.minHeight - 2 * y;
27627 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27628 scale = targetWidth / width;
27631 if(x > 0 && y == 0){
27632 scale = targetHeight / height;
27635 if(x > 0 && y > 0){
27636 scale = targetWidth / width;
27638 if(width < height){
27639 scale = targetHeight / height;
27643 context.scale(scale, scale);
27645 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27646 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27648 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27649 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27651 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27656 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27657 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27659 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27660 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27662 var targetWidth = this.minWidth - 2 * x;
27663 var targetHeight = this.minHeight - 2 * y;
27667 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27668 scale = targetWidth / width;
27671 if(x > 0 && y == 0){
27672 scale = targetHeight / height;
27675 if(x > 0 && y > 0){
27676 scale = targetWidth / width;
27678 if(width < height){
27679 scale = targetHeight / height;
27683 context.scale(scale, scale);
27685 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27686 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27688 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27689 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27691 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27693 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27698 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27699 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27701 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27702 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27704 var targetWidth = this.minWidth - 2 * x;
27705 var targetHeight = this.minHeight - 2 * y;
27709 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27710 scale = targetWidth / width;
27713 if(x > 0 && y == 0){
27714 scale = targetHeight / height;
27717 if(x > 0 && y > 0){
27718 scale = targetWidth / width;
27720 if(width < height){
27721 scale = targetHeight / height;
27725 context.scale(scale, scale);
27727 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27728 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27730 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27731 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27733 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27734 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27736 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27741 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27742 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27744 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27745 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27747 var targetWidth = this.minWidth - 2 * x;
27748 var targetHeight = this.minHeight - 2 * y;
27752 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27753 scale = targetWidth / width;
27756 if(x > 0 && y == 0){
27757 scale = targetHeight / height;
27760 if(x > 0 && y > 0){
27761 scale = targetWidth / width;
27763 if(width < height){
27764 scale = targetHeight / height;
27768 context.scale(scale, scale);
27770 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27771 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27773 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27774 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27776 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27778 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27785 this.cropData = canvas.toDataURL(this.cropType);
27787 if(this.fireEvent('crop', this, this.cropData) !== false){
27788 this.process(this.file, this.cropData);
27795 setThumbBoxSize : function()
27799 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27800 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27801 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27803 this.minWidth = width;
27804 this.minHeight = height;
27806 if(this.rotate == 90 || this.rotate == 270){
27807 this.minWidth = height;
27808 this.minHeight = width;
27813 width = Math.ceil(this.minWidth * height / this.minHeight);
27815 if(this.minWidth > this.minHeight){
27817 height = Math.ceil(this.minHeight * width / this.minWidth);
27820 this.thumbEl.setStyle({
27821 width : width + 'px',
27822 height : height + 'px'
27829 setThumbBoxPosition : function()
27831 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27832 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27834 this.thumbEl.setLeft(x);
27835 this.thumbEl.setTop(y);
27839 baseRotateLevel : function()
27841 this.baseRotate = 1;
27844 typeof(this.exif) != 'undefined' &&
27845 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27846 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27848 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27851 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27855 baseScaleLevel : function()
27859 if(this.isDocument){
27861 if(this.baseRotate == 6 || this.baseRotate == 8){
27863 height = this.thumbEl.getHeight();
27864 this.baseScale = height / this.imageEl.OriginWidth;
27866 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27867 width = this.thumbEl.getWidth();
27868 this.baseScale = width / this.imageEl.OriginHeight;
27874 height = this.thumbEl.getHeight();
27875 this.baseScale = height / this.imageEl.OriginHeight;
27877 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27878 width = this.thumbEl.getWidth();
27879 this.baseScale = width / this.imageEl.OriginWidth;
27885 if(this.baseRotate == 6 || this.baseRotate == 8){
27887 width = this.thumbEl.getHeight();
27888 this.baseScale = width / this.imageEl.OriginHeight;
27890 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27891 height = this.thumbEl.getWidth();
27892 this.baseScale = height / this.imageEl.OriginHeight;
27895 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27896 height = this.thumbEl.getWidth();
27897 this.baseScale = height / this.imageEl.OriginHeight;
27899 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27900 width = this.thumbEl.getHeight();
27901 this.baseScale = width / this.imageEl.OriginWidth;
27908 width = this.thumbEl.getWidth();
27909 this.baseScale = width / this.imageEl.OriginWidth;
27911 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27912 height = this.thumbEl.getHeight();
27913 this.baseScale = height / this.imageEl.OriginHeight;
27916 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27918 height = this.thumbEl.getHeight();
27919 this.baseScale = height / this.imageEl.OriginHeight;
27921 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27922 width = this.thumbEl.getWidth();
27923 this.baseScale = width / this.imageEl.OriginWidth;
27931 getScaleLevel : function()
27933 return this.baseScale * Math.pow(1.1, this.scale);
27936 onTouchStart : function(e)
27938 if(!this.canvasLoaded){
27939 this.beforeSelectFile(e);
27943 var touches = e.browserEvent.touches;
27949 if(touches.length == 1){
27950 this.onMouseDown(e);
27954 if(touches.length != 2){
27960 for(var i = 0, finger; finger = touches[i]; i++){
27961 coords.push(finger.pageX, finger.pageY);
27964 var x = Math.pow(coords[0] - coords[2], 2);
27965 var y = Math.pow(coords[1] - coords[3], 2);
27967 this.startDistance = Math.sqrt(x + y);
27969 this.startScale = this.scale;
27971 this.pinching = true;
27972 this.dragable = false;
27976 onTouchMove : function(e)
27978 if(!this.pinching && !this.dragable){
27982 var touches = e.browserEvent.touches;
27989 this.onMouseMove(e);
27995 for(var i = 0, finger; finger = touches[i]; i++){
27996 coords.push(finger.pageX, finger.pageY);
27999 var x = Math.pow(coords[0] - coords[2], 2);
28000 var y = Math.pow(coords[1] - coords[3], 2);
28002 this.endDistance = Math.sqrt(x + y);
28004 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28006 if(!this.zoomable()){
28007 this.scale = this.startScale;
28015 onTouchEnd : function(e)
28017 this.pinching = false;
28018 this.dragable = false;
28022 process : function(file, crop)
28025 this.maskEl.mask(this.loadingText);
28028 this.xhr = new XMLHttpRequest();
28030 file.xhr = this.xhr;
28032 this.xhr.open(this.method, this.url, true);
28035 "Accept": "application/json",
28036 "Cache-Control": "no-cache",
28037 "X-Requested-With": "XMLHttpRequest"
28040 for (var headerName in headers) {
28041 var headerValue = headers[headerName];
28043 this.xhr.setRequestHeader(headerName, headerValue);
28049 this.xhr.onload = function()
28051 _this.xhrOnLoad(_this.xhr);
28054 this.xhr.onerror = function()
28056 _this.xhrOnError(_this.xhr);
28059 var formData = new FormData();
28061 formData.append('returnHTML', 'NO');
28064 formData.append('crop', crop);
28067 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28068 formData.append(this.paramName, file, file.name);
28071 if(typeof(file.filename) != 'undefined'){
28072 formData.append('filename', file.filename);
28075 if(typeof(file.mimetype) != 'undefined'){
28076 formData.append('mimetype', file.mimetype);
28079 if(this.fireEvent('arrange', this, formData) != false){
28080 this.xhr.send(formData);
28084 xhrOnLoad : function(xhr)
28087 this.maskEl.unmask();
28090 if (xhr.readyState !== 4) {
28091 this.fireEvent('exception', this, xhr);
28095 var response = Roo.decode(xhr.responseText);
28097 if(!response.success){
28098 this.fireEvent('exception', this, xhr);
28102 var response = Roo.decode(xhr.responseText);
28104 this.fireEvent('upload', this, response);
28108 xhrOnError : function()
28111 this.maskEl.unmask();
28114 Roo.log('xhr on error');
28116 var response = Roo.decode(xhr.responseText);
28122 prepare : function(file)
28125 this.maskEl.mask(this.loadingText);
28131 if(typeof(file) === 'string'){
28132 this.loadCanvas(file);
28136 if(!file || !this.urlAPI){
28141 this.cropType = file.type;
28145 if(this.fireEvent('prepare', this, this.file) != false){
28147 var reader = new FileReader();
28149 reader.onload = function (e) {
28150 if (e.target.error) {
28151 Roo.log(e.target.error);
28155 var buffer = e.target.result,
28156 dataView = new DataView(buffer),
28158 maxOffset = dataView.byteLength - 4,
28162 if (dataView.getUint16(0) === 0xffd8) {
28163 while (offset < maxOffset) {
28164 markerBytes = dataView.getUint16(offset);
28166 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28167 markerLength = dataView.getUint16(offset + 2) + 2;
28168 if (offset + markerLength > dataView.byteLength) {
28169 Roo.log('Invalid meta data: Invalid segment size.');
28173 if(markerBytes == 0xffe1){
28174 _this.parseExifData(
28181 offset += markerLength;
28191 var url = _this.urlAPI.createObjectURL(_this.file);
28193 _this.loadCanvas(url);
28198 reader.readAsArrayBuffer(this.file);
28204 parseExifData : function(dataView, offset, length)
28206 var tiffOffset = offset + 10,
28210 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28211 // No Exif data, might be XMP data instead
28215 // Check for the ASCII code for "Exif" (0x45786966):
28216 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28217 // No Exif data, might be XMP data instead
28220 if (tiffOffset + 8 > dataView.byteLength) {
28221 Roo.log('Invalid Exif data: Invalid segment size.');
28224 // Check for the two null bytes:
28225 if (dataView.getUint16(offset + 8) !== 0x0000) {
28226 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28229 // Check the byte alignment:
28230 switch (dataView.getUint16(tiffOffset)) {
28232 littleEndian = true;
28235 littleEndian = false;
28238 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28241 // Check for the TIFF tag marker (0x002A):
28242 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28243 Roo.log('Invalid Exif data: Missing TIFF marker.');
28246 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28247 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28249 this.parseExifTags(
28252 tiffOffset + dirOffset,
28257 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28262 if (dirOffset + 6 > dataView.byteLength) {
28263 Roo.log('Invalid Exif data: Invalid directory offset.');
28266 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28267 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28268 if (dirEndOffset + 4 > dataView.byteLength) {
28269 Roo.log('Invalid Exif data: Invalid directory size.');
28272 for (i = 0; i < tagsNumber; i += 1) {
28276 dirOffset + 2 + 12 * i, // tag offset
28280 // Return the offset to the next directory:
28281 return dataView.getUint32(dirEndOffset, littleEndian);
28284 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28286 var tag = dataView.getUint16(offset, littleEndian);
28288 this.exif[tag] = this.getExifValue(
28292 dataView.getUint16(offset + 2, littleEndian), // tag type
28293 dataView.getUint32(offset + 4, littleEndian), // tag length
28298 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28300 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28309 Roo.log('Invalid Exif data: Invalid tag type.');
28313 tagSize = tagType.size * length;
28314 // Determine if the value is contained in the dataOffset bytes,
28315 // or if the value at the dataOffset is a pointer to the actual data:
28316 dataOffset = tagSize > 4 ?
28317 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28318 if (dataOffset + tagSize > dataView.byteLength) {
28319 Roo.log('Invalid Exif data: Invalid data offset.');
28322 if (length === 1) {
28323 return tagType.getValue(dataView, dataOffset, littleEndian);
28326 for (i = 0; i < length; i += 1) {
28327 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28330 if (tagType.ascii) {
28332 // Concatenate the chars:
28333 for (i = 0; i < values.length; i += 1) {
28335 // Ignore the terminating NULL byte(s):
28336 if (c === '\u0000') {
28348 Roo.apply(Roo.bootstrap.UploadCropbox, {
28350 'Orientation': 0x0112
28354 1: 0, //'top-left',
28356 3: 180, //'bottom-right',
28357 // 4: 'bottom-left',
28359 6: 90, //'right-top',
28360 // 7: 'right-bottom',
28361 8: 270 //'left-bottom'
28365 // byte, 8-bit unsigned int:
28367 getValue: function (dataView, dataOffset) {
28368 return dataView.getUint8(dataOffset);
28372 // ascii, 8-bit byte:
28374 getValue: function (dataView, dataOffset) {
28375 return String.fromCharCode(dataView.getUint8(dataOffset));
28380 // short, 16 bit int:
28382 getValue: function (dataView, dataOffset, littleEndian) {
28383 return dataView.getUint16(dataOffset, littleEndian);
28387 // long, 32 bit int:
28389 getValue: function (dataView, dataOffset, littleEndian) {
28390 return dataView.getUint32(dataOffset, littleEndian);
28394 // rational = two long values, first is numerator, second is denominator:
28396 getValue: function (dataView, dataOffset, littleEndian) {
28397 return dataView.getUint32(dataOffset, littleEndian) /
28398 dataView.getUint32(dataOffset + 4, littleEndian);
28402 // slong, 32 bit signed int:
28404 getValue: function (dataView, dataOffset, littleEndian) {
28405 return dataView.getInt32(dataOffset, littleEndian);
28409 // srational, two slongs, first is numerator, second is denominator:
28411 getValue: function (dataView, dataOffset, littleEndian) {
28412 return dataView.getInt32(dataOffset, littleEndian) /
28413 dataView.getInt32(dataOffset + 4, littleEndian);
28423 cls : 'btn-group roo-upload-cropbox-rotate-left',
28424 action : 'rotate-left',
28428 cls : 'btn btn-default',
28429 html : '<i class="fa fa-undo"></i>'
28435 cls : 'btn-group roo-upload-cropbox-picture',
28436 action : 'picture',
28440 cls : 'btn btn-default',
28441 html : '<i class="fa fa-picture-o"></i>'
28447 cls : 'btn-group roo-upload-cropbox-rotate-right',
28448 action : 'rotate-right',
28452 cls : 'btn btn-default',
28453 html : '<i class="fa fa-repeat"></i>'
28461 cls : 'btn-group roo-upload-cropbox-rotate-left',
28462 action : 'rotate-left',
28466 cls : 'btn btn-default',
28467 html : '<i class="fa fa-undo"></i>'
28473 cls : 'btn-group roo-upload-cropbox-download',
28474 action : 'download',
28478 cls : 'btn btn-default',
28479 html : '<i class="fa fa-download"></i>'
28485 cls : 'btn-group roo-upload-cropbox-crop',
28490 cls : 'btn btn-default',
28491 html : '<i class="fa fa-crop"></i>'
28497 cls : 'btn-group roo-upload-cropbox-trash',
28502 cls : 'btn btn-default',
28503 html : '<i class="fa fa-trash"></i>'
28509 cls : 'btn-group roo-upload-cropbox-rotate-right',
28510 action : 'rotate-right',
28514 cls : 'btn btn-default',
28515 html : '<i class="fa fa-repeat"></i>'
28523 cls : 'btn-group roo-upload-cropbox-rotate-left',
28524 action : 'rotate-left',
28528 cls : 'btn btn-default',
28529 html : '<i class="fa fa-undo"></i>'
28535 cls : 'btn-group roo-upload-cropbox-rotate-right',
28536 action : 'rotate-right',
28540 cls : 'btn btn-default',
28541 html : '<i class="fa fa-repeat"></i>'
28554 * @class Roo.bootstrap.DocumentManager
28555 * @extends Roo.bootstrap.Component
28556 * Bootstrap DocumentManager class
28557 * @cfg {String} paramName default 'imageUpload'
28558 * @cfg {String} toolTipName default 'filename'
28559 * @cfg {String} method default POST
28560 * @cfg {String} url action url
28561 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28562 * @cfg {Boolean} multiple multiple upload default true
28563 * @cfg {Number} thumbSize default 300
28564 * @cfg {String} fieldLabel
28565 * @cfg {Number} labelWidth default 4
28566 * @cfg {String} labelAlign (left|top) default left
28567 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28568 * @cfg {Number} labellg set the width of label (1-12)
28569 * @cfg {Number} labelmd set the width of label (1-12)
28570 * @cfg {Number} labelsm set the width of label (1-12)
28571 * @cfg {Number} labelxs set the width of label (1-12)
28574 * Create a new DocumentManager
28575 * @param {Object} config The config object
28578 Roo.bootstrap.DocumentManager = function(config){
28579 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28582 this.delegates = [];
28587 * Fire when initial the DocumentManager
28588 * @param {Roo.bootstrap.DocumentManager} this
28593 * inspect selected file
28594 * @param {Roo.bootstrap.DocumentManager} this
28595 * @param {File} file
28600 * Fire when xhr load exception
28601 * @param {Roo.bootstrap.DocumentManager} this
28602 * @param {XMLHttpRequest} xhr
28604 "exception" : true,
28606 * @event afterupload
28607 * Fire when xhr load exception
28608 * @param {Roo.bootstrap.DocumentManager} this
28609 * @param {XMLHttpRequest} xhr
28611 "afterupload" : true,
28614 * prepare the form data
28615 * @param {Roo.bootstrap.DocumentManager} this
28616 * @param {Object} formData
28621 * Fire when remove the file
28622 * @param {Roo.bootstrap.DocumentManager} this
28623 * @param {Object} file
28628 * Fire after refresh the file
28629 * @param {Roo.bootstrap.DocumentManager} this
28634 * Fire after click the image
28635 * @param {Roo.bootstrap.DocumentManager} this
28636 * @param {Object} file
28641 * Fire when upload a image and editable set to true
28642 * @param {Roo.bootstrap.DocumentManager} this
28643 * @param {Object} file
28647 * @event beforeselectfile
28648 * Fire before select file
28649 * @param {Roo.bootstrap.DocumentManager} this
28651 "beforeselectfile" : true,
28654 * Fire before process file
28655 * @param {Roo.bootstrap.DocumentManager} this
28656 * @param {Object} file
28660 * @event previewrendered
28661 * Fire when preview rendered
28662 * @param {Roo.bootstrap.DocumentManager} this
28663 * @param {Object} file
28665 "previewrendered" : true
28670 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28679 paramName : 'imageUpload',
28680 toolTipName : 'filename',
28683 labelAlign : 'left',
28693 getAutoCreate : function()
28695 var managerWidget = {
28697 cls : 'roo-document-manager',
28701 cls : 'roo-document-manager-selector',
28706 cls : 'roo-document-manager-uploader',
28710 cls : 'roo-document-manager-upload-btn',
28711 html : '<i class="fa fa-plus"></i>'
28722 cls : 'column col-md-12',
28727 if(this.fieldLabel.length){
28732 cls : 'column col-md-12',
28733 html : this.fieldLabel
28737 cls : 'column col-md-12',
28742 if(this.labelAlign == 'left'){
28747 html : this.fieldLabel
28756 if(this.labelWidth > 12){
28757 content[0].style = "width: " + this.labelWidth + 'px';
28760 if(this.labelWidth < 13 && this.labelmd == 0){
28761 this.labelmd = this.labelWidth;
28764 if(this.labellg > 0){
28765 content[0].cls += ' col-lg-' + this.labellg;
28766 content[1].cls += ' col-lg-' + (12 - this.labellg);
28769 if(this.labelmd > 0){
28770 content[0].cls += ' col-md-' + this.labelmd;
28771 content[1].cls += ' col-md-' + (12 - this.labelmd);
28774 if(this.labelsm > 0){
28775 content[0].cls += ' col-sm-' + this.labelsm;
28776 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28779 if(this.labelxs > 0){
28780 content[0].cls += ' col-xs-' + this.labelxs;
28781 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28789 cls : 'row clearfix',
28797 initEvents : function()
28799 this.managerEl = this.el.select('.roo-document-manager', true).first();
28800 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28802 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28803 this.selectorEl.hide();
28806 this.selectorEl.attr('multiple', 'multiple');
28809 this.selectorEl.on('change', this.onFileSelected, this);
28811 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28812 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28814 this.uploader.on('click', this.onUploaderClick, this);
28816 this.renderProgressDialog();
28820 window.addEventListener("resize", function() { _this.refresh(); } );
28822 this.fireEvent('initial', this);
28825 renderProgressDialog : function()
28829 this.progressDialog = new Roo.bootstrap.Modal({
28830 cls : 'roo-document-manager-progress-dialog',
28831 allow_close : false,
28841 btnclick : function() {
28842 _this.uploadCancel();
28848 this.progressDialog.render(Roo.get(document.body));
28850 this.progress = new Roo.bootstrap.Progress({
28851 cls : 'roo-document-manager-progress',
28856 this.progress.render(this.progressDialog.getChildContainer());
28858 this.progressBar = new Roo.bootstrap.ProgressBar({
28859 cls : 'roo-document-manager-progress-bar',
28862 aria_valuemax : 12,
28866 this.progressBar.render(this.progress.getChildContainer());
28869 onUploaderClick : function(e)
28871 e.preventDefault();
28873 if(this.fireEvent('beforeselectfile', this) != false){
28874 this.selectorEl.dom.click();
28879 onFileSelected : function(e)
28881 e.preventDefault();
28883 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28887 Roo.each(this.selectorEl.dom.files, function(file){
28888 if(this.fireEvent('inspect', this, file) != false){
28889 this.files.push(file);
28899 this.selectorEl.dom.value = '';
28901 if(!this.files || !this.files.length){
28905 if(this.boxes > 0 && this.files.length > this.boxes){
28906 this.files = this.files.slice(0, this.boxes);
28909 this.uploader.show();
28911 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28912 this.uploader.hide();
28921 Roo.each(this.files, function(file){
28923 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28924 var f = this.renderPreview(file);
28929 if(file.type.indexOf('image') != -1){
28930 this.delegates.push(
28932 _this.process(file);
28933 }).createDelegate(this)
28941 _this.process(file);
28942 }).createDelegate(this)
28947 this.files = files;
28949 this.delegates = this.delegates.concat(docs);
28951 if(!this.delegates.length){
28956 this.progressBar.aria_valuemax = this.delegates.length;
28963 arrange : function()
28965 if(!this.delegates.length){
28966 this.progressDialog.hide();
28971 var delegate = this.delegates.shift();
28973 this.progressDialog.show();
28975 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28977 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28982 refresh : function()
28984 this.uploader.show();
28986 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28987 this.uploader.hide();
28990 Roo.isTouch ? this.closable(false) : this.closable(true);
28992 this.fireEvent('refresh', this);
28995 onRemove : function(e, el, o)
28997 e.preventDefault();
28999 this.fireEvent('remove', this, o);
29003 remove : function(o)
29007 Roo.each(this.files, function(file){
29008 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29017 this.files = files;
29024 Roo.each(this.files, function(file){
29029 file.target.remove();
29038 onClick : function(e, el, o)
29040 e.preventDefault();
29042 this.fireEvent('click', this, o);
29046 closable : function(closable)
29048 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29050 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29062 xhrOnLoad : function(xhr)
29064 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29068 if (xhr.readyState !== 4) {
29070 this.fireEvent('exception', this, xhr);
29074 var response = Roo.decode(xhr.responseText);
29076 if(!response.success){
29078 this.fireEvent('exception', this, xhr);
29082 var file = this.renderPreview(response.data);
29084 this.files.push(file);
29088 this.fireEvent('afterupload', this, xhr);
29092 xhrOnError : function(xhr)
29094 Roo.log('xhr on error');
29096 var response = Roo.decode(xhr.responseText);
29103 process : function(file)
29105 if(this.fireEvent('process', this, file) !== false){
29106 if(this.editable && file.type.indexOf('image') != -1){
29107 this.fireEvent('edit', this, file);
29111 this.uploadStart(file, false);
29118 uploadStart : function(file, crop)
29120 this.xhr = new XMLHttpRequest();
29122 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29127 file.xhr = this.xhr;
29129 this.managerEl.createChild({
29131 cls : 'roo-document-manager-loading',
29135 tooltip : file.name,
29136 cls : 'roo-document-manager-thumb',
29137 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29143 this.xhr.open(this.method, this.url, true);
29146 "Accept": "application/json",
29147 "Cache-Control": "no-cache",
29148 "X-Requested-With": "XMLHttpRequest"
29151 for (var headerName in headers) {
29152 var headerValue = headers[headerName];
29154 this.xhr.setRequestHeader(headerName, headerValue);
29160 this.xhr.onload = function()
29162 _this.xhrOnLoad(_this.xhr);
29165 this.xhr.onerror = function()
29167 _this.xhrOnError(_this.xhr);
29170 var formData = new FormData();
29172 formData.append('returnHTML', 'NO');
29175 formData.append('crop', crop);
29178 formData.append(this.paramName, file, file.name);
29185 if(this.fireEvent('prepare', this, formData, options) != false){
29187 if(options.manually){
29191 this.xhr.send(formData);
29195 this.uploadCancel();
29198 uploadCancel : function()
29204 this.delegates = [];
29206 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29213 renderPreview : function(file)
29215 if(typeof(file.target) != 'undefined' && file.target){
29219 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29221 var previewEl = this.managerEl.createChild({
29223 cls : 'roo-document-manager-preview',
29227 tooltip : file[this.toolTipName],
29228 cls : 'roo-document-manager-thumb',
29229 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29234 html : '<i class="fa fa-times-circle"></i>'
29239 var close = previewEl.select('button.close', true).first();
29241 close.on('click', this.onRemove, this, file);
29243 file.target = previewEl;
29245 var image = previewEl.select('img', true).first();
29249 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29251 image.on('click', this.onClick, this, file);
29253 this.fireEvent('previewrendered', this, file);
29259 onPreviewLoad : function(file, image)
29261 if(typeof(file.target) == 'undefined' || !file.target){
29265 var width = image.dom.naturalWidth || image.dom.width;
29266 var height = image.dom.naturalHeight || image.dom.height;
29268 if(width > height){
29269 file.target.addClass('wide');
29273 file.target.addClass('tall');
29278 uploadFromSource : function(file, crop)
29280 this.xhr = new XMLHttpRequest();
29282 this.managerEl.createChild({
29284 cls : 'roo-document-manager-loading',
29288 tooltip : file.name,
29289 cls : 'roo-document-manager-thumb',
29290 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29296 this.xhr.open(this.method, this.url, true);
29299 "Accept": "application/json",
29300 "Cache-Control": "no-cache",
29301 "X-Requested-With": "XMLHttpRequest"
29304 for (var headerName in headers) {
29305 var headerValue = headers[headerName];
29307 this.xhr.setRequestHeader(headerName, headerValue);
29313 this.xhr.onload = function()
29315 _this.xhrOnLoad(_this.xhr);
29318 this.xhr.onerror = function()
29320 _this.xhrOnError(_this.xhr);
29323 var formData = new FormData();
29325 formData.append('returnHTML', 'NO');
29327 formData.append('crop', crop);
29329 if(typeof(file.filename) != 'undefined'){
29330 formData.append('filename', file.filename);
29333 if(typeof(file.mimetype) != 'undefined'){
29334 formData.append('mimetype', file.mimetype);
29339 if(this.fireEvent('prepare', this, formData) != false){
29340 this.xhr.send(formData);
29350 * @class Roo.bootstrap.DocumentViewer
29351 * @extends Roo.bootstrap.Component
29352 * Bootstrap DocumentViewer class
29353 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29354 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29357 * Create a new DocumentViewer
29358 * @param {Object} config The config object
29361 Roo.bootstrap.DocumentViewer = function(config){
29362 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29367 * Fire after initEvent
29368 * @param {Roo.bootstrap.DocumentViewer} this
29374 * @param {Roo.bootstrap.DocumentViewer} this
29379 * Fire after download button
29380 * @param {Roo.bootstrap.DocumentViewer} this
29385 * Fire after trash button
29386 * @param {Roo.bootstrap.DocumentViewer} this
29393 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29395 showDownload : true,
29399 getAutoCreate : function()
29403 cls : 'roo-document-viewer',
29407 cls : 'roo-document-viewer-body',
29411 cls : 'roo-document-viewer-thumb',
29415 cls : 'roo-document-viewer-image'
29423 cls : 'roo-document-viewer-footer',
29426 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29430 cls : 'btn-group roo-document-viewer-download',
29434 cls : 'btn btn-default',
29435 html : '<i class="fa fa-download"></i>'
29441 cls : 'btn-group roo-document-viewer-trash',
29445 cls : 'btn btn-default',
29446 html : '<i class="fa fa-trash"></i>'
29459 initEvents : function()
29461 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29462 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29464 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29465 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29467 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29468 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29470 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29471 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29473 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29474 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29476 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29477 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29479 this.bodyEl.on('click', this.onClick, this);
29480 this.downloadBtn.on('click', this.onDownload, this);
29481 this.trashBtn.on('click', this.onTrash, this);
29483 this.downloadBtn.hide();
29484 this.trashBtn.hide();
29486 if(this.showDownload){
29487 this.downloadBtn.show();
29490 if(this.showTrash){
29491 this.trashBtn.show();
29494 if(!this.showDownload && !this.showTrash) {
29495 this.footerEl.hide();
29500 initial : function()
29502 this.fireEvent('initial', this);
29506 onClick : function(e)
29508 e.preventDefault();
29510 this.fireEvent('click', this);
29513 onDownload : function(e)
29515 e.preventDefault();
29517 this.fireEvent('download', this);
29520 onTrash : function(e)
29522 e.preventDefault();
29524 this.fireEvent('trash', this);
29536 * @class Roo.bootstrap.NavProgressBar
29537 * @extends Roo.bootstrap.Component
29538 * Bootstrap NavProgressBar class
29541 * Create a new nav progress bar
29542 * @param {Object} config The config object
29545 Roo.bootstrap.NavProgressBar = function(config){
29546 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29548 this.bullets = this.bullets || [];
29550 // Roo.bootstrap.NavProgressBar.register(this);
29554 * Fires when the active item changes
29555 * @param {Roo.bootstrap.NavProgressBar} this
29556 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29557 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29564 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29569 getAutoCreate : function()
29571 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29575 cls : 'roo-navigation-bar-group',
29579 cls : 'roo-navigation-top-bar'
29583 cls : 'roo-navigation-bullets-bar',
29587 cls : 'roo-navigation-bar'
29594 cls : 'roo-navigation-bottom-bar'
29604 initEvents: function()
29609 onRender : function(ct, position)
29611 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29613 if(this.bullets.length){
29614 Roo.each(this.bullets, function(b){
29623 addItem : function(cfg)
29625 var item = new Roo.bootstrap.NavProgressItem(cfg);
29627 item.parentId = this.id;
29628 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29631 var top = new Roo.bootstrap.Element({
29633 cls : 'roo-navigation-bar-text'
29636 var bottom = new Roo.bootstrap.Element({
29638 cls : 'roo-navigation-bar-text'
29641 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29642 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29644 var topText = new Roo.bootstrap.Element({
29646 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29649 var bottomText = new Roo.bootstrap.Element({
29651 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29654 topText.onRender(top.el, null);
29655 bottomText.onRender(bottom.el, null);
29658 item.bottomEl = bottom;
29661 this.barItems.push(item);
29666 getActive : function()
29668 var active = false;
29670 Roo.each(this.barItems, function(v){
29672 if (!v.isActive()) {
29684 setActiveItem : function(item)
29688 Roo.each(this.barItems, function(v){
29689 if (v.rid == item.rid) {
29693 if (v.isActive()) {
29694 v.setActive(false);
29699 item.setActive(true);
29701 this.fireEvent('changed', this, item, prev);
29704 getBarItem: function(rid)
29708 Roo.each(this.barItems, function(e) {
29709 if (e.rid != rid) {
29720 indexOfItem : function(item)
29724 Roo.each(this.barItems, function(v, i){
29726 if (v.rid != item.rid) {
29737 setActiveNext : function()
29739 var i = this.indexOfItem(this.getActive());
29741 if (i > this.barItems.length) {
29745 this.setActiveItem(this.barItems[i+1]);
29748 setActivePrev : function()
29750 var i = this.indexOfItem(this.getActive());
29756 this.setActiveItem(this.barItems[i-1]);
29759 format : function()
29761 if(!this.barItems.length){
29765 var width = 100 / this.barItems.length;
29767 Roo.each(this.barItems, function(i){
29768 i.el.setStyle('width', width + '%');
29769 i.topEl.el.setStyle('width', width + '%');
29770 i.bottomEl.el.setStyle('width', width + '%');
29779 * Nav Progress Item
29784 * @class Roo.bootstrap.NavProgressItem
29785 * @extends Roo.bootstrap.Component
29786 * Bootstrap NavProgressItem class
29787 * @cfg {String} rid the reference id
29788 * @cfg {Boolean} active (true|false) Is item active default false
29789 * @cfg {Boolean} disabled (true|false) Is item active default false
29790 * @cfg {String} html
29791 * @cfg {String} position (top|bottom) text position default bottom
29792 * @cfg {String} icon show icon instead of number
29795 * Create a new NavProgressItem
29796 * @param {Object} config The config object
29798 Roo.bootstrap.NavProgressItem = function(config){
29799 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29804 * The raw click event for the entire grid.
29805 * @param {Roo.bootstrap.NavProgressItem} this
29806 * @param {Roo.EventObject} e
29813 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29819 position : 'bottom',
29822 getAutoCreate : function()
29824 var iconCls = 'roo-navigation-bar-item-icon';
29826 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29830 cls: 'roo-navigation-bar-item',
29840 cfg.cls += ' active';
29843 cfg.cls += ' disabled';
29849 disable : function()
29851 this.setDisabled(true);
29854 enable : function()
29856 this.setDisabled(false);
29859 initEvents: function()
29861 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29863 this.iconEl.on('click', this.onClick, this);
29866 onClick : function(e)
29868 e.preventDefault();
29874 if(this.fireEvent('click', this, e) === false){
29878 this.parent().setActiveItem(this);
29881 isActive: function ()
29883 return this.active;
29886 setActive : function(state)
29888 if(this.active == state){
29892 this.active = state;
29895 this.el.addClass('active');
29899 this.el.removeClass('active');
29904 setDisabled : function(state)
29906 if(this.disabled == state){
29910 this.disabled = state;
29913 this.el.addClass('disabled');
29917 this.el.removeClass('disabled');
29920 tooltipEl : function()
29922 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29935 * @class Roo.bootstrap.FieldLabel
29936 * @extends Roo.bootstrap.Component
29937 * Bootstrap FieldLabel class
29938 * @cfg {String} html contents of the element
29939 * @cfg {String} tag tag of the element default label
29940 * @cfg {String} cls class of the element
29941 * @cfg {String} target label target
29942 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29943 * @cfg {String} invalidClass default "text-warning"
29944 * @cfg {String} validClass default "text-success"
29945 * @cfg {String} iconTooltip default "This field is required"
29946 * @cfg {String} indicatorpos (left|right) default left
29949 * Create a new FieldLabel
29950 * @param {Object} config The config object
29953 Roo.bootstrap.FieldLabel = function(config){
29954 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29959 * Fires after the field has been marked as invalid.
29960 * @param {Roo.form.FieldLabel} this
29961 * @param {String} msg The validation message
29966 * Fires after the field has been validated with no errors.
29967 * @param {Roo.form.FieldLabel} this
29973 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29980 invalidClass : 'has-warning',
29981 validClass : 'has-success',
29982 iconTooltip : 'This field is required',
29983 indicatorpos : 'left',
29985 getAutoCreate : function(){
29989 cls : 'roo-bootstrap-field-label ' + this.cls,
29994 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29995 tooltip : this.iconTooltip
30004 if(this.indicatorpos == 'right'){
30007 cls : 'roo-bootstrap-field-label ' + this.cls,
30016 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30017 tooltip : this.iconTooltip
30026 initEvents: function()
30028 Roo.bootstrap.Element.superclass.initEvents.call(this);
30030 this.indicator = this.indicatorEl();
30032 if(this.indicator){
30033 this.indicator.removeClass('visible');
30034 this.indicator.addClass('invisible');
30037 Roo.bootstrap.FieldLabel.register(this);
30040 indicatorEl : function()
30042 var indicator = this.el.select('i.roo-required-indicator',true).first();
30053 * Mark this field as valid
30055 markValid : function()
30057 if(this.indicator){
30058 this.indicator.removeClass('visible');
30059 this.indicator.addClass('invisible');
30062 this.el.removeClass(this.invalidClass);
30064 this.el.addClass(this.validClass);
30066 this.fireEvent('valid', this);
30070 * Mark this field as invalid
30071 * @param {String} msg The validation message
30073 markInvalid : function(msg)
30075 if(this.indicator){
30076 this.indicator.removeClass('invisible');
30077 this.indicator.addClass('visible');
30080 this.el.removeClass(this.validClass);
30082 this.el.addClass(this.invalidClass);
30084 this.fireEvent('invalid', this, msg);
30090 Roo.apply(Roo.bootstrap.FieldLabel, {
30095 * register a FieldLabel Group
30096 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30098 register : function(label)
30100 if(this.groups.hasOwnProperty(label.target)){
30104 this.groups[label.target] = label;
30108 * fetch a FieldLabel Group based on the target
30109 * @param {string} target
30110 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30112 get: function(target) {
30113 if (typeof(this.groups[target]) == 'undefined') {
30117 return this.groups[target] ;
30126 * page DateSplitField.
30132 * @class Roo.bootstrap.DateSplitField
30133 * @extends Roo.bootstrap.Component
30134 * Bootstrap DateSplitField class
30135 * @cfg {string} fieldLabel - the label associated
30136 * @cfg {Number} labelWidth set the width of label (0-12)
30137 * @cfg {String} labelAlign (top|left)
30138 * @cfg {Boolean} dayAllowBlank (true|false) default false
30139 * @cfg {Boolean} monthAllowBlank (true|false) default false
30140 * @cfg {Boolean} yearAllowBlank (true|false) default false
30141 * @cfg {string} dayPlaceholder
30142 * @cfg {string} monthPlaceholder
30143 * @cfg {string} yearPlaceholder
30144 * @cfg {string} dayFormat default 'd'
30145 * @cfg {string} monthFormat default 'm'
30146 * @cfg {string} yearFormat default 'Y'
30147 * @cfg {Number} labellg set the width of label (1-12)
30148 * @cfg {Number} labelmd set the width of label (1-12)
30149 * @cfg {Number} labelsm set the width of label (1-12)
30150 * @cfg {Number} labelxs set the width of label (1-12)
30154 * Create a new DateSplitField
30155 * @param {Object} config The config object
30158 Roo.bootstrap.DateSplitField = function(config){
30159 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30165 * getting the data of years
30166 * @param {Roo.bootstrap.DateSplitField} this
30167 * @param {Object} years
30172 * getting the data of days
30173 * @param {Roo.bootstrap.DateSplitField} this
30174 * @param {Object} days
30179 * Fires after the field has been marked as invalid.
30180 * @param {Roo.form.Field} this
30181 * @param {String} msg The validation message
30186 * Fires after the field has been validated with no errors.
30187 * @param {Roo.form.Field} this
30193 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30196 labelAlign : 'top',
30198 dayAllowBlank : false,
30199 monthAllowBlank : false,
30200 yearAllowBlank : false,
30201 dayPlaceholder : '',
30202 monthPlaceholder : '',
30203 yearPlaceholder : '',
30207 isFormField : true,
30213 getAutoCreate : function()
30217 cls : 'row roo-date-split-field-group',
30222 cls : 'form-hidden-field roo-date-split-field-group-value',
30228 var labelCls = 'col-md-12';
30229 var contentCls = 'col-md-4';
30231 if(this.fieldLabel){
30235 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30239 html : this.fieldLabel
30244 if(this.labelAlign == 'left'){
30246 if(this.labelWidth > 12){
30247 label.style = "width: " + this.labelWidth + 'px';
30250 if(this.labelWidth < 13 && this.labelmd == 0){
30251 this.labelmd = this.labelWidth;
30254 if(this.labellg > 0){
30255 labelCls = ' col-lg-' + this.labellg;
30256 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30259 if(this.labelmd > 0){
30260 labelCls = ' col-md-' + this.labelmd;
30261 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30264 if(this.labelsm > 0){
30265 labelCls = ' col-sm-' + this.labelsm;
30266 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30269 if(this.labelxs > 0){
30270 labelCls = ' col-xs-' + this.labelxs;
30271 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30275 label.cls += ' ' + labelCls;
30277 cfg.cn.push(label);
30280 Roo.each(['day', 'month', 'year'], function(t){
30283 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30290 inputEl: function ()
30292 return this.el.select('.roo-date-split-field-group-value', true).first();
30295 onRender : function(ct, position)
30299 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30301 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30303 this.dayField = new Roo.bootstrap.ComboBox({
30304 allowBlank : this.dayAllowBlank,
30305 alwaysQuery : true,
30306 displayField : 'value',
30309 forceSelection : true,
30311 placeholder : this.dayPlaceholder,
30312 selectOnFocus : true,
30313 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30314 triggerAction : 'all',
30316 valueField : 'value',
30317 store : new Roo.data.SimpleStore({
30318 data : (function() {
30320 _this.fireEvent('days', _this, days);
30323 fields : [ 'value' ]
30326 select : function (_self, record, index)
30328 _this.setValue(_this.getValue());
30333 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30335 this.monthField = new Roo.bootstrap.MonthField({
30336 after : '<i class=\"fa fa-calendar\"></i>',
30337 allowBlank : this.monthAllowBlank,
30338 placeholder : this.monthPlaceholder,
30341 render : function (_self)
30343 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30344 e.preventDefault();
30348 select : function (_self, oldvalue, newvalue)
30350 _this.setValue(_this.getValue());
30355 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30357 this.yearField = new Roo.bootstrap.ComboBox({
30358 allowBlank : this.yearAllowBlank,
30359 alwaysQuery : true,
30360 displayField : 'value',
30363 forceSelection : true,
30365 placeholder : this.yearPlaceholder,
30366 selectOnFocus : true,
30367 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30368 triggerAction : 'all',
30370 valueField : 'value',
30371 store : new Roo.data.SimpleStore({
30372 data : (function() {
30374 _this.fireEvent('years', _this, years);
30377 fields : [ 'value' ]
30380 select : function (_self, record, index)
30382 _this.setValue(_this.getValue());
30387 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30390 setValue : function(v, format)
30392 this.inputEl.dom.value = v;
30394 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30396 var d = Date.parseDate(v, f);
30403 this.setDay(d.format(this.dayFormat));
30404 this.setMonth(d.format(this.monthFormat));
30405 this.setYear(d.format(this.yearFormat));
30412 setDay : function(v)
30414 this.dayField.setValue(v);
30415 this.inputEl.dom.value = this.getValue();
30420 setMonth : function(v)
30422 this.monthField.setValue(v, true);
30423 this.inputEl.dom.value = this.getValue();
30428 setYear : function(v)
30430 this.yearField.setValue(v);
30431 this.inputEl.dom.value = this.getValue();
30436 getDay : function()
30438 return this.dayField.getValue();
30441 getMonth : function()
30443 return this.monthField.getValue();
30446 getYear : function()
30448 return this.yearField.getValue();
30451 getValue : function()
30453 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30455 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30465 this.inputEl.dom.value = '';
30470 validate : function()
30472 var d = this.dayField.validate();
30473 var m = this.monthField.validate();
30474 var y = this.yearField.validate();
30479 (!this.dayAllowBlank && !d) ||
30480 (!this.monthAllowBlank && !m) ||
30481 (!this.yearAllowBlank && !y)
30486 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30495 this.markInvalid();
30500 markValid : function()
30503 var label = this.el.select('label', true).first();
30504 var icon = this.el.select('i.fa-star', true).first();
30510 this.fireEvent('valid', this);
30514 * Mark this field as invalid
30515 * @param {String} msg The validation message
30517 markInvalid : function(msg)
30520 var label = this.el.select('label', true).first();
30521 var icon = this.el.select('i.fa-star', true).first();
30523 if(label && !icon){
30524 this.el.select('.roo-date-split-field-label', true).createChild({
30526 cls : 'text-danger fa fa-lg fa-star',
30527 tooltip : 'This field is required',
30528 style : 'margin-right:5px;'
30532 this.fireEvent('invalid', this, msg);
30535 clearInvalid : function()
30537 var label = this.el.select('label', true).first();
30538 var icon = this.el.select('i.fa-star', true).first();
30544 this.fireEvent('valid', this);
30547 getName: function()
30557 * http://masonry.desandro.com
30559 * The idea is to render all the bricks based on vertical width...
30561 * The original code extends 'outlayer' - we might need to use that....
30567 * @class Roo.bootstrap.LayoutMasonry
30568 * @extends Roo.bootstrap.Component
30569 * Bootstrap Layout Masonry class
30572 * Create a new Element
30573 * @param {Object} config The config object
30576 Roo.bootstrap.LayoutMasonry = function(config){
30578 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30582 Roo.bootstrap.LayoutMasonry.register(this);
30588 * Fire after layout the items
30589 * @param {Roo.bootstrap.LayoutMasonry} this
30590 * @param {Roo.EventObject} e
30597 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30600 * @cfg {Boolean} isLayoutInstant = no animation?
30602 isLayoutInstant : false, // needed?
30605 * @cfg {Number} boxWidth width of the columns
30610 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30615 * @cfg {Number} padWidth padding below box..
30620 * @cfg {Number} gutter gutter width..
30625 * @cfg {Number} maxCols maximum number of columns
30631 * @cfg {Boolean} isAutoInitial defalut true
30633 isAutoInitial : true,
30638 * @cfg {Boolean} isHorizontal defalut false
30640 isHorizontal : false,
30642 currentSize : null,
30648 bricks: null, //CompositeElement
30652 _isLayoutInited : false,
30654 // isAlternative : false, // only use for vertical layout...
30657 * @cfg {Number} alternativePadWidth padding below box..
30659 alternativePadWidth : 50,
30661 selectedBrick : [],
30663 getAutoCreate : function(){
30665 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30669 cls: 'blog-masonary-wrapper ' + this.cls,
30671 cls : 'mas-boxes masonary'
30678 getChildContainer: function( )
30680 if (this.boxesEl) {
30681 return this.boxesEl;
30684 this.boxesEl = this.el.select('.mas-boxes').first();
30686 return this.boxesEl;
30690 initEvents : function()
30694 if(this.isAutoInitial){
30695 Roo.log('hook children rendered');
30696 this.on('childrenrendered', function() {
30697 Roo.log('children rendered');
30703 initial : function()
30705 this.selectedBrick = [];
30707 this.currentSize = this.el.getBox(true);
30709 Roo.EventManager.onWindowResize(this.resize, this);
30711 if(!this.isAutoInitial){
30719 //this.layout.defer(500,this);
30723 resize : function()
30725 var cs = this.el.getBox(true);
30728 this.currentSize.width == cs.width &&
30729 this.currentSize.x == cs.x &&
30730 this.currentSize.height == cs.height &&
30731 this.currentSize.y == cs.y
30733 Roo.log("no change in with or X or Y");
30737 this.currentSize = cs;
30743 layout : function()
30745 this._resetLayout();
30747 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30749 this.layoutItems( isInstant );
30751 this._isLayoutInited = true;
30753 this.fireEvent('layout', this);
30757 _resetLayout : function()
30759 if(this.isHorizontal){
30760 this.horizontalMeasureColumns();
30764 this.verticalMeasureColumns();
30768 verticalMeasureColumns : function()
30770 this.getContainerWidth();
30772 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30773 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30777 var boxWidth = this.boxWidth + this.padWidth;
30779 if(this.containerWidth < this.boxWidth){
30780 boxWidth = this.containerWidth
30783 var containerWidth = this.containerWidth;
30785 var cols = Math.floor(containerWidth / boxWidth);
30787 this.cols = Math.max( cols, 1 );
30789 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30791 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30793 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30795 this.colWidth = boxWidth + avail - this.padWidth;
30797 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30798 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30801 horizontalMeasureColumns : function()
30803 this.getContainerWidth();
30805 var boxWidth = this.boxWidth;
30807 if(this.containerWidth < boxWidth){
30808 boxWidth = this.containerWidth;
30811 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30813 this.el.setHeight(boxWidth);
30817 getContainerWidth : function()
30819 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30822 layoutItems : function( isInstant )
30824 Roo.log(this.bricks);
30826 var items = Roo.apply([], this.bricks);
30828 if(this.isHorizontal){
30829 this._horizontalLayoutItems( items , isInstant );
30833 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30834 // this._verticalAlternativeLayoutItems( items , isInstant );
30838 this._verticalLayoutItems( items , isInstant );
30842 _verticalLayoutItems : function ( items , isInstant)
30844 if ( !items || !items.length ) {
30849 ['xs', 'xs', 'xs', 'tall'],
30850 ['xs', 'xs', 'tall'],
30851 ['xs', 'xs', 'sm'],
30852 ['xs', 'xs', 'xs'],
30858 ['sm', 'xs', 'xs'],
30862 ['tall', 'xs', 'xs', 'xs'],
30863 ['tall', 'xs', 'xs'],
30875 Roo.each(items, function(item, k){
30877 switch (item.size) {
30878 // these layouts take up a full box,
30889 boxes.push([item]);
30912 var filterPattern = function(box, length)
30920 var pattern = box.slice(0, length);
30924 Roo.each(pattern, function(i){
30925 format.push(i.size);
30928 Roo.each(standard, function(s){
30930 if(String(s) != String(format)){
30939 if(!match && length == 1){
30944 filterPattern(box, length - 1);
30948 queue.push(pattern);
30950 box = box.slice(length, box.length);
30952 filterPattern(box, 4);
30958 Roo.each(boxes, function(box, k){
30964 if(box.length == 1){
30969 filterPattern(box, 4);
30973 this._processVerticalLayoutQueue( queue, isInstant );
30977 // _verticalAlternativeLayoutItems : function( items , isInstant )
30979 // if ( !items || !items.length ) {
30983 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30987 _horizontalLayoutItems : function ( items , isInstant)
30989 if ( !items || !items.length || items.length < 3) {
30995 var eItems = items.slice(0, 3);
30997 items = items.slice(3, items.length);
31000 ['xs', 'xs', 'xs', 'wide'],
31001 ['xs', 'xs', 'wide'],
31002 ['xs', 'xs', 'sm'],
31003 ['xs', 'xs', 'xs'],
31009 ['sm', 'xs', 'xs'],
31013 ['wide', 'xs', 'xs', 'xs'],
31014 ['wide', 'xs', 'xs'],
31027 Roo.each(items, function(item, k){
31029 switch (item.size) {
31040 boxes.push([item]);
31064 var filterPattern = function(box, length)
31072 var pattern = box.slice(0, length);
31076 Roo.each(pattern, function(i){
31077 format.push(i.size);
31080 Roo.each(standard, function(s){
31082 if(String(s) != String(format)){
31091 if(!match && length == 1){
31096 filterPattern(box, length - 1);
31100 queue.push(pattern);
31102 box = box.slice(length, box.length);
31104 filterPattern(box, 4);
31110 Roo.each(boxes, function(box, k){
31116 if(box.length == 1){
31121 filterPattern(box, 4);
31128 var pos = this.el.getBox(true);
31132 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31134 var hit_end = false;
31136 Roo.each(queue, function(box){
31140 Roo.each(box, function(b){
31142 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31152 Roo.each(box, function(b){
31154 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31157 mx = Math.max(mx, b.x);
31161 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31165 Roo.each(box, function(b){
31167 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31181 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31184 /** Sets position of item in DOM
31185 * @param {Element} item
31186 * @param {Number} x - horizontal position
31187 * @param {Number} y - vertical position
31188 * @param {Boolean} isInstant - disables transitions
31190 _processVerticalLayoutQueue : function( queue, isInstant )
31192 var pos = this.el.getBox(true);
31197 for (var i = 0; i < this.cols; i++){
31201 Roo.each(queue, function(box, k){
31203 var col = k % this.cols;
31205 Roo.each(box, function(b,kk){
31207 b.el.position('absolute');
31209 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31210 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31212 if(b.size == 'md-left' || b.size == 'md-right'){
31213 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31214 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31217 b.el.setWidth(width);
31218 b.el.setHeight(height);
31220 b.el.select('iframe',true).setSize(width,height);
31224 for (var i = 0; i < this.cols; i++){
31226 if(maxY[i] < maxY[col]){
31231 col = Math.min(col, i);
31235 x = pos.x + col * (this.colWidth + this.padWidth);
31239 var positions = [];
31241 switch (box.length){
31243 positions = this.getVerticalOneBoxColPositions(x, y, box);
31246 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31249 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31252 positions = this.getVerticalFourBoxColPositions(x, y, box);
31258 Roo.each(box, function(b,kk){
31260 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31262 var sz = b.el.getSize();
31264 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31272 for (var i = 0; i < this.cols; i++){
31273 mY = Math.max(mY, maxY[i]);
31276 this.el.setHeight(mY - pos.y);
31280 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31282 // var pos = this.el.getBox(true);
31285 // var maxX = pos.right;
31287 // var maxHeight = 0;
31289 // Roo.each(items, function(item, k){
31293 // item.el.position('absolute');
31295 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31297 // item.el.setWidth(width);
31299 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31301 // item.el.setHeight(height);
31304 // item.el.setXY([x, y], isInstant ? false : true);
31306 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31309 // y = y + height + this.alternativePadWidth;
31311 // maxHeight = maxHeight + height + this.alternativePadWidth;
31315 // this.el.setHeight(maxHeight);
31319 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31321 var pos = this.el.getBox(true);
31326 var maxX = pos.right;
31328 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31330 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31332 Roo.each(queue, function(box, k){
31334 Roo.each(box, function(b, kk){
31336 b.el.position('absolute');
31338 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31339 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31341 if(b.size == 'md-left' || b.size == 'md-right'){
31342 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31343 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31346 b.el.setWidth(width);
31347 b.el.setHeight(height);
31355 var positions = [];
31357 switch (box.length){
31359 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31362 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31365 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31368 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31374 Roo.each(box, function(b,kk){
31376 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31378 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31386 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31388 Roo.each(eItems, function(b,k){
31390 b.size = (k == 0) ? 'sm' : 'xs';
31391 b.x = (k == 0) ? 2 : 1;
31392 b.y = (k == 0) ? 2 : 1;
31394 b.el.position('absolute');
31396 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31398 b.el.setWidth(width);
31400 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31402 b.el.setHeight(height);
31406 var positions = [];
31409 x : maxX - this.unitWidth * 2 - this.gutter,
31414 x : maxX - this.unitWidth,
31415 y : minY + (this.unitWidth + this.gutter) * 2
31419 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31423 Roo.each(eItems, function(b,k){
31425 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31431 getVerticalOneBoxColPositions : function(x, y, box)
31435 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31437 if(box[0].size == 'md-left'){
31441 if(box[0].size == 'md-right'){
31446 x : x + (this.unitWidth + this.gutter) * rand,
31453 getVerticalTwoBoxColPositions : function(x, y, box)
31457 if(box[0].size == 'xs'){
31461 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31465 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31479 x : x + (this.unitWidth + this.gutter) * 2,
31480 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31487 getVerticalThreeBoxColPositions : function(x, y, box)
31491 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31499 x : x + (this.unitWidth + this.gutter) * 1,
31504 x : x + (this.unitWidth + this.gutter) * 2,
31512 if(box[0].size == 'xs' && box[1].size == 'xs'){
31521 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31525 x : x + (this.unitWidth + this.gutter) * 1,
31539 x : x + (this.unitWidth + this.gutter) * 2,
31544 x : x + (this.unitWidth + this.gutter) * 2,
31545 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31552 getVerticalFourBoxColPositions : function(x, y, box)
31556 if(box[0].size == 'xs'){
31565 y : y + (this.unitHeight + this.gutter) * 1
31570 y : y + (this.unitHeight + this.gutter) * 2
31574 x : x + (this.unitWidth + this.gutter) * 1,
31588 x : x + (this.unitWidth + this.gutter) * 2,
31593 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31594 y : y + (this.unitHeight + this.gutter) * 1
31598 x : x + (this.unitWidth + this.gutter) * 2,
31599 y : y + (this.unitWidth + this.gutter) * 2
31606 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31610 if(box[0].size == 'md-left'){
31612 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31619 if(box[0].size == 'md-right'){
31621 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31622 y : minY + (this.unitWidth + this.gutter) * 1
31628 var rand = Math.floor(Math.random() * (4 - box[0].y));
31631 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31632 y : minY + (this.unitWidth + this.gutter) * rand
31639 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31643 if(box[0].size == 'xs'){
31646 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31651 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31652 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31660 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31665 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31666 y : minY + (this.unitWidth + this.gutter) * 2
31673 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31677 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31680 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31685 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31686 y : minY + (this.unitWidth + this.gutter) * 1
31690 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31691 y : minY + (this.unitWidth + this.gutter) * 2
31698 if(box[0].size == 'xs' && box[1].size == 'xs'){
31701 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31706 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31711 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31712 y : minY + (this.unitWidth + this.gutter) * 1
31720 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31725 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31726 y : minY + (this.unitWidth + this.gutter) * 2
31730 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31731 y : minY + (this.unitWidth + this.gutter) * 2
31738 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31742 if(box[0].size == 'xs'){
31745 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31750 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31755 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),
31760 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31761 y : minY + (this.unitWidth + this.gutter) * 1
31769 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31774 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31775 y : minY + (this.unitWidth + this.gutter) * 2
31779 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31780 y : minY + (this.unitWidth + this.gutter) * 2
31784 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),
31785 y : minY + (this.unitWidth + this.gutter) * 2
31793 * remove a Masonry Brick
31794 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31796 removeBrick : function(brick_id)
31802 for (var i = 0; i<this.bricks.length; i++) {
31803 if (this.bricks[i].id == brick_id) {
31804 this.bricks.splice(i,1);
31805 this.el.dom.removeChild(Roo.get(brick_id).dom);
31812 * adds a Masonry Brick
31813 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31815 addBrick : function(cfg)
31817 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31818 //this.register(cn);
31819 cn.parentId = this.id;
31820 cn.onRender(this.el, null);
31825 * register a Masonry Brick
31826 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31829 register : function(brick)
31831 this.bricks.push(brick);
31832 brick.masonryId = this.id;
31836 * clear all the Masonry Brick
31838 clearAll : function()
31841 //this.getChildContainer().dom.innerHTML = "";
31842 this.el.dom.innerHTML = '';
31845 getSelected : function()
31847 if (!this.selectedBrick) {
31851 return this.selectedBrick;
31855 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31859 * register a Masonry Layout
31860 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31863 register : function(layout)
31865 this.groups[layout.id] = layout;
31868 * fetch a Masonry Layout based on the masonry layout ID
31869 * @param {string} the masonry layout to add
31870 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31873 get: function(layout_id) {
31874 if (typeof(this.groups[layout_id]) == 'undefined') {
31877 return this.groups[layout_id] ;
31889 * http://masonry.desandro.com
31891 * The idea is to render all the bricks based on vertical width...
31893 * The original code extends 'outlayer' - we might need to use that....
31899 * @class Roo.bootstrap.LayoutMasonryAuto
31900 * @extends Roo.bootstrap.Component
31901 * Bootstrap Layout Masonry class
31904 * Create a new Element
31905 * @param {Object} config The config object
31908 Roo.bootstrap.LayoutMasonryAuto = function(config){
31909 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31912 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31915 * @cfg {Boolean} isFitWidth - resize the width..
31917 isFitWidth : false, // options..
31919 * @cfg {Boolean} isOriginLeft = left align?
31921 isOriginLeft : true,
31923 * @cfg {Boolean} isOriginTop = top align?
31925 isOriginTop : false,
31927 * @cfg {Boolean} isLayoutInstant = no animation?
31929 isLayoutInstant : false, // needed?
31931 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31933 isResizingContainer : true,
31935 * @cfg {Number} columnWidth width of the columns
31941 * @cfg {Number} maxCols maximum number of columns
31946 * @cfg {Number} padHeight padding below box..
31952 * @cfg {Boolean} isAutoInitial defalut true
31955 isAutoInitial : true,
31961 initialColumnWidth : 0,
31962 currentSize : null,
31964 colYs : null, // array.
31971 bricks: null, //CompositeElement
31972 cols : 0, // array?
31973 // element : null, // wrapped now this.el
31974 _isLayoutInited : null,
31977 getAutoCreate : function(){
31981 cls: 'blog-masonary-wrapper ' + this.cls,
31983 cls : 'mas-boxes masonary'
31990 getChildContainer: function( )
31992 if (this.boxesEl) {
31993 return this.boxesEl;
31996 this.boxesEl = this.el.select('.mas-boxes').first();
31998 return this.boxesEl;
32002 initEvents : function()
32006 if(this.isAutoInitial){
32007 Roo.log('hook children rendered');
32008 this.on('childrenrendered', function() {
32009 Roo.log('children rendered');
32016 initial : function()
32018 this.reloadItems();
32020 this.currentSize = this.el.getBox(true);
32022 /// was window resize... - let's see if this works..
32023 Roo.EventManager.onWindowResize(this.resize, this);
32025 if(!this.isAutoInitial){
32030 this.layout.defer(500,this);
32033 reloadItems: function()
32035 this.bricks = this.el.select('.masonry-brick', true);
32037 this.bricks.each(function(b) {
32038 //Roo.log(b.getSize());
32039 if (!b.attr('originalwidth')) {
32040 b.attr('originalwidth', b.getSize().width);
32045 Roo.log(this.bricks.elements.length);
32048 resize : function()
32051 var cs = this.el.getBox(true);
32053 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32054 Roo.log("no change in with or X");
32057 this.currentSize = cs;
32061 layout : function()
32064 this._resetLayout();
32065 //this._manageStamps();
32067 // don't animate first layout
32068 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32069 this.layoutItems( isInstant );
32071 // flag for initalized
32072 this._isLayoutInited = true;
32075 layoutItems : function( isInstant )
32077 //var items = this._getItemsForLayout( this.items );
32078 // original code supports filtering layout items.. we just ignore it..
32080 this._layoutItems( this.bricks , isInstant );
32082 this._postLayout();
32084 _layoutItems : function ( items , isInstant)
32086 //this.fireEvent( 'layout', this, items );
32089 if ( !items || !items.elements.length ) {
32090 // no items, emit event with empty array
32095 items.each(function(item) {
32096 Roo.log("layout item");
32098 // get x/y object from method
32099 var position = this._getItemLayoutPosition( item );
32101 position.item = item;
32102 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32103 queue.push( position );
32106 this._processLayoutQueue( queue );
32108 /** Sets position of item in DOM
32109 * @param {Element} item
32110 * @param {Number} x - horizontal position
32111 * @param {Number} y - vertical position
32112 * @param {Boolean} isInstant - disables transitions
32114 _processLayoutQueue : function( queue )
32116 for ( var i=0, len = queue.length; i < len; i++ ) {
32117 var obj = queue[i];
32118 obj.item.position('absolute');
32119 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32125 * Any logic you want to do after each layout,
32126 * i.e. size the container
32128 _postLayout : function()
32130 this.resizeContainer();
32133 resizeContainer : function()
32135 if ( !this.isResizingContainer ) {
32138 var size = this._getContainerSize();
32140 this.el.setSize(size.width,size.height);
32141 this.boxesEl.setSize(size.width,size.height);
32147 _resetLayout : function()
32149 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32150 this.colWidth = this.el.getWidth();
32151 //this.gutter = this.el.getWidth();
32153 this.measureColumns();
32159 this.colYs.push( 0 );
32165 measureColumns : function()
32167 this.getContainerWidth();
32168 // if columnWidth is 0, default to outerWidth of first item
32169 if ( !this.columnWidth ) {
32170 var firstItem = this.bricks.first();
32171 Roo.log(firstItem);
32172 this.columnWidth = this.containerWidth;
32173 if (firstItem && firstItem.attr('originalwidth') ) {
32174 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32176 // columnWidth fall back to item of first element
32177 Roo.log("set column width?");
32178 this.initialColumnWidth = this.columnWidth ;
32180 // if first elem has no width, default to size of container
32185 if (this.initialColumnWidth) {
32186 this.columnWidth = this.initialColumnWidth;
32191 // column width is fixed at the top - however if container width get's smaller we should
32194 // this bit calcs how man columns..
32196 var columnWidth = this.columnWidth += this.gutter;
32198 // calculate columns
32199 var containerWidth = this.containerWidth + this.gutter;
32201 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32202 // fix rounding errors, typically with gutters
32203 var excess = columnWidth - containerWidth % columnWidth;
32206 // if overshoot is less than a pixel, round up, otherwise floor it
32207 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32208 cols = Math[ mathMethod ]( cols );
32209 this.cols = Math.max( cols, 1 );
32210 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32212 // padding positioning..
32213 var totalColWidth = this.cols * this.columnWidth;
32214 var padavail = this.containerWidth - totalColWidth;
32215 // so for 2 columns - we need 3 'pads'
32217 var padNeeded = (1+this.cols) * this.padWidth;
32219 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32221 this.columnWidth += padExtra
32222 //this.padWidth = Math.floor(padavail / ( this.cols));
32224 // adjust colum width so that padding is fixed??
32226 // we have 3 columns ... total = width * 3
32227 // we have X left over... that should be used by
32229 //if (this.expandC) {
32237 getContainerWidth : function()
32239 /* // container is parent if fit width
32240 var container = this.isFitWidth ? this.element.parentNode : this.element;
32241 // check that this.size and size are there
32242 // IE8 triggers resize on body size change, so they might not be
32244 var size = getSize( container ); //FIXME
32245 this.containerWidth = size && size.innerWidth; //FIXME
32248 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32252 _getItemLayoutPosition : function( item ) // what is item?
32254 // we resize the item to our columnWidth..
32256 item.setWidth(this.columnWidth);
32257 item.autoBoxAdjust = false;
32259 var sz = item.getSize();
32261 // how many columns does this brick span
32262 var remainder = this.containerWidth % this.columnWidth;
32264 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32265 // round if off by 1 pixel, otherwise use ceil
32266 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32267 colSpan = Math.min( colSpan, this.cols );
32269 // normally this should be '1' as we dont' currently allow multi width columns..
32271 var colGroup = this._getColGroup( colSpan );
32272 // get the minimum Y value from the columns
32273 var minimumY = Math.min.apply( Math, colGroup );
32274 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32276 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32278 // position the brick
32280 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32281 y: this.currentSize.y + minimumY + this.padHeight
32285 // apply setHeight to necessary columns
32286 var setHeight = minimumY + sz.height + this.padHeight;
32287 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32289 var setSpan = this.cols + 1 - colGroup.length;
32290 for ( var i = 0; i < setSpan; i++ ) {
32291 this.colYs[ shortColIndex + i ] = setHeight ;
32298 * @param {Number} colSpan - number of columns the element spans
32299 * @returns {Array} colGroup
32301 _getColGroup : function( colSpan )
32303 if ( colSpan < 2 ) {
32304 // if brick spans only one column, use all the column Ys
32309 // how many different places could this brick fit horizontally
32310 var groupCount = this.cols + 1 - colSpan;
32311 // for each group potential horizontal position
32312 for ( var i = 0; i < groupCount; i++ ) {
32313 // make an array of colY values for that one group
32314 var groupColYs = this.colYs.slice( i, i + colSpan );
32315 // and get the max value of the array
32316 colGroup[i] = Math.max.apply( Math, groupColYs );
32321 _manageStamp : function( stamp )
32323 var stampSize = stamp.getSize();
32324 var offset = stamp.getBox();
32325 // get the columns that this stamp affects
32326 var firstX = this.isOriginLeft ? offset.x : offset.right;
32327 var lastX = firstX + stampSize.width;
32328 var firstCol = Math.floor( firstX / this.columnWidth );
32329 firstCol = Math.max( 0, firstCol );
32331 var lastCol = Math.floor( lastX / this.columnWidth );
32332 // lastCol should not go over if multiple of columnWidth #425
32333 lastCol -= lastX % this.columnWidth ? 0 : 1;
32334 lastCol = Math.min( this.cols - 1, lastCol );
32336 // set colYs to bottom of the stamp
32337 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32340 for ( var i = firstCol; i <= lastCol; i++ ) {
32341 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32346 _getContainerSize : function()
32348 this.maxY = Math.max.apply( Math, this.colYs );
32353 if ( this.isFitWidth ) {
32354 size.width = this._getContainerFitWidth();
32360 _getContainerFitWidth : function()
32362 var unusedCols = 0;
32363 // count unused columns
32366 if ( this.colYs[i] !== 0 ) {
32371 // fit container to columns that have been used
32372 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32375 needsResizeLayout : function()
32377 var previousWidth = this.containerWidth;
32378 this.getContainerWidth();
32379 return previousWidth !== this.containerWidth;
32394 * @class Roo.bootstrap.MasonryBrick
32395 * @extends Roo.bootstrap.Component
32396 * Bootstrap MasonryBrick class
32399 * Create a new MasonryBrick
32400 * @param {Object} config The config object
32403 Roo.bootstrap.MasonryBrick = function(config){
32405 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32407 Roo.bootstrap.MasonryBrick.register(this);
32413 * When a MasonryBrick is clcik
32414 * @param {Roo.bootstrap.MasonryBrick} this
32415 * @param {Roo.EventObject} e
32421 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32424 * @cfg {String} title
32428 * @cfg {String} html
32432 * @cfg {String} bgimage
32436 * @cfg {String} videourl
32440 * @cfg {String} cls
32444 * @cfg {String} href
32448 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32453 * @cfg {String} placetitle (center|bottom)
32458 * @cfg {Boolean} isFitContainer defalut true
32460 isFitContainer : true,
32463 * @cfg {Boolean} preventDefault defalut false
32465 preventDefault : false,
32468 * @cfg {Boolean} inverse defalut false
32470 maskInverse : false,
32472 getAutoCreate : function()
32474 if(!this.isFitContainer){
32475 return this.getSplitAutoCreate();
32478 var cls = 'masonry-brick masonry-brick-full';
32480 if(this.href.length){
32481 cls += ' masonry-brick-link';
32484 if(this.bgimage.length){
32485 cls += ' masonry-brick-image';
32488 if(this.maskInverse){
32489 cls += ' mask-inverse';
32492 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32493 cls += ' enable-mask';
32497 cls += ' masonry-' + this.size + '-brick';
32500 if(this.placetitle.length){
32502 switch (this.placetitle) {
32504 cls += ' masonry-center-title';
32507 cls += ' masonry-bottom-title';
32514 if(!this.html.length && !this.bgimage.length){
32515 cls += ' masonry-center-title';
32518 if(!this.html.length && this.bgimage.length){
32519 cls += ' masonry-bottom-title';
32524 cls += ' ' + this.cls;
32528 tag: (this.href.length) ? 'a' : 'div',
32533 cls: 'masonry-brick-mask'
32537 cls: 'masonry-brick-paragraph',
32543 if(this.href.length){
32544 cfg.href = this.href;
32547 var cn = cfg.cn[1].cn;
32549 if(this.title.length){
32552 cls: 'masonry-brick-title',
32557 if(this.html.length){
32560 cls: 'masonry-brick-text',
32565 if (!this.title.length && !this.html.length) {
32566 cfg.cn[1].cls += ' hide';
32569 if(this.bgimage.length){
32572 cls: 'masonry-brick-image-view',
32577 if(this.videourl.length){
32578 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32579 // youtube support only?
32582 cls: 'masonry-brick-image-view',
32585 allowfullscreen : true
32593 getSplitAutoCreate : function()
32595 var cls = 'masonry-brick masonry-brick-split';
32597 if(this.href.length){
32598 cls += ' masonry-brick-link';
32601 if(this.bgimage.length){
32602 cls += ' masonry-brick-image';
32606 cls += ' masonry-' + this.size + '-brick';
32609 switch (this.placetitle) {
32611 cls += ' masonry-center-title';
32614 cls += ' masonry-bottom-title';
32617 if(!this.bgimage.length){
32618 cls += ' masonry-center-title';
32621 if(this.bgimage.length){
32622 cls += ' masonry-bottom-title';
32628 cls += ' ' + this.cls;
32632 tag: (this.href.length) ? 'a' : 'div',
32637 cls: 'masonry-brick-split-head',
32641 cls: 'masonry-brick-paragraph',
32648 cls: 'masonry-brick-split-body',
32654 if(this.href.length){
32655 cfg.href = this.href;
32658 if(this.title.length){
32659 cfg.cn[0].cn[0].cn.push({
32661 cls: 'masonry-brick-title',
32666 if(this.html.length){
32667 cfg.cn[1].cn.push({
32669 cls: 'masonry-brick-text',
32674 if(this.bgimage.length){
32675 cfg.cn[0].cn.push({
32677 cls: 'masonry-brick-image-view',
32682 if(this.videourl.length){
32683 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32684 // youtube support only?
32685 cfg.cn[0].cn.cn.push({
32687 cls: 'masonry-brick-image-view',
32690 allowfullscreen : true
32697 initEvents: function()
32699 switch (this.size) {
32732 this.el.on('touchstart', this.onTouchStart, this);
32733 this.el.on('touchmove', this.onTouchMove, this);
32734 this.el.on('touchend', this.onTouchEnd, this);
32735 this.el.on('contextmenu', this.onContextMenu, this);
32737 this.el.on('mouseenter' ,this.enter, this);
32738 this.el.on('mouseleave', this.leave, this);
32739 this.el.on('click', this.onClick, this);
32742 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32743 this.parent().bricks.push(this);
32748 onClick: function(e, el)
32750 var time = this.endTimer - this.startTimer;
32751 // Roo.log(e.preventDefault());
32754 e.preventDefault();
32759 if(!this.preventDefault){
32763 e.preventDefault();
32765 if (this.activeClass != '') {
32766 this.selectBrick();
32769 this.fireEvent('click', this, e);
32772 enter: function(e, el)
32774 e.preventDefault();
32776 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32780 if(this.bgimage.length && this.html.length){
32781 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32785 leave: function(e, el)
32787 e.preventDefault();
32789 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32793 if(this.bgimage.length && this.html.length){
32794 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32798 onTouchStart: function(e, el)
32800 // e.preventDefault();
32802 this.touchmoved = false;
32804 if(!this.isFitContainer){
32808 if(!this.bgimage.length || !this.html.length){
32812 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32814 this.timer = new Date().getTime();
32818 onTouchMove: function(e, el)
32820 this.touchmoved = true;
32823 onContextMenu : function(e,el)
32825 e.preventDefault();
32826 e.stopPropagation();
32830 onTouchEnd: function(e, el)
32832 // e.preventDefault();
32834 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32841 if(!this.bgimage.length || !this.html.length){
32843 if(this.href.length){
32844 window.location.href = this.href;
32850 if(!this.isFitContainer){
32854 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32856 window.location.href = this.href;
32859 //selection on single brick only
32860 selectBrick : function() {
32862 if (!this.parentId) {
32866 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32867 var index = m.selectedBrick.indexOf(this.id);
32870 m.selectedBrick.splice(index,1);
32871 this.el.removeClass(this.activeClass);
32875 for(var i = 0; i < m.selectedBrick.length; i++) {
32876 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32877 b.el.removeClass(b.activeClass);
32880 m.selectedBrick = [];
32882 m.selectedBrick.push(this.id);
32883 this.el.addClass(this.activeClass);
32887 isSelected : function(){
32888 return this.el.hasClass(this.activeClass);
32893 Roo.apply(Roo.bootstrap.MasonryBrick, {
32896 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32898 * register a Masonry Brick
32899 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32902 register : function(brick)
32904 //this.groups[brick.id] = brick;
32905 this.groups.add(brick.id, brick);
32908 * fetch a masonry brick based on the masonry brick ID
32909 * @param {string} the masonry brick to add
32910 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32913 get: function(brick_id)
32915 // if (typeof(this.groups[brick_id]) == 'undefined') {
32918 // return this.groups[brick_id] ;
32920 if(this.groups.key(brick_id)) {
32921 return this.groups.key(brick_id);
32939 * @class Roo.bootstrap.Brick
32940 * @extends Roo.bootstrap.Component
32941 * Bootstrap Brick class
32944 * Create a new Brick
32945 * @param {Object} config The config object
32948 Roo.bootstrap.Brick = function(config){
32949 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32955 * When a Brick is click
32956 * @param {Roo.bootstrap.Brick} this
32957 * @param {Roo.EventObject} e
32963 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32966 * @cfg {String} title
32970 * @cfg {String} html
32974 * @cfg {String} bgimage
32978 * @cfg {String} cls
32982 * @cfg {String} href
32986 * @cfg {String} video
32990 * @cfg {Boolean} square
32994 getAutoCreate : function()
32996 var cls = 'roo-brick';
32998 if(this.href.length){
32999 cls += ' roo-brick-link';
33002 if(this.bgimage.length){
33003 cls += ' roo-brick-image';
33006 if(!this.html.length && !this.bgimage.length){
33007 cls += ' roo-brick-center-title';
33010 if(!this.html.length && this.bgimage.length){
33011 cls += ' roo-brick-bottom-title';
33015 cls += ' ' + this.cls;
33019 tag: (this.href.length) ? 'a' : 'div',
33024 cls: 'roo-brick-paragraph',
33030 if(this.href.length){
33031 cfg.href = this.href;
33034 var cn = cfg.cn[0].cn;
33036 if(this.title.length){
33039 cls: 'roo-brick-title',
33044 if(this.html.length){
33047 cls: 'roo-brick-text',
33054 if(this.bgimage.length){
33057 cls: 'roo-brick-image-view',
33065 initEvents: function()
33067 if(this.title.length || this.html.length){
33068 this.el.on('mouseenter' ,this.enter, this);
33069 this.el.on('mouseleave', this.leave, this);
33072 Roo.EventManager.onWindowResize(this.resize, this);
33074 if(this.bgimage.length){
33075 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33076 this.imageEl.on('load', this.onImageLoad, this);
33083 onImageLoad : function()
33088 resize : function()
33090 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33092 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33094 if(this.bgimage.length){
33095 var image = this.el.select('.roo-brick-image-view', true).first();
33097 image.setWidth(paragraph.getWidth());
33100 image.setHeight(paragraph.getWidth());
33103 this.el.setHeight(image.getHeight());
33104 paragraph.setHeight(image.getHeight());
33110 enter: function(e, el)
33112 e.preventDefault();
33114 if(this.bgimage.length){
33115 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33116 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33120 leave: function(e, el)
33122 e.preventDefault();
33124 if(this.bgimage.length){
33125 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33126 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33141 * @class Roo.bootstrap.NumberField
33142 * @extends Roo.bootstrap.Input
33143 * Bootstrap NumberField class
33149 * Create a new NumberField
33150 * @param {Object} config The config object
33153 Roo.bootstrap.NumberField = function(config){
33154 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33157 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33160 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33162 allowDecimals : true,
33164 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33166 decimalSeparator : ".",
33168 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33170 decimalPrecision : 2,
33172 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33174 allowNegative : true,
33177 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33181 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33183 minValue : Number.NEGATIVE_INFINITY,
33185 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33187 maxValue : Number.MAX_VALUE,
33189 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33191 minText : "The minimum value for this field is {0}",
33193 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33195 maxText : "The maximum value for this field is {0}",
33197 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33198 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33200 nanText : "{0} is not a valid number",
33202 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33206 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33208 thousandsDelimiter : false,
33210 * @cfg {String} valueAlign alignment of value
33212 valueAlign : "left",
33214 getAutoCreate : function()
33216 var hiddenInput = {
33220 cls: 'hidden-number-input'
33224 hiddenInput.name = this.name;
33229 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33231 this.name = hiddenInput.name;
33233 if(cfg.cn.length > 0) {
33234 cfg.cn.push(hiddenInput);
33241 initEvents : function()
33243 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33245 var allowed = "0123456789";
33247 if(this.allowDecimals){
33248 allowed += this.decimalSeparator;
33251 if(this.allowNegative){
33255 if(this.thousandsDelimiter) {
33259 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33261 var keyPress = function(e){
33263 var k = e.getKey();
33265 var c = e.getCharCode();
33268 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33269 allowed.indexOf(String.fromCharCode(c)) === -1
33275 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33279 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33284 this.el.on("keypress", keyPress, this);
33287 validateValue : function(value)
33290 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33294 var num = this.parseValue(value);
33297 this.markInvalid(String.format(this.nanText, value));
33301 if(num < this.minValue){
33302 this.markInvalid(String.format(this.minText, this.minValue));
33306 if(num > this.maxValue){
33307 this.markInvalid(String.format(this.maxText, this.maxValue));
33314 getValue : function()
33316 var v = this.hiddenEl().getValue();
33318 return this.fixPrecision(this.parseValue(v));
33321 parseValue : function(value)
33323 if(this.thousandsDelimiter) {
33325 r = new RegExp(",", "g");
33326 value = value.replace(r, "");
33329 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33330 return isNaN(value) ? '' : value;
33333 fixPrecision : function(value)
33335 if(this.thousandsDelimiter) {
33337 r = new RegExp(",", "g");
33338 value = value.replace(r, "");
33341 var nan = isNaN(value);
33343 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33344 return nan ? '' : value;
33346 return parseFloat(value).toFixed(this.decimalPrecision);
33349 setValue : function(v)
33351 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33357 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33359 this.inputEl().dom.value = (v == '') ? '' :
33360 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33362 if(!this.allowZero && v === '0') {
33363 this.hiddenEl().dom.value = '';
33364 this.inputEl().dom.value = '';
33371 decimalPrecisionFcn : function(v)
33373 return Math.floor(v);
33376 beforeBlur : function()
33382 var v = this.parseValue(this.getRawValue());
33389 hiddenEl : function()
33391 return this.el.select('input.hidden-number-input',true).first();
33403 * @class Roo.bootstrap.DocumentSlider
33404 * @extends Roo.bootstrap.Component
33405 * Bootstrap DocumentSlider class
33408 * Create a new DocumentViewer
33409 * @param {Object} config The config object
33412 Roo.bootstrap.DocumentSlider = function(config){
33413 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33420 * Fire after initEvent
33421 * @param {Roo.bootstrap.DocumentSlider} this
33426 * Fire after update
33427 * @param {Roo.bootstrap.DocumentSlider} this
33433 * @param {Roo.bootstrap.DocumentSlider} this
33439 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33445 getAutoCreate : function()
33449 cls : 'roo-document-slider',
33453 cls : 'roo-document-slider-header',
33457 cls : 'roo-document-slider-header-title'
33463 cls : 'roo-document-slider-body',
33467 cls : 'roo-document-slider-prev',
33471 cls : 'fa fa-chevron-left'
33477 cls : 'roo-document-slider-thumb',
33481 cls : 'roo-document-slider-image'
33487 cls : 'roo-document-slider-next',
33491 cls : 'fa fa-chevron-right'
33503 initEvents : function()
33505 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33506 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33508 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33509 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33511 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33512 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33514 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33515 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33517 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33518 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33520 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33521 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33523 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33524 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33526 this.thumbEl.on('click', this.onClick, this);
33528 this.prevIndicator.on('click', this.prev, this);
33530 this.nextIndicator.on('click', this.next, this);
33534 initial : function()
33536 if(this.files.length){
33537 this.indicator = 1;
33541 this.fireEvent('initial', this);
33544 update : function()
33546 this.imageEl.attr('src', this.files[this.indicator - 1]);
33548 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33550 this.prevIndicator.show();
33552 if(this.indicator == 1){
33553 this.prevIndicator.hide();
33556 this.nextIndicator.show();
33558 if(this.indicator == this.files.length){
33559 this.nextIndicator.hide();
33562 this.thumbEl.scrollTo('top');
33564 this.fireEvent('update', this);
33567 onClick : function(e)
33569 e.preventDefault();
33571 this.fireEvent('click', this);
33576 e.preventDefault();
33578 this.indicator = Math.max(1, this.indicator - 1);
33585 e.preventDefault();
33587 this.indicator = Math.min(this.files.length, this.indicator + 1);
33601 * @class Roo.bootstrap.RadioSet
33602 * @extends Roo.bootstrap.Input
33603 * Bootstrap RadioSet class
33604 * @cfg {String} indicatorpos (left|right) default left
33605 * @cfg {Boolean} inline (true|false) inline the element (default true)
33606 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33608 * Create a new RadioSet
33609 * @param {Object} config The config object
33612 Roo.bootstrap.RadioSet = function(config){
33614 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33618 Roo.bootstrap.RadioSet.register(this);
33623 * Fires when the element is checked or unchecked.
33624 * @param {Roo.bootstrap.RadioSet} this This radio
33625 * @param {Roo.bootstrap.Radio} item The checked item
33630 * Fires when the element is click.
33631 * @param {Roo.bootstrap.RadioSet} this This radio set
33632 * @param {Roo.bootstrap.Radio} item The checked item
33633 * @param {Roo.EventObject} e The event object
33640 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33648 indicatorpos : 'left',
33650 getAutoCreate : function()
33654 cls : 'roo-radio-set-label',
33658 html : this.fieldLabel
33663 if(this.indicatorpos == 'left'){
33666 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33667 tooltip : 'This field is required'
33672 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33673 tooltip : 'This field is required'
33679 cls : 'roo-radio-set-items'
33682 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33684 if (align === 'left' && this.fieldLabel.length) {
33687 cls : "roo-radio-set-right",
33693 if(this.labelWidth > 12){
33694 label.style = "width: " + this.labelWidth + 'px';
33697 if(this.labelWidth < 13 && this.labelmd == 0){
33698 this.labelmd = this.labelWidth;
33701 if(this.labellg > 0){
33702 label.cls += ' col-lg-' + this.labellg;
33703 items.cls += ' col-lg-' + (12 - this.labellg);
33706 if(this.labelmd > 0){
33707 label.cls += ' col-md-' + this.labelmd;
33708 items.cls += ' col-md-' + (12 - this.labelmd);
33711 if(this.labelsm > 0){
33712 label.cls += ' col-sm-' + this.labelsm;
33713 items.cls += ' col-sm-' + (12 - this.labelsm);
33716 if(this.labelxs > 0){
33717 label.cls += ' col-xs-' + this.labelxs;
33718 items.cls += ' col-xs-' + (12 - this.labelxs);
33724 cls : 'roo-radio-set',
33728 cls : 'roo-radio-set-input',
33731 value : this.value ? this.value : ''
33738 if(this.weight.length){
33739 cfg.cls += ' roo-radio-' + this.weight;
33743 cfg.cls += ' roo-radio-set-inline';
33747 ['xs','sm','md','lg'].map(function(size){
33748 if (settings[size]) {
33749 cfg.cls += ' col-' + size + '-' + settings[size];
33757 initEvents : function()
33759 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33760 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33762 if(!this.fieldLabel.length){
33763 this.labelEl.hide();
33766 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33767 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33769 this.indicator = this.indicatorEl();
33771 if(this.indicator){
33772 this.indicator.addClass('invisible');
33775 this.originalValue = this.getValue();
33779 inputEl: function ()
33781 return this.el.select('.roo-radio-set-input', true).first();
33784 getChildContainer : function()
33786 return this.itemsEl;
33789 register : function(item)
33791 this.radioes.push(item);
33795 validate : function()
33797 if(this.getVisibilityEl().hasClass('hidden')){
33803 Roo.each(this.radioes, function(i){
33812 if(this.allowBlank) {
33816 if(this.disabled || valid){
33821 this.markInvalid();
33826 markValid : function()
33828 if(this.labelEl.isVisible(true)){
33829 this.indicatorEl().removeClass('visible');
33830 this.indicatorEl().addClass('invisible');
33833 this.el.removeClass([this.invalidClass, this.validClass]);
33834 this.el.addClass(this.validClass);
33836 this.fireEvent('valid', this);
33839 markInvalid : function(msg)
33841 if(this.allowBlank || this.disabled){
33845 if(this.labelEl.isVisible(true)){
33846 this.indicatorEl().removeClass('invisible');
33847 this.indicatorEl().addClass('visible');
33850 this.el.removeClass([this.invalidClass, this.validClass]);
33851 this.el.addClass(this.invalidClass);
33853 this.fireEvent('invalid', this, msg);
33857 setValue : function(v, suppressEvent)
33859 if(this.value === v){
33866 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33869 Roo.each(this.radioes, function(i){
33871 i.el.removeClass('checked');
33874 Roo.each(this.radioes, function(i){
33876 if(i.value === v || i.value.toString() === v.toString()){
33878 i.el.addClass('checked');
33880 if(suppressEvent !== true){
33881 this.fireEvent('check', this, i);
33892 clearInvalid : function(){
33894 if(!this.el || this.preventMark){
33898 this.el.removeClass([this.invalidClass]);
33900 this.fireEvent('valid', this);
33905 Roo.apply(Roo.bootstrap.RadioSet, {
33909 register : function(set)
33911 this.groups[set.name] = set;
33914 get: function(name)
33916 if (typeof(this.groups[name]) == 'undefined') {
33920 return this.groups[name] ;
33926 * Ext JS Library 1.1.1
33927 * Copyright(c) 2006-2007, Ext JS, LLC.
33929 * Originally Released Under LGPL - original licence link has changed is not relivant.
33932 * <script type="text/javascript">
33937 * @class Roo.bootstrap.SplitBar
33938 * @extends Roo.util.Observable
33939 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33943 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33944 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33945 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33946 split.minSize = 100;
33947 split.maxSize = 600;
33948 split.animate = true;
33949 split.on('moved', splitterMoved);
33952 * Create a new SplitBar
33953 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33954 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33955 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33956 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33957 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33958 position of the SplitBar).
33960 Roo.bootstrap.SplitBar = function(cfg){
33965 // dragElement : elm
33966 // resizingElement: el,
33968 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33969 // placement : Roo.bootstrap.SplitBar.LEFT ,
33970 // existingProxy ???
33973 this.el = Roo.get(cfg.dragElement, true);
33974 this.el.dom.unselectable = "on";
33976 this.resizingEl = Roo.get(cfg.resizingElement, true);
33980 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33981 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33984 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33987 * The minimum size of the resizing element. (Defaults to 0)
33993 * The maximum size of the resizing element. (Defaults to 2000)
33996 this.maxSize = 2000;
33999 * Whether to animate the transition to the new size
34002 this.animate = false;
34005 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34008 this.useShim = false;
34013 if(!cfg.existingProxy){
34015 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34017 this.proxy = Roo.get(cfg.existingProxy).dom;
34020 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34023 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34026 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34029 this.dragSpecs = {};
34032 * @private The adapter to use to positon and resize elements
34034 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34035 this.adapter.init(this);
34037 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34039 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34040 this.el.addClass("roo-splitbar-h");
34043 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34044 this.el.addClass("roo-splitbar-v");
34050 * Fires when the splitter is moved (alias for {@link #event-moved})
34051 * @param {Roo.bootstrap.SplitBar} this
34052 * @param {Number} newSize the new width or height
34057 * Fires when the splitter is moved
34058 * @param {Roo.bootstrap.SplitBar} this
34059 * @param {Number} newSize the new width or height
34063 * @event beforeresize
34064 * Fires before the splitter is dragged
34065 * @param {Roo.bootstrap.SplitBar} this
34067 "beforeresize" : true,
34069 "beforeapply" : true
34072 Roo.util.Observable.call(this);
34075 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34076 onStartProxyDrag : function(x, y){
34077 this.fireEvent("beforeresize", this);
34079 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34081 o.enableDisplayMode("block");
34082 // all splitbars share the same overlay
34083 Roo.bootstrap.SplitBar.prototype.overlay = o;
34085 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34086 this.overlay.show();
34087 Roo.get(this.proxy).setDisplayed("block");
34088 var size = this.adapter.getElementSize(this);
34089 this.activeMinSize = this.getMinimumSize();;
34090 this.activeMaxSize = this.getMaximumSize();;
34091 var c1 = size - this.activeMinSize;
34092 var c2 = Math.max(this.activeMaxSize - size, 0);
34093 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34094 this.dd.resetConstraints();
34095 this.dd.setXConstraint(
34096 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34097 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34099 this.dd.setYConstraint(0, 0);
34101 this.dd.resetConstraints();
34102 this.dd.setXConstraint(0, 0);
34103 this.dd.setYConstraint(
34104 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34105 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34108 this.dragSpecs.startSize = size;
34109 this.dragSpecs.startPoint = [x, y];
34110 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34114 * @private Called after the drag operation by the DDProxy
34116 onEndProxyDrag : function(e){
34117 Roo.get(this.proxy).setDisplayed(false);
34118 var endPoint = Roo.lib.Event.getXY(e);
34120 this.overlay.hide();
34123 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34124 newSize = this.dragSpecs.startSize +
34125 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34126 endPoint[0] - this.dragSpecs.startPoint[0] :
34127 this.dragSpecs.startPoint[0] - endPoint[0]
34130 newSize = this.dragSpecs.startSize +
34131 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34132 endPoint[1] - this.dragSpecs.startPoint[1] :
34133 this.dragSpecs.startPoint[1] - endPoint[1]
34136 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34137 if(newSize != this.dragSpecs.startSize){
34138 if(this.fireEvent('beforeapply', this, newSize) !== false){
34139 this.adapter.setElementSize(this, newSize);
34140 this.fireEvent("moved", this, newSize);
34141 this.fireEvent("resize", this, newSize);
34147 * Get the adapter this SplitBar uses
34148 * @return The adapter object
34150 getAdapter : function(){
34151 return this.adapter;
34155 * Set the adapter this SplitBar uses
34156 * @param {Object} adapter A SplitBar adapter object
34158 setAdapter : function(adapter){
34159 this.adapter = adapter;
34160 this.adapter.init(this);
34164 * Gets the minimum size for the resizing element
34165 * @return {Number} The minimum size
34167 getMinimumSize : function(){
34168 return this.minSize;
34172 * Sets the minimum size for the resizing element
34173 * @param {Number} minSize The minimum size
34175 setMinimumSize : function(minSize){
34176 this.minSize = minSize;
34180 * Gets the maximum size for the resizing element
34181 * @return {Number} The maximum size
34183 getMaximumSize : function(){
34184 return this.maxSize;
34188 * Sets the maximum size for the resizing element
34189 * @param {Number} maxSize The maximum size
34191 setMaximumSize : function(maxSize){
34192 this.maxSize = maxSize;
34196 * Sets the initialize size for the resizing element
34197 * @param {Number} size The initial size
34199 setCurrentSize : function(size){
34200 var oldAnimate = this.animate;
34201 this.animate = false;
34202 this.adapter.setElementSize(this, size);
34203 this.animate = oldAnimate;
34207 * Destroy this splitbar.
34208 * @param {Boolean} removeEl True to remove the element
34210 destroy : function(removeEl){
34212 this.shim.remove();
34215 this.proxy.parentNode.removeChild(this.proxy);
34223 * @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.
34225 Roo.bootstrap.SplitBar.createProxy = function(dir){
34226 var proxy = new Roo.Element(document.createElement("div"));
34227 proxy.unselectable();
34228 var cls = 'roo-splitbar-proxy';
34229 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34230 document.body.appendChild(proxy.dom);
34235 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34236 * Default Adapter. It assumes the splitter and resizing element are not positioned
34237 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34239 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34242 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34243 // do nothing for now
34244 init : function(s){
34248 * Called before drag operations to get the current size of the resizing element.
34249 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34251 getElementSize : function(s){
34252 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34253 return s.resizingEl.getWidth();
34255 return s.resizingEl.getHeight();
34260 * Called after drag operations to set the size of the resizing element.
34261 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34262 * @param {Number} newSize The new size to set
34263 * @param {Function} onComplete A function to be invoked when resizing is complete
34265 setElementSize : function(s, newSize, onComplete){
34266 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34268 s.resizingEl.setWidth(newSize);
34270 onComplete(s, newSize);
34273 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34278 s.resizingEl.setHeight(newSize);
34280 onComplete(s, newSize);
34283 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34290 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34291 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34292 * Adapter that moves the splitter element to align with the resized sizing element.
34293 * Used with an absolute positioned SplitBar.
34294 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34295 * document.body, make sure you assign an id to the body element.
34297 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34298 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34299 this.container = Roo.get(container);
34302 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34303 init : function(s){
34304 this.basic.init(s);
34307 getElementSize : function(s){
34308 return this.basic.getElementSize(s);
34311 setElementSize : function(s, newSize, onComplete){
34312 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34315 moveSplitter : function(s){
34316 var yes = Roo.bootstrap.SplitBar;
34317 switch(s.placement){
34319 s.el.setX(s.resizingEl.getRight());
34322 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34325 s.el.setY(s.resizingEl.getBottom());
34328 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34335 * Orientation constant - Create a vertical SplitBar
34339 Roo.bootstrap.SplitBar.VERTICAL = 1;
34342 * Orientation constant - Create a horizontal SplitBar
34346 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34349 * Placement constant - The resizing element is to the left of the splitter element
34353 Roo.bootstrap.SplitBar.LEFT = 1;
34356 * Placement constant - The resizing element is to the right of the splitter element
34360 Roo.bootstrap.SplitBar.RIGHT = 2;
34363 * Placement constant - The resizing element is positioned above the splitter element
34367 Roo.bootstrap.SplitBar.TOP = 3;
34370 * Placement constant - The resizing element is positioned under splitter element
34374 Roo.bootstrap.SplitBar.BOTTOM = 4;
34375 Roo.namespace("Roo.bootstrap.layout");/*
34377 * Ext JS Library 1.1.1
34378 * Copyright(c) 2006-2007, Ext JS, LLC.
34380 * Originally Released Under LGPL - original licence link has changed is not relivant.
34383 * <script type="text/javascript">
34387 * @class Roo.bootstrap.layout.Manager
34388 * @extends Roo.bootstrap.Component
34389 * Base class for layout managers.
34391 Roo.bootstrap.layout.Manager = function(config)
34393 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34399 /** false to disable window resize monitoring @type Boolean */
34400 this.monitorWindowResize = true;
34405 * Fires when a layout is performed.
34406 * @param {Roo.LayoutManager} this
34410 * @event regionresized
34411 * Fires when the user resizes a region.
34412 * @param {Roo.LayoutRegion} region The resized region
34413 * @param {Number} newSize The new size (width for east/west, height for north/south)
34415 "regionresized" : true,
34417 * @event regioncollapsed
34418 * Fires when a region is collapsed.
34419 * @param {Roo.LayoutRegion} region The collapsed region
34421 "regioncollapsed" : true,
34423 * @event regionexpanded
34424 * Fires when a region is expanded.
34425 * @param {Roo.LayoutRegion} region The expanded region
34427 "regionexpanded" : true
34429 this.updating = false;
34432 this.el = Roo.get(config.el);
34438 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34443 monitorWindowResize : true,
34449 onRender : function(ct, position)
34452 this.el = Roo.get(ct);
34455 //this.fireEvent('render',this);
34459 initEvents: function()
34463 // ie scrollbar fix
34464 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34465 document.body.scroll = "no";
34466 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34467 this.el.position('relative');
34469 this.id = this.el.id;
34470 this.el.addClass("roo-layout-container");
34471 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34472 if(this.el.dom != document.body ) {
34473 this.el.on('resize', this.layout,this);
34474 this.el.on('show', this.layout,this);
34480 * Returns true if this layout is currently being updated
34481 * @return {Boolean}
34483 isUpdating : function(){
34484 return this.updating;
34488 * Suspend the LayoutManager from doing auto-layouts while
34489 * making multiple add or remove calls
34491 beginUpdate : function(){
34492 this.updating = true;
34496 * Restore auto-layouts and optionally disable the manager from performing a layout
34497 * @param {Boolean} noLayout true to disable a layout update
34499 endUpdate : function(noLayout){
34500 this.updating = false;
34506 layout: function(){
34510 onRegionResized : function(region, newSize){
34511 this.fireEvent("regionresized", region, newSize);
34515 onRegionCollapsed : function(region){
34516 this.fireEvent("regioncollapsed", region);
34519 onRegionExpanded : function(region){
34520 this.fireEvent("regionexpanded", region);
34524 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34525 * performs box-model adjustments.
34526 * @return {Object} The size as an object {width: (the width), height: (the height)}
34528 getViewSize : function()
34531 if(this.el.dom != document.body){
34532 size = this.el.getSize();
34534 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34536 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34537 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34542 * Returns the Element this layout is bound to.
34543 * @return {Roo.Element}
34545 getEl : function(){
34550 * Returns the specified region.
34551 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34552 * @return {Roo.LayoutRegion}
34554 getRegion : function(target){
34555 return this.regions[target.toLowerCase()];
34558 onWindowResize : function(){
34559 if(this.monitorWindowResize){
34566 * Ext JS Library 1.1.1
34567 * Copyright(c) 2006-2007, Ext JS, LLC.
34569 * Originally Released Under LGPL - original licence link has changed is not relivant.
34572 * <script type="text/javascript">
34575 * @class Roo.bootstrap.layout.Border
34576 * @extends Roo.bootstrap.layout.Manager
34577 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34578 * please see: examples/bootstrap/nested.html<br><br>
34580 <b>The container the layout is rendered into can be either the body element or any other element.
34581 If it is not the body element, the container needs to either be an absolute positioned element,
34582 or you will need to add "position:relative" to the css of the container. You will also need to specify
34583 the container size if it is not the body element.</b>
34586 * Create a new Border
34587 * @param {Object} config Configuration options
34589 Roo.bootstrap.layout.Border = function(config){
34590 config = config || {};
34591 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34595 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34596 if(config[region]){
34597 config[region].region = region;
34598 this.addRegion(config[region]);
34604 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34606 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34608 * Creates and adds a new region if it doesn't already exist.
34609 * @param {String} target The target region key (north, south, east, west or center).
34610 * @param {Object} config The regions config object
34611 * @return {BorderLayoutRegion} The new region
34613 addRegion : function(config)
34615 if(!this.regions[config.region]){
34616 var r = this.factory(config);
34617 this.bindRegion(r);
34619 return this.regions[config.region];
34623 bindRegion : function(r){
34624 this.regions[r.config.region] = r;
34626 r.on("visibilitychange", this.layout, this);
34627 r.on("paneladded", this.layout, this);
34628 r.on("panelremoved", this.layout, this);
34629 r.on("invalidated", this.layout, this);
34630 r.on("resized", this.onRegionResized, this);
34631 r.on("collapsed", this.onRegionCollapsed, this);
34632 r.on("expanded", this.onRegionExpanded, this);
34636 * Performs a layout update.
34638 layout : function()
34640 if(this.updating) {
34644 // render all the rebions if they have not been done alreayd?
34645 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34646 if(this.regions[region] && !this.regions[region].bodyEl){
34647 this.regions[region].onRender(this.el)
34651 var size = this.getViewSize();
34652 var w = size.width;
34653 var h = size.height;
34658 //var x = 0, y = 0;
34660 var rs = this.regions;
34661 var north = rs["north"];
34662 var south = rs["south"];
34663 var west = rs["west"];
34664 var east = rs["east"];
34665 var center = rs["center"];
34666 //if(this.hideOnLayout){ // not supported anymore
34667 //c.el.setStyle("display", "none");
34669 if(north && north.isVisible()){
34670 var b = north.getBox();
34671 var m = north.getMargins();
34672 b.width = w - (m.left+m.right);
34675 centerY = b.height + b.y + m.bottom;
34676 centerH -= centerY;
34677 north.updateBox(this.safeBox(b));
34679 if(south && south.isVisible()){
34680 var b = south.getBox();
34681 var m = south.getMargins();
34682 b.width = w - (m.left+m.right);
34684 var totalHeight = (b.height + m.top + m.bottom);
34685 b.y = h - totalHeight + m.top;
34686 centerH -= totalHeight;
34687 south.updateBox(this.safeBox(b));
34689 if(west && west.isVisible()){
34690 var b = west.getBox();
34691 var m = west.getMargins();
34692 b.height = centerH - (m.top+m.bottom);
34694 b.y = centerY + m.top;
34695 var totalWidth = (b.width + m.left + m.right);
34696 centerX += totalWidth;
34697 centerW -= totalWidth;
34698 west.updateBox(this.safeBox(b));
34700 if(east && east.isVisible()){
34701 var b = east.getBox();
34702 var m = east.getMargins();
34703 b.height = centerH - (m.top+m.bottom);
34704 var totalWidth = (b.width + m.left + m.right);
34705 b.x = w - totalWidth + m.left;
34706 b.y = centerY + m.top;
34707 centerW -= totalWidth;
34708 east.updateBox(this.safeBox(b));
34711 var m = center.getMargins();
34713 x: centerX + m.left,
34714 y: centerY + m.top,
34715 width: centerW - (m.left+m.right),
34716 height: centerH - (m.top+m.bottom)
34718 //if(this.hideOnLayout){
34719 //center.el.setStyle("display", "block");
34721 center.updateBox(this.safeBox(centerBox));
34724 this.fireEvent("layout", this);
34728 safeBox : function(box){
34729 box.width = Math.max(0, box.width);
34730 box.height = Math.max(0, box.height);
34735 * Adds a ContentPanel (or subclass) to this layout.
34736 * @param {String} target The target region key (north, south, east, west or center).
34737 * @param {Roo.ContentPanel} panel The panel to add
34738 * @return {Roo.ContentPanel} The added panel
34740 add : function(target, panel){
34742 target = target.toLowerCase();
34743 return this.regions[target].add(panel);
34747 * Remove a ContentPanel (or subclass) to this layout.
34748 * @param {String} target The target region key (north, south, east, west or center).
34749 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34750 * @return {Roo.ContentPanel} The removed panel
34752 remove : function(target, panel){
34753 target = target.toLowerCase();
34754 return this.regions[target].remove(panel);
34758 * Searches all regions for a panel with the specified id
34759 * @param {String} panelId
34760 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34762 findPanel : function(panelId){
34763 var rs = this.regions;
34764 for(var target in rs){
34765 if(typeof rs[target] != "function"){
34766 var p = rs[target].getPanel(panelId);
34776 * Searches all regions for a panel with the specified id and activates (shows) it.
34777 * @param {String/ContentPanel} panelId The panels id or the panel itself
34778 * @return {Roo.ContentPanel} The shown panel or null
34780 showPanel : function(panelId) {
34781 var rs = this.regions;
34782 for(var target in rs){
34783 var r = rs[target];
34784 if(typeof r != "function"){
34785 if(r.hasPanel(panelId)){
34786 return r.showPanel(panelId);
34794 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34795 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34798 restoreState : function(provider){
34800 provider = Roo.state.Manager;
34802 var sm = new Roo.LayoutStateManager();
34803 sm.init(this, provider);
34809 * Adds a xtype elements to the layout.
34813 xtype : 'ContentPanel',
34820 xtype : 'NestedLayoutPanel',
34826 items : [ ... list of content panels or nested layout panels.. ]
34830 * @param {Object} cfg Xtype definition of item to add.
34832 addxtype : function(cfg)
34834 // basically accepts a pannel...
34835 // can accept a layout region..!?!?
34836 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34839 // theory? children can only be panels??
34841 //if (!cfg.xtype.match(/Panel$/)) {
34846 if (typeof(cfg.region) == 'undefined') {
34847 Roo.log("Failed to add Panel, region was not set");
34851 var region = cfg.region;
34857 xitems = cfg.items;
34864 case 'Content': // ContentPanel (el, cfg)
34865 case 'Scroll': // ContentPanel (el, cfg)
34867 cfg.autoCreate = true;
34868 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34870 // var el = this.el.createChild();
34871 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34874 this.add(region, ret);
34878 case 'TreePanel': // our new panel!
34879 cfg.el = this.el.createChild();
34880 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34881 this.add(region, ret);
34886 // create a new Layout (which is a Border Layout...
34888 var clayout = cfg.layout;
34889 clayout.el = this.el.createChild();
34890 clayout.items = clayout.items || [];
34894 // replace this exitems with the clayout ones..
34895 xitems = clayout.items;
34897 // force background off if it's in center...
34898 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34899 cfg.background = false;
34901 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34904 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34905 //console.log('adding nested layout panel ' + cfg.toSource());
34906 this.add(region, ret);
34907 nb = {}; /// find first...
34912 // needs grid and region
34914 //var el = this.getRegion(region).el.createChild();
34916 *var el = this.el.createChild();
34917 // create the grid first...
34918 cfg.grid.container = el;
34919 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34922 if (region == 'center' && this.active ) {
34923 cfg.background = false;
34926 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34928 this.add(region, ret);
34930 if (cfg.background) {
34931 // render grid on panel activation (if panel background)
34932 ret.on('activate', function(gp) {
34933 if (!gp.grid.rendered) {
34934 // gp.grid.render(el);
34938 // cfg.grid.render(el);
34944 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34945 // it was the old xcomponent building that caused this before.
34946 // espeically if border is the top element in the tree.
34956 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34958 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34959 this.add(region, ret);
34963 throw "Can not add '" + cfg.xtype + "' to Border";
34969 this.beginUpdate();
34973 Roo.each(xitems, function(i) {
34974 region = nb && i.region ? i.region : false;
34976 var add = ret.addxtype(i);
34979 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34980 if (!i.background) {
34981 abn[region] = nb[region] ;
34988 // make the last non-background panel active..
34989 //if (nb) { Roo.log(abn); }
34992 for(var r in abn) {
34993 region = this.getRegion(r);
34995 // tried using nb[r], but it does not work..
34997 region.showPanel(abn[r]);
35008 factory : function(cfg)
35011 var validRegions = Roo.bootstrap.layout.Border.regions;
35013 var target = cfg.region;
35016 var r = Roo.bootstrap.layout;
35020 return new r.North(cfg);
35022 return new r.South(cfg);
35024 return new r.East(cfg);
35026 return new r.West(cfg);
35028 return new r.Center(cfg);
35030 throw 'Layout region "'+target+'" not supported.';
35037 * Ext JS Library 1.1.1
35038 * Copyright(c) 2006-2007, Ext JS, LLC.
35040 * Originally Released Under LGPL - original licence link has changed is not relivant.
35043 * <script type="text/javascript">
35047 * @class Roo.bootstrap.layout.Basic
35048 * @extends Roo.util.Observable
35049 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35050 * and does not have a titlebar, tabs or any other features. All it does is size and position
35051 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35052 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35053 * @cfg {string} region the region that it inhabits..
35054 * @cfg {bool} skipConfig skip config?
35058 Roo.bootstrap.layout.Basic = function(config){
35060 this.mgr = config.mgr;
35062 this.position = config.region;
35064 var skipConfig = config.skipConfig;
35068 * @scope Roo.BasicLayoutRegion
35072 * @event beforeremove
35073 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35074 * @param {Roo.LayoutRegion} this
35075 * @param {Roo.ContentPanel} panel The panel
35076 * @param {Object} e The cancel event object
35078 "beforeremove" : true,
35080 * @event invalidated
35081 * Fires when the layout for this region is changed.
35082 * @param {Roo.LayoutRegion} this
35084 "invalidated" : true,
35086 * @event visibilitychange
35087 * Fires when this region is shown or hidden
35088 * @param {Roo.LayoutRegion} this
35089 * @param {Boolean} visibility true or false
35091 "visibilitychange" : true,
35093 * @event paneladded
35094 * Fires when a panel is added.
35095 * @param {Roo.LayoutRegion} this
35096 * @param {Roo.ContentPanel} panel The panel
35098 "paneladded" : true,
35100 * @event panelremoved
35101 * Fires when a panel is removed.
35102 * @param {Roo.LayoutRegion} this
35103 * @param {Roo.ContentPanel} panel The panel
35105 "panelremoved" : true,
35107 * @event beforecollapse
35108 * Fires when this region before collapse.
35109 * @param {Roo.LayoutRegion} this
35111 "beforecollapse" : true,
35114 * Fires when this region is collapsed.
35115 * @param {Roo.LayoutRegion} this
35117 "collapsed" : true,
35120 * Fires when this region is expanded.
35121 * @param {Roo.LayoutRegion} this
35126 * Fires when this region is slid into view.
35127 * @param {Roo.LayoutRegion} this
35129 "slideshow" : true,
35132 * Fires when this region slides out of view.
35133 * @param {Roo.LayoutRegion} this
35135 "slidehide" : true,
35137 * @event panelactivated
35138 * Fires when a panel is activated.
35139 * @param {Roo.LayoutRegion} this
35140 * @param {Roo.ContentPanel} panel The activated panel
35142 "panelactivated" : true,
35145 * Fires when the user resizes this region.
35146 * @param {Roo.LayoutRegion} this
35147 * @param {Number} newSize The new size (width for east/west, height for north/south)
35151 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35152 this.panels = new Roo.util.MixedCollection();
35153 this.panels.getKey = this.getPanelId.createDelegate(this);
35155 this.activePanel = null;
35156 // ensure listeners are added...
35158 if (config.listeners || config.events) {
35159 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35160 listeners : config.listeners || {},
35161 events : config.events || {}
35165 if(skipConfig !== true){
35166 this.applyConfig(config);
35170 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35172 getPanelId : function(p){
35176 applyConfig : function(config){
35177 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35178 this.config = config;
35183 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35184 * the width, for horizontal (north, south) the height.
35185 * @param {Number} newSize The new width or height
35187 resizeTo : function(newSize){
35188 var el = this.el ? this.el :
35189 (this.activePanel ? this.activePanel.getEl() : null);
35191 switch(this.position){
35194 el.setWidth(newSize);
35195 this.fireEvent("resized", this, newSize);
35199 el.setHeight(newSize);
35200 this.fireEvent("resized", this, newSize);
35206 getBox : function(){
35207 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35210 getMargins : function(){
35211 return this.margins;
35214 updateBox : function(box){
35216 var el = this.activePanel.getEl();
35217 el.dom.style.left = box.x + "px";
35218 el.dom.style.top = box.y + "px";
35219 this.activePanel.setSize(box.width, box.height);
35223 * Returns the container element for this region.
35224 * @return {Roo.Element}
35226 getEl : function(){
35227 return this.activePanel;
35231 * Returns true if this region is currently visible.
35232 * @return {Boolean}
35234 isVisible : function(){
35235 return this.activePanel ? true : false;
35238 setActivePanel : function(panel){
35239 panel = this.getPanel(panel);
35240 if(this.activePanel && this.activePanel != panel){
35241 this.activePanel.setActiveState(false);
35242 this.activePanel.getEl().setLeftTop(-10000,-10000);
35244 this.activePanel = panel;
35245 panel.setActiveState(true);
35247 panel.setSize(this.box.width, this.box.height);
35249 this.fireEvent("panelactivated", this, panel);
35250 this.fireEvent("invalidated");
35254 * Show the specified panel.
35255 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35256 * @return {Roo.ContentPanel} The shown panel or null
35258 showPanel : function(panel){
35259 panel = this.getPanel(panel);
35261 this.setActivePanel(panel);
35267 * Get the active panel for this region.
35268 * @return {Roo.ContentPanel} The active panel or null
35270 getActivePanel : function(){
35271 return this.activePanel;
35275 * Add the passed ContentPanel(s)
35276 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35277 * @return {Roo.ContentPanel} The panel added (if only one was added)
35279 add : function(panel){
35280 if(arguments.length > 1){
35281 for(var i = 0, len = arguments.length; i < len; i++) {
35282 this.add(arguments[i]);
35286 if(this.hasPanel(panel)){
35287 this.showPanel(panel);
35290 var el = panel.getEl();
35291 if(el.dom.parentNode != this.mgr.el.dom){
35292 this.mgr.el.dom.appendChild(el.dom);
35294 if(panel.setRegion){
35295 panel.setRegion(this);
35297 this.panels.add(panel);
35298 el.setStyle("position", "absolute");
35299 if(!panel.background){
35300 this.setActivePanel(panel);
35301 if(this.config.initialSize && this.panels.getCount()==1){
35302 this.resizeTo(this.config.initialSize);
35305 this.fireEvent("paneladded", this, panel);
35310 * Returns true if the panel is in this region.
35311 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35312 * @return {Boolean}
35314 hasPanel : function(panel){
35315 if(typeof panel == "object"){ // must be panel obj
35316 panel = panel.getId();
35318 return this.getPanel(panel) ? true : false;
35322 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35323 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35324 * @param {Boolean} preservePanel Overrides the config preservePanel option
35325 * @return {Roo.ContentPanel} The panel that was removed
35327 remove : function(panel, preservePanel){
35328 panel = this.getPanel(panel);
35333 this.fireEvent("beforeremove", this, panel, e);
35334 if(e.cancel === true){
35337 var panelId = panel.getId();
35338 this.panels.removeKey(panelId);
35343 * Returns the panel specified or null if it's not in this region.
35344 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35345 * @return {Roo.ContentPanel}
35347 getPanel : function(id){
35348 if(typeof id == "object"){ // must be panel obj
35351 return this.panels.get(id);
35355 * Returns this regions position (north/south/east/west/center).
35358 getPosition: function(){
35359 return this.position;
35363 * Ext JS Library 1.1.1
35364 * Copyright(c) 2006-2007, Ext JS, LLC.
35366 * Originally Released Under LGPL - original licence link has changed is not relivant.
35369 * <script type="text/javascript">
35373 * @class Roo.bootstrap.layout.Region
35374 * @extends Roo.bootstrap.layout.Basic
35375 * This class represents a region in a layout manager.
35377 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35378 * @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})
35379 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35380 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35381 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35382 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35383 * @cfg {String} title The title for the region (overrides panel titles)
35384 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35385 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35386 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35387 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35388 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35389 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35390 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35391 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35392 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35393 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35395 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35396 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35397 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35398 * @cfg {Number} width For East/West panels
35399 * @cfg {Number} height For North/South panels
35400 * @cfg {Boolean} split To show the splitter
35401 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35403 * @cfg {string} cls Extra CSS classes to add to region
35405 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35406 * @cfg {string} region the region that it inhabits..
35409 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35410 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35412 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35413 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35414 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35416 Roo.bootstrap.layout.Region = function(config)
35418 this.applyConfig(config);
35420 var mgr = config.mgr;
35421 var pos = config.region;
35422 config.skipConfig = true;
35423 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35426 this.onRender(mgr.el);
35429 this.visible = true;
35430 this.collapsed = false;
35431 this.unrendered_panels = [];
35434 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35436 position: '', // set by wrapper (eg. north/south etc..)
35437 unrendered_panels : null, // unrendered panels.
35438 createBody : function(){
35439 /** This region's body element
35440 * @type Roo.Element */
35441 this.bodyEl = this.el.createChild({
35443 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35447 onRender: function(ctr, pos)
35449 var dh = Roo.DomHelper;
35450 /** This region's container element
35451 * @type Roo.Element */
35452 this.el = dh.append(ctr.dom, {
35454 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35456 /** This region's title element
35457 * @type Roo.Element */
35459 this.titleEl = dh.append(this.el.dom,
35462 unselectable: "on",
35463 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35465 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35466 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35469 this.titleEl.enableDisplayMode();
35470 /** This region's title text element
35471 * @type HTMLElement */
35472 this.titleTextEl = this.titleEl.dom.firstChild;
35473 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35475 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35476 this.closeBtn.enableDisplayMode();
35477 this.closeBtn.on("click", this.closeClicked, this);
35478 this.closeBtn.hide();
35480 this.createBody(this.config);
35481 if(this.config.hideWhenEmpty){
35483 this.on("paneladded", this.validateVisibility, this);
35484 this.on("panelremoved", this.validateVisibility, this);
35486 if(this.autoScroll){
35487 this.bodyEl.setStyle("overflow", "auto");
35489 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35491 //if(c.titlebar !== false){
35492 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35493 this.titleEl.hide();
35495 this.titleEl.show();
35496 if(this.config.title){
35497 this.titleTextEl.innerHTML = this.config.title;
35501 if(this.config.collapsed){
35502 this.collapse(true);
35504 if(this.config.hidden){
35508 if (this.unrendered_panels && this.unrendered_panels.length) {
35509 for (var i =0;i< this.unrendered_panels.length; i++) {
35510 this.add(this.unrendered_panels[i]);
35512 this.unrendered_panels = null;
35518 applyConfig : function(c)
35521 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35522 var dh = Roo.DomHelper;
35523 if(c.titlebar !== false){
35524 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35525 this.collapseBtn.on("click", this.collapse, this);
35526 this.collapseBtn.enableDisplayMode();
35528 if(c.showPin === true || this.showPin){
35529 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35530 this.stickBtn.enableDisplayMode();
35531 this.stickBtn.on("click", this.expand, this);
35532 this.stickBtn.hide();
35537 /** This region's collapsed element
35538 * @type Roo.Element */
35541 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35542 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35545 if(c.floatable !== false){
35546 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35547 this.collapsedEl.on("click", this.collapseClick, this);
35550 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35551 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35552 id: "message", unselectable: "on", style:{"float":"left"}});
35553 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35555 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35556 this.expandBtn.on("click", this.expand, this);
35560 if(this.collapseBtn){
35561 this.collapseBtn.setVisible(c.collapsible == true);
35564 this.cmargins = c.cmargins || this.cmargins ||
35565 (this.position == "west" || this.position == "east" ?
35566 {top: 0, left: 2, right:2, bottom: 0} :
35567 {top: 2, left: 0, right:0, bottom: 2});
35569 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35572 this.bottomTabs = c.tabPosition != "top";
35574 this.autoScroll = c.autoScroll || false;
35579 this.duration = c.duration || .30;
35580 this.slideDuration = c.slideDuration || .45;
35585 * Returns true if this region is currently visible.
35586 * @return {Boolean}
35588 isVisible : function(){
35589 return this.visible;
35593 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35594 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35596 //setCollapsedTitle : function(title){
35597 // title = title || " ";
35598 // if(this.collapsedTitleTextEl){
35599 // this.collapsedTitleTextEl.innerHTML = title;
35603 getBox : function(){
35605 // if(!this.collapsed){
35606 b = this.el.getBox(false, true);
35608 // b = this.collapsedEl.getBox(false, true);
35613 getMargins : function(){
35614 return this.margins;
35615 //return this.collapsed ? this.cmargins : this.margins;
35618 highlight : function(){
35619 this.el.addClass("x-layout-panel-dragover");
35622 unhighlight : function(){
35623 this.el.removeClass("x-layout-panel-dragover");
35626 updateBox : function(box)
35628 if (!this.bodyEl) {
35629 return; // not rendered yet..
35633 if(!this.collapsed){
35634 this.el.dom.style.left = box.x + "px";
35635 this.el.dom.style.top = box.y + "px";
35636 this.updateBody(box.width, box.height);
35638 this.collapsedEl.dom.style.left = box.x + "px";
35639 this.collapsedEl.dom.style.top = box.y + "px";
35640 this.collapsedEl.setSize(box.width, box.height);
35643 this.tabs.autoSizeTabs();
35647 updateBody : function(w, h)
35650 this.el.setWidth(w);
35651 w -= this.el.getBorderWidth("rl");
35652 if(this.config.adjustments){
35653 w += this.config.adjustments[0];
35656 if(h !== null && h > 0){
35657 this.el.setHeight(h);
35658 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35659 h -= this.el.getBorderWidth("tb");
35660 if(this.config.adjustments){
35661 h += this.config.adjustments[1];
35663 this.bodyEl.setHeight(h);
35665 h = this.tabs.syncHeight(h);
35668 if(this.panelSize){
35669 w = w !== null ? w : this.panelSize.width;
35670 h = h !== null ? h : this.panelSize.height;
35672 if(this.activePanel){
35673 var el = this.activePanel.getEl();
35674 w = w !== null ? w : el.getWidth();
35675 h = h !== null ? h : el.getHeight();
35676 this.panelSize = {width: w, height: h};
35677 this.activePanel.setSize(w, h);
35679 if(Roo.isIE && this.tabs){
35680 this.tabs.el.repaint();
35685 * Returns the container element for this region.
35686 * @return {Roo.Element}
35688 getEl : function(){
35693 * Hides this region.
35696 //if(!this.collapsed){
35697 this.el.dom.style.left = "-2000px";
35700 // this.collapsedEl.dom.style.left = "-2000px";
35701 // this.collapsedEl.hide();
35703 this.visible = false;
35704 this.fireEvent("visibilitychange", this, false);
35708 * Shows this region if it was previously hidden.
35711 //if(!this.collapsed){
35714 // this.collapsedEl.show();
35716 this.visible = true;
35717 this.fireEvent("visibilitychange", this, true);
35720 closeClicked : function(){
35721 if(this.activePanel){
35722 this.remove(this.activePanel);
35726 collapseClick : function(e){
35728 e.stopPropagation();
35731 e.stopPropagation();
35737 * Collapses this region.
35738 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35741 collapse : function(skipAnim, skipCheck = false){
35742 if(this.collapsed) {
35746 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35748 this.collapsed = true;
35750 this.split.el.hide();
35752 if(this.config.animate && skipAnim !== true){
35753 this.fireEvent("invalidated", this);
35754 this.animateCollapse();
35756 this.el.setLocation(-20000,-20000);
35758 this.collapsedEl.show();
35759 this.fireEvent("collapsed", this);
35760 this.fireEvent("invalidated", this);
35766 animateCollapse : function(){
35771 * Expands this region if it was previously collapsed.
35772 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35773 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35776 expand : function(e, skipAnim){
35778 e.stopPropagation();
35780 if(!this.collapsed || this.el.hasActiveFx()) {
35784 this.afterSlideIn();
35787 this.collapsed = false;
35788 if(this.config.animate && skipAnim !== true){
35789 this.animateExpand();
35793 this.split.el.show();
35795 this.collapsedEl.setLocation(-2000,-2000);
35796 this.collapsedEl.hide();
35797 this.fireEvent("invalidated", this);
35798 this.fireEvent("expanded", this);
35802 animateExpand : function(){
35806 initTabs : function()
35808 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35810 var ts = new Roo.bootstrap.panel.Tabs({
35811 el: this.bodyEl.dom,
35812 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35813 disableTooltips: this.config.disableTabTips,
35814 toolbar : this.config.toolbar
35817 if(this.config.hideTabs){
35818 ts.stripWrap.setDisplayed(false);
35821 ts.resizeTabs = this.config.resizeTabs === true;
35822 ts.minTabWidth = this.config.minTabWidth || 40;
35823 ts.maxTabWidth = this.config.maxTabWidth || 250;
35824 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35825 ts.monitorResize = false;
35826 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35827 ts.bodyEl.addClass('roo-layout-tabs-body');
35828 this.panels.each(this.initPanelAsTab, this);
35831 initPanelAsTab : function(panel){
35832 var ti = this.tabs.addTab(
35836 this.config.closeOnTab && panel.isClosable(),
35839 if(panel.tabTip !== undefined){
35840 ti.setTooltip(panel.tabTip);
35842 ti.on("activate", function(){
35843 this.setActivePanel(panel);
35846 if(this.config.closeOnTab){
35847 ti.on("beforeclose", function(t, e){
35849 this.remove(panel);
35853 panel.tabItem = ti;
35858 updatePanelTitle : function(panel, title)
35860 if(this.activePanel == panel){
35861 this.updateTitle(title);
35864 var ti = this.tabs.getTab(panel.getEl().id);
35866 if(panel.tabTip !== undefined){
35867 ti.setTooltip(panel.tabTip);
35872 updateTitle : function(title){
35873 if(this.titleTextEl && !this.config.title){
35874 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35878 setActivePanel : function(panel)
35880 panel = this.getPanel(panel);
35881 if(this.activePanel && this.activePanel != panel){
35882 if(this.activePanel.setActiveState(false) === false){
35886 this.activePanel = panel;
35887 panel.setActiveState(true);
35888 if(this.panelSize){
35889 panel.setSize(this.panelSize.width, this.panelSize.height);
35892 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35894 this.updateTitle(panel.getTitle());
35896 this.fireEvent("invalidated", this);
35898 this.fireEvent("panelactivated", this, panel);
35902 * Shows the specified panel.
35903 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35904 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35906 showPanel : function(panel)
35908 panel = this.getPanel(panel);
35911 var tab = this.tabs.getTab(panel.getEl().id);
35912 if(tab.isHidden()){
35913 this.tabs.unhideTab(tab.id);
35917 this.setActivePanel(panel);
35924 * Get the active panel for this region.
35925 * @return {Roo.ContentPanel} The active panel or null
35927 getActivePanel : function(){
35928 return this.activePanel;
35931 validateVisibility : function(){
35932 if(this.panels.getCount() < 1){
35933 this.updateTitle(" ");
35934 this.closeBtn.hide();
35937 if(!this.isVisible()){
35944 * Adds the passed ContentPanel(s) to this region.
35945 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35946 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35948 add : function(panel)
35950 if(arguments.length > 1){
35951 for(var i = 0, len = arguments.length; i < len; i++) {
35952 this.add(arguments[i]);
35957 // if we have not been rendered yet, then we can not really do much of this..
35958 if (!this.bodyEl) {
35959 this.unrendered_panels.push(panel);
35966 if(this.hasPanel(panel)){
35967 this.showPanel(panel);
35970 panel.setRegion(this);
35971 this.panels.add(panel);
35972 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35973 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35974 // and hide them... ???
35975 this.bodyEl.dom.appendChild(panel.getEl().dom);
35976 if(panel.background !== true){
35977 this.setActivePanel(panel);
35979 this.fireEvent("paneladded", this, panel);
35986 this.initPanelAsTab(panel);
35990 if(panel.background !== true){
35991 this.tabs.activate(panel.getEl().id);
35993 this.fireEvent("paneladded", this, panel);
35998 * Hides the tab for the specified panel.
35999 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36001 hidePanel : function(panel){
36002 if(this.tabs && (panel = this.getPanel(panel))){
36003 this.tabs.hideTab(panel.getEl().id);
36008 * Unhides the tab for a previously hidden panel.
36009 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36011 unhidePanel : function(panel){
36012 if(this.tabs && (panel = this.getPanel(panel))){
36013 this.tabs.unhideTab(panel.getEl().id);
36017 clearPanels : function(){
36018 while(this.panels.getCount() > 0){
36019 this.remove(this.panels.first());
36024 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36025 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36026 * @param {Boolean} preservePanel Overrides the config preservePanel option
36027 * @return {Roo.ContentPanel} The panel that was removed
36029 remove : function(panel, preservePanel)
36031 panel = this.getPanel(panel);
36036 this.fireEvent("beforeremove", this, panel, e);
36037 if(e.cancel === true){
36040 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36041 var panelId = panel.getId();
36042 this.panels.removeKey(panelId);
36044 document.body.appendChild(panel.getEl().dom);
36047 this.tabs.removeTab(panel.getEl().id);
36048 }else if (!preservePanel){
36049 this.bodyEl.dom.removeChild(panel.getEl().dom);
36051 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36052 var p = this.panels.first();
36053 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36054 tempEl.appendChild(p.getEl().dom);
36055 this.bodyEl.update("");
36056 this.bodyEl.dom.appendChild(p.getEl().dom);
36058 this.updateTitle(p.getTitle());
36060 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36061 this.setActivePanel(p);
36063 panel.setRegion(null);
36064 if(this.activePanel == panel){
36065 this.activePanel = null;
36067 if(this.config.autoDestroy !== false && preservePanel !== true){
36068 try{panel.destroy();}catch(e){}
36070 this.fireEvent("panelremoved", this, panel);
36075 * Returns the TabPanel component used by this region
36076 * @return {Roo.TabPanel}
36078 getTabs : function(){
36082 createTool : function(parentEl, className){
36083 var btn = Roo.DomHelper.append(parentEl, {
36085 cls: "x-layout-tools-button",
36088 cls: "roo-layout-tools-button-inner " + className,
36092 btn.addClassOnOver("roo-layout-tools-button-over");
36097 * Ext JS Library 1.1.1
36098 * Copyright(c) 2006-2007, Ext JS, LLC.
36100 * Originally Released Under LGPL - original licence link has changed is not relivant.
36103 * <script type="text/javascript">
36109 * @class Roo.SplitLayoutRegion
36110 * @extends Roo.LayoutRegion
36111 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36113 Roo.bootstrap.layout.Split = function(config){
36114 this.cursor = config.cursor;
36115 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36118 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36120 splitTip : "Drag to resize.",
36121 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36122 useSplitTips : false,
36124 applyConfig : function(config){
36125 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36128 onRender : function(ctr,pos) {
36130 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36131 if(!this.config.split){
36136 var splitEl = Roo.DomHelper.append(ctr.dom, {
36138 id: this.el.id + "-split",
36139 cls: "roo-layout-split roo-layout-split-"+this.position,
36142 /** The SplitBar for this region
36143 * @type Roo.SplitBar */
36144 // does not exist yet...
36145 Roo.log([this.position, this.orientation]);
36147 this.split = new Roo.bootstrap.SplitBar({
36148 dragElement : splitEl,
36149 resizingElement: this.el,
36150 orientation : this.orientation
36153 this.split.on("moved", this.onSplitMove, this);
36154 this.split.useShim = this.config.useShim === true;
36155 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36156 if(this.useSplitTips){
36157 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36159 //if(config.collapsible){
36160 // this.split.el.on("dblclick", this.collapse, this);
36163 if(typeof this.config.minSize != "undefined"){
36164 this.split.minSize = this.config.minSize;
36166 if(typeof this.config.maxSize != "undefined"){
36167 this.split.maxSize = this.config.maxSize;
36169 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36170 this.hideSplitter();
36175 getHMaxSize : function(){
36176 var cmax = this.config.maxSize || 10000;
36177 var center = this.mgr.getRegion("center");
36178 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36181 getVMaxSize : function(){
36182 var cmax = this.config.maxSize || 10000;
36183 var center = this.mgr.getRegion("center");
36184 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36187 onSplitMove : function(split, newSize){
36188 this.fireEvent("resized", this, newSize);
36192 * Returns the {@link Roo.SplitBar} for this region.
36193 * @return {Roo.SplitBar}
36195 getSplitBar : function(){
36200 this.hideSplitter();
36201 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36204 hideSplitter : function(){
36206 this.split.el.setLocation(-2000,-2000);
36207 this.split.el.hide();
36213 this.split.el.show();
36215 Roo.bootstrap.layout.Split.superclass.show.call(this);
36218 beforeSlide: function(){
36219 if(Roo.isGecko){// firefox overflow auto bug workaround
36220 this.bodyEl.clip();
36222 this.tabs.bodyEl.clip();
36224 if(this.activePanel){
36225 this.activePanel.getEl().clip();
36227 if(this.activePanel.beforeSlide){
36228 this.activePanel.beforeSlide();
36234 afterSlide : function(){
36235 if(Roo.isGecko){// firefox overflow auto bug workaround
36236 this.bodyEl.unclip();
36238 this.tabs.bodyEl.unclip();
36240 if(this.activePanel){
36241 this.activePanel.getEl().unclip();
36242 if(this.activePanel.afterSlide){
36243 this.activePanel.afterSlide();
36249 initAutoHide : function(){
36250 if(this.autoHide !== false){
36251 if(!this.autoHideHd){
36252 var st = new Roo.util.DelayedTask(this.slideIn, this);
36253 this.autoHideHd = {
36254 "mouseout": function(e){
36255 if(!e.within(this.el, true)){
36259 "mouseover" : function(e){
36265 this.el.on(this.autoHideHd);
36269 clearAutoHide : function(){
36270 if(this.autoHide !== false){
36271 this.el.un("mouseout", this.autoHideHd.mouseout);
36272 this.el.un("mouseover", this.autoHideHd.mouseover);
36276 clearMonitor : function(){
36277 Roo.get(document).un("click", this.slideInIf, this);
36280 // these names are backwards but not changed for compat
36281 slideOut : function(){
36282 if(this.isSlid || this.el.hasActiveFx()){
36285 this.isSlid = true;
36286 if(this.collapseBtn){
36287 this.collapseBtn.hide();
36289 this.closeBtnState = this.closeBtn.getStyle('display');
36290 this.closeBtn.hide();
36292 this.stickBtn.show();
36295 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36296 this.beforeSlide();
36297 this.el.setStyle("z-index", 10001);
36298 this.el.slideIn(this.getSlideAnchor(), {
36299 callback: function(){
36301 this.initAutoHide();
36302 Roo.get(document).on("click", this.slideInIf, this);
36303 this.fireEvent("slideshow", this);
36310 afterSlideIn : function(){
36311 this.clearAutoHide();
36312 this.isSlid = false;
36313 this.clearMonitor();
36314 this.el.setStyle("z-index", "");
36315 if(this.collapseBtn){
36316 this.collapseBtn.show();
36318 this.closeBtn.setStyle('display', this.closeBtnState);
36320 this.stickBtn.hide();
36322 this.fireEvent("slidehide", this);
36325 slideIn : function(cb){
36326 if(!this.isSlid || this.el.hasActiveFx()){
36330 this.isSlid = false;
36331 this.beforeSlide();
36332 this.el.slideOut(this.getSlideAnchor(), {
36333 callback: function(){
36334 this.el.setLeftTop(-10000, -10000);
36336 this.afterSlideIn();
36344 slideInIf : function(e){
36345 if(!e.within(this.el)){
36350 animateCollapse : function(){
36351 this.beforeSlide();
36352 this.el.setStyle("z-index", 20000);
36353 var anchor = this.getSlideAnchor();
36354 this.el.slideOut(anchor, {
36355 callback : function(){
36356 this.el.setStyle("z-index", "");
36357 this.collapsedEl.slideIn(anchor, {duration:.3});
36359 this.el.setLocation(-10000,-10000);
36361 this.fireEvent("collapsed", this);
36368 animateExpand : function(){
36369 this.beforeSlide();
36370 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36371 this.el.setStyle("z-index", 20000);
36372 this.collapsedEl.hide({
36375 this.el.slideIn(this.getSlideAnchor(), {
36376 callback : function(){
36377 this.el.setStyle("z-index", "");
36380 this.split.el.show();
36382 this.fireEvent("invalidated", this);
36383 this.fireEvent("expanded", this);
36411 getAnchor : function(){
36412 return this.anchors[this.position];
36415 getCollapseAnchor : function(){
36416 return this.canchors[this.position];
36419 getSlideAnchor : function(){
36420 return this.sanchors[this.position];
36423 getAlignAdj : function(){
36424 var cm = this.cmargins;
36425 switch(this.position){
36441 getExpandAdj : function(){
36442 var c = this.collapsedEl, cm = this.cmargins;
36443 switch(this.position){
36445 return [-(cm.right+c.getWidth()+cm.left), 0];
36448 return [cm.right+c.getWidth()+cm.left, 0];
36451 return [0, -(cm.top+cm.bottom+c.getHeight())];
36454 return [0, cm.top+cm.bottom+c.getHeight()];
36460 * Ext JS Library 1.1.1
36461 * Copyright(c) 2006-2007, Ext JS, LLC.
36463 * Originally Released Under LGPL - original licence link has changed is not relivant.
36466 * <script type="text/javascript">
36469 * These classes are private internal classes
36471 Roo.bootstrap.layout.Center = function(config){
36472 config.region = "center";
36473 Roo.bootstrap.layout.Region.call(this, config);
36474 this.visible = true;
36475 this.minWidth = config.minWidth || 20;
36476 this.minHeight = config.minHeight || 20;
36479 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36481 // center panel can't be hidden
36485 // center panel can't be hidden
36488 getMinWidth: function(){
36489 return this.minWidth;
36492 getMinHeight: function(){
36493 return this.minHeight;
36506 Roo.bootstrap.layout.North = function(config)
36508 config.region = 'north';
36509 config.cursor = 'n-resize';
36511 Roo.bootstrap.layout.Split.call(this, config);
36515 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36516 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36517 this.split.el.addClass("roo-layout-split-v");
36519 var size = config.initialSize || config.height;
36520 if(typeof size != "undefined"){
36521 this.el.setHeight(size);
36524 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36526 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36530 getBox : function(){
36531 if(this.collapsed){
36532 return this.collapsedEl.getBox();
36534 var box = this.el.getBox();
36536 box.height += this.split.el.getHeight();
36541 updateBox : function(box){
36542 if(this.split && !this.collapsed){
36543 box.height -= this.split.el.getHeight();
36544 this.split.el.setLeft(box.x);
36545 this.split.el.setTop(box.y+box.height);
36546 this.split.el.setWidth(box.width);
36548 if(this.collapsed){
36549 this.updateBody(box.width, null);
36551 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36559 Roo.bootstrap.layout.South = function(config){
36560 config.region = 'south';
36561 config.cursor = 's-resize';
36562 Roo.bootstrap.layout.Split.call(this, config);
36564 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36565 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36566 this.split.el.addClass("roo-layout-split-v");
36568 var size = config.initialSize || config.height;
36569 if(typeof size != "undefined"){
36570 this.el.setHeight(size);
36574 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36575 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36576 getBox : function(){
36577 if(this.collapsed){
36578 return this.collapsedEl.getBox();
36580 var box = this.el.getBox();
36582 var sh = this.split.el.getHeight();
36589 updateBox : function(box){
36590 if(this.split && !this.collapsed){
36591 var sh = this.split.el.getHeight();
36594 this.split.el.setLeft(box.x);
36595 this.split.el.setTop(box.y-sh);
36596 this.split.el.setWidth(box.width);
36598 if(this.collapsed){
36599 this.updateBody(box.width, null);
36601 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36605 Roo.bootstrap.layout.East = function(config){
36606 config.region = "east";
36607 config.cursor = "e-resize";
36608 Roo.bootstrap.layout.Split.call(this, config);
36610 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36611 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36612 this.split.el.addClass("roo-layout-split-h");
36614 var size = config.initialSize || config.width;
36615 if(typeof size != "undefined"){
36616 this.el.setWidth(size);
36619 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36620 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36621 getBox : function(){
36622 if(this.collapsed){
36623 return this.collapsedEl.getBox();
36625 var box = this.el.getBox();
36627 var sw = this.split.el.getWidth();
36634 updateBox : function(box){
36635 if(this.split && !this.collapsed){
36636 var sw = this.split.el.getWidth();
36638 this.split.el.setLeft(box.x);
36639 this.split.el.setTop(box.y);
36640 this.split.el.setHeight(box.height);
36643 if(this.collapsed){
36644 this.updateBody(null, box.height);
36646 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36650 Roo.bootstrap.layout.West = function(config){
36651 config.region = "west";
36652 config.cursor = "w-resize";
36654 Roo.bootstrap.layout.Split.call(this, config);
36656 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36657 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36658 this.split.el.addClass("roo-layout-split-h");
36662 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36663 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36665 onRender: function(ctr, pos)
36667 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36668 var size = this.config.initialSize || this.config.width;
36669 if(typeof size != "undefined"){
36670 this.el.setWidth(size);
36674 getBox : function(){
36675 if(this.collapsed){
36676 return this.collapsedEl.getBox();
36678 var box = this.el.getBox();
36680 box.width += this.split.el.getWidth();
36685 updateBox : function(box){
36686 if(this.split && !this.collapsed){
36687 var sw = this.split.el.getWidth();
36689 this.split.el.setLeft(box.x+box.width);
36690 this.split.el.setTop(box.y);
36691 this.split.el.setHeight(box.height);
36693 if(this.collapsed){
36694 this.updateBody(null, box.height);
36696 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36699 Roo.namespace("Roo.bootstrap.panel");/*
36701 * Ext JS Library 1.1.1
36702 * Copyright(c) 2006-2007, Ext JS, LLC.
36704 * Originally Released Under LGPL - original licence link has changed is not relivant.
36707 * <script type="text/javascript">
36710 * @class Roo.ContentPanel
36711 * @extends Roo.util.Observable
36712 * A basic ContentPanel element.
36713 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36714 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36715 * @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
36716 * @cfg {Boolean} closable True if the panel can be closed/removed
36717 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36718 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36719 * @cfg {Toolbar} toolbar A toolbar for this panel
36720 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36721 * @cfg {String} title The title for this panel
36722 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36723 * @cfg {String} url Calls {@link #setUrl} with this value
36724 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36725 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36726 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36727 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36728 * @cfg {Boolean} badges render the badges
36731 * Create a new ContentPanel.
36732 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36733 * @param {String/Object} config A string to set only the title or a config object
36734 * @param {String} content (optional) Set the HTML content for this panel
36735 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36737 Roo.bootstrap.panel.Content = function( config){
36739 this.tpl = config.tpl || false;
36741 var el = config.el;
36742 var content = config.content;
36744 if(config.autoCreate){ // xtype is available if this is called from factory
36747 this.el = Roo.get(el);
36748 if(!this.el && config && config.autoCreate){
36749 if(typeof config.autoCreate == "object"){
36750 if(!config.autoCreate.id){
36751 config.autoCreate.id = config.id||el;
36753 this.el = Roo.DomHelper.append(document.body,
36754 config.autoCreate, true);
36756 var elcfg = { tag: "div",
36757 cls: "roo-layout-inactive-content",
36761 elcfg.html = config.html;
36765 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36768 this.closable = false;
36769 this.loaded = false;
36770 this.active = false;
36773 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36775 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36777 this.wrapEl = this.el; //this.el.wrap();
36779 if (config.toolbar.items) {
36780 ti = config.toolbar.items ;
36781 delete config.toolbar.items ;
36785 this.toolbar.render(this.wrapEl, 'before');
36786 for(var i =0;i < ti.length;i++) {
36787 // Roo.log(['add child', items[i]]);
36788 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36790 this.toolbar.items = nitems;
36791 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36792 delete config.toolbar;
36796 // xtype created footer. - not sure if will work as we normally have to render first..
36797 if (this.footer && !this.footer.el && this.footer.xtype) {
36798 if (!this.wrapEl) {
36799 this.wrapEl = this.el.wrap();
36802 this.footer.container = this.wrapEl.createChild();
36804 this.footer = Roo.factory(this.footer, Roo);
36809 if(typeof config == "string"){
36810 this.title = config;
36812 Roo.apply(this, config);
36816 this.resizeEl = Roo.get(this.resizeEl, true);
36818 this.resizeEl = this.el;
36820 // handle view.xtype
36828 * Fires when this panel is activated.
36829 * @param {Roo.ContentPanel} this
36833 * @event deactivate
36834 * Fires when this panel is activated.
36835 * @param {Roo.ContentPanel} this
36837 "deactivate" : true,
36841 * Fires when this panel is resized if fitToFrame is true.
36842 * @param {Roo.ContentPanel} this
36843 * @param {Number} width The width after any component adjustments
36844 * @param {Number} height The height after any component adjustments
36850 * Fires when this tab is created
36851 * @param {Roo.ContentPanel} this
36862 if(this.autoScroll){
36863 this.resizeEl.setStyle("overflow", "auto");
36865 // fix randome scrolling
36866 //this.el.on('scroll', function() {
36867 // Roo.log('fix random scolling');
36868 // this.scrollTo('top',0);
36871 content = content || this.content;
36873 this.setContent(content);
36875 if(config && config.url){
36876 this.setUrl(this.url, this.params, this.loadOnce);
36881 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36883 if (this.view && typeof(this.view.xtype) != 'undefined') {
36884 this.view.el = this.el.appendChild(document.createElement("div"));
36885 this.view = Roo.factory(this.view);
36886 this.view.render && this.view.render(false, '');
36890 this.fireEvent('render', this);
36893 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36897 setRegion : function(region){
36898 this.region = region;
36899 this.setActiveClass(region && !this.background);
36903 setActiveClass: function(state)
36906 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36907 this.el.setStyle('position','relative');
36909 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36910 this.el.setStyle('position', 'absolute');
36915 * Returns the toolbar for this Panel if one was configured.
36916 * @return {Roo.Toolbar}
36918 getToolbar : function(){
36919 return this.toolbar;
36922 setActiveState : function(active)
36924 this.active = active;
36925 this.setActiveClass(active);
36927 if(this.fireEvent("deactivate", this) === false){
36932 this.fireEvent("activate", this);
36936 * Updates this panel's element
36937 * @param {String} content The new content
36938 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36940 setContent : function(content, loadScripts){
36941 this.el.update(content, loadScripts);
36944 ignoreResize : function(w, h){
36945 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36948 this.lastSize = {width: w, height: h};
36953 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36954 * @return {Roo.UpdateManager} The UpdateManager
36956 getUpdateManager : function(){
36957 return this.el.getUpdateManager();
36960 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36961 * @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:
36964 url: "your-url.php",
36965 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36966 callback: yourFunction,
36967 scope: yourObject, //(optional scope)
36970 text: "Loading...",
36975 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36976 * 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.
36977 * @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}
36978 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36979 * @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.
36980 * @return {Roo.ContentPanel} this
36983 var um = this.el.getUpdateManager();
36984 um.update.apply(um, arguments);
36990 * 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.
36991 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36992 * @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)
36993 * @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)
36994 * @return {Roo.UpdateManager} The UpdateManager
36996 setUrl : function(url, params, loadOnce){
36997 if(this.refreshDelegate){
36998 this.removeListener("activate", this.refreshDelegate);
37000 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37001 this.on("activate", this.refreshDelegate);
37002 return this.el.getUpdateManager();
37005 _handleRefresh : function(url, params, loadOnce){
37006 if(!loadOnce || !this.loaded){
37007 var updater = this.el.getUpdateManager();
37008 updater.update(url, params, this._setLoaded.createDelegate(this));
37012 _setLoaded : function(){
37013 this.loaded = true;
37017 * Returns this panel's id
37020 getId : function(){
37025 * Returns this panel's element - used by regiosn to add.
37026 * @return {Roo.Element}
37028 getEl : function(){
37029 return this.wrapEl || this.el;
37034 adjustForComponents : function(width, height)
37036 //Roo.log('adjustForComponents ');
37037 if(this.resizeEl != this.el){
37038 width -= this.el.getFrameWidth('lr');
37039 height -= this.el.getFrameWidth('tb');
37042 var te = this.toolbar.getEl();
37043 te.setWidth(width);
37044 height -= te.getHeight();
37047 var te = this.footer.getEl();
37048 te.setWidth(width);
37049 height -= te.getHeight();
37053 if(this.adjustments){
37054 width += this.adjustments[0];
37055 height += this.adjustments[1];
37057 return {"width": width, "height": height};
37060 setSize : function(width, height){
37061 if(this.fitToFrame && !this.ignoreResize(width, height)){
37062 if(this.fitContainer && this.resizeEl != this.el){
37063 this.el.setSize(width, height);
37065 var size = this.adjustForComponents(width, height);
37066 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37067 this.fireEvent('resize', this, size.width, size.height);
37072 * Returns this panel's title
37075 getTitle : function(){
37077 if (typeof(this.title) != 'object') {
37082 for (var k in this.title) {
37083 if (!this.title.hasOwnProperty(k)) {
37087 if (k.indexOf('-') >= 0) {
37088 var s = k.split('-');
37089 for (var i = 0; i<s.length; i++) {
37090 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37093 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37100 * Set this panel's title
37101 * @param {String} title
37103 setTitle : function(title){
37104 this.title = title;
37106 this.region.updatePanelTitle(this, title);
37111 * Returns true is this panel was configured to be closable
37112 * @return {Boolean}
37114 isClosable : function(){
37115 return this.closable;
37118 beforeSlide : function(){
37120 this.resizeEl.clip();
37123 afterSlide : function(){
37125 this.resizeEl.unclip();
37129 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37130 * Will fail silently if the {@link #setUrl} method has not been called.
37131 * This does not activate the panel, just updates its content.
37133 refresh : function(){
37134 if(this.refreshDelegate){
37135 this.loaded = false;
37136 this.refreshDelegate();
37141 * Destroys this panel
37143 destroy : function(){
37144 this.el.removeAllListeners();
37145 var tempEl = document.createElement("span");
37146 tempEl.appendChild(this.el.dom);
37147 tempEl.innerHTML = "";
37153 * form - if the content panel contains a form - this is a reference to it.
37154 * @type {Roo.form.Form}
37158 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37159 * This contains a reference to it.
37165 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37175 * @param {Object} cfg Xtype definition of item to add.
37179 getChildContainer: function () {
37180 return this.getEl();
37185 var ret = new Roo.factory(cfg);
37190 if (cfg.xtype.match(/^Form$/)) {
37193 //if (this.footer) {
37194 // el = this.footer.container.insertSibling(false, 'before');
37196 el = this.el.createChild();
37199 this.form = new Roo.form.Form(cfg);
37202 if ( this.form.allItems.length) {
37203 this.form.render(el.dom);
37207 // should only have one of theses..
37208 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37209 // views.. should not be just added - used named prop 'view''
37211 cfg.el = this.el.appendChild(document.createElement("div"));
37214 var ret = new Roo.factory(cfg);
37216 ret.render && ret.render(false, ''); // render blank..
37226 * @class Roo.bootstrap.panel.Grid
37227 * @extends Roo.bootstrap.panel.Content
37229 * Create a new GridPanel.
37230 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37231 * @param {Object} config A the config object
37237 Roo.bootstrap.panel.Grid = function(config)
37241 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37242 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37244 config.el = this.wrapper;
37245 //this.el = this.wrapper;
37247 if (config.container) {
37248 // ctor'ed from a Border/panel.grid
37251 this.wrapper.setStyle("overflow", "hidden");
37252 this.wrapper.addClass('roo-grid-container');
37257 if(config.toolbar){
37258 var tool_el = this.wrapper.createChild();
37259 this.toolbar = Roo.factory(config.toolbar);
37261 if (config.toolbar.items) {
37262 ti = config.toolbar.items ;
37263 delete config.toolbar.items ;
37267 this.toolbar.render(tool_el);
37268 for(var i =0;i < ti.length;i++) {
37269 // Roo.log(['add child', items[i]]);
37270 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37272 this.toolbar.items = nitems;
37274 delete config.toolbar;
37277 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37278 config.grid.scrollBody = true;;
37279 config.grid.monitorWindowResize = false; // turn off autosizing
37280 config.grid.autoHeight = false;
37281 config.grid.autoWidth = false;
37283 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37285 if (config.background) {
37286 // render grid on panel activation (if panel background)
37287 this.on('activate', function(gp) {
37288 if (!gp.grid.rendered) {
37289 gp.grid.render(this.wrapper);
37290 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37295 this.grid.render(this.wrapper);
37296 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37299 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37300 // ??? needed ??? config.el = this.wrapper;
37305 // xtype created footer. - not sure if will work as we normally have to render first..
37306 if (this.footer && !this.footer.el && this.footer.xtype) {
37308 var ctr = this.grid.getView().getFooterPanel(true);
37309 this.footer.dataSource = this.grid.dataSource;
37310 this.footer = Roo.factory(this.footer, Roo);
37311 this.footer.render(ctr);
37321 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37322 getId : function(){
37323 return this.grid.id;
37327 * Returns the grid for this panel
37328 * @return {Roo.bootstrap.Table}
37330 getGrid : function(){
37334 setSize : function(width, height){
37335 if(!this.ignoreResize(width, height)){
37336 var grid = this.grid;
37337 var size = this.adjustForComponents(width, height);
37338 var gridel = grid.getGridEl();
37339 gridel.setSize(size.width, size.height);
37341 var thd = grid.getGridEl().select('thead',true).first();
37342 var tbd = grid.getGridEl().select('tbody', true).first();
37344 tbd.setSize(width, height - thd.getHeight());
37353 beforeSlide : function(){
37354 this.grid.getView().scroller.clip();
37357 afterSlide : function(){
37358 this.grid.getView().scroller.unclip();
37361 destroy : function(){
37362 this.grid.destroy();
37364 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37369 * @class Roo.bootstrap.panel.Nest
37370 * @extends Roo.bootstrap.panel.Content
37372 * Create a new Panel, that can contain a layout.Border.
37375 * @param {Roo.BorderLayout} layout The layout for this panel
37376 * @param {String/Object} config A string to set only the title or a config object
37378 Roo.bootstrap.panel.Nest = function(config)
37380 // construct with only one argument..
37381 /* FIXME - implement nicer consturctors
37382 if (layout.layout) {
37384 layout = config.layout;
37385 delete config.layout;
37387 if (layout.xtype && !layout.getEl) {
37388 // then layout needs constructing..
37389 layout = Roo.factory(layout, Roo);
37393 config.el = config.layout.getEl();
37395 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37397 config.layout.monitorWindowResize = false; // turn off autosizing
37398 this.layout = config.layout;
37399 this.layout.getEl().addClass("roo-layout-nested-layout");
37406 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37408 setSize : function(width, height){
37409 if(!this.ignoreResize(width, height)){
37410 var size = this.adjustForComponents(width, height);
37411 var el = this.layout.getEl();
37412 if (size.height < 1) {
37413 el.setWidth(size.width);
37415 el.setSize(size.width, size.height);
37417 var touch = el.dom.offsetWidth;
37418 this.layout.layout();
37419 // ie requires a double layout on the first pass
37420 if(Roo.isIE && !this.initialized){
37421 this.initialized = true;
37422 this.layout.layout();
37427 // activate all subpanels if not currently active..
37429 setActiveState : function(active){
37430 this.active = active;
37431 this.setActiveClass(active);
37434 this.fireEvent("deactivate", this);
37438 this.fireEvent("activate", this);
37439 // not sure if this should happen before or after..
37440 if (!this.layout) {
37441 return; // should not happen..
37444 for (var r in this.layout.regions) {
37445 reg = this.layout.getRegion(r);
37446 if (reg.getActivePanel()) {
37447 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37448 reg.setActivePanel(reg.getActivePanel());
37451 if (!reg.panels.length) {
37454 reg.showPanel(reg.getPanel(0));
37463 * Returns the nested BorderLayout for this panel
37464 * @return {Roo.BorderLayout}
37466 getLayout : function(){
37467 return this.layout;
37471 * Adds a xtype elements to the layout of the nested panel
37475 xtype : 'ContentPanel',
37482 xtype : 'NestedLayoutPanel',
37488 items : [ ... list of content panels or nested layout panels.. ]
37492 * @param {Object} cfg Xtype definition of item to add.
37494 addxtype : function(cfg) {
37495 return this.layout.addxtype(cfg);
37500 * Ext JS Library 1.1.1
37501 * Copyright(c) 2006-2007, Ext JS, LLC.
37503 * Originally Released Under LGPL - original licence link has changed is not relivant.
37506 * <script type="text/javascript">
37509 * @class Roo.TabPanel
37510 * @extends Roo.util.Observable
37511 * A lightweight tab container.
37515 // basic tabs 1, built from existing content
37516 var tabs = new Roo.TabPanel("tabs1");
37517 tabs.addTab("script", "View Script");
37518 tabs.addTab("markup", "View Markup");
37519 tabs.activate("script");
37521 // more advanced tabs, built from javascript
37522 var jtabs = new Roo.TabPanel("jtabs");
37523 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37525 // set up the UpdateManager
37526 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37527 var updater = tab2.getUpdateManager();
37528 updater.setDefaultUrl("ajax1.htm");
37529 tab2.on('activate', updater.refresh, updater, true);
37531 // Use setUrl for Ajax loading
37532 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37533 tab3.setUrl("ajax2.htm", null, true);
37536 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37539 jtabs.activate("jtabs-1");
37542 * Create a new TabPanel.
37543 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37544 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37546 Roo.bootstrap.panel.Tabs = function(config){
37548 * The container element for this TabPanel.
37549 * @type Roo.Element
37551 this.el = Roo.get(config.el);
37554 if(typeof config == "boolean"){
37555 this.tabPosition = config ? "bottom" : "top";
37557 Roo.apply(this, config);
37561 if(this.tabPosition == "bottom"){
37562 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37563 this.el.addClass("roo-tabs-bottom");
37565 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37566 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37567 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37569 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37571 if(this.tabPosition != "bottom"){
37572 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37573 * @type Roo.Element
37575 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37576 this.el.addClass("roo-tabs-top");
37580 this.bodyEl.setStyle("position", "relative");
37582 this.active = null;
37583 this.activateDelegate = this.activate.createDelegate(this);
37588 * Fires when the active tab changes
37589 * @param {Roo.TabPanel} this
37590 * @param {Roo.TabPanelItem} activePanel The new active tab
37594 * @event beforetabchange
37595 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37596 * @param {Roo.TabPanel} this
37597 * @param {Object} e Set cancel to true on this object to cancel the tab change
37598 * @param {Roo.TabPanelItem} tab The tab being changed to
37600 "beforetabchange" : true
37603 Roo.EventManager.onWindowResize(this.onResize, this);
37604 this.cpad = this.el.getPadding("lr");
37605 this.hiddenCount = 0;
37608 // toolbar on the tabbar support...
37609 if (this.toolbar) {
37610 alert("no toolbar support yet");
37611 this.toolbar = false;
37613 var tcfg = this.toolbar;
37614 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37615 this.toolbar = new Roo.Toolbar(tcfg);
37616 if (Roo.isSafari) {
37617 var tbl = tcfg.container.child('table', true);
37618 tbl.setAttribute('width', '100%');
37626 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37629 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37631 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37633 tabPosition : "top",
37635 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37637 currentTabWidth : 0,
37639 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37643 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37647 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37649 preferredTabWidth : 175,
37651 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37653 resizeTabs : false,
37655 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37657 monitorResize : true,
37659 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37664 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37665 * @param {String} id The id of the div to use <b>or create</b>
37666 * @param {String} text The text for the tab
37667 * @param {String} content (optional) Content to put in the TabPanelItem body
37668 * @param {Boolean} closable (optional) True to create a close icon on the tab
37669 * @return {Roo.TabPanelItem} The created TabPanelItem
37671 addTab : function(id, text, content, closable, tpl)
37673 var item = new Roo.bootstrap.panel.TabItem({
37677 closable : closable,
37680 this.addTabItem(item);
37682 item.setContent(content);
37688 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37689 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37690 * @return {Roo.TabPanelItem}
37692 getTab : function(id){
37693 return this.items[id];
37697 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37698 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37700 hideTab : function(id){
37701 var t = this.items[id];
37704 this.hiddenCount++;
37705 this.autoSizeTabs();
37710 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37711 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37713 unhideTab : function(id){
37714 var t = this.items[id];
37716 t.setHidden(false);
37717 this.hiddenCount--;
37718 this.autoSizeTabs();
37723 * Adds an existing {@link Roo.TabPanelItem}.
37724 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37726 addTabItem : function(item){
37727 this.items[item.id] = item;
37728 this.items.push(item);
37729 // if(this.resizeTabs){
37730 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37731 // this.autoSizeTabs();
37733 // item.autoSize();
37738 * Removes a {@link Roo.TabPanelItem}.
37739 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37741 removeTab : function(id){
37742 var items = this.items;
37743 var tab = items[id];
37744 if(!tab) { return; }
37745 var index = items.indexOf(tab);
37746 if(this.active == tab && items.length > 1){
37747 var newTab = this.getNextAvailable(index);
37752 this.stripEl.dom.removeChild(tab.pnode.dom);
37753 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37754 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37756 items.splice(index, 1);
37757 delete this.items[tab.id];
37758 tab.fireEvent("close", tab);
37759 tab.purgeListeners();
37760 this.autoSizeTabs();
37763 getNextAvailable : function(start){
37764 var items = this.items;
37766 // look for a next tab that will slide over to
37767 // replace the one being removed
37768 while(index < items.length){
37769 var item = items[++index];
37770 if(item && !item.isHidden()){
37774 // if one isn't found select the previous tab (on the left)
37777 var item = items[--index];
37778 if(item && !item.isHidden()){
37786 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37787 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37789 disableTab : function(id){
37790 var tab = this.items[id];
37791 if(tab && this.active != tab){
37797 * Enables a {@link Roo.TabPanelItem} that is disabled.
37798 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37800 enableTab : function(id){
37801 var tab = this.items[id];
37806 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37807 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37808 * @return {Roo.TabPanelItem} The TabPanelItem.
37810 activate : function(id){
37811 var tab = this.items[id];
37815 if(tab == this.active || tab.disabled){
37819 this.fireEvent("beforetabchange", this, e, tab);
37820 if(e.cancel !== true && !tab.disabled){
37822 this.active.hide();
37824 this.active = this.items[id];
37825 this.active.show();
37826 this.fireEvent("tabchange", this, this.active);
37832 * Gets the active {@link Roo.TabPanelItem}.
37833 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37835 getActiveTab : function(){
37836 return this.active;
37840 * Updates the tab body element to fit the height of the container element
37841 * for overflow scrolling
37842 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37844 syncHeight : function(targetHeight){
37845 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37846 var bm = this.bodyEl.getMargins();
37847 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37848 this.bodyEl.setHeight(newHeight);
37852 onResize : function(){
37853 if(this.monitorResize){
37854 this.autoSizeTabs();
37859 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37861 beginUpdate : function(){
37862 this.updating = true;
37866 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37868 endUpdate : function(){
37869 this.updating = false;
37870 this.autoSizeTabs();
37874 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37876 autoSizeTabs : function(){
37877 var count = this.items.length;
37878 var vcount = count - this.hiddenCount;
37879 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37882 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37883 var availWidth = Math.floor(w / vcount);
37884 var b = this.stripBody;
37885 if(b.getWidth() > w){
37886 var tabs = this.items;
37887 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37888 if(availWidth < this.minTabWidth){
37889 /*if(!this.sleft){ // incomplete scrolling code
37890 this.createScrollButtons();
37893 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37896 if(this.currentTabWidth < this.preferredTabWidth){
37897 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37903 * Returns the number of tabs in this TabPanel.
37906 getCount : function(){
37907 return this.items.length;
37911 * Resizes all the tabs to the passed width
37912 * @param {Number} The new width
37914 setTabWidth : function(width){
37915 this.currentTabWidth = width;
37916 for(var i = 0, len = this.items.length; i < len; i++) {
37917 if(!this.items[i].isHidden()) {
37918 this.items[i].setWidth(width);
37924 * Destroys this TabPanel
37925 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37927 destroy : function(removeEl){
37928 Roo.EventManager.removeResizeListener(this.onResize, this);
37929 for(var i = 0, len = this.items.length; i < len; i++){
37930 this.items[i].purgeListeners();
37932 if(removeEl === true){
37933 this.el.update("");
37938 createStrip : function(container)
37940 var strip = document.createElement("nav");
37941 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37942 container.appendChild(strip);
37946 createStripList : function(strip)
37948 // div wrapper for retard IE
37949 // returns the "tr" element.
37950 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37951 //'<div class="x-tabs-strip-wrap">'+
37952 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37953 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37954 return strip.firstChild; //.firstChild.firstChild.firstChild;
37956 createBody : function(container)
37958 var body = document.createElement("div");
37959 Roo.id(body, "tab-body");
37960 //Roo.fly(body).addClass("x-tabs-body");
37961 Roo.fly(body).addClass("tab-content");
37962 container.appendChild(body);
37965 createItemBody :function(bodyEl, id){
37966 var body = Roo.getDom(id);
37968 body = document.createElement("div");
37971 //Roo.fly(body).addClass("x-tabs-item-body");
37972 Roo.fly(body).addClass("tab-pane");
37973 bodyEl.insertBefore(body, bodyEl.firstChild);
37977 createStripElements : function(stripEl, text, closable, tpl)
37979 var td = document.createElement("li"); // was td..
37982 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37985 stripEl.appendChild(td);
37987 td.className = "x-tabs-closable";
37988 if(!this.closeTpl){
37989 this.closeTpl = new Roo.Template(
37990 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37991 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37992 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37995 var el = this.closeTpl.overwrite(td, {"text": text});
37996 var close = el.getElementsByTagName("div")[0];
37997 var inner = el.getElementsByTagName("em")[0];
37998 return {"el": el, "close": close, "inner": inner};
38001 // not sure what this is..
38002 // if(!this.tabTpl){
38003 //this.tabTpl = new Roo.Template(
38004 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38005 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38007 // this.tabTpl = new Roo.Template(
38008 // '<a href="#">' +
38009 // '<span unselectable="on"' +
38010 // (this.disableTooltips ? '' : ' title="{text}"') +
38011 // ' >{text}</span></a>'
38017 var template = tpl || this.tabTpl || false;
38021 template = new Roo.Template(
38023 '<span unselectable="on"' +
38024 (this.disableTooltips ? '' : ' title="{text}"') +
38025 ' >{text}</span></a>'
38029 switch (typeof(template)) {
38033 template = new Roo.Template(template);
38039 var el = template.overwrite(td, {"text": text});
38041 var inner = el.getElementsByTagName("span")[0];
38043 return {"el": el, "inner": inner};
38051 * @class Roo.TabPanelItem
38052 * @extends Roo.util.Observable
38053 * Represents an individual item (tab plus body) in a TabPanel.
38054 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38055 * @param {String} id The id of this TabPanelItem
38056 * @param {String} text The text for the tab of this TabPanelItem
38057 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38059 Roo.bootstrap.panel.TabItem = function(config){
38061 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38062 * @type Roo.TabPanel
38064 this.tabPanel = config.panel;
38066 * The id for this TabPanelItem
38069 this.id = config.id;
38071 this.disabled = false;
38073 this.text = config.text;
38075 this.loaded = false;
38076 this.closable = config.closable;
38079 * The body element for this TabPanelItem.
38080 * @type Roo.Element
38082 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38083 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38084 this.bodyEl.setStyle("display", "block");
38085 this.bodyEl.setStyle("zoom", "1");
38086 //this.hideAction();
38088 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38090 this.el = Roo.get(els.el);
38091 this.inner = Roo.get(els.inner, true);
38092 this.textEl = Roo.get(this.el.dom.firstChild, true);
38093 this.pnode = Roo.get(els.el.parentNode, true);
38094 // this.el.on("mousedown", this.onTabMouseDown, this);
38095 this.el.on("click", this.onTabClick, this);
38097 if(config.closable){
38098 var c = Roo.get(els.close, true);
38099 c.dom.title = this.closeText;
38100 c.addClassOnOver("close-over");
38101 c.on("click", this.closeClick, this);
38107 * Fires when this tab becomes the active tab.
38108 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38109 * @param {Roo.TabPanelItem} this
38113 * @event beforeclose
38114 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38115 * @param {Roo.TabPanelItem} this
38116 * @param {Object} e Set cancel to true on this object to cancel the close.
38118 "beforeclose": true,
38121 * Fires when this tab is closed.
38122 * @param {Roo.TabPanelItem} this
38126 * @event deactivate
38127 * Fires when this tab is no longer the active tab.
38128 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38129 * @param {Roo.TabPanelItem} this
38131 "deactivate" : true
38133 this.hidden = false;
38135 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38138 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38140 purgeListeners : function(){
38141 Roo.util.Observable.prototype.purgeListeners.call(this);
38142 this.el.removeAllListeners();
38145 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38148 this.pnode.addClass("active");
38151 this.tabPanel.stripWrap.repaint();
38153 this.fireEvent("activate", this.tabPanel, this);
38157 * Returns true if this tab is the active tab.
38158 * @return {Boolean}
38160 isActive : function(){
38161 return this.tabPanel.getActiveTab() == this;
38165 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38168 this.pnode.removeClass("active");
38170 this.fireEvent("deactivate", this.tabPanel, this);
38173 hideAction : function(){
38174 this.bodyEl.hide();
38175 this.bodyEl.setStyle("position", "absolute");
38176 this.bodyEl.setLeft("-20000px");
38177 this.bodyEl.setTop("-20000px");
38180 showAction : function(){
38181 this.bodyEl.setStyle("position", "relative");
38182 this.bodyEl.setTop("");
38183 this.bodyEl.setLeft("");
38184 this.bodyEl.show();
38188 * Set the tooltip for the tab.
38189 * @param {String} tooltip The tab's tooltip
38191 setTooltip : function(text){
38192 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38193 this.textEl.dom.qtip = text;
38194 this.textEl.dom.removeAttribute('title');
38196 this.textEl.dom.title = text;
38200 onTabClick : function(e){
38201 e.preventDefault();
38202 this.tabPanel.activate(this.id);
38205 onTabMouseDown : function(e){
38206 e.preventDefault();
38207 this.tabPanel.activate(this.id);
38210 getWidth : function(){
38211 return this.inner.getWidth();
38214 setWidth : function(width){
38215 var iwidth = width - this.pnode.getPadding("lr");
38216 this.inner.setWidth(iwidth);
38217 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38218 this.pnode.setWidth(width);
38222 * Show or hide the tab
38223 * @param {Boolean} hidden True to hide or false to show.
38225 setHidden : function(hidden){
38226 this.hidden = hidden;
38227 this.pnode.setStyle("display", hidden ? "none" : "");
38231 * Returns true if this tab is "hidden"
38232 * @return {Boolean}
38234 isHidden : function(){
38235 return this.hidden;
38239 * Returns the text for this tab
38242 getText : function(){
38246 autoSize : function(){
38247 //this.el.beginMeasure();
38248 this.textEl.setWidth(1);
38250 * #2804 [new] Tabs in Roojs
38251 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38253 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38254 //this.el.endMeasure();
38258 * Sets the text for the tab (Note: this also sets the tooltip text)
38259 * @param {String} text The tab's text and tooltip
38261 setText : function(text){
38263 this.textEl.update(text);
38264 this.setTooltip(text);
38265 //if(!this.tabPanel.resizeTabs){
38266 // this.autoSize();
38270 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38272 activate : function(){
38273 this.tabPanel.activate(this.id);
38277 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38279 disable : function(){
38280 if(this.tabPanel.active != this){
38281 this.disabled = true;
38282 this.pnode.addClass("disabled");
38287 * Enables this TabPanelItem if it was previously disabled.
38289 enable : function(){
38290 this.disabled = false;
38291 this.pnode.removeClass("disabled");
38295 * Sets the content for this TabPanelItem.
38296 * @param {String} content The content
38297 * @param {Boolean} loadScripts true to look for and load scripts
38299 setContent : function(content, loadScripts){
38300 this.bodyEl.update(content, loadScripts);
38304 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38305 * @return {Roo.UpdateManager} The UpdateManager
38307 getUpdateManager : function(){
38308 return this.bodyEl.getUpdateManager();
38312 * Set a URL to be used to load the content for this TabPanelItem.
38313 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38314 * @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)
38315 * @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)
38316 * @return {Roo.UpdateManager} The UpdateManager
38318 setUrl : function(url, params, loadOnce){
38319 if(this.refreshDelegate){
38320 this.un('activate', this.refreshDelegate);
38322 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38323 this.on("activate", this.refreshDelegate);
38324 return this.bodyEl.getUpdateManager();
38328 _handleRefresh : function(url, params, loadOnce){
38329 if(!loadOnce || !this.loaded){
38330 var updater = this.bodyEl.getUpdateManager();
38331 updater.update(url, params, this._setLoaded.createDelegate(this));
38336 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38337 * Will fail silently if the setUrl method has not been called.
38338 * This does not activate the panel, just updates its content.
38340 refresh : function(){
38341 if(this.refreshDelegate){
38342 this.loaded = false;
38343 this.refreshDelegate();
38348 _setLoaded : function(){
38349 this.loaded = true;
38353 closeClick : function(e){
38356 this.fireEvent("beforeclose", this, o);
38357 if(o.cancel !== true){
38358 this.tabPanel.removeTab(this.id);
38362 * The text displayed in the tooltip for the close icon.
38365 closeText : "Close this tab"
38368 * This script refer to:
38369 * Title: International Telephone Input
38370 * Author: Jack O'Connor
38371 * Code version: v12.1.12
38372 * Availability: https://github.com/jackocnr/intl-tel-input.git
38375 Roo.bootstrap.PhoneInputData = function() {
38378 "Afghanistan (افغانستان)",
38383 "Albania (Shqipëri)",
38388 "Algeria (الجزائر)",
38413 "Antigua and Barbuda",
38423 "Armenia (Հայաստան)",
38439 "Austria (Österreich)",
38444 "Azerbaijan (Azərbaycan)",
38454 "Bahrain (البحرين)",
38459 "Bangladesh (বাংলাদেশ)",
38469 "Belarus (Беларусь)",
38474 "Belgium (België)",
38504 "Bosnia and Herzegovina (Босна и Херцеговина)",
38519 "British Indian Ocean Territory",
38524 "British Virgin Islands",
38534 "Bulgaria (България)",
38544 "Burundi (Uburundi)",
38549 "Cambodia (កម្ពុជា)",
38554 "Cameroon (Cameroun)",
38563 ["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"]
38566 "Cape Verde (Kabu Verdi)",
38571 "Caribbean Netherlands",
38582 "Central African Republic (République centrafricaine)",
38602 "Christmas Island",
38608 "Cocos (Keeling) Islands",
38619 "Comoros (جزر القمر)",
38624 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38629 "Congo (Republic) (Congo-Brazzaville)",
38649 "Croatia (Hrvatska)",
38670 "Czech Republic (Česká republika)",
38675 "Denmark (Danmark)",
38690 "Dominican Republic (República Dominicana)",
38694 ["809", "829", "849"]
38712 "Equatorial Guinea (Guinea Ecuatorial)",
38732 "Falkland Islands (Islas Malvinas)",
38737 "Faroe Islands (Føroyar)",
38758 "French Guiana (Guyane française)",
38763 "French Polynesia (Polynésie française)",
38778 "Georgia (საქართველო)",
38783 "Germany (Deutschland)",
38803 "Greenland (Kalaallit Nunaat)",
38840 "Guinea-Bissau (Guiné Bissau)",
38865 "Hungary (Magyarország)",
38870 "Iceland (Ísland)",
38890 "Iraq (العراق)",
38906 "Israel (ישראל)",
38933 "Jordan (الأردن)",
38938 "Kazakhstan (Казахстан)",
38959 "Kuwait (الكويت)",
38964 "Kyrgyzstan (Кыргызстан)",
38974 "Latvia (Latvija)",
38979 "Lebanon (لبنان)",
38994 "Libya (ليبيا)",
39004 "Lithuania (Lietuva)",
39019 "Macedonia (FYROM) (Македонија)",
39024 "Madagascar (Madagasikara)",
39054 "Marshall Islands",
39064 "Mauritania (موريتانيا)",
39069 "Mauritius (Moris)",
39090 "Moldova (Republica Moldova)",
39100 "Mongolia (Монгол)",
39105 "Montenegro (Crna Gora)",
39115 "Morocco (المغرب)",
39121 "Mozambique (Moçambique)",
39126 "Myanmar (Burma) (မြန်မာ)",
39131 "Namibia (Namibië)",
39146 "Netherlands (Nederland)",
39151 "New Caledonia (Nouvelle-Calédonie)",
39186 "North Korea (조선 민주주의 인민 공화국)",
39191 "Northern Mariana Islands",
39207 "Pakistan (پاکستان)",
39217 "Palestine (فلسطين)",
39227 "Papua New Guinea",
39269 "Réunion (La Réunion)",
39275 "Romania (România)",
39291 "Saint Barthélemy",
39302 "Saint Kitts and Nevis",
39312 "Saint Martin (Saint-Martin (partie française))",
39318 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39323 "Saint Vincent and the Grenadines",
39338 "São Tomé and Príncipe (São Tomé e Príncipe)",
39343 "Saudi Arabia (المملكة العربية السعودية)",
39348 "Senegal (Sénégal)",
39378 "Slovakia (Slovensko)",
39383 "Slovenia (Slovenija)",
39393 "Somalia (Soomaaliya)",
39403 "South Korea (대한민국)",
39408 "South Sudan (جنوب السودان)",
39418 "Sri Lanka (ශ්රී ලංකාව)",
39423 "Sudan (السودان)",
39433 "Svalbard and Jan Mayen",
39444 "Sweden (Sverige)",
39449 "Switzerland (Schweiz)",
39454 "Syria (سوريا)",
39499 "Trinidad and Tobago",
39504 "Tunisia (تونس)",
39509 "Turkey (Türkiye)",
39519 "Turks and Caicos Islands",
39529 "U.S. Virgin Islands",
39539 "Ukraine (Україна)",
39544 "United Arab Emirates (الإمارات العربية المتحدة)",
39566 "Uzbekistan (Oʻzbekiston)",
39576 "Vatican City (Città del Vaticano)",
39587 "Vietnam (Việt Nam)",
39592 "Wallis and Futuna (Wallis-et-Futuna)",
39597 "Western Sahara (الصحراء الغربية)",
39603 "Yemen (اليمن)",
39627 * This script refer to:
39628 * Title: International Telephone Input
39629 * Author: Jack O'Connor
39630 * Code version: v12.1.12
39631 * Availability: https://github.com/jackocnr/intl-tel-input.git
39635 * @class Roo.bootstrap.PhoneInput
39636 * @extends Roo.bootstrap.TriggerField
39637 * An input with International dial-code selection
39639 * @cfg {String} defaultDialCode default '+852'
39640 * @cfg {Array} preferedCountries default []
39643 * Create a new PhoneInput.
39644 * @param {Object} config Configuration options
39647 Roo.bootstrap.PhoneInput = function(config) {
39648 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39651 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39653 listWidth: undefined,
39655 selectedClass: 'active',
39657 invalidClass : "has-warning",
39659 validClass: 'has-success',
39661 allowed: '0123456789',
39664 * @cfg {String} defaultDialCode The default dial code when initializing the input
39666 defaultDialCode: '+852',
39669 * @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
39671 preferedCountries: false,
39673 getAutoCreate : function()
39675 var data = Roo.bootstrap.PhoneInputData();
39676 var align = this.labelAlign || this.parentLabelAlign();
39679 this.allCountries = [];
39680 this.dialCodeMapping = [];
39682 for (var i = 0; i < data.length; i++) {
39684 this.allCountries[i] = {
39688 priority: c[3] || 0,
39689 areaCodes: c[4] || null
39691 this.dialCodeMapping[c[2]] = {
39694 priority: c[3] || 0,
39695 areaCodes: c[4] || null
39707 cls : 'form-control tel-input',
39708 autocomplete: 'new-password'
39711 var hiddenInput = {
39714 cls: 'hidden-tel-input'
39718 hiddenInput.name = this.name;
39721 if (this.disabled) {
39722 input.disabled = true;
39725 var flag_container = {
39742 cls: this.hasFeedback ? 'has-feedback' : '',
39748 cls: 'dial-code-holder',
39755 cls: 'roo-select2-container input-group',
39762 if (this.fieldLabel.length) {
39765 tooltip: 'This field is required'
39771 cls: 'control-label',
39777 html: this.fieldLabel
39780 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39786 if(this.indicatorpos == 'right') {
39787 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39794 if(align == 'left') {
39802 if(this.labelWidth > 12){
39803 label.style = "width: " + this.labelWidth + 'px';
39805 if(this.labelWidth < 13 && this.labelmd == 0){
39806 this.labelmd = this.labelWidth;
39808 if(this.labellg > 0){
39809 label.cls += ' col-lg-' + this.labellg;
39810 input.cls += ' col-lg-' + (12 - this.labellg);
39812 if(this.labelmd > 0){
39813 label.cls += ' col-md-' + this.labelmd;
39814 container.cls += ' col-md-' + (12 - this.labelmd);
39816 if(this.labelsm > 0){
39817 label.cls += ' col-sm-' + this.labelsm;
39818 container.cls += ' col-sm-' + (12 - this.labelsm);
39820 if(this.labelxs > 0){
39821 label.cls += ' col-xs-' + this.labelxs;
39822 container.cls += ' col-xs-' + (12 - this.labelxs);
39832 var settings = this;
39834 ['xs','sm','md','lg'].map(function(size){
39835 if (settings[size]) {
39836 cfg.cls += ' col-' + size + '-' + settings[size];
39840 this.store = new Roo.data.Store({
39841 proxy : new Roo.data.MemoryProxy({}),
39842 reader : new Roo.data.JsonReader({
39853 'name' : 'dialCode',
39857 'name' : 'priority',
39861 'name' : 'areaCodes',
39868 if(!this.preferedCountries) {
39869 this.preferedCountries = [
39876 var p = this.preferedCountries.reverse();
39879 for (var i = 0; i < p.length; i++) {
39880 for (var j = 0; j < this.allCountries.length; j++) {
39881 if(this.allCountries[j].iso2 == p[i]) {
39882 var t = this.allCountries[j];
39883 this.allCountries.splice(j,1);
39884 this.allCountries.unshift(t);
39890 this.store.proxy.data = {
39892 data: this.allCountries
39898 initEvents : function()
39901 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39903 this.indicator = this.indicatorEl();
39904 this.flag = this.flagEl();
39905 this.dialCodeHolder = this.dialCodeHolderEl();
39907 this.trigger = this.el.select('div.flag-box',true).first();
39908 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39913 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39914 _this.list.setWidth(lw);
39917 this.list.on('mouseover', this.onViewOver, this);
39918 this.list.on('mousemove', this.onViewMove, this);
39919 this.inputEl().on("keyup", this.onKeyUp, this);
39921 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39923 this.view = new Roo.View(this.list, this.tpl, {
39924 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39927 this.view.on('click', this.onViewClick, this);
39928 this.setValue(this.defaultDialCode);
39931 onTriggerClick : function(e)
39933 Roo.log('trigger click');
39938 if(this.isExpanded()){
39940 this.hasFocus = false;
39942 this.store.load({});
39943 this.hasFocus = true;
39948 isExpanded : function()
39950 return this.list.isVisible();
39953 collapse : function()
39955 if(!this.isExpanded()){
39959 Roo.get(document).un('mousedown', this.collapseIf, this);
39960 Roo.get(document).un('mousewheel', this.collapseIf, this);
39961 this.fireEvent('collapse', this);
39965 expand : function()
39969 if(this.isExpanded() || !this.hasFocus){
39973 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39974 this.list.setWidth(lw);
39977 this.restrictHeight();
39979 Roo.get(document).on('mousedown', this.collapseIf, this);
39980 Roo.get(document).on('mousewheel', this.collapseIf, this);
39982 this.fireEvent('expand', this);
39985 restrictHeight : function()
39987 this.list.alignTo(this.inputEl(), this.listAlign);
39988 this.list.alignTo(this.inputEl(), this.listAlign);
39991 onViewOver : function(e, t)
39993 if(this.inKeyMode){
39996 var item = this.view.findItemFromChild(t);
39999 var index = this.view.indexOf(item);
40000 this.select(index, false);
40005 onViewClick : function(view, doFocus, el, e)
40007 var index = this.view.getSelectedIndexes()[0];
40009 var r = this.store.getAt(index);
40012 this.onSelect(r, index);
40014 if(doFocus !== false && !this.blockFocus){
40015 this.inputEl().focus();
40019 onViewMove : function(e, t)
40021 this.inKeyMode = false;
40024 select : function(index, scrollIntoView)
40026 this.selectedIndex = index;
40027 this.view.select(index);
40028 if(scrollIntoView !== false){
40029 var el = this.view.getNode(index);
40031 this.list.scrollChildIntoView(el, false);
40036 createList : function()
40038 this.list = Roo.get(document.body).createChild({
40040 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40041 style: 'display:none'
40043 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40046 collapseIf : function(e)
40048 var in_combo = e.within(this.el);
40049 var in_list = e.within(this.list);
40050 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40052 if (in_combo || in_list || is_list) {
40058 onSelect : function(record, index)
40060 if(this.fireEvent('beforeselect', this, record, index) !== false){
40062 this.setFlagClass(record.data.iso2);
40063 this.setDialCode(record.data.dialCode);
40064 this.hasFocus = false;
40066 this.fireEvent('select', this, record, index);
40070 flagEl : function()
40072 var flag = this.el.select('div.flag',true).first();
40079 dialCodeHolderEl : function()
40081 var d = this.el.select('input.dial-code-holder',true).first();
40088 setDialCode : function(v)
40090 this.dialCodeHolder.dom.value = '+'+v;
40093 setFlagClass : function(n)
40095 this.flag.dom.className = 'flag '+n;
40098 getValue : function()
40100 var v = this.inputEl().getValue();
40101 if(this.dialCodeHolder) {
40102 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40107 setValue : function(v)
40109 var d = this.getDialCode(v);
40111 //invalid dial code
40112 if(v.length == 0 || !d || d.length == 0) {
40114 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40115 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40121 this.setFlagClass(this.dialCodeMapping[d].iso2);
40122 this.setDialCode(d);
40123 this.inputEl().dom.value = v.replace('+'+d,'');
40124 this.hiddenEl().dom.value = this.getValue();
40129 getDialCode : function(v = '')
40131 if (v.length == 0) {
40132 return this.dialCodeHolder.dom.value;
40136 if (v.charAt(0) != "+") {
40139 var numericChars = "";
40140 for (var i = 1; i < v.length; i++) {
40141 var c = v.charAt(i);
40144 if (this.dialCodeMapping[numericChars]) {
40145 dialCode = v.substr(1, i);
40147 if (numericChars.length == 4) {
40157 this.setValue(this.defaultDialCode);
40161 hiddenEl : function()
40163 return this.el.select('input.hidden-tel-input',true).first();
40166 onKeyUp : function(e){
40168 var k = e.getKey();
40169 var c = e.getCharCode();
40172 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40173 this.allowed.indexOf(String.fromCharCode(c)) === -1
40178 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40181 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40185 this.setValue(this.getValue());
40190 * @class Roo.bootstrap.MoneyField
40191 * @extends Roo.bootstrap.ComboBox
40192 * Bootstrap MoneyField class
40195 * Create a new MoneyField.
40196 * @param {Object} config Configuration options
40199 Roo.bootstrap.MoneyField = function(config) {
40201 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40205 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40208 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40210 allowDecimals : true,
40212 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40214 decimalSeparator : ".",
40216 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40218 decimalPrecision : 0,
40220 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40222 allowNegative : true,
40224 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40226 minValue : Number.NEGATIVE_INFINITY,
40228 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40230 maxValue : Number.MAX_VALUE,
40232 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40234 minText : "The minimum value for this field is {0}",
40236 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40238 maxText : "The maximum value for this field is {0}",
40240 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40241 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40243 nanText : "{0} is not a valid number",
40245 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40249 * @cfg {String} defaults currency of the MoneyField
40250 * value should be in lkey
40252 defaultCurrency : false,
40254 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40256 thousandsDelimiter : false,
40266 getAutoCreate : function()
40268 var align = this.labelAlign || this.parentLabelAlign();
40280 cls : 'form-control roo-money-amount-input',
40281 autocomplete: 'new-password'
40284 var hiddenInput = {
40288 cls: 'hidden-number-input'
40292 hiddenInput.name = this.name;
40295 if (this.disabled) {
40296 input.disabled = true;
40299 var clg = 12 - this.inputlg;
40300 var cmd = 12 - this.inputmd;
40301 var csm = 12 - this.inputsm;
40302 var cxs = 12 - this.inputxs;
40306 cls : 'row roo-money-field',
40310 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40314 cls: 'roo-select2-container input-group',
40318 cls : 'form-control roo-money-currency-input',
40319 autocomplete: 'new-password',
40321 name : this.currencyName
40325 cls : 'input-group-addon',
40339 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40343 cls: this.hasFeedback ? 'has-feedback' : '',
40354 if (this.fieldLabel.length) {
40357 tooltip: 'This field is required'
40363 cls: 'control-label',
40369 html: this.fieldLabel
40372 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40378 if(this.indicatorpos == 'right') {
40379 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40386 if(align == 'left') {
40394 if(this.labelWidth > 12){
40395 label.style = "width: " + this.labelWidth + 'px';
40397 if(this.labelWidth < 13 && this.labelmd == 0){
40398 this.labelmd = this.labelWidth;
40400 if(this.labellg > 0){
40401 label.cls += ' col-lg-' + this.labellg;
40402 input.cls += ' col-lg-' + (12 - this.labellg);
40404 if(this.labelmd > 0){
40405 label.cls += ' col-md-' + this.labelmd;
40406 container.cls += ' col-md-' + (12 - this.labelmd);
40408 if(this.labelsm > 0){
40409 label.cls += ' col-sm-' + this.labelsm;
40410 container.cls += ' col-sm-' + (12 - this.labelsm);
40412 if(this.labelxs > 0){
40413 label.cls += ' col-xs-' + this.labelxs;
40414 container.cls += ' col-xs-' + (12 - this.labelxs);
40425 var settings = this;
40427 ['xs','sm','md','lg'].map(function(size){
40428 if (settings[size]) {
40429 cfg.cls += ' col-' + size + '-' + settings[size];
40436 initEvents : function()
40438 this.indicator = this.indicatorEl();
40440 this.initCurrencyEvent();
40442 this.initNumberEvent();
40445 initCurrencyEvent : function()
40448 throw "can not find store for combo";
40451 this.store = Roo.factory(this.store, Roo.data);
40452 this.store.parent = this;
40456 this.triggerEl = this.el.select('.input-group-addon', true).first();
40458 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40463 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40464 _this.list.setWidth(lw);
40467 this.list.on('mouseover', this.onViewOver, this);
40468 this.list.on('mousemove', this.onViewMove, this);
40469 this.list.on('scroll', this.onViewScroll, this);
40472 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40475 this.view = new Roo.View(this.list, this.tpl, {
40476 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40479 this.view.on('click', this.onViewClick, this);
40481 this.store.on('beforeload', this.onBeforeLoad, this);
40482 this.store.on('load', this.onLoad, this);
40483 this.store.on('loadexception', this.onLoadException, this);
40485 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40486 "up" : function(e){
40487 this.inKeyMode = true;
40491 "down" : function(e){
40492 if(!this.isExpanded()){
40493 this.onTriggerClick();
40495 this.inKeyMode = true;
40500 "enter" : function(e){
40503 if(this.fireEvent("specialkey", this, e)){
40504 this.onViewClick(false);
40510 "esc" : function(e){
40514 "tab" : function(e){
40517 if(this.fireEvent("specialkey", this, e)){
40518 this.onViewClick(false);
40526 doRelay : function(foo, bar, hname){
40527 if(hname == 'down' || this.scope.isExpanded()){
40528 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40536 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40540 initNumberEvent : function(e)
40542 this.inputEl().on("keydown" , this.fireKey, this);
40543 this.inputEl().on("focus", this.onFocus, this);
40544 this.inputEl().on("blur", this.onBlur, this);
40546 this.inputEl().relayEvent('keyup', this);
40548 if(this.indicator){
40549 this.indicator.addClass('invisible');
40552 this.originalValue = this.getValue();
40554 if(this.validationEvent == 'keyup'){
40555 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40556 this.inputEl().on('keyup', this.filterValidation, this);
40558 else if(this.validationEvent !== false){
40559 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40562 if(this.selectOnFocus){
40563 this.on("focus", this.preFocus, this);
40566 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40567 this.inputEl().on("keypress", this.filterKeys, this);
40569 this.inputEl().relayEvent('keypress', this);
40572 var allowed = "0123456789";
40574 if(this.allowDecimals){
40575 allowed += this.decimalSeparator;
40578 if(this.allowNegative){
40582 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40584 var keyPress = function(e){
40586 var k = e.getKey();
40588 var c = e.getCharCode();
40591 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40592 allowed.indexOf(String.fromCharCode(c)) === -1
40598 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40602 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40607 this.inputEl().on("keypress", keyPress, this);
40611 onTriggerClick : function(e)
40618 this.loadNext = false;
40620 if(this.isExpanded()){
40625 this.hasFocus = true;
40627 if(this.triggerAction == 'all') {
40628 this.doQuery(this.allQuery, true);
40632 this.doQuery(this.getRawValue());
40635 getCurrency : function()
40637 var v = this.currencyEl().getValue();
40642 restrictHeight : function()
40644 this.list.alignTo(this.currencyEl(), this.listAlign);
40645 this.list.alignTo(this.currencyEl(), this.listAlign);
40648 onViewClick : function(view, doFocus, el, e)
40650 var index = this.view.getSelectedIndexes()[0];
40652 var r = this.store.getAt(index);
40655 this.onSelect(r, index);
40659 onSelect : function(record, index){
40661 if(this.fireEvent('beforeselect', this, record, index) !== false){
40663 this.setFromCurrencyData(index > -1 ? record.data : false);
40667 this.fireEvent('select', this, record, index);
40671 setFromCurrencyData : function(o)
40675 this.lastCurrency = o;
40677 if (this.currencyField) {
40678 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40680 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40683 this.lastSelectionText = currency;
40685 //setting default currency
40686 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40687 this.setCurrency(this.defaultCurrency);
40691 this.setCurrency(currency);
40694 setFromData : function(o)
40698 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40700 this.setFromCurrencyData(c);
40705 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40707 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40710 this.setValue(value);
40714 setCurrency : function(v)
40716 this.currencyValue = v;
40719 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40724 setValue : function(v)
40726 v = this.fixPrecision(v);
40728 v = String(v).replace(".", this.decimalSeparator);
40734 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40736 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40737 this.thousandsDelimiter || ','
40740 if(this.allowBlank && !v) {
40741 this.inputEl().dom.value = '';
40748 getRawValue : function()
40750 var v = this.inputEl().getValue();
40755 getValue : function()
40757 return this.fixPrecision(this.parseValue(this.getRawValue()));
40760 parseValue : function(value)
40762 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40763 return isNaN(value) ? '' : value;
40766 fixPrecision : function(value)
40768 var nan = isNaN(value);
40770 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40771 return nan ? '' : value;
40774 return parseFloat(value).toFixed(this.decimalPrecision);
40777 decimalPrecisionFcn : function(v)
40779 return Math.floor(v);
40782 validateValue : function(value)
40784 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40788 var num = this.parseValue(value);
40791 this.markInvalid(String.format(this.nanText, value));
40795 if(num < this.minValue){
40796 this.markInvalid(String.format(this.minText, this.minValue));
40800 if(num > this.maxValue){
40801 this.markInvalid(String.format(this.maxText, this.maxValue));
40808 validate : function()
40810 if(this.disabled || this.allowBlank){
40815 var currency = this.getCurrency();
40817 if(this.validateValue(this.getRawValue()) && currency.length){
40822 this.markInvalid();
40826 getName: function()
40831 beforeBlur : function()
40837 var v = this.parseValue(this.getRawValue());
40844 onBlur : function()
40848 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40849 //this.el.removeClass(this.focusClass);
40852 this.hasFocus = false;
40854 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40858 var v = this.getValue();
40860 if(String(v) !== String(this.startValue)){
40861 this.fireEvent('change', this, v, this.startValue);
40864 this.fireEvent("blur", this);
40867 inputEl : function()
40869 return this.el.select('.roo-money-amount-input', true).first();
40872 currencyEl : function()
40874 return this.el.select('.roo-money-currency-input', true).first();
40877 hiddenEl : function()
40879 return this.el.select('input.hidden-number-input',true).first();