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)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
233 addxtypeChild : function (tree, cntr, is_body)
235 Roo.debug && Roo.log('addxtypeChild:' + cntr);
237 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
240 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
241 (typeof(tree['flexy:foreach']) != 'undefined');
245 skip_children = false;
246 // render the element if it's not BODY.
249 cn = Roo.factory(tree);
251 cn.parentType = this.xtype; //??
252 cn.parentId = this.id;
254 var build_from_html = Roo.XComponent.build_from_html;
257 // does the container contain child eleemnts with 'xtype' attributes.
258 // that match this xtype..
259 // note - when we render we create these as well..
260 // so we should check to see if body has xtype set.
261 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
263 var self_cntr_el = Roo.get(this[cntr](false));
264 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
266 //Roo.log(Roo.XComponent.build_from_html);
267 //Roo.log("got echild:");
270 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
271 // and are not displayed -this causes this to use up the wrong element when matching.
272 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
275 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
276 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
282 //echild.dom.removeAttribute('xtype');
284 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
285 Roo.debug && Roo.log(self_cntr_el);
286 Roo.debug && Roo.log(echild);
287 Roo.debug && Roo.log(cn);
293 // if object has flexy:if - then it may or may not be rendered.
294 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
295 // skip a flexy if element.
296 Roo.debug && Roo.log('skipping render');
297 Roo.debug && Roo.log(tree);
299 Roo.debug && Roo.log('skipping all children');
300 skip_children = true;
305 // actually if flexy:foreach is found, we really want to create
306 // multiple copies here...
308 //Roo.log(this[cntr]());
309 cn.render(this[cntr](true));
311 // then add the element..
319 if (typeof (tree.menu) != 'undefined') {
320 tree.menu.parentType = cn.xtype;
321 tree.menu.triggerEl = cn.el;
322 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
326 if (!tree.items || !tree.items.length) {
328 //Roo.log(["no children", this]);
333 var items = tree.items;
336 //Roo.log(items.length);
338 if (!skip_children) {
339 for(var i =0;i < items.length;i++) {
340 // Roo.log(['add child', items[i]]);
341 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
347 //Roo.log("fire childrenrendered");
349 cn.fireEvent('childrenrendered', this);
354 * Show a component - removes 'hidden' class
359 this.el.removeClass('hidden');
363 * Hide a component - adds 'hidden' class
367 if (this.el && !this.el.hasClass('hidden')) {
368 this.el.addClass('hidden');
382 * @class Roo.bootstrap.Body
383 * @extends Roo.bootstrap.Component
384 * Bootstrap Body class
388 * @param {Object} config The config object
391 Roo.bootstrap.Body = function(config){
392 Roo.bootstrap.Body.superclass.constructor.call(this, config);
393 this.el = Roo.get(document.body);
394 if (this.cls && this.cls.length) {
395 Roo.get(document.body).addClass(this.cls);
399 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
401 is_body : true,// just to make sure it's constructed?
406 onRender : function(ct, position)
408 /* Roo.log("Roo.bootstrap.Body - onRender");
409 if (this.cls && this.cls.length) {
410 Roo.get(document.body).addClass(this.cls);
430 * @class Roo.bootstrap.ButtonGroup
431 * @extends Roo.bootstrap.Component
432 * Bootstrap ButtonGroup class
433 * @cfg {String} size lg | sm | xs (default empty normal)
434 * @cfg {String} align vertical | justified (default none)
435 * @cfg {String} direction up | down (default down)
436 * @cfg {Boolean} toolbar false | true
437 * @cfg {Boolean} btn true | false
442 * @param {Object} config The config object
445 Roo.bootstrap.ButtonGroup = function(config){
446 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
449 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
457 getAutoCreate : function(){
463 cfg.html = this.html || cfg.html;
474 if (['vertical','justified'].indexOf(this.align)!==-1) {
475 cfg.cls = 'btn-group-' + this.align;
477 if (this.align == 'justified') {
478 console.log(this.items);
482 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
483 cfg.cls += ' btn-group-' + this.size;
486 if (this.direction == 'up') {
487 cfg.cls += ' dropup' ;
503 * @class Roo.bootstrap.Button
504 * @extends Roo.bootstrap.Component
505 * Bootstrap Button class
506 * @cfg {String} html The button content
507 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
508 * @cfg {String} size ( lg | sm | xs)
509 * @cfg {String} tag ( a | input | submit)
510 * @cfg {String} href empty or href
511 * @cfg {Boolean} disabled default false;
512 * @cfg {Boolean} isClose default false;
513 * @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)
514 * @cfg {String} badge text for badge
515 * @cfg {String} theme default
516 * @cfg {Boolean} inverse
517 * @cfg {Boolean} toggle
518 * @cfg {String} ontext text for on toggle state
519 * @cfg {String} offtext text for off toggle state
520 * @cfg {Boolean} defaulton
521 * @cfg {Boolean} preventDefault default true
522 * @cfg {Boolean} removeClass remove the standard class..
523 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
526 * Create a new button
527 * @param {Object} config The config object
531 Roo.bootstrap.Button = function(config){
532 Roo.bootstrap.Button.superclass.constructor.call(this, config);
537 * When a butotn is pressed
538 * @param {Roo.bootstrap.Button} this
539 * @param {Roo.EventObject} e
544 * After the button has been toggles
545 * @param {Roo.EventObject} e
546 * @param {boolean} pressed (also available as button.pressed)
552 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
570 preventDefault: true,
579 getAutoCreate : function(){
587 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
588 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
593 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
595 if (this.toggle == true) {
598 cls: 'slider-frame roo-button',
603 'data-off-text':'OFF',
604 cls: 'slider-button',
610 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
611 cfg.cls += ' '+this.weight;
620 cfg["aria-hidden"] = true;
622 cfg.html = "×";
628 if (this.theme==='default') {
629 cfg.cls = 'btn roo-button';
631 //if (this.parentType != 'Navbar') {
632 this.weight = this.weight.length ? this.weight : 'default';
634 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
636 cfg.cls += ' btn-' + this.weight;
638 } else if (this.theme==='glow') {
641 cfg.cls = 'btn-glow roo-button';
643 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
645 cfg.cls += ' ' + this.weight;
651 this.cls += ' inverse';
656 cfg.cls += ' active';
660 cfg.disabled = 'disabled';
664 Roo.log('changing to ul' );
666 this.glyphicon = 'caret';
669 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
671 //gsRoo.log(this.parentType);
672 if (this.parentType === 'Navbar' && !this.parent().bar) {
673 Roo.log('changing to li?');
682 href : this.href || '#'
685 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
686 cfg.cls += ' dropdown';
693 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
695 if (this.glyphicon) {
696 cfg.html = ' ' + cfg.html;
701 cls: 'glyphicon glyphicon-' + this.glyphicon
711 // cfg.cls='btn roo-button';
715 var value = cfg.html;
720 cls: 'glyphicon glyphicon-' + this.glyphicon,
739 cfg.cls += ' dropdown';
740 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
743 if (cfg.tag !== 'a' && this.href !== '') {
744 throw "Tag must be a to set href.";
745 } else if (this.href.length > 0) {
746 cfg.href = this.href;
749 if(this.removeClass){
754 cfg.target = this.target;
759 initEvents: function() {
760 // Roo.log('init events?');
761 // Roo.log(this.el.dom);
764 if (typeof (this.menu) != 'undefined') {
765 this.menu.parentType = this.xtype;
766 this.menu.triggerEl = this.el;
767 this.addxtype(Roo.apply({}, this.menu));
771 if (this.el.hasClass('roo-button')) {
772 this.el.on('click', this.onClick, this);
774 this.el.select('.roo-button').on('click', this.onClick, this);
777 if(this.removeClass){
778 this.el.on('click', this.onClick, this);
781 this.el.enableDisplayMode();
784 onClick : function(e)
791 Roo.log('button on click ');
792 if(this.preventDefault){
795 if (this.pressed === true || this.pressed === false) {
796 this.pressed = !this.pressed;
797 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
798 this.fireEvent('toggle', this, e, this.pressed);
802 this.fireEvent('click', this, e);
806 * Enables this button
810 this.disabled = false;
811 this.el.removeClass('disabled');
815 * Disable this button
819 this.disabled = true;
820 this.el.addClass('disabled');
823 * sets the active state on/off,
824 * @param {Boolean} state (optional) Force a particular state
826 setActive : function(v) {
828 this.el[v ? 'addClass' : 'removeClass']('active');
831 * toggles the current active state
833 toggleActive : function()
835 var active = this.el.hasClass('active');
836 this.setActive(!active);
840 setText : function(str)
842 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
846 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
869 * @class Roo.bootstrap.Column
870 * @extends Roo.bootstrap.Component
871 * Bootstrap Column class
872 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
873 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
874 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
875 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
876 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
877 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
878 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
879 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
882 * @cfg {Boolean} hidden (true|false) hide the element
883 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
884 * @cfg {String} fa (ban|check|...) font awesome icon
885 * @cfg {Number} fasize (1|2|....) font awsome size
887 * @cfg {String} icon (info-sign|check|...) glyphicon name
889 * @cfg {String} html content of column.
892 * Create a new Column
893 * @param {Object} config The config object
896 Roo.bootstrap.Column = function(config){
897 Roo.bootstrap.Column.superclass.constructor.call(this, config);
900 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
918 getAutoCreate : function(){
919 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
927 ['xs','sm','md','lg'].map(function(size){
928 //Roo.log( size + ':' + settings[size]);
930 if (settings[size+'off'] !== false) {
931 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
934 if (settings[size] === false) {
938 if (!settings[size]) { // 0 = hidden
939 cfg.cls += ' hidden-' + size;
942 cfg.cls += ' col-' + size + '-' + settings[size];
947 cfg.cls += ' hidden';
950 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
951 cfg.cls +=' alert alert-' + this.alert;
955 if (this.html.length) {
956 cfg.html = this.html;
960 if (this.fasize > 1) {
961 fasize = ' fa-' + this.fasize + 'x';
963 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
968 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
987 * @class Roo.bootstrap.Container
988 * @extends Roo.bootstrap.Component
989 * Bootstrap Container class
990 * @cfg {Boolean} jumbotron is it a jumbotron element
991 * @cfg {String} html content of element
992 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
993 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
994 * @cfg {String} header content of header (for panel)
995 * @cfg {String} footer content of footer (for panel)
996 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
997 * @cfg {String} tag (header|aside|section) type of HTML tag.
998 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
999 * @cfg {String} fa font awesome icon
1000 * @cfg {String} icon (info-sign|check|...) glyphicon name
1001 * @cfg {Boolean} hidden (true|false) hide the element
1002 * @cfg {Boolean} expandable (true|false) default false
1003 * @cfg {Boolean} expanded (true|false) default true
1004 * @cfg {String} rheader contet on the right of header
1005 * @cfg {Boolean} clickable (true|false) default false
1009 * Create a new Container
1010 * @param {Object} config The config object
1013 Roo.bootstrap.Container = function(config){
1014 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1020 * After the panel has been expand
1022 * @param {Roo.bootstrap.Container} this
1027 * After the panel has been collapsed
1029 * @param {Roo.bootstrap.Container} this
1034 * When a element is chick
1035 * @param {Roo.bootstrap.Container} this
1036 * @param {Roo.EventObject} e
1042 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1060 getChildContainer : function() {
1066 if (this.panel.length) {
1067 return this.el.select('.panel-body',true).first();
1074 getAutoCreate : function(){
1077 tag : this.tag || 'div',
1081 if (this.jumbotron) {
1082 cfg.cls = 'jumbotron';
1087 // - this is applied by the parent..
1089 // cfg.cls = this.cls + '';
1092 if (this.sticky.length) {
1094 var bd = Roo.get(document.body);
1095 if (!bd.hasClass('bootstrap-sticky')) {
1096 bd.addClass('bootstrap-sticky');
1097 Roo.select('html',true).setStyle('height', '100%');
1100 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1104 if (this.well.length) {
1105 switch (this.well) {
1108 cfg.cls +=' well well-' +this.well;
1117 cfg.cls += ' hidden';
1121 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1122 cfg.cls +=' alert alert-' + this.alert;
1127 if (this.panel.length) {
1128 cfg.cls += ' panel panel-' + this.panel;
1130 if (this.header.length) {
1134 if(this.expandable){
1136 cfg.cls = cfg.cls + ' expandable';
1140 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1148 cls : 'panel-title',
1149 html : (this.expandable ? ' ' : '') + this.header
1153 cls: 'panel-header-right',
1159 cls : 'panel-heading',
1160 style : this.expandable ? 'cursor: pointer' : '',
1168 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1173 if (this.footer.length) {
1175 cls : 'panel-footer',
1184 body.html = this.html || cfg.html;
1185 // prefix with the icons..
1187 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1190 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1195 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1196 cfg.cls = 'container';
1202 initEvents: function()
1204 if(this.expandable){
1205 var headerEl = this.headerEl();
1208 headerEl.on('click', this.onToggleClick, this);
1213 this.el.on('click', this.onClick, this);
1218 onToggleClick : function()
1220 var headerEl = this.headerEl();
1236 if(this.fireEvent('expand', this)) {
1238 this.expanded = true;
1240 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1242 this.el.select('.panel-body',true).first().removeClass('hide');
1244 var toggleEl = this.toggleEl();
1250 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1255 collapse : function()
1257 if(this.fireEvent('collapse', this)) {
1259 this.expanded = false;
1261 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1262 this.el.select('.panel-body',true).first().addClass('hide');
1264 var toggleEl = this.toggleEl();
1270 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1274 toggleEl : function()
1276 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1280 return this.el.select('.panel-heading .fa',true).first();
1283 headerEl : function()
1285 if(!this.el || !this.panel.length || !this.header.length){
1289 return this.el.select('.panel-heading',true).first()
1292 titleEl : function()
1294 if(!this.el || !this.panel.length || !this.header.length){
1298 return this.el.select('.panel-title',true).first();
1301 setTitle : function(v)
1303 var titleEl = this.titleEl();
1309 titleEl.dom.innerHTML = v;
1312 getTitle : function()
1315 var titleEl = this.titleEl();
1321 return titleEl.dom.innerHTML;
1324 setRightTitle : function(v)
1326 var t = this.el.select('.panel-header-right',true).first();
1332 t.dom.innerHTML = v;
1335 onClick : function(e)
1339 this.fireEvent('click', this, e);
1353 * @class Roo.bootstrap.Img
1354 * @extends Roo.bootstrap.Component
1355 * Bootstrap Img class
1356 * @cfg {Boolean} imgResponsive false | true
1357 * @cfg {String} border rounded | circle | thumbnail
1358 * @cfg {String} src image source
1359 * @cfg {String} alt image alternative text
1360 * @cfg {String} href a tag href
1361 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1362 * @cfg {String} xsUrl xs image source
1363 * @cfg {String} smUrl sm image source
1364 * @cfg {String} mdUrl md image source
1365 * @cfg {String} lgUrl lg image source
1368 * Create a new Input
1369 * @param {Object} config The config object
1372 Roo.bootstrap.Img = function(config){
1373 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1379 * The img click event for the img.
1380 * @param {Roo.EventObject} e
1386 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1388 imgResponsive: true,
1398 getAutoCreate : function()
1400 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1401 return this.createSingleImg();
1406 cls: 'roo-image-responsive-group',
1411 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1413 if(!_this[size + 'Url']){
1419 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1420 html: _this.html || cfg.html,
1421 src: _this[size + 'Url']
1424 img.cls += ' roo-image-responsive-' + size;
1426 var s = ['xs', 'sm', 'md', 'lg'];
1428 s.splice(s.indexOf(size), 1);
1430 Roo.each(s, function(ss){
1431 img.cls += ' hidden-' + ss;
1434 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1435 cfg.cls += ' img-' + _this.border;
1439 cfg.alt = _this.alt;
1452 a.target = _this.target;
1456 cfg.cn.push((_this.href) ? a : img);
1463 createSingleImg : function()
1467 cls: (this.imgResponsive) ? 'img-responsive' : '',
1469 src : 'about:blank' // just incase src get's set to undefined?!?
1472 cfg.html = this.html || cfg.html;
1474 cfg.src = this.src || cfg.src;
1476 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1477 cfg.cls += ' img-' + this.border;
1494 a.target = this.target;
1499 return (this.href) ? a : cfg;
1502 initEvents: function()
1505 this.el.on('click', this.onClick, this);
1510 onClick : function(e)
1512 Roo.log('img onclick');
1513 this.fireEvent('click', this, e);
1527 * @class Roo.bootstrap.Link
1528 * @extends Roo.bootstrap.Component
1529 * Bootstrap Link Class
1530 * @cfg {String} alt image alternative text
1531 * @cfg {String} href a tag href
1532 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1533 * @cfg {String} html the content of the link.
1534 * @cfg {String} anchor name for the anchor link
1535 * @cfg {String} fa - favicon
1537 * @cfg {Boolean} preventDefault (true | false) default false
1541 * Create a new Input
1542 * @param {Object} config The config object
1545 Roo.bootstrap.Link = function(config){
1546 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1552 * The img click event for the img.
1553 * @param {Roo.EventObject} e
1559 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1563 preventDefault: false,
1569 getAutoCreate : function()
1571 var html = this.html || '';
1573 if (this.fa !== false) {
1574 html = '<i class="fa fa-' + this.fa + '"></i>';
1579 // anchor's do not require html/href...
1580 if (this.anchor === false) {
1582 cfg.href = this.href || '#';
1584 cfg.name = this.anchor;
1585 if (this.html !== false || this.fa !== false) {
1588 if (this.href !== false) {
1589 cfg.href = this.href;
1593 if(this.alt !== false){
1598 if(this.target !== false) {
1599 cfg.target = this.target;
1605 initEvents: function() {
1607 if(!this.href || this.preventDefault){
1608 this.el.on('click', this.onClick, this);
1612 onClick : function(e)
1614 if(this.preventDefault){
1617 //Roo.log('img onclick');
1618 this.fireEvent('click', this, e);
1631 * @class Roo.bootstrap.Header
1632 * @extends Roo.bootstrap.Component
1633 * Bootstrap Header class
1634 * @cfg {String} html content of header
1635 * @cfg {Number} level (1|2|3|4|5|6) default 1
1638 * Create a new Header
1639 * @param {Object} config The config object
1643 Roo.bootstrap.Header = function(config){
1644 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1647 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1655 getAutoCreate : function(){
1660 tag: 'h' + (1 *this.level),
1661 html: this.html || ''
1673 * Ext JS Library 1.1.1
1674 * Copyright(c) 2006-2007, Ext JS, LLC.
1676 * Originally Released Under LGPL - original licence link has changed is not relivant.
1679 * <script type="text/javascript">
1683 * @class Roo.bootstrap.MenuMgr
1684 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1687 Roo.bootstrap.MenuMgr = function(){
1688 var menus, active, groups = {}, attached = false, lastShow = new Date();
1690 // private - called when first menu is created
1693 active = new Roo.util.MixedCollection();
1694 Roo.get(document).addKeyListener(27, function(){
1695 if(active.length > 0){
1703 if(active && active.length > 0){
1704 var c = active.clone();
1714 if(active.length < 1){
1715 Roo.get(document).un("mouseup", onMouseDown);
1723 var last = active.last();
1724 lastShow = new Date();
1727 Roo.get(document).on("mouseup", onMouseDown);
1732 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1733 m.parentMenu.activeChild = m;
1734 }else if(last && last.isVisible()){
1735 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1740 function onBeforeHide(m){
1742 m.activeChild.hide();
1744 if(m.autoHideTimer){
1745 clearTimeout(m.autoHideTimer);
1746 delete m.autoHideTimer;
1751 function onBeforeShow(m){
1752 var pm = m.parentMenu;
1753 if(!pm && !m.allowOtherMenus){
1755 }else if(pm && pm.activeChild && active != m){
1756 pm.activeChild.hide();
1760 // private this should really trigger on mouseup..
1761 function onMouseDown(e){
1762 Roo.log("on Mouse Up");
1764 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1765 Roo.log("MenuManager hideAll");
1774 function onBeforeCheck(mi, state){
1776 var g = groups[mi.group];
1777 for(var i = 0, l = g.length; i < l; i++){
1779 g[i].setChecked(false);
1788 * Hides all menus that are currently visible
1790 hideAll : function(){
1795 register : function(menu){
1799 menus[menu.id] = menu;
1800 menu.on("beforehide", onBeforeHide);
1801 menu.on("hide", onHide);
1802 menu.on("beforeshow", onBeforeShow);
1803 menu.on("show", onShow);
1805 if(g && menu.events["checkchange"]){
1809 groups[g].push(menu);
1810 menu.on("checkchange", onCheck);
1815 * Returns a {@link Roo.menu.Menu} object
1816 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1817 * be used to generate and return a new Menu instance.
1819 get : function(menu){
1820 if(typeof menu == "string"){ // menu id
1822 }else if(menu.events){ // menu instance
1825 /*else if(typeof menu.length == 'number'){ // array of menu items?
1826 return new Roo.bootstrap.Menu({items:menu});
1827 }else{ // otherwise, must be a config
1828 return new Roo.bootstrap.Menu(menu);
1835 unregister : function(menu){
1836 delete menus[menu.id];
1837 menu.un("beforehide", onBeforeHide);
1838 menu.un("hide", onHide);
1839 menu.un("beforeshow", onBeforeShow);
1840 menu.un("show", onShow);
1842 if(g && menu.events["checkchange"]){
1843 groups[g].remove(menu);
1844 menu.un("checkchange", onCheck);
1849 registerCheckable : function(menuItem){
1850 var g = menuItem.group;
1855 groups[g].push(menuItem);
1856 menuItem.on("beforecheckchange", onBeforeCheck);
1861 unregisterCheckable : function(menuItem){
1862 var g = menuItem.group;
1864 groups[g].remove(menuItem);
1865 menuItem.un("beforecheckchange", onBeforeCheck);
1877 * @class Roo.bootstrap.Menu
1878 * @extends Roo.bootstrap.Component
1879 * Bootstrap Menu class - container for MenuItems
1880 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1881 * @cfg {bool} hidden if the menu should be hidden when rendered.
1882 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1883 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1887 * @param {Object} config The config object
1891 Roo.bootstrap.Menu = function(config){
1892 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1893 if (this.registerMenu && this.type != 'treeview') {
1894 Roo.bootstrap.MenuMgr.register(this);
1899 * Fires before this menu is displayed
1900 * @param {Roo.menu.Menu} this
1905 * Fires before this menu is hidden
1906 * @param {Roo.menu.Menu} this
1911 * Fires after this menu is displayed
1912 * @param {Roo.menu.Menu} this
1917 * Fires after this menu is hidden
1918 * @param {Roo.menu.Menu} this
1923 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1924 * @param {Roo.menu.Menu} this
1925 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1926 * @param {Roo.EventObject} e
1931 * Fires when the mouse is hovering over this menu
1932 * @param {Roo.menu.Menu} this
1933 * @param {Roo.EventObject} e
1934 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1939 * Fires when the mouse exits this menu
1940 * @param {Roo.menu.Menu} this
1941 * @param {Roo.EventObject} e
1942 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1947 * Fires when a menu item contained in this menu is clicked
1948 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1949 * @param {Roo.EventObject} e
1953 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1956 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1960 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1963 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1965 registerMenu : true,
1967 menuItems :false, // stores the menu items..
1977 getChildContainer : function() {
1981 getAutoCreate : function(){
1983 //if (['right'].indexOf(this.align)!==-1) {
1984 // cfg.cn[1].cls += ' pull-right'
1990 cls : 'dropdown-menu' ,
1991 style : 'z-index:1000'
1995 if (this.type === 'submenu') {
1996 cfg.cls = 'submenu active';
1998 if (this.type === 'treeview') {
1999 cfg.cls = 'treeview-menu';
2004 initEvents : function() {
2006 // Roo.log("ADD event");
2007 // Roo.log(this.triggerEl.dom);
2009 this.triggerEl.on('click', this.onTriggerClick, this);
2011 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2013 this.triggerEl.addClass('dropdown-toggle');
2016 this.el.on('touchstart' , this.onTouch, this);
2018 this.el.on('click' , this.onClick, this);
2020 this.el.on("mouseover", this.onMouseOver, this);
2021 this.el.on("mouseout", this.onMouseOut, this);
2025 findTargetItem : function(e)
2027 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2031 //Roo.log(t); Roo.log(t.id);
2033 //Roo.log(this.menuitems);
2034 return this.menuitems.get(t.id);
2036 //return this.items.get(t.menuItemId);
2042 onTouch : function(e)
2044 Roo.log("menu.onTouch");
2045 //e.stopEvent(); this make the user popdown broken
2049 onClick : function(e)
2051 Roo.log("menu.onClick");
2053 var t = this.findTargetItem(e);
2054 if(!t || t.isContainer){
2059 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2060 if(t == this.activeItem && t.shouldDeactivate(e)){
2061 this.activeItem.deactivate();
2062 delete this.activeItem;
2066 this.setActiveItem(t, true);
2074 Roo.log('pass click event');
2078 this.fireEvent("click", this, t, e);
2082 (function() { _this.hide(); }).defer(500);
2085 onMouseOver : function(e){
2086 var t = this.findTargetItem(e);
2089 // if(t.canActivate && !t.disabled){
2090 // this.setActiveItem(t, true);
2094 this.fireEvent("mouseover", this, e, t);
2096 isVisible : function(){
2097 return !this.hidden;
2099 onMouseOut : function(e){
2100 var t = this.findTargetItem(e);
2103 // if(t == this.activeItem && t.shouldDeactivate(e)){
2104 // this.activeItem.deactivate();
2105 // delete this.activeItem;
2108 this.fireEvent("mouseout", this, e, t);
2113 * Displays this menu relative to another element
2114 * @param {String/HTMLElement/Roo.Element} element The element to align to
2115 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2116 * the element (defaults to this.defaultAlign)
2117 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2119 show : function(el, pos, parentMenu){
2120 this.parentMenu = parentMenu;
2124 this.fireEvent("beforeshow", this);
2125 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2128 * Displays this menu at a specific xy position
2129 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2130 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2132 showAt : function(xy, parentMenu, /* private: */_e){
2133 this.parentMenu = parentMenu;
2138 this.fireEvent("beforeshow", this);
2139 //xy = this.el.adjustForConstraints(xy);
2143 this.hideMenuItems();
2144 this.hidden = false;
2145 this.triggerEl.addClass('open');
2147 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2148 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2151 if(this.el.getStyle('top').slice(-1) != "%"){
2156 this.fireEvent("show", this);
2162 this.doFocus.defer(50, this);
2166 doFocus : function(){
2168 this.focusEl.focus();
2173 * Hides this menu and optionally all parent menus
2174 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2176 hide : function(deep)
2179 this.hideMenuItems();
2180 if(this.el && this.isVisible()){
2181 this.fireEvent("beforehide", this);
2182 if(this.activeItem){
2183 this.activeItem.deactivate();
2184 this.activeItem = null;
2186 this.triggerEl.removeClass('open');;
2188 this.fireEvent("hide", this);
2190 if(deep === true && this.parentMenu){
2191 this.parentMenu.hide(true);
2195 onTriggerClick : function(e)
2197 Roo.log('trigger click');
2199 var target = e.getTarget();
2201 Roo.log(target.nodeName.toLowerCase());
2203 if(target.nodeName.toLowerCase() === 'i'){
2209 onTriggerPress : function(e)
2211 Roo.log('trigger press');
2212 //Roo.log(e.getTarget());
2213 // Roo.log(this.triggerEl.dom);
2215 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2216 var pel = Roo.get(e.getTarget());
2217 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2218 Roo.log('is treeview or dropdown?');
2222 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2226 if (this.isVisible()) {
2231 this.show(this.triggerEl, false, false);
2234 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2241 hideMenuItems : function()
2243 Roo.log("hide Menu Items");
2247 //$(backdrop).remove()
2248 this.el.select('.open',true).each(function(aa) {
2250 aa.removeClass('open');
2251 //var parent = getParent($(this))
2252 //var relatedTarget = { relatedTarget: this }
2254 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2255 //if (e.isDefaultPrevented()) return
2256 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2259 addxtypeChild : function (tree, cntr) {
2260 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2262 this.menuitems.add(comp);
2283 * @class Roo.bootstrap.MenuItem
2284 * @extends Roo.bootstrap.Component
2285 * Bootstrap MenuItem class
2286 * @cfg {String} html the menu label
2287 * @cfg {String} href the link
2288 * @cfg {Boolean} preventDefault do not trigger A href on clicks.
2289 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2290 * @cfg {Boolean} active used on sidebars to highlight active itesm
2291 * @cfg {String} fa favicon to show on left of menu item.
2292 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2296 * Create a new MenuItem
2297 * @param {Object} config The config object
2301 Roo.bootstrap.MenuItem = function(config){
2302 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2307 * The raw click event for the entire grid.
2308 * @param {Roo.bootstrap.MenuItem} this
2309 * @param {Roo.EventObject} e
2315 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2319 preventDefault: true,
2320 isContainer : false,
2324 getAutoCreate : function(){
2326 if(this.isContainer){
2329 cls: 'dropdown-menu-item'
2343 if (this.fa !== false) {
2346 cls : 'fa fa-' + this.fa
2355 cls: 'dropdown-menu-item',
2358 if (this.parent().type == 'treeview') {
2359 cfg.cls = 'treeview-menu';
2362 cfg.cls += ' active';
2367 anc.href = this.href || cfg.cn[0].href ;
2368 ctag.html = this.html || cfg.cn[0].html ;
2372 initEvents: function()
2374 if (this.parent().type == 'treeview') {
2375 this.el.select('a').on('click', this.onClick, this);
2378 this.menu.parentType = this.xtype;
2379 this.menu.triggerEl = this.el;
2380 this.menu = this.addxtype(Roo.apply({}, this.menu));
2384 onClick : function(e)
2386 Roo.log('item on click ');
2387 //if(this.preventDefault){
2388 // e.preventDefault();
2390 //this.parent().hideMenuItems();
2392 this.fireEvent('click', this, e);
2411 * @class Roo.bootstrap.MenuSeparator
2412 * @extends Roo.bootstrap.Component
2413 * Bootstrap MenuSeparator class
2416 * Create a new MenuItem
2417 * @param {Object} config The config object
2421 Roo.bootstrap.MenuSeparator = function(config){
2422 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2425 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2427 getAutoCreate : function(){
2446 * @class Roo.bootstrap.Modal
2447 * @extends Roo.bootstrap.Component
2448 * Bootstrap Modal class
2449 * @cfg {String} title Title of dialog
2450 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2451 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2452 * @cfg {Boolean} specificTitle default false
2453 * @cfg {Array} buttons Array of buttons or standard button set..
2454 * @cfg {String} buttonPosition (left|right|center) default right
2455 * @cfg {Boolean} animate default true
2456 * @cfg {Boolean} allow_close default true
2459 * Create a new Modal Dialog
2460 * @param {Object} config The config object
2463 Roo.bootstrap.Modal = function(config){
2464 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2469 * The raw btnclick event for the button
2470 * @param {Roo.EventObject} e
2474 this.buttons = this.buttons || [];
2477 this.tmpl = Roo.factory(this.tmpl);
2482 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2484 title : 'test dialog',
2494 specificTitle: false,
2496 buttonPosition: 'right',
2510 onRender : function(ct, position)
2512 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2515 var cfg = Roo.apply({}, this.getAutoCreate());
2518 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2520 //if (!cfg.name.length) {
2524 cfg.cls += ' ' + this.cls;
2527 cfg.style = this.style;
2529 this.el = Roo.get(document.body).createChild(cfg, position);
2531 //var type = this.el.dom.type;
2534 if(this.tabIndex !== undefined){
2535 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2539 this.bodyEl = this.el.select('.modal-body',true).first();
2540 this.closeEl = this.el.select('.modal-header .close', true).first();
2541 this.footerEl = this.el.select('.modal-footer',true).first();
2542 this.titleEl = this.el.select('.modal-title',true).first();
2546 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2547 this.maskEl.enableDisplayMode("block");
2549 //this.el.addClass("x-dlg-modal");
2551 if (this.buttons.length) {
2552 Roo.each(this.buttons, function(bb) {
2553 var b = Roo.apply({}, bb);
2554 b.xns = b.xns || Roo.bootstrap;
2555 b.xtype = b.xtype || 'Button';
2556 if (typeof(b.listeners) == 'undefined') {
2557 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2560 var btn = Roo.factory(b);
2562 btn.render(this.el.select('.modal-footer div').first());
2566 // render the children.
2569 if(typeof(this.items) != 'undefined'){
2570 var items = this.items;
2573 for(var i =0;i < items.length;i++) {
2574 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2578 this.items = nitems;
2580 // where are these used - they used to be body/close/footer
2584 //this.el.addClass([this.fieldClass, this.cls]);
2588 getAutoCreate : function(){
2593 html : this.html || ''
2598 cls : 'modal-title',
2602 if(this.specificTitle){
2608 if (this.allow_close) {
2619 style : 'display: none',
2622 cls: "modal-dialog",
2625 cls : "modal-content",
2628 cls : 'modal-header',
2633 cls : 'modal-footer',
2637 cls: 'btn-' + this.buttonPosition
2654 modal.cls += ' fade';
2660 getChildContainer : function() {
2665 getButtonContainer : function() {
2666 return this.el.select('.modal-footer div',true).first();
2669 initEvents : function()
2671 if (this.allow_close) {
2672 this.closeEl.on('click', this.hide, this);
2677 window.addEventListener("resize", function() { _this.resize(); } );
2683 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2688 if (!this.rendered) {
2692 this.el.setStyle('display', 'block');
2694 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2697 this.el.addClass('in');
2700 this.el.addClass('in');
2704 // not sure how we can show data in here..
2706 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2709 Roo.get(document.body).addClass("x-body-masked");
2710 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2712 this.el.setStyle('zIndex', '10001');
2714 this.fireEvent('show', this);
2722 Roo.get(document.body).removeClass("x-body-masked");
2723 this.el.removeClass('in');
2724 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2726 if(this.animate){ // why
2728 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2730 this.el.setStyle('display', 'none');
2733 this.fireEvent('hide', this);
2736 addButton : function(str, cb)
2740 var b = Roo.apply({}, { html : str } );
2741 b.xns = b.xns || Roo.bootstrap;
2742 b.xtype = b.xtype || 'Button';
2743 if (typeof(b.listeners) == 'undefined') {
2744 b.listeners = { click : cb.createDelegate(this) };
2747 var btn = Roo.factory(b);
2749 btn.render(this.el.select('.modal-footer div').first());
2755 setDefaultButton : function(btn)
2757 //this.el.select('.modal-footer').()
2761 resizeTo: function(w,h)
2765 this.el.select('.modal-dialog',true).first().setWidth(w);
2766 if (this.diff === false) {
2767 this.diff = this.el.select('.modal-dialog',true).first().getHeight() - this.el.select('.modal-body',true).first().getHeight();
2770 this.el.select('.modal-body',true).first().setHeight(h-this.diff);
2774 setContentSize : function(w, h)
2778 onButtonClick: function(btn,e)
2781 this.fireEvent('btnclick', btn.name, e);
2784 * Set the title of the Dialog
2785 * @param {String} str new Title
2787 setTitle: function(str) {
2788 this.titleEl.dom.innerHTML = str;
2791 * Set the body of the Dialog
2792 * @param {String} str new Title
2794 setBody: function(str) {
2795 this.bodyEl.dom.innerHTML = str;
2798 * Set the body of the Dialog using the template
2799 * @param {Obj} data - apply this data to the template and replace the body contents.
2801 applyBody: function(obj)
2804 Roo.log("Error - using apply Body without a template");
2807 this.tmpl.overwrite(this.bodyEl, obj);
2813 Roo.apply(Roo.bootstrap.Modal, {
2815 * Button config that displays a single OK button
2824 * Button config that displays Yes and No buttons
2840 * Button config that displays OK and Cancel buttons
2855 * Button config that displays Yes, No and Cancel buttons
2878 * messagebox - can be used as a replace
2882 * @class Roo.MessageBox
2883 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2887 Roo.Msg.alert('Status', 'Changes saved successfully.');
2889 // Prompt for user data:
2890 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2892 // process text value...
2896 // Show a dialog using config options:
2898 title:'Save Changes?',
2899 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2900 buttons: Roo.Msg.YESNOCANCEL,
2907 Roo.bootstrap.MessageBox = function(){
2908 var dlg, opt, mask, waitTimer;
2909 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2910 var buttons, activeTextEl, bwidth;
2914 var handleButton = function(button){
2916 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2920 var handleHide = function(){
2922 dlg.el.removeClass(opt.cls);
2925 // Roo.TaskMgr.stop(waitTimer);
2926 // waitTimer = null;
2931 var updateButtons = function(b){
2934 buttons["ok"].hide();
2935 buttons["cancel"].hide();
2936 buttons["yes"].hide();
2937 buttons["no"].hide();
2938 //dlg.footer.dom.style.display = 'none';
2941 dlg.footerEl.dom.style.display = '';
2942 for(var k in buttons){
2943 if(typeof buttons[k] != "function"){
2946 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2947 width += buttons[k].el.getWidth()+15;
2957 var handleEsc = function(d, k, e){
2958 if(opt && opt.closable !== false){
2968 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2969 * @return {Roo.BasicDialog} The BasicDialog element
2971 getDialog : function(){
2973 dlg = new Roo.bootstrap.Modal( {
2976 //constraintoviewport:false,
2978 //collapsible : false,
2983 //buttonAlign:"center",
2984 closeClick : function(){
2985 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2988 handleButton("cancel");
2993 dlg.on("hide", handleHide);
2995 //dlg.addKeyListener(27, handleEsc);
2997 this.buttons = buttons;
2998 var bt = this.buttonText;
2999 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3000 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3001 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3002 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3004 bodyEl = dlg.bodyEl.createChild({
3006 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3007 '<textarea class="roo-mb-textarea"></textarea>' +
3008 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3010 msgEl = bodyEl.dom.firstChild;
3011 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3012 textboxEl.enableDisplayMode();
3013 textboxEl.addKeyListener([10,13], function(){
3014 if(dlg.isVisible() && opt && opt.buttons){
3017 }else if(opt.buttons.yes){
3018 handleButton("yes");
3022 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3023 textareaEl.enableDisplayMode();
3024 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3025 progressEl.enableDisplayMode();
3026 var pf = progressEl.dom.firstChild;
3028 pp = Roo.get(pf.firstChild);
3029 pp.setHeight(pf.offsetHeight);
3037 * Updates the message box body text
3038 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3039 * the XHTML-compliant non-breaking space character '&#160;')
3040 * @return {Roo.MessageBox} This message box
3042 updateText : function(text){
3043 if(!dlg.isVisible() && !opt.width){
3044 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3046 msgEl.innerHTML = text || ' ';
3048 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3049 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3051 Math.min(opt.width || cw , this.maxWidth),
3052 Math.max(opt.minWidth || this.minWidth, bwidth)
3055 activeTextEl.setWidth(w);
3057 if(dlg.isVisible()){
3058 dlg.fixedcenter = false;
3060 // to big, make it scroll. = But as usual stupid IE does not support
3063 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3064 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3065 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3067 bodyEl.dom.style.height = '';
3068 bodyEl.dom.style.overflowY = '';
3071 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3073 bodyEl.dom.style.overflowX = '';
3076 dlg.setContentSize(w, bodyEl.getHeight());
3077 if(dlg.isVisible()){
3078 dlg.fixedcenter = true;
3084 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3085 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3086 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3087 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3088 * @return {Roo.MessageBox} This message box
3090 updateProgress : function(value, text){
3092 this.updateText(text);
3094 if (pp) { // weird bug on my firefox - for some reason this is not defined
3095 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3101 * Returns true if the message box is currently displayed
3102 * @return {Boolean} True if the message box is visible, else false
3104 isVisible : function(){
3105 return dlg && dlg.isVisible();
3109 * Hides the message box if it is displayed
3112 if(this.isVisible()){
3118 * Displays a new message box, or reinitializes an existing message box, based on the config options
3119 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3120 * The following config object properties are supported:
3122 Property Type Description
3123 ---------- --------------- ------------------------------------------------------------------------------------
3124 animEl String/Element An id or Element from which the message box should animate as it opens and
3125 closes (defaults to undefined)
3126 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3127 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3128 closable Boolean False to hide the top-right close button (defaults to true). Note that
3129 progress and wait dialogs will ignore this property and always hide the
3130 close button as they can only be closed programmatically.
3131 cls String A custom CSS class to apply to the message box element
3132 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3133 displayed (defaults to 75)
3134 fn Function A callback function to execute after closing the dialog. The arguments to the
3135 function will be btn (the name of the button that was clicked, if applicable,
3136 e.g. "ok"), and text (the value of the active text field, if applicable).
3137 Progress and wait dialogs will ignore this option since they do not respond to
3138 user actions and can only be closed programmatically, so any required function
3139 should be called by the same code after it closes the dialog.
3140 icon String A CSS class that provides a background image to be used as an icon for
3141 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3142 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3143 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3144 modal Boolean False to allow user interaction with the page while the message box is
3145 displayed (defaults to true)
3146 msg String A string that will replace the existing message box body text (defaults
3147 to the XHTML-compliant non-breaking space character ' ')
3148 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3149 progress Boolean True to display a progress bar (defaults to false)
3150 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3151 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3152 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3153 title String The title text
3154 value String The string value to set into the active textbox element if displayed
3155 wait Boolean True to display a progress bar (defaults to false)
3156 width Number The width of the dialog in pixels
3163 msg: 'Please enter your address:',
3165 buttons: Roo.MessageBox.OKCANCEL,
3168 animEl: 'addAddressBtn'
3171 * @param {Object} config Configuration options
3172 * @return {Roo.MessageBox} This message box
3174 show : function(options)
3177 // this causes nightmares if you show one dialog after another
3178 // especially on callbacks..
3180 if(this.isVisible()){
3183 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3184 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3185 Roo.log("New Dialog Message:" + options.msg )
3186 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3187 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3190 var d = this.getDialog();
3192 d.setTitle(opt.title || " ");
3193 d.closeEl.setDisplayed(opt.closable !== false);
3194 activeTextEl = textboxEl;
3195 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3200 textareaEl.setHeight(typeof opt.multiline == "number" ?
3201 opt.multiline : this.defaultTextHeight);
3202 activeTextEl = textareaEl;
3211 progressEl.setDisplayed(opt.progress === true);
3212 this.updateProgress(0);
3213 activeTextEl.dom.value = opt.value || "";
3215 dlg.setDefaultButton(activeTextEl);
3217 var bs = opt.buttons;
3221 }else if(bs && bs.yes){
3222 db = buttons["yes"];
3224 dlg.setDefaultButton(db);
3226 bwidth = updateButtons(opt.buttons);
3227 this.updateText(opt.msg);
3229 d.el.addClass(opt.cls);
3231 d.proxyDrag = opt.proxyDrag === true;
3232 d.modal = opt.modal !== false;
3233 d.mask = opt.modal !== false ? mask : false;
3235 // force it to the end of the z-index stack so it gets a cursor in FF
3236 document.body.appendChild(dlg.el.dom);
3237 d.animateTarget = null;
3238 d.show(options.animEl);
3244 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3245 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3246 * and closing the message box when the process is complete.
3247 * @param {String} title The title bar text
3248 * @param {String} msg The message box body text
3249 * @return {Roo.MessageBox} This message box
3251 progress : function(title, msg){
3258 minWidth: this.minProgressWidth,
3265 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3266 * If a callback function is passed it will be called after the user clicks the button, and the
3267 * id of the button that was clicked will be passed as the only parameter to the callback
3268 * (could also be the top-right close button).
3269 * @param {String} title The title bar text
3270 * @param {String} msg The message box body text
3271 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3272 * @param {Object} scope (optional) The scope of the callback function
3273 * @return {Roo.MessageBox} This message box
3275 alert : function(title, msg, fn, scope){
3288 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3289 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3290 * You are responsible for closing the message box when the process is complete.
3291 * @param {String} msg The message box body text
3292 * @param {String} title (optional) The title bar text
3293 * @return {Roo.MessageBox} This message box
3295 wait : function(msg, title){
3306 waitTimer = Roo.TaskMgr.start({
3308 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3316 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3317 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3318 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3319 * @param {String} title The title bar text
3320 * @param {String} msg The message box body text
3321 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3322 * @param {Object} scope (optional) The scope of the callback function
3323 * @return {Roo.MessageBox} This message box
3325 confirm : function(title, msg, fn, scope){
3329 buttons: this.YESNO,
3338 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3339 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3340 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3341 * (could also be the top-right close button) and the text that was entered will be passed as the two
3342 * parameters to the callback.
3343 * @param {String} title The title bar text
3344 * @param {String} msg The message box body text
3345 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3346 * @param {Object} scope (optional) The scope of the callback function
3347 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3348 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3349 * @return {Roo.MessageBox} This message box
3351 prompt : function(title, msg, fn, scope, multiline){
3355 buttons: this.OKCANCEL,
3360 multiline: multiline,
3367 * Button config that displays a single OK button
3372 * Button config that displays Yes and No buttons
3375 YESNO : {yes:true, no:true},
3377 * Button config that displays OK and Cancel buttons
3380 OKCANCEL : {ok:true, cancel:true},
3382 * Button config that displays Yes, No and Cancel buttons
3385 YESNOCANCEL : {yes:true, no:true, cancel:true},
3388 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3391 defaultTextHeight : 75,
3393 * The maximum width in pixels of the message box (defaults to 600)
3398 * The minimum width in pixels of the message box (defaults to 100)
3403 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3404 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3407 minProgressWidth : 250,
3409 * An object containing the default button text strings that can be overriden for localized language support.
3410 * Supported properties are: ok, cancel, yes and no.
3411 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3424 * Shorthand for {@link Roo.MessageBox}
3426 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3427 Roo.Msg = Roo.Msg || Roo.MessageBox;
3436 * @class Roo.bootstrap.Navbar
3437 * @extends Roo.bootstrap.Component
3438 * Bootstrap Navbar class
3441 * Create a new Navbar
3442 * @param {Object} config The config object
3446 Roo.bootstrap.Navbar = function(config){
3447 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3451 * @event beforetoggle
3452 * Fire before toggle the menu
3453 * @param {Roo.EventObject} e
3455 "beforetoggle" : true
3459 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3468 getAutoCreate : function(){
3471 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3475 initEvents :function ()
3477 //Roo.log(this.el.select('.navbar-toggle',true));
3478 this.el.select('.navbar-toggle',true).on('click', function() {
3479 if(this.fireEvent('beforetoggle', this) !== false){
3480 this.el.select('.navbar-collapse',true).toggleClass('in');
3490 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3492 var size = this.el.getSize();
3493 this.maskEl.setSize(size.width, size.height);
3494 this.maskEl.enableDisplayMode("block");
3503 getChildContainer : function()
3505 if (this.el.select('.collapse').getCount()) {
3506 return this.el.select('.collapse',true).first();
3539 * @class Roo.bootstrap.NavSimplebar
3540 * @extends Roo.bootstrap.Navbar
3541 * Bootstrap Sidebar class
3543 * @cfg {Boolean} inverse is inverted color
3545 * @cfg {String} type (nav | pills | tabs)
3546 * @cfg {Boolean} arrangement stacked | justified
3547 * @cfg {String} align (left | right) alignment
3549 * @cfg {Boolean} main (true|false) main nav bar? default false
3550 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3552 * @cfg {String} tag (header|footer|nav|div) default is nav
3558 * Create a new Sidebar
3559 * @param {Object} config The config object
3563 Roo.bootstrap.NavSimplebar = function(config){
3564 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3567 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3583 getAutoCreate : function(){
3587 tag : this.tag || 'div',
3600 this.type = this.type || 'nav';
3601 if (['tabs','pills'].indexOf(this.type)!==-1) {
3602 cfg.cn[0].cls += ' nav-' + this.type
3606 if (this.type!=='nav') {
3607 Roo.log('nav type must be nav/tabs/pills')
3609 cfg.cn[0].cls += ' navbar-nav'
3615 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3616 cfg.cn[0].cls += ' nav-' + this.arrangement;
3620 if (this.align === 'right') {
3621 cfg.cn[0].cls += ' navbar-right';
3625 cfg.cls += ' navbar-inverse';
3652 * @class Roo.bootstrap.NavHeaderbar
3653 * @extends Roo.bootstrap.NavSimplebar
3654 * Bootstrap Sidebar class
3656 * @cfg {String} brand what is brand
3657 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3658 * @cfg {String} brand_href href of the brand
3659 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3660 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3661 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3662 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3665 * Create a new Sidebar
3666 * @param {Object} config The config object
3670 Roo.bootstrap.NavHeaderbar = function(config){
3671 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3675 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3682 desktopCenter : false,
3685 getAutoCreate : function(){
3688 tag: this.nav || 'nav',
3695 if (this.desktopCenter) {
3696 cn.push({cls : 'container', cn : []});
3703 cls: 'navbar-header',
3708 cls: 'navbar-toggle',
3709 'data-toggle': 'collapse',
3714 html: 'Toggle navigation'
3736 cls: 'collapse navbar-collapse',
3740 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3742 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3743 cfg.cls += ' navbar-' + this.position;
3745 // tag can override this..
3747 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3750 if (this.brand !== '') {
3753 href: this.brand_href ? this.brand_href : '#',
3754 cls: 'navbar-brand',
3762 cfg.cls += ' main-nav';
3770 getHeaderChildContainer : function()
3772 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3773 return this.el.select('.navbar-header',true).first();
3776 return this.getChildContainer();
3780 initEvents : function()
3782 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3784 if (this.autohide) {
3789 Roo.get(document).on('scroll',function(e) {
3790 var ns = Roo.get(document).getScroll().top;
3791 var os = prevScroll;
3795 ft.removeClass('slideDown');
3796 ft.addClass('slideUp');
3799 ft.removeClass('slideUp');
3800 ft.addClass('slideDown');
3821 * @class Roo.bootstrap.NavSidebar
3822 * @extends Roo.bootstrap.Navbar
3823 * Bootstrap Sidebar class
3826 * Create a new Sidebar
3827 * @param {Object} config The config object
3831 Roo.bootstrap.NavSidebar = function(config){
3832 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3835 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3837 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3839 getAutoCreate : function(){
3844 cls: 'sidebar sidebar-nav'
3866 * @class Roo.bootstrap.NavGroup
3867 * @extends Roo.bootstrap.Component
3868 * Bootstrap NavGroup class
3869 * @cfg {String} align (left|right)
3870 * @cfg {Boolean} inverse
3871 * @cfg {String} type (nav|pills|tab) default nav
3872 * @cfg {String} navId - reference Id for navbar.
3876 * Create a new nav group
3877 * @param {Object} config The config object
3880 Roo.bootstrap.NavGroup = function(config){
3881 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3884 Roo.bootstrap.NavGroup.register(this);
3888 * Fires when the active item changes
3889 * @param {Roo.bootstrap.NavGroup} this
3890 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3891 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3898 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3909 getAutoCreate : function()
3911 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3918 if (['tabs','pills'].indexOf(this.type)!==-1) {
3919 cfg.cls += ' nav-' + this.type
3921 if (this.type!=='nav') {
3922 Roo.log('nav type must be nav/tabs/pills')
3924 cfg.cls += ' navbar-nav'
3927 if (this.parent().sidebar) {
3930 cls: 'dashboard-menu sidebar-menu'
3936 if (this.form === true) {
3942 if (this.align === 'right') {
3943 cfg.cls += ' navbar-right';
3945 cfg.cls += ' navbar-left';
3949 if (this.align === 'right') {
3950 cfg.cls += ' navbar-right';
3954 cfg.cls += ' navbar-inverse';
3962 * sets the active Navigation item
3963 * @param {Roo.bootstrap.NavItem} the new current navitem
3965 setActiveItem : function(item)
3968 Roo.each(this.navItems, function(v){
3973 v.setActive(false, true);
3980 item.setActive(true, true);
3981 this.fireEvent('changed', this, item, prev);
3986 * gets the active Navigation item
3987 * @return {Roo.bootstrap.NavItem} the current navitem
3989 getActive : function()
3993 Roo.each(this.navItems, function(v){
4004 indexOfNav : function()
4008 Roo.each(this.navItems, function(v,i){
4019 * adds a Navigation item
4020 * @param {Roo.bootstrap.NavItem} the navitem to add
4022 addItem : function(cfg)
4024 var cn = new Roo.bootstrap.NavItem(cfg);
4026 cn.parentId = this.id;
4027 cn.onRender(this.el, null);
4031 * register a Navigation item
4032 * @param {Roo.bootstrap.NavItem} the navitem to add
4034 register : function(item)
4036 this.navItems.push( item);
4037 item.navId = this.navId;
4042 * clear all the Navigation item
4045 clearAll : function()
4048 this.el.dom.innerHTML = '';
4051 getNavItem: function(tabId)
4054 Roo.each(this.navItems, function(e) {
4055 if (e.tabId == tabId) {
4065 setActiveNext : function()
4067 var i = this.indexOfNav(this.getActive());
4068 if (i > this.navItems.length) {
4071 this.setActiveItem(this.navItems[i+1]);
4073 setActivePrev : function()
4075 var i = this.indexOfNav(this.getActive());
4079 this.setActiveItem(this.navItems[i-1]);
4081 clearWasActive : function(except) {
4082 Roo.each(this.navItems, function(e) {
4083 if (e.tabId != except.tabId && e.was_active) {
4084 e.was_active = false;
4091 getWasActive : function ()
4094 Roo.each(this.navItems, function(e) {
4109 Roo.apply(Roo.bootstrap.NavGroup, {
4113 * register a Navigation Group
4114 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4116 register : function(navgrp)
4118 this.groups[navgrp.navId] = navgrp;
4122 * fetch a Navigation Group based on the navigation ID
4123 * @param {string} the navgroup to add
4124 * @returns {Roo.bootstrap.NavGroup} the navgroup
4126 get: function(navId) {
4127 if (typeof(this.groups[navId]) == 'undefined') {
4129 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4131 return this.groups[navId] ;
4146 * @class Roo.bootstrap.NavItem
4147 * @extends Roo.bootstrap.Component
4148 * Bootstrap Navbar.NavItem class
4149 * @cfg {String} href link to
4150 * @cfg {String} html content of button
4151 * @cfg {String} badge text inside badge
4152 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4153 * @cfg {String} glyphicon name of glyphicon
4154 * @cfg {String} icon name of font awesome icon
4155 * @cfg {Boolean} active Is item active
4156 * @cfg {Boolean} disabled Is item disabled
4158 * @cfg {Boolean} preventDefault (true | false) default false
4159 * @cfg {String} tabId the tab that this item activates.
4160 * @cfg {String} tagtype (a|span) render as a href or span?
4161 * @cfg {Boolean} animateRef (true|false) link to element default false
4164 * Create a new Navbar Item
4165 * @param {Object} config The config object
4167 Roo.bootstrap.NavItem = function(config){
4168 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4173 * The raw click event for the entire grid.
4174 * @param {Roo.EventObject} e
4179 * Fires when the active item active state changes
4180 * @param {Roo.bootstrap.NavItem} this
4181 * @param {boolean} state the new state
4187 * Fires when scroll to element
4188 * @param {Roo.bootstrap.NavItem} this
4189 * @param {Object} options
4190 * @param {Roo.EventObject} e
4198 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4206 preventDefault : false,
4213 getAutoCreate : function(){
4222 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4224 if (this.disabled) {
4225 cfg.cls += ' disabled';
4228 if (this.href || this.html || this.glyphicon || this.icon) {
4232 href : this.href || "#",
4233 html: this.html || ''
4238 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4241 if(this.glyphicon) {
4242 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4247 cfg.cn[0].html += " <span class='caret'></span>";
4251 if (this.badge !== '') {
4253 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4261 initEvents: function()
4263 if (typeof (this.menu) != 'undefined') {
4264 this.menu.parentType = this.xtype;
4265 this.menu.triggerEl = this.el;
4266 this.menu = this.addxtype(Roo.apply({}, this.menu));
4269 this.el.select('a',true).on('click', this.onClick, this);
4271 if(this.tagtype == 'span'){
4272 this.el.select('span',true).on('click', this.onClick, this);
4275 // at this point parent should be available..
4276 this.parent().register(this);
4279 onClick : function(e)
4281 if (e.getTarget('.dropdown-menu-item')) {
4282 // did you click on a menu itemm.... - then don't trigger onclick..
4287 this.preventDefault ||
4290 Roo.log("NavItem - prevent Default?");
4294 if (this.disabled) {
4298 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4299 if (tg && tg.transition) {
4300 Roo.log("waiting for the transitionend");
4306 //Roo.log("fire event clicked");
4307 if(this.fireEvent('click', this, e) === false){
4311 if(this.tagtype == 'span'){
4315 //Roo.log(this.href);
4316 var ael = this.el.select('a',true).first();
4319 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4320 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4321 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4322 return; // ignore... - it's a 'hash' to another page.
4324 Roo.log("NavItem - prevent Default?");
4326 this.scrollToElement(e);
4330 var p = this.parent();
4332 if (['tabs','pills'].indexOf(p.type)!==-1) {
4333 if (typeof(p.setActiveItem) !== 'undefined') {
4334 p.setActiveItem(this);
4338 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4339 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4340 // remove the collapsed menu expand...
4341 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4345 isActive: function () {
4348 setActive : function(state, fire, is_was_active)
4350 if (this.active && !state && this.navId) {
4351 this.was_active = true;
4352 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4354 nv.clearWasActive(this);
4358 this.active = state;
4361 this.el.removeClass('active');
4362 } else if (!this.el.hasClass('active')) {
4363 this.el.addClass('active');
4366 this.fireEvent('changed', this, state);
4369 // show a panel if it's registered and related..
4371 if (!this.navId || !this.tabId || !state || is_was_active) {
4375 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4379 var pan = tg.getPanelByName(this.tabId);
4383 // if we can not flip to new panel - go back to old nav highlight..
4384 if (false == tg.showPanel(pan)) {
4385 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4387 var onav = nv.getWasActive();
4389 onav.setActive(true, false, true);
4398 // this should not be here...
4399 setDisabled : function(state)
4401 this.disabled = state;
4403 this.el.removeClass('disabled');
4404 } else if (!this.el.hasClass('disabled')) {
4405 this.el.addClass('disabled');
4411 * Fetch the element to display the tooltip on.
4412 * @return {Roo.Element} defaults to this.el
4414 tooltipEl : function()
4416 return this.el.select('' + this.tagtype + '', true).first();
4419 scrollToElement : function(e)
4421 var c = document.body;
4424 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4426 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4427 c = document.documentElement;
4430 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4436 var o = target.calcOffsetsTo(c);
4443 this.fireEvent('scrollto', this, options, e);
4445 Roo.get(c).scrollTo('top', options.value, true);
4458 * <span> icon </span>
4459 * <span> text </span>
4460 * <span>badge </span>
4464 * @class Roo.bootstrap.NavSidebarItem
4465 * @extends Roo.bootstrap.NavItem
4466 * Bootstrap Navbar.NavSidebarItem class
4467 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4468 * {bool} open is the menu open
4470 * Create a new Navbar Button
4471 * @param {Object} config The config object
4473 Roo.bootstrap.NavSidebarItem = function(config){
4474 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4479 * The raw click event for the entire grid.
4480 * @param {Roo.EventObject} e
4485 * Fires when the active item active state changes
4486 * @param {Roo.bootstrap.NavSidebarItem} this
4487 * @param {boolean} state the new state
4495 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4497 badgeWeight : 'default',
4501 getAutoCreate : function(){
4506 href : this.href || '#',
4518 html : this.html || ''
4523 cfg.cls += ' active';
4526 if (this.disabled) {
4527 cfg.cls += ' disabled';
4530 cfg.cls += ' open x-open';
4533 if (this.glyphicon || this.icon) {
4534 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4535 a.cn.push({ tag : 'i', cls : c }) ;
4540 if (this.badge !== '') {
4542 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4546 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4547 a.cls += 'dropdown-toggle treeview' ;
4555 initEvents : function()
4557 if (typeof (this.menu) != 'undefined') {
4558 this.menu.parentType = this.xtype;
4559 this.menu.triggerEl = this.el;
4560 this.menu = this.addxtype(Roo.apply({}, this.menu));
4563 this.el.on('click', this.onClick, this);
4566 if(this.badge !== ''){
4568 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4573 onClick : function(e)
4580 if(this.preventDefault){
4584 this.fireEvent('click', this);
4587 disable : function()
4589 this.setDisabled(true);
4594 this.setDisabled(false);
4597 setDisabled : function(state)
4599 if(this.disabled == state){
4603 this.disabled = state;
4606 this.el.addClass('disabled');
4610 this.el.removeClass('disabled');
4615 setActive : function(state)
4617 if(this.active == state){
4621 this.active = state;
4624 this.el.addClass('active');
4628 this.el.removeClass('active');
4633 isActive: function ()
4638 setBadge : function(str)
4644 this.badgeEl.dom.innerHTML = str;
4661 * @class Roo.bootstrap.Row
4662 * @extends Roo.bootstrap.Component
4663 * Bootstrap Row class (contains columns...)
4667 * @param {Object} config The config object
4670 Roo.bootstrap.Row = function(config){
4671 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4674 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4676 getAutoCreate : function(){
4695 * @class Roo.bootstrap.Element
4696 * @extends Roo.bootstrap.Component
4697 * Bootstrap Element class
4698 * @cfg {String} html contents of the element
4699 * @cfg {String} tag tag of the element
4700 * @cfg {String} cls class of the element
4701 * @cfg {Boolean} preventDefault (true|false) default false
4702 * @cfg {Boolean} clickable (true|false) default false
4705 * Create a new Element
4706 * @param {Object} config The config object
4709 Roo.bootstrap.Element = function(config){
4710 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4716 * When a element is chick
4717 * @param {Roo.bootstrap.Element} this
4718 * @param {Roo.EventObject} e
4724 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4729 preventDefault: false,
4732 getAutoCreate : function(){
4743 initEvents: function()
4745 Roo.bootstrap.Element.superclass.initEvents.call(this);
4748 this.el.on('click', this.onClick, this);
4753 onClick : function(e)
4755 if(this.preventDefault){
4759 this.fireEvent('click', this, e);
4762 getValue : function()
4764 return this.el.dom.innerHTML;
4767 setValue : function(value)
4769 this.el.dom.innerHTML = value;
4784 * @class Roo.bootstrap.Pagination
4785 * @extends Roo.bootstrap.Component
4786 * Bootstrap Pagination class
4787 * @cfg {String} size xs | sm | md | lg
4788 * @cfg {Boolean} inverse false | true
4791 * Create a new Pagination
4792 * @param {Object} config The config object
4795 Roo.bootstrap.Pagination = function(config){
4796 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4799 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4805 getAutoCreate : function(){
4811 cfg.cls += ' inverse';
4817 cfg.cls += " " + this.cls;
4835 * @class Roo.bootstrap.PaginationItem
4836 * @extends Roo.bootstrap.Component
4837 * Bootstrap PaginationItem class
4838 * @cfg {String} html text
4839 * @cfg {String} href the link
4840 * @cfg {Boolean} preventDefault (true | false) default true
4841 * @cfg {Boolean} active (true | false) default false
4842 * @cfg {Boolean} disabled default false
4846 * Create a new PaginationItem
4847 * @param {Object} config The config object
4851 Roo.bootstrap.PaginationItem = function(config){
4852 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4857 * The raw click event for the entire grid.
4858 * @param {Roo.EventObject} e
4864 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4868 preventDefault: true,
4873 getAutoCreate : function(){
4879 href : this.href ? this.href : '#',
4880 html : this.html ? this.html : ''
4890 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4894 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4900 initEvents: function() {
4902 this.el.on('click', this.onClick, this);
4905 onClick : function(e)
4907 Roo.log('PaginationItem on click ');
4908 if(this.preventDefault){
4916 this.fireEvent('click', this, e);
4932 * @class Roo.bootstrap.Slider
4933 * @extends Roo.bootstrap.Component
4934 * Bootstrap Slider class
4937 * Create a new Slider
4938 * @param {Object} config The config object
4941 Roo.bootstrap.Slider = function(config){
4942 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4945 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4947 getAutoCreate : function(){
4951 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4955 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4967 * Ext JS Library 1.1.1
4968 * Copyright(c) 2006-2007, Ext JS, LLC.
4970 * Originally Released Under LGPL - original licence link has changed is not relivant.
4973 * <script type="text/javascript">
4978 * @class Roo.grid.ColumnModel
4979 * @extends Roo.util.Observable
4980 * This is the default implementation of a ColumnModel used by the Grid. It defines
4981 * the columns in the grid.
4984 var colModel = new Roo.grid.ColumnModel([
4985 {header: "Ticker", width: 60, sortable: true, locked: true},
4986 {header: "Company Name", width: 150, sortable: true},
4987 {header: "Market Cap.", width: 100, sortable: true},
4988 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4989 {header: "Employees", width: 100, sortable: true, resizable: false}
4994 * The config options listed for this class are options which may appear in each
4995 * individual column definition.
4996 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4998 * @param {Object} config An Array of column config objects. See this class's
4999 * config objects for details.
5001 Roo.grid.ColumnModel = function(config){
5003 * The config passed into the constructor
5005 this.config = config;
5008 // if no id, create one
5009 // if the column does not have a dataIndex mapping,
5010 // map it to the order it is in the config
5011 for(var i = 0, len = config.length; i < len; i++){
5013 if(typeof c.dataIndex == "undefined"){
5016 if(typeof c.renderer == "string"){
5017 c.renderer = Roo.util.Format[c.renderer];
5019 if(typeof c.id == "undefined"){
5022 if(c.editor && c.editor.xtype){
5023 c.editor = Roo.factory(c.editor, Roo.grid);
5025 if(c.editor && c.editor.isFormField){
5026 c.editor = new Roo.grid.GridEditor(c.editor);
5028 this.lookup[c.id] = c;
5032 * The width of columns which have no width specified (defaults to 100)
5035 this.defaultWidth = 100;
5038 * Default sortable of columns which have no sortable specified (defaults to false)
5041 this.defaultSortable = false;
5045 * @event widthchange
5046 * Fires when the width of a column changes.
5047 * @param {ColumnModel} this
5048 * @param {Number} columnIndex The column index
5049 * @param {Number} newWidth The new width
5051 "widthchange": true,
5053 * @event headerchange
5054 * Fires when the text of a header changes.
5055 * @param {ColumnModel} this
5056 * @param {Number} columnIndex The column index
5057 * @param {Number} newText The new header text
5059 "headerchange": true,
5061 * @event hiddenchange
5062 * Fires when a column is hidden or "unhidden".
5063 * @param {ColumnModel} this
5064 * @param {Number} columnIndex The column index
5065 * @param {Boolean} hidden true if hidden, false otherwise
5067 "hiddenchange": true,
5069 * @event columnmoved
5070 * Fires when a column is moved.
5071 * @param {ColumnModel} this
5072 * @param {Number} oldIndex
5073 * @param {Number} newIndex
5075 "columnmoved" : true,
5077 * @event columlockchange
5078 * Fires when a column's locked state is changed
5079 * @param {ColumnModel} this
5080 * @param {Number} colIndex
5081 * @param {Boolean} locked true if locked
5083 "columnlockchange" : true
5085 Roo.grid.ColumnModel.superclass.constructor.call(this);
5087 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5089 * @cfg {String} header The header text to display in the Grid view.
5092 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5093 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5094 * specified, the column's index is used as an index into the Record's data Array.
5097 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5098 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5101 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5102 * Defaults to the value of the {@link #defaultSortable} property.
5103 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5106 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5109 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5112 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5115 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5118 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5119 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5120 * default renderer uses the raw data value. If an object is returned (bootstrap only)
5121 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5124 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5127 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5130 * @cfg {String} cursor (Optional)
5133 * @cfg {String} tooltip (Optional)
5136 * @cfg {Number} xs (Optional)
5139 * @cfg {Number} sm (Optional)
5142 * @cfg {Number} md (Optional)
5145 * @cfg {Number} lg (Optional)
5148 * Returns the id of the column at the specified index.
5149 * @param {Number} index The column index
5150 * @return {String} the id
5152 getColumnId : function(index){
5153 return this.config[index].id;
5157 * Returns the column for a specified id.
5158 * @param {String} id The column id
5159 * @return {Object} the column
5161 getColumnById : function(id){
5162 return this.lookup[id];
5167 * Returns the column for a specified dataIndex.
5168 * @param {String} dataIndex The column dataIndex
5169 * @return {Object|Boolean} the column or false if not found
5171 getColumnByDataIndex: function(dataIndex){
5172 var index = this.findColumnIndex(dataIndex);
5173 return index > -1 ? this.config[index] : false;
5177 * Returns the index for a specified column id.
5178 * @param {String} id The column id
5179 * @return {Number} the index, or -1 if not found
5181 getIndexById : function(id){
5182 for(var i = 0, len = this.config.length; i < len; i++){
5183 if(this.config[i].id == id){
5191 * Returns the index for a specified column dataIndex.
5192 * @param {String} dataIndex The column dataIndex
5193 * @return {Number} the index, or -1 if not found
5196 findColumnIndex : function(dataIndex){
5197 for(var i = 0, len = this.config.length; i < len; i++){
5198 if(this.config[i].dataIndex == dataIndex){
5206 moveColumn : function(oldIndex, newIndex){
5207 var c = this.config[oldIndex];
5208 this.config.splice(oldIndex, 1);
5209 this.config.splice(newIndex, 0, c);
5210 this.dataMap = null;
5211 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5214 isLocked : function(colIndex){
5215 return this.config[colIndex].locked === true;
5218 setLocked : function(colIndex, value, suppressEvent){
5219 if(this.isLocked(colIndex) == value){
5222 this.config[colIndex].locked = value;
5224 this.fireEvent("columnlockchange", this, colIndex, value);
5228 getTotalLockedWidth : function(){
5230 for(var i = 0; i < this.config.length; i++){
5231 if(this.isLocked(i) && !this.isHidden(i)){
5232 this.totalWidth += this.getColumnWidth(i);
5238 getLockedCount : function(){
5239 for(var i = 0, len = this.config.length; i < len; i++){
5240 if(!this.isLocked(i)){
5245 return this.config.length;
5249 * Returns the number of columns.
5252 getColumnCount : function(visibleOnly){
5253 if(visibleOnly === true){
5255 for(var i = 0, len = this.config.length; i < len; i++){
5256 if(!this.isHidden(i)){
5262 return this.config.length;
5266 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5267 * @param {Function} fn
5268 * @param {Object} scope (optional)
5269 * @return {Array} result
5271 getColumnsBy : function(fn, scope){
5273 for(var i = 0, len = this.config.length; i < len; i++){
5274 var c = this.config[i];
5275 if(fn.call(scope||this, c, i) === true){
5283 * Returns true if the specified column is sortable.
5284 * @param {Number} col The column index
5287 isSortable : function(col){
5288 if(typeof this.config[col].sortable == "undefined"){
5289 return this.defaultSortable;
5291 return this.config[col].sortable;
5295 * Returns the rendering (formatting) function defined for the column.
5296 * @param {Number} col The column index.
5297 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5299 getRenderer : function(col){
5300 if(!this.config[col].renderer){
5301 return Roo.grid.ColumnModel.defaultRenderer;
5303 return this.config[col].renderer;
5307 * Sets the rendering (formatting) function for a column.
5308 * @param {Number} col The column index
5309 * @param {Function} fn The function to use to process the cell's raw data
5310 * to return HTML markup for the grid view. The render function is called with
5311 * the following parameters:<ul>
5312 * <li>Data value.</li>
5313 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5314 * <li>css A CSS style string to apply to the table cell.</li>
5315 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5316 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5317 * <li>Row index</li>
5318 * <li>Column index</li>
5319 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5321 setRenderer : function(col, fn){
5322 this.config[col].renderer = fn;
5326 * Returns the width for the specified column.
5327 * @param {Number} col The column index
5330 getColumnWidth : function(col){
5331 return this.config[col].width * 1 || this.defaultWidth;
5335 * Sets the width for a column.
5336 * @param {Number} col The column index
5337 * @param {Number} width The new width
5339 setColumnWidth : function(col, width, suppressEvent){
5340 this.config[col].width = width;
5341 this.totalWidth = null;
5343 this.fireEvent("widthchange", this, col, width);
5348 * Returns the total width of all columns.
5349 * @param {Boolean} includeHidden True to include hidden column widths
5352 getTotalWidth : function(includeHidden){
5353 if(!this.totalWidth){
5354 this.totalWidth = 0;
5355 for(var i = 0, len = this.config.length; i < len; i++){
5356 if(includeHidden || !this.isHidden(i)){
5357 this.totalWidth += this.getColumnWidth(i);
5361 return this.totalWidth;
5365 * Returns the header for the specified column.
5366 * @param {Number} col The column index
5369 getColumnHeader : function(col){
5370 return this.config[col].header;
5374 * Sets the header for a column.
5375 * @param {Number} col The column index
5376 * @param {String} header The new header
5378 setColumnHeader : function(col, header){
5379 this.config[col].header = header;
5380 this.fireEvent("headerchange", this, col, header);
5384 * Returns the tooltip for the specified column.
5385 * @param {Number} col The column index
5388 getColumnTooltip : function(col){
5389 return this.config[col].tooltip;
5392 * Sets the tooltip for a column.
5393 * @param {Number} col The column index
5394 * @param {String} tooltip The new tooltip
5396 setColumnTooltip : function(col, tooltip){
5397 this.config[col].tooltip = tooltip;
5401 * Returns the dataIndex for the specified column.
5402 * @param {Number} col The column index
5405 getDataIndex : function(col){
5406 return this.config[col].dataIndex;
5410 * Sets the dataIndex for a column.
5411 * @param {Number} col The column index
5412 * @param {Number} dataIndex The new dataIndex
5414 setDataIndex : function(col, dataIndex){
5415 this.config[col].dataIndex = dataIndex;
5421 * Returns true if the cell is editable.
5422 * @param {Number} colIndex The column index
5423 * @param {Number} rowIndex The row index - this is nto actually used..?
5426 isCellEditable : function(colIndex, rowIndex){
5427 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5431 * Returns the editor defined for the cell/column.
5432 * return false or null to disable editing.
5433 * @param {Number} colIndex The column index
5434 * @param {Number} rowIndex The row index
5437 getCellEditor : function(colIndex, rowIndex){
5438 return this.config[colIndex].editor;
5442 * Sets if a column is editable.
5443 * @param {Number} col The column index
5444 * @param {Boolean} editable True if the column is editable
5446 setEditable : function(col, editable){
5447 this.config[col].editable = editable;
5452 * Returns true if the column is hidden.
5453 * @param {Number} colIndex The column index
5456 isHidden : function(colIndex){
5457 return this.config[colIndex].hidden;
5462 * Returns true if the column width cannot be changed
5464 isFixed : function(colIndex){
5465 return this.config[colIndex].fixed;
5469 * Returns true if the column can be resized
5472 isResizable : function(colIndex){
5473 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5476 * Sets if a column is hidden.
5477 * @param {Number} colIndex The column index
5478 * @param {Boolean} hidden True if the column is hidden
5480 setHidden : function(colIndex, hidden){
5481 this.config[colIndex].hidden = hidden;
5482 this.totalWidth = null;
5483 this.fireEvent("hiddenchange", this, colIndex, hidden);
5487 * Sets the editor for a column.
5488 * @param {Number} col The column index
5489 * @param {Object} editor The editor object
5491 setEditor : function(col, editor){
5492 this.config[col].editor = editor;
5496 Roo.grid.ColumnModel.defaultRenderer = function(value){
5497 if(typeof value == "string" && value.length < 1){
5503 // Alias for backwards compatibility
5504 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5507 * Ext JS Library 1.1.1
5508 * Copyright(c) 2006-2007, Ext JS, LLC.
5510 * Originally Released Under LGPL - original licence link has changed is not relivant.
5513 * <script type="text/javascript">
5517 * @class Roo.LoadMask
5518 * A simple utility class for generically masking elements while loading data. If the element being masked has
5519 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5520 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5521 * element's UpdateManager load indicator and will be destroyed after the initial load.
5523 * Create a new LoadMask
5524 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5525 * @param {Object} config The config object
5527 Roo.LoadMask = function(el, config){
5528 this.el = Roo.get(el);
5529 Roo.apply(this, config);
5531 this.store.on('beforeload', this.onBeforeLoad, this);
5532 this.store.on('load', this.onLoad, this);
5533 this.store.on('loadexception', this.onLoadException, this);
5534 this.removeMask = false;
5536 var um = this.el.getUpdateManager();
5537 um.showLoadIndicator = false; // disable the default indicator
5538 um.on('beforeupdate', this.onBeforeLoad, this);
5539 um.on('update', this.onLoad, this);
5540 um.on('failure', this.onLoad, this);
5541 this.removeMask = true;
5545 Roo.LoadMask.prototype = {
5547 * @cfg {Boolean} removeMask
5548 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5549 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5553 * The text to display in a centered loading message box (defaults to 'Loading...')
5557 * @cfg {String} msgCls
5558 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5560 msgCls : 'x-mask-loading',
5563 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5569 * Disables the mask to prevent it from being displayed
5571 disable : function(){
5572 this.disabled = true;
5576 * Enables the mask so that it can be displayed
5578 enable : function(){
5579 this.disabled = false;
5582 onLoadException : function()
5586 if (typeof(arguments[3]) != 'undefined') {
5587 Roo.MessageBox.alert("Error loading",arguments[3]);
5591 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5592 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5601 this.el.unmask(this.removeMask);
5606 this.el.unmask(this.removeMask);
5610 onBeforeLoad : function(){
5612 this.el.mask(this.msg, this.msgCls);
5617 destroy : function(){
5619 this.store.un('beforeload', this.onBeforeLoad, this);
5620 this.store.un('load', this.onLoad, this);
5621 this.store.un('loadexception', this.onLoadException, this);
5623 var um = this.el.getUpdateManager();
5624 um.un('beforeupdate', this.onBeforeLoad, this);
5625 um.un('update', this.onLoad, this);
5626 um.un('failure', this.onLoad, this);
5637 * @class Roo.bootstrap.Table
5638 * @extends Roo.bootstrap.Component
5639 * Bootstrap Table class
5640 * @cfg {String} cls table class
5641 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5642 * @cfg {String} bgcolor Specifies the background color for a table
5643 * @cfg {Number} border Specifies whether the table cells should have borders or not
5644 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5645 * @cfg {Number} cellspacing Specifies the space between cells
5646 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5647 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5648 * @cfg {String} sortable Specifies that the table should be sortable
5649 * @cfg {String} summary Specifies a summary of the content of a table
5650 * @cfg {Number} width Specifies the width of a table
5651 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5653 * @cfg {boolean} striped Should the rows be alternative striped
5654 * @cfg {boolean} bordered Add borders to the table
5655 * @cfg {boolean} hover Add hover highlighting
5656 * @cfg {boolean} condensed Format condensed
5657 * @cfg {boolean} responsive Format condensed
5658 * @cfg {Boolean} loadMask (true|false) default false
5659 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5660 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5661 * @cfg {Boolean} rowSelection (true|false) default false
5662 * @cfg {Boolean} cellSelection (true|false) default false
5663 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5667 * Create a new Table
5668 * @param {Object} config The config object
5671 Roo.bootstrap.Table = function(config){
5672 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5675 this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
5676 this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
5677 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5678 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5682 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5683 this.sm = this.selModel;
5684 this.sm.xmodule = this.xmodule || false;
5686 if (this.cm && typeof(this.cm.config) == 'undefined') {
5687 this.colModel = new Roo.grid.ColumnModel(this.cm);
5688 this.cm = this.colModel;
5689 this.cm.xmodule = this.xmodule || false;
5692 this.store= Roo.factory(this.store, Roo.data);
5693 this.ds = this.store;
5694 this.ds.xmodule = this.xmodule || false;
5697 if (this.footer && this.store) {
5698 this.footer.dataSource = this.ds;
5699 this.footer = Roo.factory(this.footer);
5706 * Fires when a cell is clicked
5707 * @param {Roo.bootstrap.Table} this
5708 * @param {Roo.Element} el
5709 * @param {Number} rowIndex
5710 * @param {Number} columnIndex
5711 * @param {Roo.EventObject} e
5715 * @event celldblclick
5716 * Fires when a cell is double clicked
5717 * @param {Roo.bootstrap.Table} this
5718 * @param {Roo.Element} el
5719 * @param {Number} rowIndex
5720 * @param {Number} columnIndex
5721 * @param {Roo.EventObject} e
5723 "celldblclick" : true,
5726 * Fires when a row is clicked
5727 * @param {Roo.bootstrap.Table} this
5728 * @param {Roo.Element} el
5729 * @param {Number} rowIndex
5730 * @param {Roo.EventObject} e
5734 * @event rowdblclick
5735 * Fires when a row is double clicked
5736 * @param {Roo.bootstrap.Table} this
5737 * @param {Roo.Element} el
5738 * @param {Number} rowIndex
5739 * @param {Roo.EventObject} e
5741 "rowdblclick" : true,
5744 * Fires when a mouseover occur
5745 * @param {Roo.bootstrap.Table} this
5746 * @param {Roo.Element} el
5747 * @param {Number} rowIndex
5748 * @param {Number} columnIndex
5749 * @param {Roo.EventObject} e
5754 * Fires when a mouseout occur
5755 * @param {Roo.bootstrap.Table} this
5756 * @param {Roo.Element} el
5757 * @param {Number} rowIndex
5758 * @param {Number} columnIndex
5759 * @param {Roo.EventObject} e
5764 * Fires when a row is rendered, so you can change add a style to it.
5765 * @param {Roo.bootstrap.Table} this
5766 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5770 * @event rowsrendered
5771 * Fires when all the rows have been rendered
5772 * @param {Roo.bootstrap.Table} this
5774 'rowsrendered' : true,
5776 * @event contextmenu
5777 * The raw contextmenu event for the entire grid.
5778 * @param {Roo.EventObject} e
5780 "contextmenu" : true,
5782 * @event rowcontextmenu
5783 * Fires when a row is right clicked
5784 * @param {Roo.bootstrap.Table} this
5785 * @param {Number} rowIndex
5786 * @param {Roo.EventObject} e
5788 "rowcontextmenu" : true,
5790 * @event cellcontextmenu
5791 * Fires when a cell is right clicked
5792 * @param {Roo.bootstrap.Table} this
5793 * @param {Number} rowIndex
5794 * @param {Number} cellIndex
5795 * @param {Roo.EventObject} e
5797 "cellcontextmenu" : true,
5799 * @event headercontextmenu
5800 * Fires when a header is right clicked
5801 * @param {Roo.bootstrap.Table} this
5802 * @param {Number} columnIndex
5803 * @param {Roo.EventObject} e
5805 "headercontextmenu" : true
5809 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5834 rowSelection : false,
5835 cellSelection : false,
5838 // Roo.Element - the tbody
5841 getAutoCreate : function(){
5842 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5851 cfg.cls += ' table-striped';
5855 cfg.cls += ' table-hover';
5857 if (this.bordered) {
5858 cfg.cls += ' table-bordered';
5860 if (this.condensed) {
5861 cfg.cls += ' table-condensed';
5863 if (this.responsive) {
5864 cfg.cls += ' table-responsive';
5868 cfg.cls+= ' ' +this.cls;
5871 // this lot should be simplifed...
5874 cfg.align=this.align;
5877 cfg.bgcolor=this.bgcolor;
5880 cfg.border=this.border;
5882 if (this.cellpadding) {
5883 cfg.cellpadding=this.cellpadding;
5885 if (this.cellspacing) {
5886 cfg.cellspacing=this.cellspacing;
5889 cfg.frame=this.frame;
5892 cfg.rules=this.rules;
5894 if (this.sortable) {
5895 cfg.sortable=this.sortable;
5898 cfg.summary=this.summary;
5901 cfg.width=this.width;
5904 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5907 if(this.store || this.cm){
5908 if(this.headerShow){
5909 cfg.cn.push(this.renderHeader());
5912 cfg.cn.push(this.renderBody());
5914 if(this.footerShow){
5915 cfg.cn.push(this.renderFooter());
5918 cfg.cls+= ' TableGrid';
5921 return { cn : [ cfg ] };
5924 initEvents : function()
5926 if(!this.store || !this.cm){
5930 //Roo.log('initEvents with ds!!!!');
5932 this.mainBody = this.el.select('tbody', true).first();
5937 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5938 e.on('click', _this.sort, _this);
5941 this.el.on("click", this.onClick, this);
5942 this.el.on("dblclick", this.onDblClick, this);
5944 // why is this done????? = it breaks dialogs??
5945 //this.parent().el.setStyle('position', 'relative');
5949 this.footer.parentId = this.id;
5950 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5953 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5955 this.store.on('load', this.onLoad, this);
5956 this.store.on('beforeload', this.onBeforeLoad, this);
5957 this.store.on('update', this.onUpdate, this);
5958 this.store.on('add', this.onAdd, this);
5960 this.el.on("contextmenu", this.onContextMenu, this);
5964 onContextMenu : function(e, t)
5966 this.processEvent("contextmenu", e);
5969 processEvent : function(name, e)
5971 if (name != 'touchstart' ) {
5972 this.fireEvent(name, e);
5975 var t = e.getTarget();
5977 var cell = Roo.get(t);
5983 if(cell.findParent('tfoot', false, true)){
5987 if(cell.findParent('thead', false, true)){
5989 if(e.getTarget().nodeName.toLowerCase() != 'th'){
5990 cell = Roo.get(t).findParent('th', false, true);
5993 var cellIndex = cell.dom.cellIndex;
5995 var ename = name == 'touchstart' ? 'click' : name;
5996 this.fireEvent("header" + ename, this, cellIndex, e);
6001 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6002 cell = Roo.get(t).findParent('td', false, true);
6005 var row = cell.findParent('tr', false, true);
6006 var cellIndex = cell.dom.cellIndex;
6007 var rowIndex = row.dom.rowIndex - 1;
6011 this.fireEvent("row" + name, this, rowIndex, e);
6015 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6021 onMouseover : function(e, el)
6023 var cell = Roo.get(el);
6029 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6030 cell = cell.findParent('td', false, true);
6033 var row = cell.findParent('tr', false, true);
6034 var cellIndex = cell.dom.cellIndex;
6035 var rowIndex = row.dom.rowIndex - 1; // start from 0
6037 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6041 onMouseout : function(e, el)
6043 var cell = Roo.get(el);
6049 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6050 cell = cell.findParent('td', false, true);
6053 var row = cell.findParent('tr', false, true);
6054 var cellIndex = cell.dom.cellIndex;
6055 var rowIndex = row.dom.rowIndex - 1; // start from 0
6057 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6061 onClick : function(e, el)
6063 var cell = Roo.get(el);
6065 if(!cell || (!this.cellSelection && !this.rowSelection)){
6069 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6070 cell = cell.findParent('td', false, true);
6073 if(!cell || typeof(cell) == 'undefined'){
6077 var row = cell.findParent('tr', false, true);
6079 if(!row || typeof(row) == 'undefined'){
6083 var cellIndex = cell.dom.cellIndex;
6084 var rowIndex = this.getRowIndex(row);
6086 // why??? - should these not be based on SelectionModel?
6087 if(this.cellSelection){
6088 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6091 if(this.rowSelection){
6092 this.fireEvent('rowclick', this, row, rowIndex, e);
6098 onDblClick : function(e,el)
6100 var cell = Roo.get(el);
6102 if(!cell || (!this.CellSelection && !this.RowSelection)){
6106 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6107 cell = cell.findParent('td', false, true);
6110 if(!cell || typeof(cell) == 'undefined'){
6114 var row = cell.findParent('tr', false, true);
6116 if(!row || typeof(row) == 'undefined'){
6120 var cellIndex = cell.dom.cellIndex;
6121 var rowIndex = this.getRowIndex(row);
6123 if(this.CellSelection){
6124 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6127 if(this.RowSelection){
6128 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6132 sort : function(e,el)
6134 var col = Roo.get(el);
6136 if(!col.hasClass('sortable')){
6140 var sort = col.attr('sort');
6143 if(col.hasClass('glyphicon-arrow-up')){
6147 this.store.sortInfo = {field : sort, direction : dir};
6150 Roo.log("calling footer first");
6151 this.footer.onClick('first');
6154 this.store.load({ params : { start : 0 } });
6158 renderHeader : function()
6167 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6169 var config = cm.config[i];
6174 html: cm.getColumnHeader(i)
6179 if(typeof(config.lgHeader) != 'undefined'){
6180 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6183 if(typeof(config.mdHeader) != 'undefined'){
6184 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6187 if(typeof(config.smHeader) != 'undefined'){
6188 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6191 if(typeof(config.xsHeader) != 'undefined'){
6192 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6199 if(typeof(config.tooltip) != 'undefined'){
6200 c.tooltip = config.tooltip;
6203 if(typeof(config.colspan) != 'undefined'){
6204 c.colspan = config.colspan;
6207 if(typeof(config.hidden) != 'undefined' && config.hidden){
6208 c.style += ' display:none;';
6211 if(typeof(config.dataIndex) != 'undefined'){
6212 c.sort = config.dataIndex;
6215 if(typeof(config.sortable) != 'undefined' && config.sortable){
6219 if(typeof(config.align) != 'undefined' && config.align.length){
6220 c.style += ' text-align:' + config.align + ';';
6223 if(typeof(config.width) != 'undefined'){
6224 c.style += ' width:' + config.width + 'px;';
6227 if(typeof(config.cls) != 'undefined'){
6228 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6231 ['xs','sm','md','lg'].map(function(size){
6233 if(typeof(config[size]) == 'undefined'){
6237 if (!config[size]) { // 0 = hidden
6238 c.cls += ' hidden-' + size;
6242 c.cls += ' col-' + size + '-' + config[size];
6252 renderBody : function()
6262 colspan : this.cm.getColumnCount()
6272 renderFooter : function()
6282 colspan : this.cm.getColumnCount()
6296 // Roo.log('ds onload');
6301 var ds = this.store;
6303 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6304 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
6306 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6307 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
6310 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6311 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
6315 var tbody = this.mainBody;
6317 if(ds.getCount() > 0){
6318 ds.data.each(function(d,rowIndex){
6319 var row = this.renderRow(cm, ds, rowIndex);
6321 tbody.createChild(row);
6325 if(row.cellObjects.length){
6326 Roo.each(row.cellObjects, function(r){
6327 _this.renderCellObject(r);
6334 Roo.each(this.el.select('tbody td', true).elements, function(e){
6335 e.on('mouseover', _this.onMouseover, _this);
6338 Roo.each(this.el.select('tbody td', true).elements, function(e){
6339 e.on('mouseout', _this.onMouseout, _this);
6341 this.fireEvent('rowsrendered', this);
6342 //if(this.loadMask){
6343 // this.maskEl.hide();
6348 onUpdate : function(ds,record)
6350 this.refreshRow(record);
6353 onRemove : function(ds, record, index, isUpdate){
6354 if(isUpdate !== true){
6355 this.fireEvent("beforerowremoved", this, index, record);
6357 var bt = this.mainBody.dom;
6359 var rows = this.el.select('tbody > tr', true).elements;
6361 if(typeof(rows[index]) != 'undefined'){
6362 bt.removeChild(rows[index].dom);
6365 // if(bt.rows[index]){
6366 // bt.removeChild(bt.rows[index]);
6369 if(isUpdate !== true){
6370 //this.stripeRows(index);
6371 //this.syncRowHeights(index, index);
6373 this.fireEvent("rowremoved", this, index, record);
6377 onAdd : function(ds, records, rowIndex)
6379 //Roo.log('on Add called');
6380 // - note this does not handle multiple adding very well..
6381 var bt = this.mainBody.dom;
6382 for (var i =0 ; i < records.length;i++) {
6383 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6384 //Roo.log(records[i]);
6385 //Roo.log(this.store.getAt(rowIndex+i));
6386 this.insertRow(this.store, rowIndex + i, false);
6393 refreshRow : function(record){
6394 var ds = this.store, index;
6395 if(typeof record == 'number'){
6397 record = ds.getAt(index);
6399 index = ds.indexOf(record);
6401 this.insertRow(ds, index, true);
6402 this.onRemove(ds, record, index+1, true);
6403 //this.syncRowHeights(index, index);
6405 this.fireEvent("rowupdated", this, index, record);
6408 insertRow : function(dm, rowIndex, isUpdate){
6411 this.fireEvent("beforerowsinserted", this, rowIndex);
6413 //var s = this.getScrollState();
6414 var row = this.renderRow(this.cm, this.store, rowIndex);
6415 // insert before rowIndex..
6416 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6420 if(row.cellObjects.length){
6421 Roo.each(row.cellObjects, function(r){
6422 _this.renderCellObject(r);
6427 this.fireEvent("rowsinserted", this, rowIndex);
6428 //this.syncRowHeights(firstRow, lastRow);
6429 //this.stripeRows(firstRow);
6436 getRowDom : function(rowIndex)
6438 var rows = this.el.select('tbody > tr', true).elements;
6440 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6443 // returns the object tree for a tr..
6446 renderRow : function(cm, ds, rowIndex)
6449 var d = ds.getAt(rowIndex);
6456 var cellObjects = [];
6458 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6459 var config = cm.config[i];
6461 var renderer = cm.getRenderer(i);
6465 if(typeof(renderer) !== 'undefined'){
6466 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6468 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6469 // and are rendered into the cells after the row is rendered - using the id for the element.
6471 if(typeof(value) === 'object'){
6481 rowIndex : rowIndex,
6486 this.fireEvent('rowclass', this, rowcfg);
6490 cls : rowcfg.rowClass,
6492 html: (typeof(value) === 'object') ? '' : value
6499 if(typeof(config.colspan) != 'undefined'){
6500 td.colspan = config.colspan;
6503 if(typeof(config.hidden) != 'undefined' && config.hidden){
6504 td.style += ' display:none;';
6507 if(typeof(config.align) != 'undefined' && config.align.length){
6508 td.style += ' text-align:' + config.align + ';';
6511 if(typeof(config.width) != 'undefined'){
6512 td.style += ' width:' + config.width + 'px;';
6515 if(typeof(config.cursor) != 'undefined'){
6516 td.style += ' cursor:' + config.cursor + ';';
6519 if(typeof(config.cls) != 'undefined'){
6520 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6523 ['xs','sm','md','lg'].map(function(size){
6525 if(typeof(config[size]) == 'undefined'){
6529 if (!config[size]) { // 0 = hidden
6530 td.cls += ' hidden-' + size;
6534 td.cls += ' col-' + size + '-' + config[size];
6542 row.cellObjects = cellObjects;
6550 onBeforeLoad : function()
6552 //Roo.log('ds onBeforeLoad');
6556 //if(this.loadMask){
6557 // this.maskEl.show();
6565 this.el.select('tbody', true).first().dom.innerHTML = '';
6568 * Show or hide a row.
6569 * @param {Number} rowIndex to show or hide
6570 * @param {Boolean} state hide
6572 setRowVisibility : function(rowIndex, state)
6574 var bt = this.mainBody.dom;
6576 var rows = this.el.select('tbody > tr', true).elements;
6578 if(typeof(rows[rowIndex]) == 'undefined'){
6581 rows[rowIndex].dom.style.display = state ? '' : 'none';
6585 getSelectionModel : function(){
6587 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6589 return this.selModel;
6592 * Render the Roo.bootstrap object from renderder
6594 renderCellObject : function(r)
6598 var t = r.cfg.render(r.container);
6601 Roo.each(r.cfg.cn, function(c){
6603 container: t.getChildContainer(),
6606 _this.renderCellObject(child);
6611 getRowIndex : function(row)
6615 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6638 * @class Roo.bootstrap.TableCell
6639 * @extends Roo.bootstrap.Component
6640 * Bootstrap TableCell class
6641 * @cfg {String} html cell contain text
6642 * @cfg {String} cls cell class
6643 * @cfg {String} tag cell tag (td|th) default td
6644 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6645 * @cfg {String} align Aligns the content in a cell
6646 * @cfg {String} axis Categorizes cells
6647 * @cfg {String} bgcolor Specifies the background color of a cell
6648 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6649 * @cfg {Number} colspan Specifies the number of columns a cell should span
6650 * @cfg {String} headers Specifies one or more header cells a cell is related to
6651 * @cfg {Number} height Sets the height of a cell
6652 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6653 * @cfg {Number} rowspan Sets the number of rows a cell should span
6654 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6655 * @cfg {String} valign Vertical aligns the content in a cell
6656 * @cfg {Number} width Specifies the width of a cell
6659 * Create a new TableCell
6660 * @param {Object} config The config object
6663 Roo.bootstrap.TableCell = function(config){
6664 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6667 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6687 getAutoCreate : function(){
6688 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6708 cfg.align=this.align
6714 cfg.bgcolor=this.bgcolor
6717 cfg.charoff=this.charoff
6720 cfg.colspan=this.colspan
6723 cfg.headers=this.headers
6726 cfg.height=this.height
6729 cfg.nowrap=this.nowrap
6732 cfg.rowspan=this.rowspan
6735 cfg.scope=this.scope
6738 cfg.valign=this.valign
6741 cfg.width=this.width
6760 * @class Roo.bootstrap.TableRow
6761 * @extends Roo.bootstrap.Component
6762 * Bootstrap TableRow class
6763 * @cfg {String} cls row class
6764 * @cfg {String} align Aligns the content in a table row
6765 * @cfg {String} bgcolor Specifies a background color for a table row
6766 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6767 * @cfg {String} valign Vertical aligns the content in a table row
6770 * Create a new TableRow
6771 * @param {Object} config The config object
6774 Roo.bootstrap.TableRow = function(config){
6775 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6778 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6786 getAutoCreate : function(){
6787 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6797 cfg.align = this.align;
6800 cfg.bgcolor = this.bgcolor;
6803 cfg.charoff = this.charoff;
6806 cfg.valign = this.valign;
6824 * @class Roo.bootstrap.TableBody
6825 * @extends Roo.bootstrap.Component
6826 * Bootstrap TableBody class
6827 * @cfg {String} cls element class
6828 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6829 * @cfg {String} align Aligns the content inside the element
6830 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6831 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6834 * Create a new TableBody
6835 * @param {Object} config The config object
6838 Roo.bootstrap.TableBody = function(config){
6839 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6842 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6850 getAutoCreate : function(){
6851 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6865 cfg.align = this.align;
6868 cfg.charoff = this.charoff;
6871 cfg.valign = this.valign;
6878 // initEvents : function()
6885 // this.store = Roo.factory(this.store, Roo.data);
6886 // this.store.on('load', this.onLoad, this);
6888 // this.store.load();
6892 // onLoad: function ()
6894 // this.fireEvent('load', this);
6904 * Ext JS Library 1.1.1
6905 * Copyright(c) 2006-2007, Ext JS, LLC.
6907 * Originally Released Under LGPL - original licence link has changed is not relivant.
6910 * <script type="text/javascript">
6913 // as we use this in bootstrap.
6914 Roo.namespace('Roo.form');
6916 * @class Roo.form.Action
6917 * Internal Class used to handle form actions
6919 * @param {Roo.form.BasicForm} el The form element or its id
6920 * @param {Object} config Configuration options
6925 // define the action interface
6926 Roo.form.Action = function(form, options){
6928 this.options = options || {};
6931 * Client Validation Failed
6934 Roo.form.Action.CLIENT_INVALID = 'client';
6936 * Server Validation Failed
6939 Roo.form.Action.SERVER_INVALID = 'server';
6941 * Connect to Server Failed
6944 Roo.form.Action.CONNECT_FAILURE = 'connect';
6946 * Reading Data from Server Failed
6949 Roo.form.Action.LOAD_FAILURE = 'load';
6951 Roo.form.Action.prototype = {
6953 failureType : undefined,
6954 response : undefined,
6958 run : function(options){
6963 success : function(response){
6968 handleResponse : function(response){
6972 // default connection failure
6973 failure : function(response){
6975 this.response = response;
6976 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6977 this.form.afterAction(this, false);
6980 processResponse : function(response){
6981 this.response = response;
6982 if(!response.responseText){
6985 this.result = this.handleResponse(response);
6989 // utility functions used internally
6990 getUrl : function(appendParams){
6991 var url = this.options.url || this.form.url || this.form.el.dom.action;
6993 var p = this.getParams();
6995 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7001 getMethod : function(){
7002 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7005 getParams : function(){
7006 var bp = this.form.baseParams;
7007 var p = this.options.params;
7009 if(typeof p == "object"){
7010 p = Roo.urlEncode(Roo.applyIf(p, bp));
7011 }else if(typeof p == 'string' && bp){
7012 p += '&' + Roo.urlEncode(bp);
7015 p = Roo.urlEncode(bp);
7020 createCallback : function(){
7022 success: this.success,
7023 failure: this.failure,
7025 timeout: (this.form.timeout*1000),
7026 upload: this.form.fileUpload ? this.success : undefined
7031 Roo.form.Action.Submit = function(form, options){
7032 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7035 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7038 haveProgress : false,
7039 uploadComplete : false,
7041 // uploadProgress indicator.
7042 uploadProgress : function()
7044 if (!this.form.progressUrl) {
7048 if (!this.haveProgress) {
7049 Roo.MessageBox.progress("Uploading", "Uploading");
7051 if (this.uploadComplete) {
7052 Roo.MessageBox.hide();
7056 this.haveProgress = true;
7058 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7060 var c = new Roo.data.Connection();
7062 url : this.form.progressUrl,
7067 success : function(req){
7068 //console.log(data);
7072 rdata = Roo.decode(req.responseText)
7074 Roo.log("Invalid data from server..");
7078 if (!rdata || !rdata.success) {
7080 Roo.MessageBox.alert(Roo.encode(rdata));
7083 var data = rdata.data;
7085 if (this.uploadComplete) {
7086 Roo.MessageBox.hide();
7091 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7092 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7095 this.uploadProgress.defer(2000,this);
7098 failure: function(data) {
7099 Roo.log('progress url failed ');
7110 // run get Values on the form, so it syncs any secondary forms.
7111 this.form.getValues();
7113 var o = this.options;
7114 var method = this.getMethod();
7115 var isPost = method == 'POST';
7116 if(o.clientValidation === false || this.form.isValid()){
7118 if (this.form.progressUrl) {
7119 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7120 (new Date() * 1) + '' + Math.random());
7125 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7126 form:this.form.el.dom,
7127 url:this.getUrl(!isPost),
7129 params:isPost ? this.getParams() : null,
7130 isUpload: this.form.fileUpload
7133 this.uploadProgress();
7135 }else if (o.clientValidation !== false){ // client validation failed
7136 this.failureType = Roo.form.Action.CLIENT_INVALID;
7137 this.form.afterAction(this, false);
7141 success : function(response)
7143 this.uploadComplete= true;
7144 if (this.haveProgress) {
7145 Roo.MessageBox.hide();
7149 var result = this.processResponse(response);
7150 if(result === true || result.success){
7151 this.form.afterAction(this, true);
7155 this.form.markInvalid(result.errors);
7156 this.failureType = Roo.form.Action.SERVER_INVALID;
7158 this.form.afterAction(this, false);
7160 failure : function(response)
7162 this.uploadComplete= true;
7163 if (this.haveProgress) {
7164 Roo.MessageBox.hide();
7167 this.response = response;
7168 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7169 this.form.afterAction(this, false);
7172 handleResponse : function(response){
7173 if(this.form.errorReader){
7174 var rs = this.form.errorReader.read(response);
7177 for(var i = 0, len = rs.records.length; i < len; i++) {
7178 var r = rs.records[i];
7182 if(errors.length < 1){
7186 success : rs.success,
7192 ret = Roo.decode(response.responseText);
7196 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7206 Roo.form.Action.Load = function(form, options){
7207 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7208 this.reader = this.form.reader;
7211 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7216 Roo.Ajax.request(Roo.apply(
7217 this.createCallback(), {
7218 method:this.getMethod(),
7219 url:this.getUrl(false),
7220 params:this.getParams()
7224 success : function(response){
7226 var result = this.processResponse(response);
7227 if(result === true || !result.success || !result.data){
7228 this.failureType = Roo.form.Action.LOAD_FAILURE;
7229 this.form.afterAction(this, false);
7232 this.form.clearInvalid();
7233 this.form.setValues(result.data);
7234 this.form.afterAction(this, true);
7237 handleResponse : function(response){
7238 if(this.form.reader){
7239 var rs = this.form.reader.read(response);
7240 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7242 success : rs.success,
7246 return Roo.decode(response.responseText);
7250 Roo.form.Action.ACTION_TYPES = {
7251 'load' : Roo.form.Action.Load,
7252 'submit' : Roo.form.Action.Submit
7261 * @class Roo.bootstrap.Form
7262 * @extends Roo.bootstrap.Component
7263 * Bootstrap Form class
7264 * @cfg {String} method GET | POST (default POST)
7265 * @cfg {String} labelAlign top | left (default top)
7266 * @cfg {String} align left | right - for navbars
7267 * @cfg {Boolean} loadMask load mask when submit (default true)
7272 * @param {Object} config The config object
7276 Roo.bootstrap.Form = function(config){
7277 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7280 * @event clientvalidation
7281 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7282 * @param {Form} this
7283 * @param {Boolean} valid true if the form has passed client-side validation
7285 clientvalidation: true,
7287 * @event beforeaction
7288 * Fires before any action is performed. Return false to cancel the action.
7289 * @param {Form} this
7290 * @param {Action} action The action to be performed
7294 * @event actionfailed
7295 * Fires when an action fails.
7296 * @param {Form} this
7297 * @param {Action} action The action that failed
7299 actionfailed : true,
7301 * @event actioncomplete
7302 * Fires when an action is completed.
7303 * @param {Form} this
7304 * @param {Action} action The action that completed
7306 actioncomplete : true
7311 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7314 * @cfg {String} method
7315 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7320 * The URL to use for form actions if one isn't supplied in the action options.
7323 * @cfg {Boolean} fileUpload
7324 * Set to true if this form is a file upload.
7328 * @cfg {Object} baseParams
7329 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7333 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7337 * @cfg {Sting} align (left|right) for navbar forms
7342 activeAction : null,
7345 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7346 * element by passing it or its id or mask the form itself by passing in true.
7349 waitMsgTarget : false,
7353 getAutoCreate : function(){
7357 method : this.method || 'POST',
7358 id : this.id || Roo.id(),
7361 if (this.parent().xtype.match(/^Nav/)) {
7362 cfg.cls = 'navbar-form navbar-' + this.align;
7366 if (this.labelAlign == 'left' ) {
7367 cfg.cls += ' form-horizontal';
7373 initEvents : function()
7375 this.el.on('submit', this.onSubmit, this);
7376 // this was added as random key presses on the form where triggering form submit.
7377 this.el.on('keypress', function(e) {
7378 if (e.getCharCode() != 13) {
7381 // we might need to allow it for textareas.. and some other items.
7382 // check e.getTarget().
7384 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7388 Roo.log("keypress blocked");
7396 onSubmit : function(e){
7401 * Returns true if client-side validation on the form is successful.
7404 isValid : function(){
7405 var items = this.getItems();
7407 items.each(function(f){
7416 * Returns true if any fields in this form have changed since their original load.
7419 isDirty : function(){
7421 var items = this.getItems();
7422 items.each(function(f){
7432 * Performs a predefined action (submit or load) or custom actions you define on this form.
7433 * @param {String} actionName The name of the action type
7434 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7435 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7436 * accept other config options):
7438 Property Type Description
7439 ---------------- --------------- ----------------------------------------------------------------------------------
7440 url String The url for the action (defaults to the form's url)
7441 method String The form method to use (defaults to the form's method, or POST if not defined)
7442 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7443 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7444 validate the form on the client (defaults to false)
7446 * @return {BasicForm} this
7448 doAction : function(action, options){
7449 if(typeof action == 'string'){
7450 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7452 if(this.fireEvent('beforeaction', this, action) !== false){
7453 this.beforeAction(action);
7454 action.run.defer(100, action);
7460 beforeAction : function(action){
7461 var o = action.options;
7464 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7466 // not really supported yet.. ??
7468 //if(this.waitMsgTarget === true){
7469 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7470 //}else if(this.waitMsgTarget){
7471 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7472 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7474 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7480 afterAction : function(action, success){
7481 this.activeAction = null;
7482 var o = action.options;
7484 //if(this.waitMsgTarget === true){
7486 //}else if(this.waitMsgTarget){
7487 // this.waitMsgTarget.unmask();
7489 // Roo.MessageBox.updateProgress(1);
7490 // Roo.MessageBox.hide();
7497 Roo.callback(o.success, o.scope, [this, action]);
7498 this.fireEvent('actioncomplete', this, action);
7502 // failure condition..
7503 // we have a scenario where updates need confirming.
7504 // eg. if a locking scenario exists..
7505 // we look for { errors : { needs_confirm : true }} in the response.
7507 (typeof(action.result) != 'undefined') &&
7508 (typeof(action.result.errors) != 'undefined') &&
7509 (typeof(action.result.errors.needs_confirm) != 'undefined')
7512 Roo.log("not supported yet");
7515 Roo.MessageBox.confirm(
7516 "Change requires confirmation",
7517 action.result.errorMsg,
7522 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7532 Roo.callback(o.failure, o.scope, [this, action]);
7533 // show an error message if no failed handler is set..
7534 if (!this.hasListener('actionfailed')) {
7535 Roo.log("need to add dialog support");
7537 Roo.MessageBox.alert("Error",
7538 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7539 action.result.errorMsg :
7540 "Saving Failed, please check your entries or try again"
7545 this.fireEvent('actionfailed', this, action);
7550 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7551 * @param {String} id The value to search for
7554 findField : function(id){
7555 var items = this.getItems();
7556 var field = items.get(id);
7558 items.each(function(f){
7559 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7566 return field || null;
7569 * Mark fields in this form invalid in bulk.
7570 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7571 * @return {BasicForm} this
7573 markInvalid : function(errors){
7574 if(errors instanceof Array){
7575 for(var i = 0, len = errors.length; i < len; i++){
7576 var fieldError = errors[i];
7577 var f = this.findField(fieldError.id);
7579 f.markInvalid(fieldError.msg);
7585 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7586 field.markInvalid(errors[id]);
7590 //Roo.each(this.childForms || [], function (f) {
7591 // f.markInvalid(errors);
7598 * Set values for fields in this form in bulk.
7599 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7600 * @return {BasicForm} this
7602 setValues : function(values){
7603 if(values instanceof Array){ // array of objects
7604 for(var i = 0, len = values.length; i < len; i++){
7606 var f = this.findField(v.id);
7608 f.setValue(v.value);
7609 if(this.trackResetOnLoad){
7610 f.originalValue = f.getValue();
7614 }else{ // object hash
7617 if(typeof values[id] != 'function' && (field = this.findField(id))){
7619 if (field.setFromData &&
7621 field.displayField &&
7622 // combos' with local stores can
7623 // be queried via setValue()
7624 // to set their value..
7625 (field.store && !field.store.isLocal)
7629 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7630 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7631 field.setFromData(sd);
7634 field.setValue(values[id]);
7638 if(this.trackResetOnLoad){
7639 field.originalValue = field.getValue();
7645 //Roo.each(this.childForms || [], function (f) {
7646 // f.setValues(values);
7653 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7654 * they are returned as an array.
7655 * @param {Boolean} asString
7658 getValues : function(asString){
7659 //if (this.childForms) {
7660 // copy values from the child forms
7661 // Roo.each(this.childForms, function (f) {
7662 // this.setValues(f.getValues());
7668 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7669 if(asString === true){
7672 return Roo.urlDecode(fs);
7676 * Returns the fields in this form as an object with key/value pairs.
7677 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7680 getFieldValues : function(with_hidden)
7682 var items = this.getItems();
7684 items.each(function(f){
7688 var v = f.getValue();
7689 if (f.inputType =='radio') {
7690 if (typeof(ret[f.getName()]) == 'undefined') {
7691 ret[f.getName()] = ''; // empty..
7694 if (!f.el.dom.checked) {
7702 // not sure if this supported any more..
7703 if ((typeof(v) == 'object') && f.getRawValue) {
7704 v = f.getRawValue() ; // dates..
7706 // combo boxes where name != hiddenName...
7707 if (f.name != f.getName()) {
7708 ret[f.name] = f.getRawValue();
7710 ret[f.getName()] = v;
7717 * Clears all invalid messages in this form.
7718 * @return {BasicForm} this
7720 clearInvalid : function(){
7721 var items = this.getItems();
7723 items.each(function(f){
7734 * @return {BasicForm} this
7737 var items = this.getItems();
7738 items.each(function(f){
7742 Roo.each(this.childForms || [], function (f) {
7749 getItems : function()
7751 var r=new Roo.util.MixedCollection(false, function(o){
7752 return o.id || (o.id = Roo.id());
7754 var iter = function(el) {
7761 Roo.each(el.items,function(e) {
7781 * Ext JS Library 1.1.1
7782 * Copyright(c) 2006-2007, Ext JS, LLC.
7784 * Originally Released Under LGPL - original licence link has changed is not relivant.
7787 * <script type="text/javascript">
7790 * @class Roo.form.VTypes
7791 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7794 Roo.form.VTypes = function(){
7795 // closure these in so they are only created once.
7796 var alpha = /^[a-zA-Z_]+$/;
7797 var alphanum = /^[a-zA-Z0-9_]+$/;
7798 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7799 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7801 // All these messages and functions are configurable
7804 * The function used to validate email addresses
7805 * @param {String} value The email address
7807 'email' : function(v){
7808 return email.test(v);
7811 * The error text to display when the email validation function returns false
7814 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7816 * The keystroke filter mask to be applied on email input
7819 'emailMask' : /[a-z0-9_\.\-@]/i,
7822 * The function used to validate URLs
7823 * @param {String} value The URL
7825 'url' : function(v){
7829 * The error text to display when the url validation function returns false
7832 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7835 * The function used to validate alpha values
7836 * @param {String} value The value
7838 'alpha' : function(v){
7839 return alpha.test(v);
7842 * The error text to display when the alpha validation function returns false
7845 'alphaText' : 'This field should only contain letters and _',
7847 * The keystroke filter mask to be applied on alpha input
7850 'alphaMask' : /[a-z_]/i,
7853 * The function used to validate alphanumeric values
7854 * @param {String} value The value
7856 'alphanum' : function(v){
7857 return alphanum.test(v);
7860 * The error text to display when the alphanumeric validation function returns false
7863 'alphanumText' : 'This field should only contain letters, numbers and _',
7865 * The keystroke filter mask to be applied on alphanumeric input
7868 'alphanumMask' : /[a-z0-9_]/i
7878 * @class Roo.bootstrap.Input
7879 * @extends Roo.bootstrap.Component
7880 * Bootstrap Input class
7881 * @cfg {Boolean} disabled is it disabled
7882 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7883 * @cfg {String} name name of the input
7884 * @cfg {string} fieldLabel - the label associated
7885 * @cfg {string} placeholder - placeholder to put in text.
7886 * @cfg {string} before - input group add on before
7887 * @cfg {string} after - input group add on after
7888 * @cfg {string} size - (lg|sm) or leave empty..
7889 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7890 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7891 * @cfg {Number} md colspan out of 12 for computer-sized screens
7892 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7893 * @cfg {string} value default value of the input
7894 * @cfg {Number} labelWidth set the width of label (0-12)
7895 * @cfg {String} labelAlign (top|left)
7896 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7897 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7899 * @cfg {String} align (left|center|right) Default left
7900 * @cfg {Boolean} forceFeedback (true|false) Default false
7906 * Create a new Input
7907 * @param {Object} config The config object
7910 Roo.bootstrap.Input = function(config){
7911 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7916 * Fires when this field receives input focus.
7917 * @param {Roo.form.Field} this
7922 * Fires when this field loses input focus.
7923 * @param {Roo.form.Field} this
7928 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7929 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7930 * @param {Roo.form.Field} this
7931 * @param {Roo.EventObject} e The event object
7936 * Fires just before the field blurs if the field value has changed.
7937 * @param {Roo.form.Field} this
7938 * @param {Mixed} newValue The new value
7939 * @param {Mixed} oldValue The original value
7944 * Fires after the field has been marked as invalid.
7945 * @param {Roo.form.Field} this
7946 * @param {String} msg The validation message
7951 * Fires after the field has been validated with no errors.
7952 * @param {Roo.form.Field} this
7957 * Fires after the key up
7958 * @param {Roo.form.Field} this
7959 * @param {Roo.EventObject} e The event Object
7965 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7967 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7968 automatic validation (defaults to "keyup").
7970 validationEvent : "keyup",
7972 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7974 validateOnBlur : true,
7976 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7978 validationDelay : 250,
7980 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7982 focusClass : "x-form-focus", // not needed???
7986 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7988 invalidClass : "has-warning",
7991 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7993 validClass : "has-success",
7996 * @cfg {Boolean} hasFeedback (true|false) default true
8001 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8003 invalidFeedbackClass : "glyphicon-warning-sign",
8006 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8008 validFeedbackClass : "glyphicon-ok",
8011 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8013 selectOnFocus : false,
8016 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8020 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8025 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8027 disableKeyFilter : false,
8030 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8034 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8038 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8040 blankText : "This field is required",
8043 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8047 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8049 maxLength : Number.MAX_VALUE,
8051 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8053 minLengthText : "The minimum length for this field is {0}",
8055 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8057 maxLengthText : "The maximum length for this field is {0}",
8061 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8062 * If available, this function will be called only after the basic validators all return true, and will be passed the
8063 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8067 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8068 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8069 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8073 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8077 autocomplete: false,
8096 formatedValue : false,
8097 forceFeedback : false,
8099 parentLabelAlign : function()
8102 while (parent.parent()) {
8103 parent = parent.parent();
8104 if (typeof(parent.labelAlign) !='undefined') {
8105 return parent.labelAlign;
8112 getAutoCreate : function(){
8114 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8120 if(this.inputType != 'hidden'){
8121 cfg.cls = 'form-group' //input-group
8127 type : this.inputType,
8129 cls : 'form-control',
8130 placeholder : this.placeholder || '',
8131 autocomplete : this.autocomplete || 'new-password'
8136 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8139 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8140 input.maxLength = this.maxLength;
8143 if (this.disabled) {
8144 input.disabled=true;
8147 if (this.readOnly) {
8148 input.readonly=true;
8152 input.name = this.name;
8155 input.cls += ' input-' + this.size;
8158 ['xs','sm','md','lg'].map(function(size){
8159 if (settings[size]) {
8160 cfg.cls += ' col-' + size + '-' + settings[size];
8164 var inputblock = input;
8168 cls: 'glyphicon form-control-feedback'
8171 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8174 cls : 'has-feedback',
8182 if (this.before || this.after) {
8185 cls : 'input-group',
8189 if (this.before && typeof(this.before) == 'string') {
8191 inputblock.cn.push({
8193 cls : 'roo-input-before input-group-addon',
8197 if (this.before && typeof(this.before) == 'object') {
8198 this.before = Roo.factory(this.before);
8200 inputblock.cn.push({
8202 cls : 'roo-input-before input-group-' +
8203 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8207 inputblock.cn.push(input);
8209 if (this.after && typeof(this.after) == 'string') {
8210 inputblock.cn.push({
8212 cls : 'roo-input-after input-group-addon',
8216 if (this.after && typeof(this.after) == 'object') {
8217 this.after = Roo.factory(this.after);
8219 inputblock.cn.push({
8221 cls : 'roo-input-after input-group-' +
8222 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8226 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8227 inputblock.cls += ' has-feedback';
8228 inputblock.cn.push(feedback);
8232 if (align ==='left' && this.fieldLabel.length) {
8239 cls : 'control-label col-sm-' + this.labelWidth,
8240 html : this.fieldLabel
8244 cls : "col-sm-" + (12 - this.labelWidth),
8251 } else if ( this.fieldLabel.length) {
8257 //cls : 'input-group-addon',
8258 html : this.fieldLabel
8277 if (this.parentType === 'Navbar' && this.parent().bar) {
8278 cfg.cls += ' navbar-form';
8285 * return the real input element.
8287 inputEl: function ()
8289 return this.el.select('input.form-control',true).first();
8292 tooltipEl : function()
8294 return this.inputEl();
8297 setDisabled : function(v)
8299 var i = this.inputEl().dom;
8301 i.removeAttribute('disabled');
8305 i.setAttribute('disabled','true');
8307 initEvents : function()
8310 this.inputEl().on("keydown" , this.fireKey, this);
8311 this.inputEl().on("focus", this.onFocus, this);
8312 this.inputEl().on("blur", this.onBlur, this);
8314 this.inputEl().relayEvent('keyup', this);
8316 // reference to original value for reset
8317 this.originalValue = this.getValue();
8318 //Roo.form.TextField.superclass.initEvents.call(this);
8319 if(this.validationEvent == 'keyup'){
8320 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8321 this.inputEl().on('keyup', this.filterValidation, this);
8323 else if(this.validationEvent !== false){
8324 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8327 if(this.selectOnFocus){
8328 this.on("focus", this.preFocus, this);
8331 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8332 this.inputEl().on("keypress", this.filterKeys, this);
8335 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8336 this.el.on("click", this.autoSize, this);
8339 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8340 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8343 if (typeof(this.before) == 'object') {
8344 this.before.render(this.el.select('.roo-input-before',true).first());
8346 if (typeof(this.after) == 'object') {
8347 this.after.render(this.el.select('.roo-input-after',true).first());
8352 filterValidation : function(e){
8353 if(!e.isNavKeyPress()){
8354 this.validationTask.delay(this.validationDelay);
8358 * Validates the field value
8359 * @return {Boolean} True if the value is valid, else false
8361 validate : function(){
8362 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8363 if(this.disabled || this.validateValue(this.getRawValue())){
8374 * Validates a value according to the field's validation rules and marks the field as invalid
8375 * if the validation fails
8376 * @param {Mixed} value The value to validate
8377 * @return {Boolean} True if the value is valid, else false
8379 validateValue : function(value){
8380 if(value.length < 1) { // if it's blank
8381 if(this.allowBlank){
8387 if(value.length < this.minLength){
8390 if(value.length > this.maxLength){
8394 var vt = Roo.form.VTypes;
8395 if(!vt[this.vtype](value, this)){
8399 if(typeof this.validator == "function"){
8400 var msg = this.validator(value);
8406 if(this.regex && !this.regex.test(value)){
8416 fireKey : function(e){
8417 //Roo.log('field ' + e.getKey());
8418 if(e.isNavKeyPress()){
8419 this.fireEvent("specialkey", this, e);
8422 focus : function (selectText){
8424 this.inputEl().focus();
8425 if(selectText === true){
8426 this.inputEl().dom.select();
8432 onFocus : function(){
8433 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8434 // this.el.addClass(this.focusClass);
8437 this.hasFocus = true;
8438 this.startValue = this.getValue();
8439 this.fireEvent("focus", this);
8443 beforeBlur : Roo.emptyFn,
8447 onBlur : function(){
8449 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8450 //this.el.removeClass(this.focusClass);
8452 this.hasFocus = false;
8453 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8456 var v = this.getValue();
8457 if(String(v) !== String(this.startValue)){
8458 this.fireEvent('change', this, v, this.startValue);
8460 this.fireEvent("blur", this);
8464 * Resets the current field value to the originally loaded value and clears any validation messages
8467 this.setValue(this.originalValue);
8471 * Returns the name of the field
8472 * @return {Mixed} name The name field
8474 getName: function(){
8478 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8479 * @return {Mixed} value The field value
8481 getValue : function(){
8483 var v = this.inputEl().getValue();
8488 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8489 * @return {Mixed} value The field value
8491 getRawValue : function(){
8492 var v = this.inputEl().getValue();
8498 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8499 * @param {Mixed} value The value to set
8501 setRawValue : function(v){
8502 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8505 selectText : function(start, end){
8506 var v = this.getRawValue();
8508 start = start === undefined ? 0 : start;
8509 end = end === undefined ? v.length : end;
8510 var d = this.inputEl().dom;
8511 if(d.setSelectionRange){
8512 d.setSelectionRange(start, end);
8513 }else if(d.createTextRange){
8514 var range = d.createTextRange();
8515 range.moveStart("character", start);
8516 range.moveEnd("character", v.length-end);
8523 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8524 * @param {Mixed} value The value to set
8526 setValue : function(v){
8529 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8535 processValue : function(value){
8536 if(this.stripCharsRe){
8537 var newValue = value.replace(this.stripCharsRe, '');
8538 if(newValue !== value){
8539 this.setRawValue(newValue);
8546 preFocus : function(){
8548 if(this.selectOnFocus){
8549 this.inputEl().dom.select();
8552 filterKeys : function(e){
8554 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8557 var c = e.getCharCode(), cc = String.fromCharCode(c);
8558 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8561 if(!this.maskRe.test(cc)){
8566 * Clear any invalid styles/messages for this field
8568 clearInvalid : function(){
8570 if(!this.el || this.preventMark){ // not rendered
8574 var label = this.el.select('label', true).first();
8575 var icon = this.el.select('i.fa-star', true).first();
8581 this.el.removeClass(this.invalidClass);
8583 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8585 var feedback = this.el.select('.form-control-feedback', true).first();
8588 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8593 this.fireEvent('valid', this);
8597 * Mark this field as valid
8599 markValid : function()
8601 if(!this.el || this.preventMark){ // not rendered
8605 this.el.removeClass([this.invalidClass, this.validClass]);
8607 var feedback = this.el.select('.form-control-feedback', true).first();
8610 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8613 if(this.disabled || this.allowBlank){
8617 var formGroup = this.el.findParent('.form-group', false, true);
8621 var label = formGroup.select('label', true).first();
8622 var icon = formGroup.select('i.fa-star', true).first();
8629 this.el.addClass(this.validClass);
8631 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8633 var feedback = this.el.select('.form-control-feedback', true).first();
8636 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8637 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8642 this.fireEvent('valid', this);
8646 * Mark this field as invalid
8647 * @param {String} msg The validation message
8649 markInvalid : function(msg)
8651 if(!this.el || this.preventMark){ // not rendered
8655 this.el.removeClass([this.invalidClass, this.validClass]);
8657 var feedback = this.el.select('.form-control-feedback', true).first();
8660 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8663 if(this.disabled || this.allowBlank){
8667 var formGroup = this.el.findParent('.form-group', false, true);
8670 var label = formGroup.select('label', true).first();
8671 var icon = formGroup.select('i.fa-star', true).first();
8673 if(!this.getValue().length && label && !icon){
8674 this.el.findParent('.form-group', false, true).createChild({
8676 cls : 'text-danger fa fa-lg fa-star',
8677 tooltip : 'This field is required',
8678 style : 'margin-right:5px;'
8684 this.el.addClass(this.invalidClass);
8686 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8688 var feedback = this.el.select('.form-control-feedback', true).first();
8691 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8693 if(this.getValue().length || this.forceFeedback){
8694 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8701 this.fireEvent('invalid', this, msg);
8704 SafariOnKeyDown : function(event)
8706 // this is a workaround for a password hang bug on chrome/ webkit.
8708 var isSelectAll = false;
8710 if(this.inputEl().dom.selectionEnd > 0){
8711 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8713 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8714 event.preventDefault();
8719 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8721 event.preventDefault();
8722 // this is very hacky as keydown always get's upper case.
8724 var cc = String.fromCharCode(event.getCharCode());
8725 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8729 adjustWidth : function(tag, w){
8730 tag = tag.toLowerCase();
8731 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8732 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8736 if(tag == 'textarea'){
8739 }else if(Roo.isOpera){
8743 if(tag == 'textarea'){
8762 * @class Roo.bootstrap.TextArea
8763 * @extends Roo.bootstrap.Input
8764 * Bootstrap TextArea class
8765 * @cfg {Number} cols Specifies the visible width of a text area
8766 * @cfg {Number} rows Specifies the visible number of lines in a text area
8767 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8768 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8769 * @cfg {string} html text
8772 * Create a new TextArea
8773 * @param {Object} config The config object
8776 Roo.bootstrap.TextArea = function(config){
8777 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8781 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8791 getAutoCreate : function(){
8793 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8804 value : this.value || '',
8805 html: this.html || '',
8806 cls : 'form-control',
8807 placeholder : this.placeholder || ''
8811 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8812 input.maxLength = this.maxLength;
8816 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8820 input.cols = this.cols;
8823 if (this.readOnly) {
8824 input.readonly = true;
8828 input.name = this.name;
8832 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8836 ['xs','sm','md','lg'].map(function(size){
8837 if (settings[size]) {
8838 cfg.cls += ' col-' + size + '-' + settings[size];
8842 var inputblock = input;
8844 if(this.hasFeedback && !this.allowBlank){
8848 cls: 'glyphicon form-control-feedback'
8852 cls : 'has-feedback',
8861 if (this.before || this.after) {
8864 cls : 'input-group',
8868 inputblock.cn.push({
8870 cls : 'input-group-addon',
8875 inputblock.cn.push(input);
8877 if(this.hasFeedback && !this.allowBlank){
8878 inputblock.cls += ' has-feedback';
8879 inputblock.cn.push(feedback);
8883 inputblock.cn.push({
8885 cls : 'input-group-addon',
8892 if (align ==='left' && this.fieldLabel.length) {
8893 // Roo.log("left and has label");
8899 cls : 'control-label col-sm-' + this.labelWidth,
8900 html : this.fieldLabel
8904 cls : "col-sm-" + (12 - this.labelWidth),
8911 } else if ( this.fieldLabel.length) {
8912 // Roo.log(" label");
8917 //cls : 'input-group-addon',
8918 html : this.fieldLabel
8928 // Roo.log(" no label && no align");
8938 if (this.disabled) {
8939 input.disabled=true;
8946 * return the real textarea element.
8948 inputEl: function ()
8950 return this.el.select('textarea.form-control',true).first();
8954 * Clear any invalid styles/messages for this field
8956 clearInvalid : function()
8959 if(!this.el || this.preventMark){ // not rendered
8963 var label = this.el.select('label', true).first();
8964 var icon = this.el.select('i.fa-star', true).first();
8970 this.el.removeClass(this.invalidClass);
8972 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8974 var feedback = this.el.select('.form-control-feedback', true).first();
8977 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8982 this.fireEvent('valid', this);
8986 * Mark this field as valid
8988 markValid : function()
8990 if(!this.el || this.preventMark){ // not rendered
8994 this.el.removeClass([this.invalidClass, this.validClass]);
8996 var feedback = this.el.select('.form-control-feedback', true).first();
8999 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9002 if(this.disabled || this.allowBlank){
9006 var label = this.el.select('label', true).first();
9007 var icon = this.el.select('i.fa-star', true).first();
9013 this.el.addClass(this.validClass);
9015 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9017 var feedback = this.el.select('.form-control-feedback', true).first();
9020 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9021 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9026 this.fireEvent('valid', this);
9030 * Mark this field as invalid
9031 * @param {String} msg The validation message
9033 markInvalid : function(msg)
9035 if(!this.el || this.preventMark){ // not rendered
9039 this.el.removeClass([this.invalidClass, this.validClass]);
9041 var feedback = this.el.select('.form-control-feedback', true).first();
9044 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9047 if(this.disabled || this.allowBlank){
9051 var label = this.el.select('label', true).first();
9052 var icon = this.el.select('i.fa-star', true).first();
9054 if(!this.getValue().length && label && !icon){
9055 this.el.createChild({
9057 cls : 'text-danger fa fa-lg fa-star',
9058 tooltip : 'This field is required',
9059 style : 'margin-right:5px;'
9063 this.el.addClass(this.invalidClass);
9065 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9067 var feedback = this.el.select('.form-control-feedback', true).first();
9070 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9072 if(this.getValue().length || this.forceFeedback){
9073 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9080 this.fireEvent('invalid', this, msg);
9088 * trigger field - base class for combo..
9093 * @class Roo.bootstrap.TriggerField
9094 * @extends Roo.bootstrap.Input
9095 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9096 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9097 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9098 * for which you can provide a custom implementation. For example:
9100 var trigger = new Roo.bootstrap.TriggerField();
9101 trigger.onTriggerClick = myTriggerFn;
9102 trigger.applyTo('my-field');
9105 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9106 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9107 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9108 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9109 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9112 * Create a new TriggerField.
9113 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9114 * to the base TextField)
9116 Roo.bootstrap.TriggerField = function(config){
9117 this.mimicing = false;
9118 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9121 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9123 * @cfg {String} triggerClass A CSS class to apply to the trigger
9126 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9131 * @cfg {Boolean} removable (true|false) special filter default false
9135 /** @cfg {Boolean} grow @hide */
9136 /** @cfg {Number} growMin @hide */
9137 /** @cfg {Number} growMax @hide */
9143 autoSize: Roo.emptyFn,
9150 actionMode : 'wrap',
9155 getAutoCreate : function(){
9157 var align = this.labelAlign || this.parentLabelAlign();
9162 cls: 'form-group' //input-group
9169 type : this.inputType,
9170 cls : 'form-control',
9171 autocomplete: 'new-password',
9172 placeholder : this.placeholder || ''
9176 input.name = this.name;
9179 input.cls += ' input-' + this.size;
9182 if (this.disabled) {
9183 input.disabled=true;
9186 var inputblock = input;
9188 if(this.hasFeedback && !this.allowBlank){
9192 cls: 'glyphicon form-control-feedback'
9195 if(this.removable && !this.editable && !this.tickable){
9197 cls : 'has-feedback',
9203 cls : 'roo-combo-removable-btn close'
9210 cls : 'has-feedback',
9219 if(this.removable && !this.editable && !this.tickable){
9221 cls : 'roo-removable',
9227 cls : 'roo-combo-removable-btn close'
9234 if (this.before || this.after) {
9237 cls : 'input-group',
9241 inputblock.cn.push({
9243 cls : 'input-group-addon',
9248 inputblock.cn.push(input);
9250 if(this.hasFeedback && !this.allowBlank){
9251 inputblock.cls += ' has-feedback';
9252 inputblock.cn.push(feedback);
9256 inputblock.cn.push({
9258 cls : 'input-group-addon',
9271 cls: 'form-hidden-field'
9285 cls: 'form-hidden-field'
9289 cls: 'roo-select2-choices',
9293 cls: 'roo-select2-search-field',
9306 cls: 'roo-select2-container input-group',
9311 // cls: 'typeahead typeahead-long dropdown-menu',
9312 // style: 'display:none'
9317 if(!this.multiple && this.showToggleBtn){
9323 if (this.caret != false) {
9326 cls: 'fa fa-' + this.caret
9333 cls : 'input-group-addon btn dropdown-toggle',
9338 cls: 'combobox-clear',
9352 combobox.cls += ' roo-select2-container-multi';
9355 if (align ==='left' && this.fieldLabel.length) {
9357 // Roo.log("left and has label");
9363 cls : 'control-label col-sm-' + this.labelWidth,
9364 html : this.fieldLabel
9368 cls : "col-sm-" + (12 - this.labelWidth),
9375 } else if ( this.fieldLabel.length) {
9376 // Roo.log(" label");
9381 //cls : 'input-group-addon',
9382 html : this.fieldLabel
9392 // Roo.log(" no label && no align");
9399 ['xs','sm','md','lg'].map(function(size){
9400 if (settings[size]) {
9401 cfg.cls += ' col-' + size + '-' + settings[size];
9412 onResize : function(w, h){
9413 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9414 // if(typeof w == 'number'){
9415 // var x = w - this.trigger.getWidth();
9416 // this.inputEl().setWidth(this.adjustWidth('input', x));
9417 // this.trigger.setStyle('left', x+'px');
9422 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9425 getResizeEl : function(){
9426 return this.inputEl();
9430 getPositionEl : function(){
9431 return this.inputEl();
9435 alignErrorIcon : function(){
9436 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9440 initEvents : function(){
9444 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9445 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9446 if(!this.multiple && this.showToggleBtn){
9447 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9448 if(this.hideTrigger){
9449 this.trigger.setDisplayed(false);
9451 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9455 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9458 if(this.removable && !this.editable && !this.tickable){
9459 var close = this.closeTriggerEl();
9462 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9463 close.on('click', this.removeBtnClick, this, close);
9467 //this.trigger.addClassOnOver('x-form-trigger-over');
9468 //this.trigger.addClassOnClick('x-form-trigger-click');
9471 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9475 closeTriggerEl : function()
9477 var close = this.el.select('.roo-combo-removable-btn', true).first();
9478 return close ? close : false;
9481 removeBtnClick : function(e, h, el)
9485 if(this.fireEvent("remove", this) !== false){
9487 this.fireEvent("afterremove", this)
9491 createList : function()
9493 this.list = Roo.get(document.body).createChild({
9495 cls: 'typeahead typeahead-long dropdown-menu',
9496 style: 'display:none'
9499 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9504 initTrigger : function(){
9509 onDestroy : function(){
9511 this.trigger.removeAllListeners();
9512 // this.trigger.remove();
9515 // this.wrap.remove();
9517 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9521 onFocus : function(){
9522 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9525 this.wrap.addClass('x-trigger-wrap-focus');
9526 this.mimicing = true;
9527 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9528 if(this.monitorTab){
9529 this.el.on("keydown", this.checkTab, this);
9536 checkTab : function(e){
9537 if(e.getKey() == e.TAB){
9543 onBlur : function(){
9548 mimicBlur : function(e, t){
9550 if(!this.wrap.contains(t) && this.validateBlur()){
9557 triggerBlur : function(){
9558 this.mimicing = false;
9559 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9560 if(this.monitorTab){
9561 this.el.un("keydown", this.checkTab, this);
9563 //this.wrap.removeClass('x-trigger-wrap-focus');
9564 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9568 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9569 validateBlur : function(e, t){
9574 onDisable : function(){
9575 this.inputEl().dom.disabled = true;
9576 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9578 // this.wrap.addClass('x-item-disabled');
9583 onEnable : function(){
9584 this.inputEl().dom.disabled = false;
9585 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9587 // this.el.removeClass('x-item-disabled');
9592 onShow : function(){
9593 var ae = this.getActionEl();
9596 ae.dom.style.display = '';
9597 ae.dom.style.visibility = 'visible';
9603 onHide : function(){
9604 var ae = this.getActionEl();
9605 ae.dom.style.display = 'none';
9609 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9610 * by an implementing function.
9612 * @param {EventObject} e
9614 onTriggerClick : Roo.emptyFn
9618 * Ext JS Library 1.1.1
9619 * Copyright(c) 2006-2007, Ext JS, LLC.
9621 * Originally Released Under LGPL - original licence link has changed is not relivant.
9624 * <script type="text/javascript">
9629 * @class Roo.data.SortTypes
9631 * Defines the default sorting (casting?) comparison functions used when sorting data.
9633 Roo.data.SortTypes = {
9635 * Default sort that does nothing
9636 * @param {Mixed} s The value being converted
9637 * @return {Mixed} The comparison value
9644 * The regular expression used to strip tags
9648 stripTagsRE : /<\/?[^>]+>/gi,
9651 * Strips all HTML tags to sort on text only
9652 * @param {Mixed} s The value being converted
9653 * @return {String} The comparison value
9655 asText : function(s){
9656 return String(s).replace(this.stripTagsRE, "");
9660 * Strips all HTML tags to sort on text only - Case insensitive
9661 * @param {Mixed} s The value being converted
9662 * @return {String} The comparison value
9664 asUCText : function(s){
9665 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9669 * Case insensitive string
9670 * @param {Mixed} s The value being converted
9671 * @return {String} The comparison value
9673 asUCString : function(s) {
9674 return String(s).toUpperCase();
9679 * @param {Mixed} s The value being converted
9680 * @return {Number} The comparison value
9682 asDate : function(s) {
9686 if(s instanceof Date){
9689 return Date.parse(String(s));
9694 * @param {Mixed} s The value being converted
9695 * @return {Float} The comparison value
9697 asFloat : function(s) {
9698 var val = parseFloat(String(s).replace(/,/g, ""));
9707 * @param {Mixed} s The value being converted
9708 * @return {Number} The comparison value
9710 asInt : function(s) {
9711 var val = parseInt(String(s).replace(/,/g, ""));
9719 * Ext JS Library 1.1.1
9720 * Copyright(c) 2006-2007, Ext JS, LLC.
9722 * Originally Released Under LGPL - original licence link has changed is not relivant.
9725 * <script type="text/javascript">
9729 * @class Roo.data.Record
9730 * Instances of this class encapsulate both record <em>definition</em> information, and record
9731 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9732 * to access Records cached in an {@link Roo.data.Store} object.<br>
9734 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9735 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9738 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9740 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9741 * {@link #create}. The parameters are the same.
9742 * @param {Array} data An associative Array of data values keyed by the field name.
9743 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9744 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9745 * not specified an integer id is generated.
9747 Roo.data.Record = function(data, id){
9748 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9753 * Generate a constructor for a specific record layout.
9754 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9755 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9756 * Each field definition object may contain the following properties: <ul>
9757 * <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,
9758 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9759 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9760 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9761 * is being used, then this is a string containing the javascript expression to reference the data relative to
9762 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9763 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9764 * this may be omitted.</p></li>
9765 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9766 * <ul><li>auto (Default, implies no conversion)</li>
9771 * <li>date</li></ul></p></li>
9772 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9773 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9774 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9775 * by the Reader into an object that will be stored in the Record. It is passed the
9776 * following parameters:<ul>
9777 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9779 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9781 * <br>usage:<br><pre><code>
9782 var TopicRecord = Roo.data.Record.create(
9783 {name: 'title', mapping: 'topic_title'},
9784 {name: 'author', mapping: 'username'},
9785 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9786 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9787 {name: 'lastPoster', mapping: 'user2'},
9788 {name: 'excerpt', mapping: 'post_text'}
9791 var myNewRecord = new TopicRecord({
9792 title: 'Do my job please',
9795 lastPost: new Date(),
9796 lastPoster: 'Animal',
9797 excerpt: 'No way dude!'
9799 myStore.add(myNewRecord);
9804 Roo.data.Record.create = function(o){
9806 f.superclass.constructor.apply(this, arguments);
9808 Roo.extend(f, Roo.data.Record);
9809 var p = f.prototype;
9810 p.fields = new Roo.util.MixedCollection(false, function(field){
9813 for(var i = 0, len = o.length; i < len; i++){
9814 p.fields.add(new Roo.data.Field(o[i]));
9816 f.getField = function(name){
9817 return p.fields.get(name);
9822 Roo.data.Record.AUTO_ID = 1000;
9823 Roo.data.Record.EDIT = 'edit';
9824 Roo.data.Record.REJECT = 'reject';
9825 Roo.data.Record.COMMIT = 'commit';
9827 Roo.data.Record.prototype = {
9829 * Readonly flag - true if this record has been modified.
9838 join : function(store){
9843 * Set the named field to the specified value.
9844 * @param {String} name The name of the field to set.
9845 * @param {Object} value The value to set the field to.
9847 set : function(name, value){
9848 if(this.data[name] == value){
9855 if(typeof this.modified[name] == 'undefined'){
9856 this.modified[name] = this.data[name];
9858 this.data[name] = value;
9859 if(!this.editing && this.store){
9860 this.store.afterEdit(this);
9865 * Get the value of the named field.
9866 * @param {String} name The name of the field to get the value of.
9867 * @return {Object} The value of the field.
9869 get : function(name){
9870 return this.data[name];
9874 beginEdit : function(){
9875 this.editing = true;
9880 cancelEdit : function(){
9881 this.editing = false;
9882 delete this.modified;
9886 endEdit : function(){
9887 this.editing = false;
9888 if(this.dirty && this.store){
9889 this.store.afterEdit(this);
9894 * Usually called by the {@link Roo.data.Store} which owns the Record.
9895 * Rejects all changes made to the Record since either creation, or the last commit operation.
9896 * Modified fields are reverted to their original values.
9898 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9899 * of reject operations.
9901 reject : function(){
9902 var m = this.modified;
9904 if(typeof m[n] != "function"){
9905 this.data[n] = m[n];
9909 delete this.modified;
9910 this.editing = false;
9912 this.store.afterReject(this);
9917 * Usually called by the {@link Roo.data.Store} which owns the Record.
9918 * Commits all changes made to the Record since either creation, or the last commit operation.
9920 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9921 * of commit operations.
9923 commit : function(){
9925 delete this.modified;
9926 this.editing = false;
9928 this.store.afterCommit(this);
9933 hasError : function(){
9934 return this.error != null;
9938 clearError : function(){
9943 * Creates a copy of this record.
9944 * @param {String} id (optional) A new record id if you don't want to use this record's id
9947 copy : function(newId) {
9948 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9952 * Ext JS Library 1.1.1
9953 * Copyright(c) 2006-2007, Ext JS, LLC.
9955 * Originally Released Under LGPL - original licence link has changed is not relivant.
9958 * <script type="text/javascript">
9964 * @class Roo.data.Store
9965 * @extends Roo.util.Observable
9966 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9967 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9969 * 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
9970 * has no knowledge of the format of the data returned by the Proxy.<br>
9972 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9973 * instances from the data object. These records are cached and made available through accessor functions.
9975 * Creates a new Store.
9976 * @param {Object} config A config object containing the objects needed for the Store to access data,
9977 * and read the data into Records.
9979 Roo.data.Store = function(config){
9980 this.data = new Roo.util.MixedCollection(false);
9981 this.data.getKey = function(o){
9984 this.baseParams = {};
9991 "multisort" : "_multisort"
9994 if(config && config.data){
9995 this.inlineData = config.data;
9999 Roo.apply(this, config);
10001 if(this.reader){ // reader passed
10002 this.reader = Roo.factory(this.reader, Roo.data);
10003 this.reader.xmodule = this.xmodule || false;
10004 if(!this.recordType){
10005 this.recordType = this.reader.recordType;
10007 if(this.reader.onMetaChange){
10008 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10012 if(this.recordType){
10013 this.fields = this.recordType.prototype.fields;
10015 this.modified = [];
10019 * @event datachanged
10020 * Fires when the data cache has changed, and a widget which is using this Store
10021 * as a Record cache should refresh its view.
10022 * @param {Store} this
10024 datachanged : true,
10026 * @event metachange
10027 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10028 * @param {Store} this
10029 * @param {Object} meta The JSON metadata
10034 * Fires when Records have been added to the Store
10035 * @param {Store} this
10036 * @param {Roo.data.Record[]} records The array of Records added
10037 * @param {Number} index The index at which the record(s) were added
10042 * Fires when a Record has been removed from the Store
10043 * @param {Store} this
10044 * @param {Roo.data.Record} record The Record that was removed
10045 * @param {Number} index The index at which the record was removed
10050 * Fires when a Record has been updated
10051 * @param {Store} this
10052 * @param {Roo.data.Record} record The Record that was updated
10053 * @param {String} operation The update operation being performed. Value may be one of:
10055 Roo.data.Record.EDIT
10056 Roo.data.Record.REJECT
10057 Roo.data.Record.COMMIT
10063 * Fires when the data cache has been cleared.
10064 * @param {Store} this
10068 * @event beforeload
10069 * Fires before a request is made for a new data object. If the beforeload handler returns false
10070 * the load action will be canceled.
10071 * @param {Store} this
10072 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10076 * @event beforeloadadd
10077 * Fires after a new set of Records has been loaded.
10078 * @param {Store} this
10079 * @param {Roo.data.Record[]} records The Records that were loaded
10080 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10082 beforeloadadd : true,
10085 * Fires after a new set of Records has been loaded, before they are added to the store.
10086 * @param {Store} this
10087 * @param {Roo.data.Record[]} records The Records that were loaded
10088 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10089 * @params {Object} return from reader
10093 * @event loadexception
10094 * Fires if an exception occurs in the Proxy during loading.
10095 * Called with the signature of the Proxy's "loadexception" event.
10096 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10099 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10100 * @param {Object} load options
10101 * @param {Object} jsonData from your request (normally this contains the Exception)
10103 loadexception : true
10107 this.proxy = Roo.factory(this.proxy, Roo.data);
10108 this.proxy.xmodule = this.xmodule || false;
10109 this.relayEvents(this.proxy, ["loadexception"]);
10111 this.sortToggle = {};
10112 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10114 Roo.data.Store.superclass.constructor.call(this);
10116 if(this.inlineData){
10117 this.loadData(this.inlineData);
10118 delete this.inlineData;
10122 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10124 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10125 * without a remote query - used by combo/forms at present.
10129 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10132 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10135 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10136 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10139 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10140 * on any HTTP request
10143 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10146 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10150 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10151 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10153 remoteSort : false,
10156 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10157 * loaded or when a record is removed. (defaults to false).
10159 pruneModifiedRecords : false,
10162 lastOptions : null,
10165 * Add Records to the Store and fires the add event.
10166 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10168 add : function(records){
10169 records = [].concat(records);
10170 for(var i = 0, len = records.length; i < len; i++){
10171 records[i].join(this);
10173 var index = this.data.length;
10174 this.data.addAll(records);
10175 this.fireEvent("add", this, records, index);
10179 * Remove a Record from the Store and fires the remove event.
10180 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10182 remove : function(record){
10183 var index = this.data.indexOf(record);
10184 this.data.removeAt(index);
10185 if(this.pruneModifiedRecords){
10186 this.modified.remove(record);
10188 this.fireEvent("remove", this, record, index);
10192 * Remove all Records from the Store and fires the clear event.
10194 removeAll : function(){
10196 if(this.pruneModifiedRecords){
10197 this.modified = [];
10199 this.fireEvent("clear", this);
10203 * Inserts Records to the Store at the given index and fires the add event.
10204 * @param {Number} index The start index at which to insert the passed Records.
10205 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10207 insert : function(index, records){
10208 records = [].concat(records);
10209 for(var i = 0, len = records.length; i < len; i++){
10210 this.data.insert(index, records[i]);
10211 records[i].join(this);
10213 this.fireEvent("add", this, records, index);
10217 * Get the index within the cache of the passed Record.
10218 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10219 * @return {Number} The index of the passed Record. Returns -1 if not found.
10221 indexOf : function(record){
10222 return this.data.indexOf(record);
10226 * Get the index within the cache of the Record with the passed id.
10227 * @param {String} id The id of the Record to find.
10228 * @return {Number} The index of the Record. Returns -1 if not found.
10230 indexOfId : function(id){
10231 return this.data.indexOfKey(id);
10235 * Get the Record with the specified id.
10236 * @param {String} id The id of the Record to find.
10237 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10239 getById : function(id){
10240 return this.data.key(id);
10244 * Get the Record at the specified index.
10245 * @param {Number} index The index of the Record to find.
10246 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10248 getAt : function(index){
10249 return this.data.itemAt(index);
10253 * Returns a range of Records between specified indices.
10254 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10255 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10256 * @return {Roo.data.Record[]} An array of Records
10258 getRange : function(start, end){
10259 return this.data.getRange(start, end);
10263 storeOptions : function(o){
10264 o = Roo.apply({}, o);
10267 this.lastOptions = o;
10271 * Loads the Record cache from the configured Proxy using the configured Reader.
10273 * If using remote paging, then the first load call must specify the <em>start</em>
10274 * and <em>limit</em> properties in the options.params property to establish the initial
10275 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10277 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10278 * and this call will return before the new data has been loaded. Perform any post-processing
10279 * in a callback function, or in a "load" event handler.</strong>
10281 * @param {Object} options An object containing properties which control loading options:<ul>
10282 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10283 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10284 * passed the following arguments:<ul>
10285 * <li>r : Roo.data.Record[]</li>
10286 * <li>options: Options object from the load call</li>
10287 * <li>success: Boolean success indicator</li></ul></li>
10288 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10289 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10292 load : function(options){
10293 options = options || {};
10294 if(this.fireEvent("beforeload", this, options) !== false){
10295 this.storeOptions(options);
10296 var p = Roo.apply(options.params || {}, this.baseParams);
10297 // if meta was not loaded from remote source.. try requesting it.
10298 if (!this.reader.metaFromRemote) {
10299 p._requestMeta = 1;
10301 if(this.sortInfo && this.remoteSort){
10302 var pn = this.paramNames;
10303 p[pn["sort"]] = this.sortInfo.field;
10304 p[pn["dir"]] = this.sortInfo.direction;
10306 if (this.multiSort) {
10307 var pn = this.paramNames;
10308 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10311 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10316 * Reloads the Record cache from the configured Proxy using the configured Reader and
10317 * the options from the last load operation performed.
10318 * @param {Object} options (optional) An object containing properties which may override the options
10319 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10320 * the most recently used options are reused).
10322 reload : function(options){
10323 this.load(Roo.applyIf(options||{}, this.lastOptions));
10327 // Called as a callback by the Reader during a load operation.
10328 loadRecords : function(o, options, success){
10329 if(!o || success === false){
10330 if(success !== false){
10331 this.fireEvent("load", this, [], options, o);
10333 if(options.callback){
10334 options.callback.call(options.scope || this, [], options, false);
10338 // if data returned failure - throw an exception.
10339 if (o.success === false) {
10340 // show a message if no listener is registered.
10341 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10342 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10344 // loadmask wil be hooked into this..
10345 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10348 var r = o.records, t = o.totalRecords || r.length;
10350 this.fireEvent("beforeloadadd", this, r, options, o);
10352 if(!options || options.add !== true){
10353 if(this.pruneModifiedRecords){
10354 this.modified = [];
10356 for(var i = 0, len = r.length; i < len; i++){
10360 this.data = this.snapshot;
10361 delete this.snapshot;
10364 this.data.addAll(r);
10365 this.totalLength = t;
10367 this.fireEvent("datachanged", this);
10369 this.totalLength = Math.max(t, this.data.length+r.length);
10372 this.fireEvent("load", this, r, options, o);
10373 if(options.callback){
10374 options.callback.call(options.scope || this, r, options, true);
10380 * Loads data from a passed data block. A Reader which understands the format of the data
10381 * must have been configured in the constructor.
10382 * @param {Object} data The data block from which to read the Records. The format of the data expected
10383 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10384 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10386 loadData : function(o, append){
10387 var r = this.reader.readRecords(o);
10388 this.loadRecords(r, {add: append}, true);
10392 * Gets the number of cached records.
10394 * <em>If using paging, this may not be the total size of the dataset. If the data object
10395 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10396 * the data set size</em>
10398 getCount : function(){
10399 return this.data.length || 0;
10403 * Gets the total number of records in the dataset as returned by the server.
10405 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10406 * the dataset size</em>
10408 getTotalCount : function(){
10409 return this.totalLength || 0;
10413 * Returns the sort state of the Store as an object with two properties:
10415 field {String} The name of the field by which the Records are sorted
10416 direction {String} The sort order, "ASC" or "DESC"
10419 getSortState : function(){
10420 return this.sortInfo;
10424 applySort : function(){
10425 if(this.sortInfo && !this.remoteSort){
10426 var s = this.sortInfo, f = s.field;
10427 var st = this.fields.get(f).sortType;
10428 var fn = function(r1, r2){
10429 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10430 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10432 this.data.sort(s.direction, fn);
10433 if(this.snapshot && this.snapshot != this.data){
10434 this.snapshot.sort(s.direction, fn);
10440 * Sets the default sort column and order to be used by the next load operation.
10441 * @param {String} fieldName The name of the field to sort by.
10442 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10444 setDefaultSort : function(field, dir){
10445 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10449 * Sort the Records.
10450 * If remote sorting is used, the sort is performed on the server, and the cache is
10451 * reloaded. If local sorting is used, the cache is sorted internally.
10452 * @param {String} fieldName The name of the field to sort by.
10453 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10455 sort : function(fieldName, dir){
10456 var f = this.fields.get(fieldName);
10458 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10460 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10461 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10466 this.sortToggle[f.name] = dir;
10467 this.sortInfo = {field: f.name, direction: dir};
10468 if(!this.remoteSort){
10470 this.fireEvent("datachanged", this);
10472 this.load(this.lastOptions);
10477 * Calls the specified function for each of the Records in the cache.
10478 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10479 * Returning <em>false</em> aborts and exits the iteration.
10480 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10482 each : function(fn, scope){
10483 this.data.each(fn, scope);
10487 * Gets all records modified since the last commit. Modified records are persisted across load operations
10488 * (e.g., during paging).
10489 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10491 getModifiedRecords : function(){
10492 return this.modified;
10496 createFilterFn : function(property, value, anyMatch){
10497 if(!value.exec){ // not a regex
10498 value = String(value);
10499 if(value.length == 0){
10502 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10504 return function(r){
10505 return value.test(r.data[property]);
10510 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10511 * @param {String} property A field on your records
10512 * @param {Number} start The record index to start at (defaults to 0)
10513 * @param {Number} end The last record index to include (defaults to length - 1)
10514 * @return {Number} The sum
10516 sum : function(property, start, end){
10517 var rs = this.data.items, v = 0;
10518 start = start || 0;
10519 end = (end || end === 0) ? end : rs.length-1;
10521 for(var i = start; i <= end; i++){
10522 v += (rs[i].data[property] || 0);
10528 * Filter the records by a specified property.
10529 * @param {String} field A field on your records
10530 * @param {String/RegExp} value Either a string that the field
10531 * should start with or a RegExp to test against the field
10532 * @param {Boolean} anyMatch True to match any part not just the beginning
10534 filter : function(property, value, anyMatch){
10535 var fn = this.createFilterFn(property, value, anyMatch);
10536 return fn ? this.filterBy(fn) : this.clearFilter();
10540 * Filter by a function. The specified function will be called with each
10541 * record in this data source. If the function returns true the record is included,
10542 * otherwise it is filtered.
10543 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10544 * @param {Object} scope (optional) The scope of the function (defaults to this)
10546 filterBy : function(fn, scope){
10547 this.snapshot = this.snapshot || this.data;
10548 this.data = this.queryBy(fn, scope||this);
10549 this.fireEvent("datachanged", this);
10553 * Query the records by a specified property.
10554 * @param {String} field A field on your records
10555 * @param {String/RegExp} value Either a string that the field
10556 * should start with or a RegExp to test against the field
10557 * @param {Boolean} anyMatch True to match any part not just the beginning
10558 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10560 query : function(property, value, anyMatch){
10561 var fn = this.createFilterFn(property, value, anyMatch);
10562 return fn ? this.queryBy(fn) : this.data.clone();
10566 * Query by a function. The specified function will be called with each
10567 * record in this data source. If the function returns true the record is included
10569 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10570 * @param {Object} scope (optional) The scope of the function (defaults to this)
10571 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10573 queryBy : function(fn, scope){
10574 var data = this.snapshot || this.data;
10575 return data.filterBy(fn, scope||this);
10579 * Collects unique values for a particular dataIndex from this store.
10580 * @param {String} dataIndex The property to collect
10581 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10582 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10583 * @return {Array} An array of the unique values
10585 collect : function(dataIndex, allowNull, bypassFilter){
10586 var d = (bypassFilter === true && this.snapshot) ?
10587 this.snapshot.items : this.data.items;
10588 var v, sv, r = [], l = {};
10589 for(var i = 0, len = d.length; i < len; i++){
10590 v = d[i].data[dataIndex];
10592 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10601 * Revert to a view of the Record cache with no filtering applied.
10602 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10604 clearFilter : function(suppressEvent){
10605 if(this.snapshot && this.snapshot != this.data){
10606 this.data = this.snapshot;
10607 delete this.snapshot;
10608 if(suppressEvent !== true){
10609 this.fireEvent("datachanged", this);
10615 afterEdit : function(record){
10616 if(this.modified.indexOf(record) == -1){
10617 this.modified.push(record);
10619 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10623 afterReject : function(record){
10624 this.modified.remove(record);
10625 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10629 afterCommit : function(record){
10630 this.modified.remove(record);
10631 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10635 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10636 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10638 commitChanges : function(){
10639 var m = this.modified.slice(0);
10640 this.modified = [];
10641 for(var i = 0, len = m.length; i < len; i++){
10647 * Cancel outstanding changes on all changed records.
10649 rejectChanges : function(){
10650 var m = this.modified.slice(0);
10651 this.modified = [];
10652 for(var i = 0, len = m.length; i < len; i++){
10657 onMetaChange : function(meta, rtype, o){
10658 this.recordType = rtype;
10659 this.fields = rtype.prototype.fields;
10660 delete this.snapshot;
10661 this.sortInfo = meta.sortInfo || this.sortInfo;
10662 this.modified = [];
10663 this.fireEvent('metachange', this, this.reader.meta);
10666 moveIndex : function(data, type)
10668 var index = this.indexOf(data);
10670 var newIndex = index + type;
10674 this.insert(newIndex, data);
10679 * Ext JS Library 1.1.1
10680 * Copyright(c) 2006-2007, Ext JS, LLC.
10682 * Originally Released Under LGPL - original licence link has changed is not relivant.
10685 * <script type="text/javascript">
10689 * @class Roo.data.SimpleStore
10690 * @extends Roo.data.Store
10691 * Small helper class to make creating Stores from Array data easier.
10692 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10693 * @cfg {Array} fields An array of field definition objects, or field name strings.
10694 * @cfg {Array} data The multi-dimensional array of data
10696 * @param {Object} config
10698 Roo.data.SimpleStore = function(config){
10699 Roo.data.SimpleStore.superclass.constructor.call(this, {
10701 reader: new Roo.data.ArrayReader({
10704 Roo.data.Record.create(config.fields)
10706 proxy : new Roo.data.MemoryProxy(config.data)
10710 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10712 * Ext JS Library 1.1.1
10713 * Copyright(c) 2006-2007, Ext JS, LLC.
10715 * Originally Released Under LGPL - original licence link has changed is not relivant.
10718 * <script type="text/javascript">
10723 * @extends Roo.data.Store
10724 * @class Roo.data.JsonStore
10725 * Small helper class to make creating Stores for JSON data easier. <br/>
10727 var store = new Roo.data.JsonStore({
10728 url: 'get-images.php',
10730 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10733 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10734 * JsonReader and HttpProxy (unless inline data is provided).</b>
10735 * @cfg {Array} fields An array of field definition objects, or field name strings.
10737 * @param {Object} config
10739 Roo.data.JsonStore = function(c){
10740 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10741 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10742 reader: new Roo.data.JsonReader(c, c.fields)
10745 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10747 * Ext JS Library 1.1.1
10748 * Copyright(c) 2006-2007, Ext JS, LLC.
10750 * Originally Released Under LGPL - original licence link has changed is not relivant.
10753 * <script type="text/javascript">
10757 Roo.data.Field = function(config){
10758 if(typeof config == "string"){
10759 config = {name: config};
10761 Roo.apply(this, config);
10764 this.type = "auto";
10767 var st = Roo.data.SortTypes;
10768 // named sortTypes are supported, here we look them up
10769 if(typeof this.sortType == "string"){
10770 this.sortType = st[this.sortType];
10773 // set default sortType for strings and dates
10774 if(!this.sortType){
10777 this.sortType = st.asUCString;
10780 this.sortType = st.asDate;
10783 this.sortType = st.none;
10788 var stripRe = /[\$,%]/g;
10790 // prebuilt conversion function for this field, instead of
10791 // switching every time we're reading a value
10793 var cv, dateFormat = this.dateFormat;
10798 cv = function(v){ return v; };
10801 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10805 return v !== undefined && v !== null && v !== '' ?
10806 parseInt(String(v).replace(stripRe, ""), 10) : '';
10811 return v !== undefined && v !== null && v !== '' ?
10812 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10817 cv = function(v){ return v === true || v === "true" || v == 1; };
10824 if(v instanceof Date){
10828 if(dateFormat == "timestamp"){
10829 return new Date(v*1000);
10831 return Date.parseDate(v, dateFormat);
10833 var parsed = Date.parse(v);
10834 return parsed ? new Date(parsed) : null;
10843 Roo.data.Field.prototype = {
10851 * Ext JS Library 1.1.1
10852 * Copyright(c) 2006-2007, Ext JS, LLC.
10854 * Originally Released Under LGPL - original licence link has changed is not relivant.
10857 * <script type="text/javascript">
10860 // Base class for reading structured data from a data source. This class is intended to be
10861 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10864 * @class Roo.data.DataReader
10865 * Base class for reading structured data from a data source. This class is intended to be
10866 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10869 Roo.data.DataReader = function(meta, recordType){
10873 this.recordType = recordType instanceof Array ?
10874 Roo.data.Record.create(recordType) : recordType;
10877 Roo.data.DataReader.prototype = {
10879 * Create an empty record
10880 * @param {Object} data (optional) - overlay some values
10881 * @return {Roo.data.Record} record created.
10883 newRow : function(d) {
10885 this.recordType.prototype.fields.each(function(c) {
10887 case 'int' : da[c.name] = 0; break;
10888 case 'date' : da[c.name] = new Date(); break;
10889 case 'float' : da[c.name] = 0.0; break;
10890 case 'boolean' : da[c.name] = false; break;
10891 default : da[c.name] = ""; break;
10895 return new this.recordType(Roo.apply(da, d));
10900 * Ext JS Library 1.1.1
10901 * Copyright(c) 2006-2007, Ext JS, LLC.
10903 * Originally Released Under LGPL - original licence link has changed is not relivant.
10906 * <script type="text/javascript">
10910 * @class Roo.data.DataProxy
10911 * @extends Roo.data.Observable
10912 * This class is an abstract base class for implementations which provide retrieval of
10913 * unformatted data objects.<br>
10915 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10916 * (of the appropriate type which knows how to parse the data object) to provide a block of
10917 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10919 * Custom implementations must implement the load method as described in
10920 * {@link Roo.data.HttpProxy#load}.
10922 Roo.data.DataProxy = function(){
10925 * @event beforeload
10926 * Fires before a network request is made to retrieve a data object.
10927 * @param {Object} This DataProxy object.
10928 * @param {Object} params The params parameter to the load function.
10933 * Fires before the load method's callback is called.
10934 * @param {Object} This DataProxy object.
10935 * @param {Object} o The data object.
10936 * @param {Object} arg The callback argument object passed to the load function.
10940 * @event loadexception
10941 * Fires if an Exception occurs during data retrieval.
10942 * @param {Object} This DataProxy object.
10943 * @param {Object} o The data object.
10944 * @param {Object} arg The callback argument object passed to the load function.
10945 * @param {Object} e The Exception.
10947 loadexception : true
10949 Roo.data.DataProxy.superclass.constructor.call(this);
10952 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10955 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10959 * Ext JS Library 1.1.1
10960 * Copyright(c) 2006-2007, Ext JS, LLC.
10962 * Originally Released Under LGPL - original licence link has changed is not relivant.
10965 * <script type="text/javascript">
10968 * @class Roo.data.MemoryProxy
10969 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10970 * to the Reader when its load method is called.
10972 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10974 Roo.data.MemoryProxy = function(data){
10978 Roo.data.MemoryProxy.superclass.constructor.call(this);
10982 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10984 * Load data from the requested source (in this case an in-memory
10985 * data object passed to the constructor), read the data object into
10986 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10987 * process that block using the passed callback.
10988 * @param {Object} params This parameter is not used by the MemoryProxy class.
10989 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10990 * object into a block of Roo.data.Records.
10991 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10992 * The function must be passed <ul>
10993 * <li>The Record block object</li>
10994 * <li>The "arg" argument from the load function</li>
10995 * <li>A boolean success indicator</li>
10997 * @param {Object} scope The scope in which to call the callback
10998 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11000 load : function(params, reader, callback, scope, arg){
11001 params = params || {};
11004 result = reader.readRecords(this.data);
11006 this.fireEvent("loadexception", this, arg, null, e);
11007 callback.call(scope, null, arg, false);
11010 callback.call(scope, result, arg, true);
11014 update : function(params, records){
11019 * Ext JS Library 1.1.1
11020 * Copyright(c) 2006-2007, Ext JS, LLC.
11022 * Originally Released Under LGPL - original licence link has changed is not relivant.
11025 * <script type="text/javascript">
11028 * @class Roo.data.HttpProxy
11029 * @extends Roo.data.DataProxy
11030 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11031 * configured to reference a certain URL.<br><br>
11033 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11034 * from which the running page was served.<br><br>
11036 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11038 * Be aware that to enable the browser to parse an XML document, the server must set
11039 * the Content-Type header in the HTTP response to "text/xml".
11041 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11042 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11043 * will be used to make the request.
11045 Roo.data.HttpProxy = function(conn){
11046 Roo.data.HttpProxy.superclass.constructor.call(this);
11047 // is conn a conn config or a real conn?
11049 this.useAjax = !conn || !conn.events;
11053 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11054 // thse are take from connection...
11057 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11060 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11061 * extra parameters to each request made by this object. (defaults to undefined)
11064 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11065 * to each request made by this object. (defaults to undefined)
11068 * @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)
11071 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11074 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11080 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11084 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11085 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11086 * a finer-grained basis than the DataProxy events.
11088 getConnection : function(){
11089 return this.useAjax ? Roo.Ajax : this.conn;
11093 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11094 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11095 * process that block using the passed callback.
11096 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11097 * for the request to the remote server.
11098 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11099 * object into a block of Roo.data.Records.
11100 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11101 * The function must be passed <ul>
11102 * <li>The Record block object</li>
11103 * <li>The "arg" argument from the load function</li>
11104 * <li>A boolean success indicator</li>
11106 * @param {Object} scope The scope in which to call the callback
11107 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11109 load : function(params, reader, callback, scope, arg){
11110 if(this.fireEvent("beforeload", this, params) !== false){
11112 params : params || {},
11114 callback : callback,
11119 callback : this.loadResponse,
11123 Roo.applyIf(o, this.conn);
11124 if(this.activeRequest){
11125 Roo.Ajax.abort(this.activeRequest);
11127 this.activeRequest = Roo.Ajax.request(o);
11129 this.conn.request(o);
11132 callback.call(scope||this, null, arg, false);
11137 loadResponse : function(o, success, response){
11138 delete this.activeRequest;
11140 this.fireEvent("loadexception", this, o, response);
11141 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11146 result = o.reader.read(response);
11148 this.fireEvent("loadexception", this, o, response, e);
11149 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11153 this.fireEvent("load", this, o, o.request.arg);
11154 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11158 update : function(dataSet){
11163 updateResponse : function(dataSet){
11168 * Ext JS Library 1.1.1
11169 * Copyright(c) 2006-2007, Ext JS, LLC.
11171 * Originally Released Under LGPL - original licence link has changed is not relivant.
11174 * <script type="text/javascript">
11178 * @class Roo.data.ScriptTagProxy
11179 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11180 * other than the originating domain of the running page.<br><br>
11182 * <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
11183 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11185 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11186 * source code that is used as the source inside a <script> tag.<br><br>
11188 * In order for the browser to process the returned data, the server must wrap the data object
11189 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11190 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11191 * depending on whether the callback name was passed:
11194 boolean scriptTag = false;
11195 String cb = request.getParameter("callback");
11198 response.setContentType("text/javascript");
11200 response.setContentType("application/x-json");
11202 Writer out = response.getWriter();
11204 out.write(cb + "(");
11206 out.print(dataBlock.toJsonString());
11213 * @param {Object} config A configuration object.
11215 Roo.data.ScriptTagProxy = function(config){
11216 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11217 Roo.apply(this, config);
11218 this.head = document.getElementsByTagName("head")[0];
11221 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11223 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11225 * @cfg {String} url The URL from which to request the data object.
11228 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11232 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11233 * the server the name of the callback function set up by the load call to process the returned data object.
11234 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11235 * javascript output which calls this named function passing the data object as its only parameter.
11237 callbackParam : "callback",
11239 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11240 * name to the request.
11245 * Load data from the configured URL, read the data object into
11246 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11247 * process that block using the passed callback.
11248 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11249 * for the request to the remote server.
11250 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11251 * object into a block of Roo.data.Records.
11252 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11253 * The function must be passed <ul>
11254 * <li>The Record block object</li>
11255 * <li>The "arg" argument from the load function</li>
11256 * <li>A boolean success indicator</li>
11258 * @param {Object} scope The scope in which to call the callback
11259 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11261 load : function(params, reader, callback, scope, arg){
11262 if(this.fireEvent("beforeload", this, params) !== false){
11264 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11266 var url = this.url;
11267 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11269 url += "&_dc=" + (new Date().getTime());
11271 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11274 cb : "stcCallback"+transId,
11275 scriptId : "stcScript"+transId,
11279 callback : callback,
11285 window[trans.cb] = function(o){
11286 conn.handleResponse(o, trans);
11289 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11291 if(this.autoAbort !== false){
11295 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11297 var script = document.createElement("script");
11298 script.setAttribute("src", url);
11299 script.setAttribute("type", "text/javascript");
11300 script.setAttribute("id", trans.scriptId);
11301 this.head.appendChild(script);
11303 this.trans = trans;
11305 callback.call(scope||this, null, arg, false);
11310 isLoading : function(){
11311 return this.trans ? true : false;
11315 * Abort the current server request.
11317 abort : function(){
11318 if(this.isLoading()){
11319 this.destroyTrans(this.trans);
11324 destroyTrans : function(trans, isLoaded){
11325 this.head.removeChild(document.getElementById(trans.scriptId));
11326 clearTimeout(trans.timeoutId);
11328 window[trans.cb] = undefined;
11330 delete window[trans.cb];
11333 // if hasn't been loaded, wait for load to remove it to prevent script error
11334 window[trans.cb] = function(){
11335 window[trans.cb] = undefined;
11337 delete window[trans.cb];
11344 handleResponse : function(o, trans){
11345 this.trans = false;
11346 this.destroyTrans(trans, true);
11349 result = trans.reader.readRecords(o);
11351 this.fireEvent("loadexception", this, o, trans.arg, e);
11352 trans.callback.call(trans.scope||window, null, trans.arg, false);
11355 this.fireEvent("load", this, o, trans.arg);
11356 trans.callback.call(trans.scope||window, result, trans.arg, true);
11360 handleFailure : function(trans){
11361 this.trans = false;
11362 this.destroyTrans(trans, false);
11363 this.fireEvent("loadexception", this, null, trans.arg);
11364 trans.callback.call(trans.scope||window, null, trans.arg, false);
11368 * Ext JS Library 1.1.1
11369 * Copyright(c) 2006-2007, Ext JS, LLC.
11371 * Originally Released Under LGPL - original licence link has changed is not relivant.
11374 * <script type="text/javascript">
11378 * @class Roo.data.JsonReader
11379 * @extends Roo.data.DataReader
11380 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11381 * based on mappings in a provided Roo.data.Record constructor.
11383 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11384 * in the reply previously.
11389 var RecordDef = Roo.data.Record.create([
11390 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11391 {name: 'occupation'} // This field will use "occupation" as the mapping.
11393 var myReader = new Roo.data.JsonReader({
11394 totalProperty: "results", // The property which contains the total dataset size (optional)
11395 root: "rows", // The property which contains an Array of row objects
11396 id: "id" // The property within each row object that provides an ID for the record (optional)
11400 * This would consume a JSON file like this:
11402 { 'results': 2, 'rows': [
11403 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11404 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11407 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11408 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11409 * paged from the remote server.
11410 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11411 * @cfg {String} root name of the property which contains the Array of row objects.
11412 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11413 * @cfg {Array} fields Array of field definition objects
11415 * Create a new JsonReader
11416 * @param {Object} meta Metadata configuration options
11417 * @param {Object} recordType Either an Array of field definition objects,
11418 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11420 Roo.data.JsonReader = function(meta, recordType){
11423 // set some defaults:
11424 Roo.applyIf(meta, {
11425 totalProperty: 'total',
11426 successProperty : 'success',
11431 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11433 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11436 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11437 * Used by Store query builder to append _requestMeta to params.
11440 metaFromRemote : false,
11442 * This method is only used by a DataProxy which has retrieved data from a remote server.
11443 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11444 * @return {Object} data A data block which is used by an Roo.data.Store object as
11445 * a cache of Roo.data.Records.
11447 read : function(response){
11448 var json = response.responseText;
11450 var o = /* eval:var:o */ eval("("+json+")");
11452 throw {message: "JsonReader.read: Json object not found"};
11458 this.metaFromRemote = true;
11459 this.meta = o.metaData;
11460 this.recordType = Roo.data.Record.create(o.metaData.fields);
11461 this.onMetaChange(this.meta, this.recordType, o);
11463 return this.readRecords(o);
11466 // private function a store will implement
11467 onMetaChange : function(meta, recordType, o){
11474 simpleAccess: function(obj, subsc) {
11481 getJsonAccessor: function(){
11483 return function(expr) {
11485 return(re.test(expr))
11486 ? new Function("obj", "return obj." + expr)
11491 return Roo.emptyFn;
11496 * Create a data block containing Roo.data.Records from an XML document.
11497 * @param {Object} o An object which contains an Array of row objects in the property specified
11498 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11499 * which contains the total size of the dataset.
11500 * @return {Object} data A data block which is used by an Roo.data.Store object as
11501 * a cache of Roo.data.Records.
11503 readRecords : function(o){
11505 * After any data loads, the raw JSON data is available for further custom processing.
11509 var s = this.meta, Record = this.recordType,
11510 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11512 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11514 if(s.totalProperty) {
11515 this.getTotal = this.getJsonAccessor(s.totalProperty);
11517 if(s.successProperty) {
11518 this.getSuccess = this.getJsonAccessor(s.successProperty);
11520 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11522 var g = this.getJsonAccessor(s.id);
11523 this.getId = function(rec) {
11525 return (r === undefined || r === "") ? null : r;
11528 this.getId = function(){return null;};
11531 for(var jj = 0; jj < fl; jj++){
11533 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11534 this.ef[jj] = this.getJsonAccessor(map);
11538 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11539 if(s.totalProperty){
11540 var vt = parseInt(this.getTotal(o), 10);
11545 if(s.successProperty){
11546 var vs = this.getSuccess(o);
11547 if(vs === false || vs === 'false'){
11552 for(var i = 0; i < c; i++){
11555 var id = this.getId(n);
11556 for(var j = 0; j < fl; j++){
11558 var v = this.ef[j](n);
11560 Roo.log('missing convert for ' + f.name);
11564 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11566 var record = new Record(values, id);
11568 records[i] = record;
11574 totalRecords : totalRecords
11579 * Ext JS Library 1.1.1
11580 * Copyright(c) 2006-2007, Ext JS, LLC.
11582 * Originally Released Under LGPL - original licence link has changed is not relivant.
11585 * <script type="text/javascript">
11589 * @class Roo.data.ArrayReader
11590 * @extends Roo.data.DataReader
11591 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11592 * Each element of that Array represents a row of data fields. The
11593 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11594 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11598 var RecordDef = Roo.data.Record.create([
11599 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11600 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11602 var myReader = new Roo.data.ArrayReader({
11603 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11607 * This would consume an Array like this:
11609 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11611 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11613 * Create a new JsonReader
11614 * @param {Object} meta Metadata configuration options.
11615 * @param {Object} recordType Either an Array of field definition objects
11616 * as specified to {@link Roo.data.Record#create},
11617 * or an {@link Roo.data.Record} object
11618 * created using {@link Roo.data.Record#create}.
11620 Roo.data.ArrayReader = function(meta, recordType){
11621 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11624 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11626 * Create a data block containing Roo.data.Records from an XML document.
11627 * @param {Object} o An Array of row objects which represents the dataset.
11628 * @return {Object} data A data block which is used by an Roo.data.Store object as
11629 * a cache of Roo.data.Records.
11631 readRecords : function(o){
11632 var sid = this.meta ? this.meta.id : null;
11633 var recordType = this.recordType, fields = recordType.prototype.fields;
11636 for(var i = 0; i < root.length; i++){
11639 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11640 for(var j = 0, jlen = fields.length; j < jlen; j++){
11641 var f = fields.items[j];
11642 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11643 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11645 values[f.name] = v;
11647 var record = new recordType(values, id);
11649 records[records.length] = record;
11653 totalRecords : records.length
11662 * @class Roo.bootstrap.ComboBox
11663 * @extends Roo.bootstrap.TriggerField
11664 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11665 * @cfg {Boolean} append (true|false) default false
11666 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11667 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11668 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11669 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11670 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11671 * @cfg {Boolean} animate default true
11672 * @cfg {Boolean} emptyResultText only for touch device
11673 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11675 * Create a new ComboBox.
11676 * @param {Object} config Configuration options
11678 Roo.bootstrap.ComboBox = function(config){
11679 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11683 * Fires when the dropdown list is expanded
11684 * @param {Roo.bootstrap.ComboBox} combo This combo box
11689 * Fires when the dropdown list is collapsed
11690 * @param {Roo.bootstrap.ComboBox} combo This combo box
11694 * @event beforeselect
11695 * Fires before a list item is selected. Return false to cancel the selection.
11696 * @param {Roo.bootstrap.ComboBox} combo This combo box
11697 * @param {Roo.data.Record} record The data record returned from the underlying store
11698 * @param {Number} index The index of the selected item in the dropdown list
11700 'beforeselect' : true,
11703 * Fires when a list item is selected
11704 * @param {Roo.bootstrap.ComboBox} combo This combo box
11705 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11706 * @param {Number} index The index of the selected item in the dropdown list
11710 * @event beforequery
11711 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11712 * The event object passed has these properties:
11713 * @param {Roo.bootstrap.ComboBox} combo This combo box
11714 * @param {String} query The query
11715 * @param {Boolean} forceAll true to force "all" query
11716 * @param {Boolean} cancel true to cancel the query
11717 * @param {Object} e The query event object
11719 'beforequery': true,
11722 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11723 * @param {Roo.bootstrap.ComboBox} combo This combo box
11728 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11729 * @param {Roo.bootstrap.ComboBox} combo This combo box
11730 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11735 * Fires when the remove value from the combobox array
11736 * @param {Roo.bootstrap.ComboBox} combo This combo box
11740 * @event afterremove
11741 * Fires when the remove value from the combobox array
11742 * @param {Roo.bootstrap.ComboBox} combo This combo box
11744 'afterremove' : true,
11746 * @event specialfilter
11747 * Fires when specialfilter
11748 * @param {Roo.bootstrap.ComboBox} combo This combo box
11750 'specialfilter' : true,
11753 * Fires when tick the element
11754 * @param {Roo.bootstrap.ComboBox} combo This combo box
11758 * @event touchviewdisplay
11759 * Fires when touch view require special display (default is using displayField)
11760 * @param {Roo.bootstrap.ComboBox} combo This combo box
11761 * @param {Object} cfg set html .
11763 'touchviewdisplay' : true
11768 this.tickItems = [];
11770 this.selectedIndex = -1;
11771 if(this.mode == 'local'){
11772 if(config.queryDelay === undefined){
11773 this.queryDelay = 10;
11775 if(config.minChars === undefined){
11781 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11784 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11785 * rendering into an Roo.Editor, defaults to false)
11788 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11789 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11792 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11795 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11796 * the dropdown list (defaults to undefined, with no header element)
11800 * @cfg {String/Roo.Template} tpl The template to use to render the output
11804 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11806 listWidth: undefined,
11808 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11809 * mode = 'remote' or 'text' if mode = 'local')
11811 displayField: undefined,
11814 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11815 * mode = 'remote' or 'value' if mode = 'local').
11816 * Note: use of a valueField requires the user make a selection
11817 * in order for a value to be mapped.
11819 valueField: undefined,
11823 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11824 * field's data value (defaults to the underlying DOM element's name)
11826 hiddenName: undefined,
11828 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11832 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11834 selectedClass: 'active',
11837 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11841 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11842 * anchor positions (defaults to 'tl-bl')
11844 listAlign: 'tl-bl?',
11846 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11850 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11851 * query specified by the allQuery config option (defaults to 'query')
11853 triggerAction: 'query',
11855 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11856 * (defaults to 4, does not apply if editable = false)
11860 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11861 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11865 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11866 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11870 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11871 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11875 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11876 * when editable = true (defaults to false)
11878 selectOnFocus:false,
11880 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11882 queryParam: 'query',
11884 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11885 * when mode = 'remote' (defaults to 'Loading...')
11887 loadingText: 'Loading...',
11889 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11893 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11897 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11898 * traditional select (defaults to true)
11902 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11906 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11910 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11911 * listWidth has a higher value)
11915 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11916 * allow the user to set arbitrary text into the field (defaults to false)
11918 forceSelection:false,
11920 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11921 * if typeAhead = true (defaults to 250)
11923 typeAheadDelay : 250,
11925 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11926 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11928 valueNotFoundText : undefined,
11930 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11932 blockFocus : false,
11935 * @cfg {Boolean} disableClear Disable showing of clear button.
11937 disableClear : false,
11939 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11941 alwaysQuery : false,
11944 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11949 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11951 invalidClass : "has-warning",
11954 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11956 validClass : "has-success",
11959 * @cfg {Boolean} specialFilter (true|false) special filter default false
11961 specialFilter : false,
11964 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
11966 mobileTouchView : true,
11978 btnPosition : 'right',
11979 triggerList : true,
11980 showToggleBtn : true,
11982 emptyResultText: 'Empty',
11983 triggerText : 'Select',
11985 // element that contains real text value.. (when hidden is used..)
11987 getAutoCreate : function()
11995 if(Roo.isTouch && this.mobileTouchView){
11996 cfg = this.getAutoCreateTouchView();
12003 if(!this.tickable){
12004 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12009 * ComboBox with tickable selections
12012 var align = this.labelAlign || this.parentLabelAlign();
12015 cls : 'form-group roo-combobox-tickable' //input-group
12020 cls : 'tickable-buttons',
12025 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12026 html : this.triggerText
12032 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12039 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12046 buttons.cn.unshift({
12048 cls: 'roo-select2-search-field-input'
12054 Roo.each(buttons.cn, function(c){
12056 c.cls += ' btn-' + _this.size;
12059 if (_this.disabled) {
12070 cls: 'form-hidden-field'
12074 cls: 'roo-select2-choices',
12078 cls: 'roo-select2-search-field',
12090 cls: 'roo-select2-container input-group roo-select2-container-multi',
12095 // cls: 'typeahead typeahead-long dropdown-menu',
12096 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12101 if(this.hasFeedback && !this.allowBlank){
12105 cls: 'glyphicon form-control-feedback'
12108 combobox.cn.push(feedback);
12111 if (align ==='left' && this.fieldLabel.length) {
12113 // Roo.log("left and has label");
12119 cls : 'control-label col-sm-' + this.labelWidth,
12120 html : this.fieldLabel
12124 cls : "col-sm-" + (12 - this.labelWidth),
12131 } else if ( this.fieldLabel.length) {
12132 // Roo.log(" label");
12137 //cls : 'input-group-addon',
12138 html : this.fieldLabel
12148 // Roo.log(" no label && no align");
12155 ['xs','sm','md','lg'].map(function(size){
12156 if (settings[size]) {
12157 cfg.cls += ' col-' + size + '-' + settings[size];
12165 _initEventsCalled : false,
12168 initEvents: function()
12171 if (this._initEventsCalled) { // as we call render... prevent looping...
12174 this._initEventsCalled = true;
12177 throw "can not find store for combo";
12180 this.store = Roo.factory(this.store, Roo.data);
12182 // if we are building from html. then this element is so complex, that we can not really
12183 // use the rendered HTML.
12184 // so we have to trash and replace the previous code.
12185 if (Roo.XComponent.build_from_html) {
12187 // remove this element....
12188 var e = this.el.dom, k=0;
12189 while (e ) { e = e.previousSibling; ++k;}
12194 this.rendered = false;
12196 this.render(this.parent().getChildContainer(true), k);
12207 if(Roo.isTouch && this.mobileTouchView){
12208 this.initTouchView();
12213 this.initTickableEvents();
12217 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12219 if(this.hiddenName){
12221 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12223 this.hiddenField.dom.value =
12224 this.hiddenValue !== undefined ? this.hiddenValue :
12225 this.value !== undefined ? this.value : '';
12227 // prevent input submission
12228 this.el.dom.removeAttribute('name');
12229 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12234 // this.el.dom.setAttribute('autocomplete', 'off');
12237 var cls = 'x-combo-list';
12239 //this.list = new Roo.Layer({
12240 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12246 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12247 _this.list.setWidth(lw);
12250 this.list.on('mouseover', this.onViewOver, this);
12251 this.list.on('mousemove', this.onViewMove, this);
12253 this.list.on('scroll', this.onViewScroll, this);
12256 this.list.swallowEvent('mousewheel');
12257 this.assetHeight = 0;
12260 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12261 this.assetHeight += this.header.getHeight();
12264 this.innerList = this.list.createChild({cls:cls+'-inner'});
12265 this.innerList.on('mouseover', this.onViewOver, this);
12266 this.innerList.on('mousemove', this.onViewMove, this);
12267 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12269 if(this.allowBlank && !this.pageSize && !this.disableClear){
12270 this.footer = this.list.createChild({cls:cls+'-ft'});
12271 this.pageTb = new Roo.Toolbar(this.footer);
12275 this.footer = this.list.createChild({cls:cls+'-ft'});
12276 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12277 {pageSize: this.pageSize});
12281 if (this.pageTb && this.allowBlank && !this.disableClear) {
12283 this.pageTb.add(new Roo.Toolbar.Fill(), {
12284 cls: 'x-btn-icon x-btn-clear',
12286 handler: function()
12289 _this.clearValue();
12290 _this.onSelect(false, -1);
12295 this.assetHeight += this.footer.getHeight();
12300 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12303 this.view = new Roo.View(this.list, this.tpl, {
12304 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12306 //this.view.wrapEl.setDisplayed(false);
12307 this.view.on('click', this.onViewClick, this);
12311 this.store.on('beforeload', this.onBeforeLoad, this);
12312 this.store.on('load', this.onLoad, this);
12313 this.store.on('loadexception', this.onLoadException, this);
12315 if(this.resizable){
12316 this.resizer = new Roo.Resizable(this.list, {
12317 pinned:true, handles:'se'
12319 this.resizer.on('resize', function(r, w, h){
12320 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12321 this.listWidth = w;
12322 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12323 this.restrictHeight();
12325 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12328 if(!this.editable){
12329 this.editable = true;
12330 this.setEditable(false);
12335 if (typeof(this.events.add.listeners) != 'undefined') {
12337 this.addicon = this.wrap.createChild(
12338 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12340 this.addicon.on('click', function(e) {
12341 this.fireEvent('add', this);
12344 if (typeof(this.events.edit.listeners) != 'undefined') {
12346 this.editicon = this.wrap.createChild(
12347 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12348 if (this.addicon) {
12349 this.editicon.setStyle('margin-left', '40px');
12351 this.editicon.on('click', function(e) {
12353 // we fire even if inothing is selected..
12354 this.fireEvent('edit', this, this.lastData );
12360 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12361 "up" : function(e){
12362 this.inKeyMode = true;
12366 "down" : function(e){
12367 if(!this.isExpanded()){
12368 this.onTriggerClick();
12370 this.inKeyMode = true;
12375 "enter" : function(e){
12376 // this.onViewClick();
12380 if(this.fireEvent("specialkey", this, e)){
12381 this.onViewClick(false);
12387 "esc" : function(e){
12391 "tab" : function(e){
12394 if(this.fireEvent("specialkey", this, e)){
12395 this.onViewClick(false);
12403 doRelay : function(foo, bar, hname){
12404 if(hname == 'down' || this.scope.isExpanded()){
12405 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12414 this.queryDelay = Math.max(this.queryDelay || 10,
12415 this.mode == 'local' ? 10 : 250);
12418 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12420 if(this.typeAhead){
12421 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12423 if(this.editable !== false){
12424 this.inputEl().on("keyup", this.onKeyUp, this);
12426 if(this.forceSelection){
12427 this.inputEl().on('blur', this.doForce, this);
12431 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12432 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12436 initTickableEvents: function()
12440 if(this.hiddenName){
12442 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12444 this.hiddenField.dom.value =
12445 this.hiddenValue !== undefined ? this.hiddenValue :
12446 this.value !== undefined ? this.value : '';
12448 // prevent input submission
12449 this.el.dom.removeAttribute('name');
12450 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12455 // this.list = this.el.select('ul.dropdown-menu',true).first();
12457 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12458 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12459 if(this.triggerList){
12460 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12463 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12464 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12466 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12467 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12469 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12470 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12472 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12473 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12474 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12477 this.cancelBtn.hide();
12482 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12483 _this.list.setWidth(lw);
12486 this.list.on('mouseover', this.onViewOver, this);
12487 this.list.on('mousemove', this.onViewMove, this);
12489 this.list.on('scroll', this.onViewScroll, this);
12492 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></li>';
12495 this.view = new Roo.View(this.list, this.tpl, {
12496 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12499 //this.view.wrapEl.setDisplayed(false);
12500 this.view.on('click', this.onViewClick, this);
12504 this.store.on('beforeload', this.onBeforeLoad, this);
12505 this.store.on('load', this.onLoad, this);
12506 this.store.on('loadexception', this.onLoadException, this);
12509 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12510 "up" : function(e){
12511 this.inKeyMode = true;
12515 "down" : function(e){
12516 this.inKeyMode = true;
12520 "enter" : function(e){
12521 if(this.fireEvent("specialkey", this, e)){
12522 this.onViewClick(false);
12528 "esc" : function(e){
12529 this.onTickableFooterButtonClick(e, false, false);
12532 "tab" : function(e){
12533 this.fireEvent("specialkey", this, e);
12535 this.onTickableFooterButtonClick(e, false, false);
12542 doRelay : function(e, fn, key){
12543 if(this.scope.isExpanded()){
12544 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12553 this.queryDelay = Math.max(this.queryDelay || 10,
12554 this.mode == 'local' ? 10 : 250);
12557 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12559 if(this.typeAhead){
12560 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12563 if(this.editable !== false){
12564 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12569 onDestroy : function(){
12571 this.view.setStore(null);
12572 this.view.el.removeAllListeners();
12573 this.view.el.remove();
12574 this.view.purgeListeners();
12577 this.list.dom.innerHTML = '';
12581 this.store.un('beforeload', this.onBeforeLoad, this);
12582 this.store.un('load', this.onLoad, this);
12583 this.store.un('loadexception', this.onLoadException, this);
12585 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12589 fireKey : function(e){
12590 if(e.isNavKeyPress() && !this.list.isVisible()){
12591 this.fireEvent("specialkey", this, e);
12596 onResize: function(w, h){
12597 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12599 // if(typeof w != 'number'){
12600 // // we do not handle it!?!?
12603 // var tw = this.trigger.getWidth();
12604 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12605 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12607 // this.inputEl().setWidth( this.adjustWidth('input', x));
12609 // //this.trigger.setStyle('left', x+'px');
12611 // if(this.list && this.listWidth === undefined){
12612 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12613 // this.list.setWidth(lw);
12614 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12622 * Allow or prevent the user from directly editing the field text. If false is passed,
12623 * the user will only be able to select from the items defined in the dropdown list. This method
12624 * is the runtime equivalent of setting the 'editable' config option at config time.
12625 * @param {Boolean} value True to allow the user to directly edit the field text
12627 setEditable : function(value){
12628 if(value == this.editable){
12631 this.editable = value;
12633 this.inputEl().dom.setAttribute('readOnly', true);
12634 this.inputEl().on('mousedown', this.onTriggerClick, this);
12635 this.inputEl().addClass('x-combo-noedit');
12637 this.inputEl().dom.setAttribute('readOnly', false);
12638 this.inputEl().un('mousedown', this.onTriggerClick, this);
12639 this.inputEl().removeClass('x-combo-noedit');
12645 onBeforeLoad : function(combo,opts){
12646 if(!this.hasFocus){
12650 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12652 this.restrictHeight();
12653 this.selectedIndex = -1;
12657 onLoad : function(){
12659 this.hasQuery = false;
12661 if(!this.hasFocus){
12665 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12666 this.loading.hide();
12669 if(this.store.getCount() > 0){
12671 this.restrictHeight();
12672 if(this.lastQuery == this.allQuery){
12673 if(this.editable && !this.tickable){
12674 this.inputEl().dom.select();
12678 !this.selectByValue(this.value, true) &&
12681 !this.store.lastOptions ||
12682 typeof(this.store.lastOptions.add) == 'undefined' ||
12683 this.store.lastOptions.add != true
12686 this.select(0, true);
12689 if(this.autoFocus){
12692 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12693 this.taTask.delay(this.typeAheadDelay);
12697 this.onEmptyResults();
12703 onLoadException : function()
12705 this.hasQuery = false;
12707 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12708 this.loading.hide();
12711 if(this.tickable && this.editable){
12716 // only causes errors at present
12717 //Roo.log(this.store.reader.jsonData);
12718 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12720 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12726 onTypeAhead : function(){
12727 if(this.store.getCount() > 0){
12728 var r = this.store.getAt(0);
12729 var newValue = r.data[this.displayField];
12730 var len = newValue.length;
12731 var selStart = this.getRawValue().length;
12733 if(selStart != len){
12734 this.setRawValue(newValue);
12735 this.selectText(selStart, newValue.length);
12741 onSelect : function(record, index){
12743 if(this.fireEvent('beforeselect', this, record, index) !== false){
12745 this.setFromData(index > -1 ? record.data : false);
12748 this.fireEvent('select', this, record, index);
12753 * Returns the currently selected field value or empty string if no value is set.
12754 * @return {String} value The selected value
12756 getValue : function(){
12759 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12762 if(this.valueField){
12763 return typeof this.value != 'undefined' ? this.value : '';
12765 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12770 * Clears any text/value currently set in the field
12772 clearValue : function(){
12773 if(this.hiddenField){
12774 this.hiddenField.dom.value = '';
12777 this.setRawValue('');
12778 this.lastSelectionText = '';
12779 this.lastData = false;
12781 var close = this.closeTriggerEl();
12790 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12791 * will be displayed in the field. If the value does not match the data value of an existing item,
12792 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12793 * Otherwise the field will be blank (although the value will still be set).
12794 * @param {String} value The value to match
12796 setValue : function(v){
12803 if(this.valueField){
12804 var r = this.findRecord(this.valueField, v);
12806 text = r.data[this.displayField];
12807 }else if(this.valueNotFoundText !== undefined){
12808 text = this.valueNotFoundText;
12811 this.lastSelectionText = text;
12812 if(this.hiddenField){
12813 this.hiddenField.dom.value = v;
12815 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12818 var close = this.closeTriggerEl();
12821 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12825 * @property {Object} the last set data for the element
12830 * Sets the value of the field based on a object which is related to the record format for the store.
12831 * @param {Object} value the value to set as. or false on reset?
12833 setFromData : function(o){
12840 var dv = ''; // display value
12841 var vv = ''; // value value..
12843 if (this.displayField) {
12844 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12846 // this is an error condition!!!
12847 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12850 if(this.valueField){
12851 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12854 var close = this.closeTriggerEl();
12857 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12860 if(this.hiddenField){
12861 this.hiddenField.dom.value = vv;
12863 this.lastSelectionText = dv;
12864 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12868 // no hidden field.. - we store the value in 'value', but still display
12869 // display field!!!!
12870 this.lastSelectionText = dv;
12871 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12878 reset : function(){
12879 // overridden so that last data is reset..
12886 this.setValue(this.originalValue);
12887 this.clearInvalid();
12888 this.lastData = false;
12890 this.view.clearSelections();
12894 findRecord : function(prop, value){
12896 if(this.store.getCount() > 0){
12897 this.store.each(function(r){
12898 if(r.data[prop] == value){
12908 getName: function()
12910 // returns hidden if it's set..
12911 if (!this.rendered) {return ''};
12912 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12916 onViewMove : function(e, t){
12917 this.inKeyMode = false;
12921 onViewOver : function(e, t){
12922 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12925 var item = this.view.findItemFromChild(t);
12928 var index = this.view.indexOf(item);
12929 this.select(index, false);
12934 onViewClick : function(view, doFocus, el, e)
12936 var index = this.view.getSelectedIndexes()[0];
12938 var r = this.store.getAt(index);
12942 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12949 Roo.each(this.tickItems, function(v,k){
12951 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12953 _this.tickItems.splice(k, 1);
12955 if(typeof(e) == 'undefined' && view == false){
12956 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12968 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
12969 this.tickItems.push(r.data);
12972 if(typeof(e) == 'undefined' && view == false){
12973 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12980 this.onSelect(r, index);
12982 if(doFocus !== false && !this.blockFocus){
12983 this.inputEl().focus();
12988 restrictHeight : function(){
12989 //this.innerList.dom.style.height = '';
12990 //var inner = this.innerList.dom;
12991 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12992 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12993 //this.list.beginUpdate();
12994 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12995 this.list.alignTo(this.inputEl(), this.listAlign);
12996 this.list.alignTo(this.inputEl(), this.listAlign);
12997 //this.list.endUpdate();
13001 onEmptyResults : function(){
13003 if(this.tickable && this.editable){
13004 this.restrictHeight();
13012 * Returns true if the dropdown list is expanded, else false.
13014 isExpanded : function(){
13015 return this.list.isVisible();
13019 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13020 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13021 * @param {String} value The data value of the item to select
13022 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13023 * selected item if it is not currently in view (defaults to true)
13024 * @return {Boolean} True if the value matched an item in the list, else false
13026 selectByValue : function(v, scrollIntoView){
13027 if(v !== undefined && v !== null){
13028 var r = this.findRecord(this.valueField || this.displayField, v);
13030 this.select(this.store.indexOf(r), scrollIntoView);
13038 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13039 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13040 * @param {Number} index The zero-based index of the list item to select
13041 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13042 * selected item if it is not currently in view (defaults to true)
13044 select : function(index, scrollIntoView){
13045 this.selectedIndex = index;
13046 this.view.select(index);
13047 if(scrollIntoView !== false){
13048 var el = this.view.getNode(index);
13050 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13053 this.list.scrollChildIntoView(el, false);
13059 selectNext : function(){
13060 var ct = this.store.getCount();
13062 if(this.selectedIndex == -1){
13064 }else if(this.selectedIndex < ct-1){
13065 this.select(this.selectedIndex+1);
13071 selectPrev : function(){
13072 var ct = this.store.getCount();
13074 if(this.selectedIndex == -1){
13076 }else if(this.selectedIndex != 0){
13077 this.select(this.selectedIndex-1);
13083 onKeyUp : function(e){
13084 if(this.editable !== false && !e.isSpecialKey()){
13085 this.lastKey = e.getKey();
13086 this.dqTask.delay(this.queryDelay);
13091 validateBlur : function(){
13092 return !this.list || !this.list.isVisible();
13096 initQuery : function(){
13098 var v = this.getRawValue();
13100 if(this.tickable && this.editable){
13101 v = this.tickableInputEl().getValue();
13108 doForce : function(){
13109 if(this.inputEl().dom.value.length > 0){
13110 this.inputEl().dom.value =
13111 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13117 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13118 * query allowing the query action to be canceled if needed.
13119 * @param {String} query The SQL query to execute
13120 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13121 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13122 * saved in the current store (defaults to false)
13124 doQuery : function(q, forceAll){
13126 if(q === undefined || q === null){
13131 forceAll: forceAll,
13135 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13140 forceAll = qe.forceAll;
13141 if(forceAll === true || (q.length >= this.minChars)){
13143 this.hasQuery = true;
13145 if(this.lastQuery != q || this.alwaysQuery){
13146 this.lastQuery = q;
13147 if(this.mode == 'local'){
13148 this.selectedIndex = -1;
13150 this.store.clearFilter();
13153 if(this.specialFilter){
13154 this.fireEvent('specialfilter', this);
13159 this.store.filter(this.displayField, q);
13162 this.store.fireEvent("datachanged", this.store);
13169 this.store.baseParams[this.queryParam] = q;
13171 var options = {params : this.getParams(q)};
13174 options.add = true;
13175 options.params.start = this.page * this.pageSize;
13178 this.store.load(options);
13181 * this code will make the page width larger, at the beginning, the list not align correctly,
13182 * we should expand the list on onLoad
13183 * so command out it
13188 this.selectedIndex = -1;
13193 this.loadNext = false;
13197 getParams : function(q){
13199 //p[this.queryParam] = q;
13203 p.limit = this.pageSize;
13209 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13211 collapse : function(){
13212 if(!this.isExpanded()){
13219 this.hasFocus = false;
13221 this.cancelBtn.hide();
13222 this.trigger.show();
13225 this.tickableInputEl().dom.value = '';
13226 this.tickableInputEl().blur();
13231 Roo.get(document).un('mousedown', this.collapseIf, this);
13232 Roo.get(document).un('mousewheel', this.collapseIf, this);
13233 if (!this.editable) {
13234 Roo.get(document).un('keydown', this.listKeyPress, this);
13236 this.fireEvent('collapse', this);
13240 collapseIf : function(e){
13241 var in_combo = e.within(this.el);
13242 var in_list = e.within(this.list);
13243 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13245 if (in_combo || in_list || is_list) {
13246 //e.stopPropagation();
13251 this.onTickableFooterButtonClick(e, false, false);
13259 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13261 expand : function(){
13263 if(this.isExpanded() || !this.hasFocus){
13267 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13268 this.list.setWidth(lw);
13275 this.restrictHeight();
13279 this.tickItems = Roo.apply([], this.item);
13282 this.cancelBtn.show();
13283 this.trigger.hide();
13286 this.tickableInputEl().focus();
13291 Roo.get(document).on('mousedown', this.collapseIf, this);
13292 Roo.get(document).on('mousewheel', this.collapseIf, this);
13293 if (!this.editable) {
13294 Roo.get(document).on('keydown', this.listKeyPress, this);
13297 this.fireEvent('expand', this);
13301 // Implements the default empty TriggerField.onTriggerClick function
13302 onTriggerClick : function(e)
13304 Roo.log('trigger click');
13306 if(this.disabled || !this.triggerList){
13311 this.loadNext = false;
13313 if(this.isExpanded()){
13315 if (!this.blockFocus) {
13316 this.inputEl().focus();
13320 this.hasFocus = true;
13321 if(this.triggerAction == 'all') {
13322 this.doQuery(this.allQuery, true);
13324 this.doQuery(this.getRawValue());
13326 if (!this.blockFocus) {
13327 this.inputEl().focus();
13332 onTickableTriggerClick : function(e)
13339 this.loadNext = false;
13340 this.hasFocus = true;
13342 if(this.triggerAction == 'all') {
13343 this.doQuery(this.allQuery, true);
13345 this.doQuery(this.getRawValue());
13349 onSearchFieldClick : function(e)
13351 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13352 this.onTickableFooterButtonClick(e, false, false);
13356 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13361 this.loadNext = false;
13362 this.hasFocus = true;
13364 if(this.triggerAction == 'all') {
13365 this.doQuery(this.allQuery, true);
13367 this.doQuery(this.getRawValue());
13371 listKeyPress : function(e)
13373 //Roo.log('listkeypress');
13374 // scroll to first matching element based on key pres..
13375 if (e.isSpecialKey()) {
13378 var k = String.fromCharCode(e.getKey()).toUpperCase();
13381 var csel = this.view.getSelectedNodes();
13382 var cselitem = false;
13384 var ix = this.view.indexOf(csel[0]);
13385 cselitem = this.store.getAt(ix);
13386 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13392 this.store.each(function(v) {
13394 // start at existing selection.
13395 if (cselitem.id == v.id) {
13401 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13402 match = this.store.indexOf(v);
13408 if (match === false) {
13409 return true; // no more action?
13412 this.view.select(match);
13413 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13414 sn.scrollIntoView(sn.dom.parentNode, false);
13417 onViewScroll : function(e, t){
13419 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){
13423 this.hasQuery = true;
13425 this.loading = this.list.select('.loading', true).first();
13427 if(this.loading === null){
13428 this.list.createChild({
13430 cls: 'loading roo-select2-more-results roo-select2-active',
13431 html: 'Loading more results...'
13434 this.loading = this.list.select('.loading', true).first();
13436 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13438 this.loading.hide();
13441 this.loading.show();
13446 this.loadNext = true;
13448 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13453 addItem : function(o)
13455 var dv = ''; // display value
13457 if (this.displayField) {
13458 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13460 // this is an error condition!!!
13461 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13468 var choice = this.choices.createChild({
13470 cls: 'roo-select2-search-choice',
13479 cls: 'roo-select2-search-choice-close',
13484 }, this.searchField);
13486 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13488 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13496 this.inputEl().dom.value = '';
13501 onRemoveItem : function(e, _self, o)
13503 e.preventDefault();
13505 this.lastItem = Roo.apply([], this.item);
13507 var index = this.item.indexOf(o.data) * 1;
13510 Roo.log('not this item?!');
13514 this.item.splice(index, 1);
13519 this.fireEvent('remove', this, e);
13525 syncValue : function()
13527 if(!this.item.length){
13534 Roo.each(this.item, function(i){
13535 if(_this.valueField){
13536 value.push(i[_this.valueField]);
13543 this.value = value.join(',');
13545 if(this.hiddenField){
13546 this.hiddenField.dom.value = this.value;
13549 this.store.fireEvent("datachanged", this.store);
13552 clearItem : function()
13554 if(!this.multiple){
13560 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13568 if(this.tickable && !Roo.isTouch){
13569 this.view.refresh();
13573 inputEl: function ()
13575 if(Roo.isTouch && this.mobileTouchView){
13576 return this.el.select('input.form-control',true).first();
13580 return this.searchField;
13583 return this.el.select('input.form-control',true).first();
13587 onTickableFooterButtonClick : function(e, btn, el)
13589 e.preventDefault();
13591 this.lastItem = Roo.apply([], this.item);
13593 if(btn && btn.name == 'cancel'){
13594 this.tickItems = Roo.apply([], this.item);
13603 Roo.each(this.tickItems, function(o){
13611 validate : function()
13613 var v = this.getRawValue();
13616 v = this.getValue();
13619 if(this.disabled || this.allowBlank || v.length){
13624 this.markInvalid();
13628 tickableInputEl : function()
13630 if(!this.tickable || !this.editable){
13631 return this.inputEl();
13634 return this.inputEl().select('.roo-select2-search-field-input', true).first();
13638 getAutoCreateTouchView : function()
13643 cls: 'form-group' //input-group
13649 type : this.inputType,
13650 cls : 'form-control x-combo-noedit',
13651 autocomplete: 'new-password',
13652 placeholder : this.placeholder || '',
13657 input.name = this.name;
13661 input.cls += ' input-' + this.size;
13664 if (this.disabled) {
13665 input.disabled = true;
13676 inputblock.cls += ' input-group';
13678 inputblock.cn.unshift({
13680 cls : 'input-group-addon',
13685 if(this.removable && !this.multiple){
13686 inputblock.cls += ' roo-removable';
13688 inputblock.cn.push({
13691 cls : 'roo-combo-removable-btn close'
13695 if(this.hasFeedback && !this.allowBlank){
13697 inputblock.cls += ' has-feedback';
13699 inputblock.cn.push({
13701 cls: 'glyphicon form-control-feedback'
13708 inputblock.cls += (this.before) ? '' : ' input-group';
13710 inputblock.cn.push({
13712 cls : 'input-group-addon',
13723 cls: 'form-hidden-field'
13737 cls: 'form-hidden-field'
13741 cls: 'roo-select2-choices',
13745 cls: 'roo-select2-search-field',
13758 cls: 'roo-select2-container input-group',
13765 combobox.cls += ' roo-select2-container-multi';
13768 var align = this.labelAlign || this.parentLabelAlign();
13772 if(this.fieldLabel.length){
13774 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13775 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13780 cls : 'control-label ' + lw,
13781 html : this.fieldLabel
13793 var settings = this;
13795 ['xs','sm','md','lg'].map(function(size){
13796 if (settings[size]) {
13797 cfg.cls += ' col-' + size + '-' + settings[size];
13804 initTouchView : function()
13806 this.renderTouchView();
13808 this.touchViewEl.on('scroll', function(){
13809 this.el.dom.scrollTop = 0;
13812 this.originalValue = this.getValue();
13814 this.inputEl().on("click", this.showTouchView, this);
13816 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13817 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13819 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13821 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13822 this.store.on('load', this.onTouchViewLoad, this);
13823 this.store.on('loadexception', this.onTouchViewLoadException, this);
13825 if(this.hiddenName){
13827 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13829 this.hiddenField.dom.value =
13830 this.hiddenValue !== undefined ? this.hiddenValue :
13831 this.value !== undefined ? this.value : '';
13833 this.el.dom.removeAttribute('name');
13834 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13838 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13839 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13842 if(this.removable && !this.multiple){
13843 var close = this.closeTriggerEl();
13845 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13846 close.on('click', this.removeBtnClick, this, close);
13850 * fix the bug in Safari iOS8
13852 this.inputEl().on("focus", function(e){
13853 document.activeElement.blur();
13861 renderTouchView : function()
13863 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13864 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13866 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13867 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13869 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13870 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13871 this.touchViewBodyEl.setStyle('overflow', 'auto');
13873 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13874 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13876 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13877 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13881 showTouchView : function()
13887 this.touchViewHeaderEl.hide();
13889 if(this.fieldLabel.length){
13890 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13891 this.touchViewHeaderEl.show();
13894 this.touchViewEl.show();
13896 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13897 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13899 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13901 if(this.fieldLabel.length){
13902 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13905 this.touchViewBodyEl.setHeight(bodyHeight);
13909 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13911 this.touchViewEl.addClass('in');
13914 this.doTouchViewQuery();
13918 hideTouchView : function()
13920 this.touchViewEl.removeClass('in');
13924 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13926 this.touchViewEl.setStyle('display', 'none');
13931 setTouchViewValue : function()
13938 Roo.each(this.tickItems, function(o){
13943 this.hideTouchView();
13946 doTouchViewQuery : function()
13955 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
13959 if(!this.alwaysQuery || this.mode == 'local'){
13960 this.onTouchViewLoad();
13967 onTouchViewBeforeLoad : function(combo,opts)
13973 onTouchViewLoad : function()
13975 if(this.store.getCount() < 1){
13976 this.onTouchViewEmptyResults();
13980 this.clearTouchView();
13982 var rawValue = this.getRawValue();
13984 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
13986 this.tickItems = [];
13988 this.store.data.each(function(d, rowIndex){
13989 var row = this.touchViewListGroup.createChild(template);
13991 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
13992 row.addClass(d.data.cls);
13995 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
13998 html : d.data[this.displayField]
14001 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14002 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14006 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
14007 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14010 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
14011 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14012 this.tickItems.push(d.data);
14015 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14019 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14021 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14023 if(this.fieldLabel.length){
14024 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14027 var listHeight = this.touchViewListGroup.getHeight();
14031 if(firstChecked && listHeight > bodyHeight){
14032 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14037 onTouchViewLoadException : function()
14039 this.hideTouchView();
14042 onTouchViewEmptyResults : function()
14044 this.clearTouchView();
14046 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14048 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14052 clearTouchView : function()
14054 this.touchViewListGroup.dom.innerHTML = '';
14057 onTouchViewClick : function(e, el, o)
14059 e.preventDefault();
14062 var rowIndex = o.rowIndex;
14064 var r = this.store.getAt(rowIndex);
14066 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14068 if(!this.multiple){
14069 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14070 c.dom.removeAttribute('checked');
14073 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14075 this.setFromData(r.data);
14077 var close = this.closeTriggerEl();
14083 this.hideTouchView();
14085 this.fireEvent('select', this, r, rowIndex);
14090 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14091 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14092 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14096 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14097 this.addItem(r.data);
14098 this.tickItems.push(r.data);
14104 * @cfg {Boolean} grow
14108 * @cfg {Number} growMin
14112 * @cfg {Number} growMax
14121 Roo.apply(Roo.bootstrap.ComboBox, {
14125 cls: 'modal-header',
14147 cls: 'list-group-item',
14151 cls: 'roo-combobox-list-group-item-value'
14155 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14169 listItemCheckbox : {
14171 cls: 'list-group-item',
14175 cls: 'roo-combobox-list-group-item-value'
14179 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14195 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14200 cls: 'modal-footer',
14208 cls: 'col-xs-6 text-left',
14211 cls: 'btn btn-danger roo-touch-view-cancel',
14217 cls: 'col-xs-6 text-right',
14220 cls: 'btn btn-success roo-touch-view-ok',
14231 Roo.apply(Roo.bootstrap.ComboBox, {
14233 touchViewTemplate : {
14235 cls: 'modal fade roo-combobox-touch-view',
14239 cls: 'modal-dialog',
14240 style : 'position:fixed', // we have to fix position....
14244 cls: 'modal-content',
14246 Roo.bootstrap.ComboBox.header,
14247 Roo.bootstrap.ComboBox.body,
14248 Roo.bootstrap.ComboBox.footer
14257 * Ext JS Library 1.1.1
14258 * Copyright(c) 2006-2007, Ext JS, LLC.
14260 * Originally Released Under LGPL - original licence link has changed is not relivant.
14263 * <script type="text/javascript">
14268 * @extends Roo.util.Observable
14269 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14270 * This class also supports single and multi selection modes. <br>
14271 * Create a data model bound view:
14273 var store = new Roo.data.Store(...);
14275 var view = new Roo.View({
14277 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14279 singleSelect: true,
14280 selectedClass: "ydataview-selected",
14284 // listen for node click?
14285 view.on("click", function(vw, index, node, e){
14286 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14290 dataModel.load("foobar.xml");
14292 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14294 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14295 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14297 * Note: old style constructor is still suported (container, template, config)
14300 * Create a new View
14301 * @param {Object} config The config object
14304 Roo.View = function(config, depreciated_tpl, depreciated_config){
14306 this.parent = false;
14308 if (typeof(depreciated_tpl) == 'undefined') {
14309 // new way.. - universal constructor.
14310 Roo.apply(this, config);
14311 this.el = Roo.get(this.el);
14314 this.el = Roo.get(config);
14315 this.tpl = depreciated_tpl;
14316 Roo.apply(this, depreciated_config);
14318 this.wrapEl = this.el.wrap().wrap();
14319 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14322 if(typeof(this.tpl) == "string"){
14323 this.tpl = new Roo.Template(this.tpl);
14325 // support xtype ctors..
14326 this.tpl = new Roo.factory(this.tpl, Roo);
14330 this.tpl.compile();
14335 * @event beforeclick
14336 * Fires before a click is processed. Returns false to cancel the default action.
14337 * @param {Roo.View} this
14338 * @param {Number} index The index of the target node
14339 * @param {HTMLElement} node The target node
14340 * @param {Roo.EventObject} e The raw event object
14342 "beforeclick" : true,
14345 * Fires when a template node is clicked.
14346 * @param {Roo.View} this
14347 * @param {Number} index The index of the target node
14348 * @param {HTMLElement} node The target node
14349 * @param {Roo.EventObject} e The raw event object
14354 * Fires when a template node is double clicked.
14355 * @param {Roo.View} this
14356 * @param {Number} index The index of the target node
14357 * @param {HTMLElement} node The target node
14358 * @param {Roo.EventObject} e The raw event object
14362 * @event contextmenu
14363 * Fires when a template node is right clicked.
14364 * @param {Roo.View} this
14365 * @param {Number} index The index of the target node
14366 * @param {HTMLElement} node The target node
14367 * @param {Roo.EventObject} e The raw event object
14369 "contextmenu" : true,
14371 * @event selectionchange
14372 * Fires when the selected nodes change.
14373 * @param {Roo.View} this
14374 * @param {Array} selections Array of the selected nodes
14376 "selectionchange" : true,
14379 * @event beforeselect
14380 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14381 * @param {Roo.View} this
14382 * @param {HTMLElement} node The node to be selected
14383 * @param {Array} selections Array of currently selected nodes
14385 "beforeselect" : true,
14387 * @event preparedata
14388 * Fires on every row to render, to allow you to change the data.
14389 * @param {Roo.View} this
14390 * @param {Object} data to be rendered (change this)
14392 "preparedata" : true
14400 "click": this.onClick,
14401 "dblclick": this.onDblClick,
14402 "contextmenu": this.onContextMenu,
14406 this.selections = [];
14408 this.cmp = new Roo.CompositeElementLite([]);
14410 this.store = Roo.factory(this.store, Roo.data);
14411 this.setStore(this.store, true);
14414 if ( this.footer && this.footer.xtype) {
14416 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14418 this.footer.dataSource = this.store;
14419 this.footer.container = fctr;
14420 this.footer = Roo.factory(this.footer, Roo);
14421 fctr.insertFirst(this.el);
14423 // this is a bit insane - as the paging toolbar seems to detach the el..
14424 // dom.parentNode.parentNode.parentNode
14425 // they get detached?
14429 Roo.View.superclass.constructor.call(this);
14434 Roo.extend(Roo.View, Roo.util.Observable, {
14437 * @cfg {Roo.data.Store} store Data store to load data from.
14442 * @cfg {String|Roo.Element} el The container element.
14447 * @cfg {String|Roo.Template} tpl The template used by this View
14451 * @cfg {String} dataName the named area of the template to use as the data area
14452 * Works with domtemplates roo-name="name"
14456 * @cfg {String} selectedClass The css class to add to selected nodes
14458 selectedClass : "x-view-selected",
14460 * @cfg {String} emptyText The empty text to show when nothing is loaded.
14465 * @cfg {String} text to display on mask (default Loading)
14469 * @cfg {Boolean} multiSelect Allow multiple selection
14471 multiSelect : false,
14473 * @cfg {Boolean} singleSelect Allow single selection
14475 singleSelect: false,
14478 * @cfg {Boolean} toggleSelect - selecting
14480 toggleSelect : false,
14483 * @cfg {Boolean} tickable - selecting
14488 * Returns the element this view is bound to.
14489 * @return {Roo.Element}
14491 getEl : function(){
14492 return this.wrapEl;
14498 * Refreshes the view. - called by datachanged on the store. - do not call directly.
14500 refresh : function(){
14501 //Roo.log('refresh');
14504 // if we are using something like 'domtemplate', then
14505 // the what gets used is:
14506 // t.applySubtemplate(NAME, data, wrapping data..)
14507 // the outer template then get' applied with
14508 // the store 'extra data'
14509 // and the body get's added to the
14510 // roo-name="data" node?
14511 // <span class='roo-tpl-{name}'></span> ?????
14515 this.clearSelections();
14516 this.el.update("");
14518 var records = this.store.getRange();
14519 if(records.length < 1) {
14521 // is this valid?? = should it render a template??
14523 this.el.update(this.emptyText);
14527 if (this.dataName) {
14528 this.el.update(t.apply(this.store.meta)); //????
14529 el = this.el.child('.roo-tpl-' + this.dataName);
14532 for(var i = 0, len = records.length; i < len; i++){
14533 var data = this.prepareData(records[i].data, i, records[i]);
14534 this.fireEvent("preparedata", this, data, i, records[i]);
14536 var d = Roo.apply({}, data);
14539 Roo.apply(d, {'roo-id' : Roo.id()});
14543 Roo.each(this.parent.item, function(item){
14544 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
14547 Roo.apply(d, {'roo-data-checked' : 'checked'});
14551 html[html.length] = Roo.util.Format.trim(
14553 t.applySubtemplate(this.dataName, d, this.store.meta) :
14560 el.update(html.join(""));
14561 this.nodes = el.dom.childNodes;
14562 this.updateIndexes(0);
14567 * Function to override to reformat the data that is sent to
14568 * the template for each node.
14569 * DEPRICATED - use the preparedata event handler.
14570 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
14571 * a JSON object for an UpdateManager bound view).
14573 prepareData : function(data, index, record)
14575 this.fireEvent("preparedata", this, data, index, record);
14579 onUpdate : function(ds, record){
14580 // Roo.log('on update');
14581 this.clearSelections();
14582 var index = this.store.indexOf(record);
14583 var n = this.nodes[index];
14584 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
14585 n.parentNode.removeChild(n);
14586 this.updateIndexes(index, index);
14592 onAdd : function(ds, records, index)
14594 //Roo.log(['on Add', ds, records, index] );
14595 this.clearSelections();
14596 if(this.nodes.length == 0){
14600 var n = this.nodes[index];
14601 for(var i = 0, len = records.length; i < len; i++){
14602 var d = this.prepareData(records[i].data, i, records[i]);
14604 this.tpl.insertBefore(n, d);
14607 this.tpl.append(this.el, d);
14610 this.updateIndexes(index);
14613 onRemove : function(ds, record, index){
14614 // Roo.log('onRemove');
14615 this.clearSelections();
14616 var el = this.dataName ?
14617 this.el.child('.roo-tpl-' + this.dataName) :
14620 el.dom.removeChild(this.nodes[index]);
14621 this.updateIndexes(index);
14625 * Refresh an individual node.
14626 * @param {Number} index
14628 refreshNode : function(index){
14629 this.onUpdate(this.store, this.store.getAt(index));
14632 updateIndexes : function(startIndex, endIndex){
14633 var ns = this.nodes;
14634 startIndex = startIndex || 0;
14635 endIndex = endIndex || ns.length - 1;
14636 for(var i = startIndex; i <= endIndex; i++){
14637 ns[i].nodeIndex = i;
14642 * Changes the data store this view uses and refresh the view.
14643 * @param {Store} store
14645 setStore : function(store, initial){
14646 if(!initial && this.store){
14647 this.store.un("datachanged", this.refresh);
14648 this.store.un("add", this.onAdd);
14649 this.store.un("remove", this.onRemove);
14650 this.store.un("update", this.onUpdate);
14651 this.store.un("clear", this.refresh);
14652 this.store.un("beforeload", this.onBeforeLoad);
14653 this.store.un("load", this.onLoad);
14654 this.store.un("loadexception", this.onLoad);
14658 store.on("datachanged", this.refresh, this);
14659 store.on("add", this.onAdd, this);
14660 store.on("remove", this.onRemove, this);
14661 store.on("update", this.onUpdate, this);
14662 store.on("clear", this.refresh, this);
14663 store.on("beforeload", this.onBeforeLoad, this);
14664 store.on("load", this.onLoad, this);
14665 store.on("loadexception", this.onLoad, this);
14673 * onbeforeLoad - masks the loading area.
14676 onBeforeLoad : function(store,opts)
14678 //Roo.log('onBeforeLoad');
14680 this.el.update("");
14682 this.el.mask(this.mask ? this.mask : "Loading" );
14684 onLoad : function ()
14691 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
14692 * @param {HTMLElement} node
14693 * @return {HTMLElement} The template node
14695 findItemFromChild : function(node){
14696 var el = this.dataName ?
14697 this.el.child('.roo-tpl-' + this.dataName,true) :
14700 if(!node || node.parentNode == el){
14703 var p = node.parentNode;
14704 while(p && p != el){
14705 if(p.parentNode == el){
14714 onClick : function(e){
14715 var item = this.findItemFromChild(e.getTarget());
14717 var index = this.indexOf(item);
14718 if(this.onItemClick(item, index, e) !== false){
14719 this.fireEvent("click", this, index, item, e);
14722 this.clearSelections();
14727 onContextMenu : function(e){
14728 var item = this.findItemFromChild(e.getTarget());
14730 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14735 onDblClick : function(e){
14736 var item = this.findItemFromChild(e.getTarget());
14738 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14742 onItemClick : function(item, index, e)
14744 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14747 if (this.toggleSelect) {
14748 var m = this.isSelected(item) ? 'unselect' : 'select';
14751 _t[m](item, true, false);
14754 if(this.multiSelect || this.singleSelect){
14755 if(this.multiSelect && e.shiftKey && this.lastSelection){
14756 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14758 this.select(item, this.multiSelect && e.ctrlKey);
14759 this.lastSelection = item;
14762 if(!this.tickable){
14763 e.preventDefault();
14771 * Get the number of selected nodes.
14774 getSelectionCount : function(){
14775 return this.selections.length;
14779 * Get the currently selected nodes.
14780 * @return {Array} An array of HTMLElements
14782 getSelectedNodes : function(){
14783 return this.selections;
14787 * Get the indexes of the selected nodes.
14790 getSelectedIndexes : function(){
14791 var indexes = [], s = this.selections;
14792 for(var i = 0, len = s.length; i < len; i++){
14793 indexes.push(s[i].nodeIndex);
14799 * Clear all selections
14800 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14802 clearSelections : function(suppressEvent){
14803 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14804 this.cmp.elements = this.selections;
14805 this.cmp.removeClass(this.selectedClass);
14806 this.selections = [];
14807 if(!suppressEvent){
14808 this.fireEvent("selectionchange", this, this.selections);
14814 * Returns true if the passed node is selected
14815 * @param {HTMLElement/Number} node The node or node index
14816 * @return {Boolean}
14818 isSelected : function(node){
14819 var s = this.selections;
14823 node = this.getNode(node);
14824 return s.indexOf(node) !== -1;
14829 * @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
14830 * @param {Boolean} keepExisting (optional) true to keep existing selections
14831 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14833 select : function(nodeInfo, keepExisting, suppressEvent){
14834 if(nodeInfo instanceof Array){
14836 this.clearSelections(true);
14838 for(var i = 0, len = nodeInfo.length; i < len; i++){
14839 this.select(nodeInfo[i], true, true);
14843 var node = this.getNode(nodeInfo);
14844 if(!node || this.isSelected(node)){
14845 return; // already selected.
14848 this.clearSelections(true);
14851 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14852 Roo.fly(node).addClass(this.selectedClass);
14853 this.selections.push(node);
14854 if(!suppressEvent){
14855 this.fireEvent("selectionchange", this, this.selections);
14863 * @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
14864 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14865 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14867 unselect : function(nodeInfo, keepExisting, suppressEvent)
14869 if(nodeInfo instanceof Array){
14870 Roo.each(this.selections, function(s) {
14871 this.unselect(s, nodeInfo);
14875 var node = this.getNode(nodeInfo);
14876 if(!node || !this.isSelected(node)){
14877 //Roo.log("not selected");
14878 return; // not selected.
14882 Roo.each(this.selections, function(s) {
14884 Roo.fly(node).removeClass(this.selectedClass);
14891 this.selections= ns;
14892 this.fireEvent("selectionchange", this, this.selections);
14896 * Gets a template node.
14897 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14898 * @return {HTMLElement} The node or null if it wasn't found
14900 getNode : function(nodeInfo){
14901 if(typeof nodeInfo == "string"){
14902 return document.getElementById(nodeInfo);
14903 }else if(typeof nodeInfo == "number"){
14904 return this.nodes[nodeInfo];
14910 * Gets a range template nodes.
14911 * @param {Number} startIndex
14912 * @param {Number} endIndex
14913 * @return {Array} An array of nodes
14915 getNodes : function(start, end){
14916 var ns = this.nodes;
14917 start = start || 0;
14918 end = typeof end == "undefined" ? ns.length - 1 : end;
14921 for(var i = start; i <= end; i++){
14925 for(var i = start; i >= end; i--){
14933 * Finds the index of the passed node
14934 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14935 * @return {Number} The index of the node or -1
14937 indexOf : function(node){
14938 node = this.getNode(node);
14939 if(typeof node.nodeIndex == "number"){
14940 return node.nodeIndex;
14942 var ns = this.nodes;
14943 for(var i = 0, len = ns.length; i < len; i++){
14954 * based on jquery fullcalendar
14958 Roo.bootstrap = Roo.bootstrap || {};
14960 * @class Roo.bootstrap.Calendar
14961 * @extends Roo.bootstrap.Component
14962 * Bootstrap Calendar class
14963 * @cfg {Boolean} loadMask (true|false) default false
14964 * @cfg {Object} header generate the user specific header of the calendar, default false
14967 * Create a new Container
14968 * @param {Object} config The config object
14973 Roo.bootstrap.Calendar = function(config){
14974 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
14978 * Fires when a date is selected
14979 * @param {DatePicker} this
14980 * @param {Date} date The selected date
14984 * @event monthchange
14985 * Fires when the displayed month changes
14986 * @param {DatePicker} this
14987 * @param {Date} date The selected month
14989 'monthchange': true,
14991 * @event evententer
14992 * Fires when mouse over an event
14993 * @param {Calendar} this
14994 * @param {event} Event
14996 'evententer': true,
14998 * @event eventleave
14999 * Fires when the mouse leaves an
15000 * @param {Calendar} this
15003 'eventleave': true,
15005 * @event eventclick
15006 * Fires when the mouse click an
15007 * @param {Calendar} this
15016 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15019 * @cfg {Number} startDay
15020 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15028 getAutoCreate : function(){
15031 var fc_button = function(name, corner, style, content ) {
15032 return Roo.apply({},{
15034 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15036 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15039 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15050 style : 'width:100%',
15057 cls : 'fc-header-left',
15059 fc_button('prev', 'left', 'arrow', '‹' ),
15060 fc_button('next', 'right', 'arrow', '›' ),
15061 { tag: 'span', cls: 'fc-header-space' },
15062 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15070 cls : 'fc-header-center',
15074 cls: 'fc-header-title',
15077 html : 'month / year'
15085 cls : 'fc-header-right',
15087 /* fc_button('month', 'left', '', 'month' ),
15088 fc_button('week', '', '', 'week' ),
15089 fc_button('day', 'right', '', 'day' )
15101 header = this.header;
15104 var cal_heads = function() {
15106 // fixme - handle this.
15108 for (var i =0; i < Date.dayNames.length; i++) {
15109 var d = Date.dayNames[i];
15112 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15113 html : d.substring(0,3)
15117 ret[0].cls += ' fc-first';
15118 ret[6].cls += ' fc-last';
15121 var cal_cell = function(n) {
15124 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15129 cls: 'fc-day-number',
15133 cls: 'fc-day-content',
15137 style: 'position: relative;' // height: 17px;
15149 var cal_rows = function() {
15152 for (var r = 0; r < 6; r++) {
15159 for (var i =0; i < Date.dayNames.length; i++) {
15160 var d = Date.dayNames[i];
15161 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15164 row.cn[0].cls+=' fc-first';
15165 row.cn[0].cn[0].style = 'min-height:90px';
15166 row.cn[6].cls+=' fc-last';
15170 ret[0].cls += ' fc-first';
15171 ret[4].cls += ' fc-prev-last';
15172 ret[5].cls += ' fc-last';
15179 cls: 'fc-border-separate',
15180 style : 'width:100%',
15188 cls : 'fc-first fc-last',
15206 cls : 'fc-content',
15207 style : "position: relative;",
15210 cls : 'fc-view fc-view-month fc-grid',
15211 style : 'position: relative',
15212 unselectable : 'on',
15215 cls : 'fc-event-container',
15216 style : 'position:absolute;z-index:8;top:0;left:0;'
15234 initEvents : function()
15237 throw "can not find store for calendar";
15243 style: "text-align:center",
15247 style: "background-color:white;width:50%;margin:250 auto",
15251 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15262 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15264 var size = this.el.select('.fc-content', true).first().getSize();
15265 this.maskEl.setSize(size.width, size.height);
15266 this.maskEl.enableDisplayMode("block");
15267 if(!this.loadMask){
15268 this.maskEl.hide();
15271 this.store = Roo.factory(this.store, Roo.data);
15272 this.store.on('load', this.onLoad, this);
15273 this.store.on('beforeload', this.onBeforeLoad, this);
15277 this.cells = this.el.select('.fc-day',true);
15278 //Roo.log(this.cells);
15279 this.textNodes = this.el.query('.fc-day-number');
15280 this.cells.addClassOnOver('fc-state-hover');
15282 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15283 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15284 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15285 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15287 this.on('monthchange', this.onMonthChange, this);
15289 this.update(new Date().clearTime());
15292 resize : function() {
15293 var sz = this.el.getSize();
15295 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15296 this.el.select('.fc-day-content div',true).setHeight(34);
15301 showPrevMonth : function(e){
15302 this.update(this.activeDate.add("mo", -1));
15304 showToday : function(e){
15305 this.update(new Date().clearTime());
15308 showNextMonth : function(e){
15309 this.update(this.activeDate.add("mo", 1));
15313 showPrevYear : function(){
15314 this.update(this.activeDate.add("y", -1));
15318 showNextYear : function(){
15319 this.update(this.activeDate.add("y", 1));
15324 update : function(date)
15326 var vd = this.activeDate;
15327 this.activeDate = date;
15328 // if(vd && this.el){
15329 // var t = date.getTime();
15330 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15331 // Roo.log('using add remove');
15333 // this.fireEvent('monthchange', this, date);
15335 // this.cells.removeClass("fc-state-highlight");
15336 // this.cells.each(function(c){
15337 // if(c.dateValue == t){
15338 // c.addClass("fc-state-highlight");
15339 // setTimeout(function(){
15340 // try{c.dom.firstChild.focus();}catch(e){}
15350 var days = date.getDaysInMonth();
15352 var firstOfMonth = date.getFirstDateOfMonth();
15353 var startingPos = firstOfMonth.getDay()-this.startDay;
15355 if(startingPos < this.startDay){
15359 var pm = date.add(Date.MONTH, -1);
15360 var prevStart = pm.getDaysInMonth()-startingPos;
15362 this.cells = this.el.select('.fc-day',true);
15363 this.textNodes = this.el.query('.fc-day-number');
15364 this.cells.addClassOnOver('fc-state-hover');
15366 var cells = this.cells.elements;
15367 var textEls = this.textNodes;
15369 Roo.each(cells, function(cell){
15370 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15373 days += startingPos;
15375 // convert everything to numbers so it's fast
15376 var day = 86400000;
15377 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15380 //Roo.log(prevStart);
15382 var today = new Date().clearTime().getTime();
15383 var sel = date.clearTime().getTime();
15384 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15385 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15386 var ddMatch = this.disabledDatesRE;
15387 var ddText = this.disabledDatesText;
15388 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15389 var ddaysText = this.disabledDaysText;
15390 var format = this.format;
15392 var setCellClass = function(cal, cell){
15396 //Roo.log('set Cell Class');
15398 var t = d.getTime();
15402 cell.dateValue = t;
15404 cell.className += " fc-today";
15405 cell.className += " fc-state-highlight";
15406 cell.title = cal.todayText;
15409 // disable highlight in other month..
15410 //cell.className += " fc-state-highlight";
15415 cell.className = " fc-state-disabled";
15416 cell.title = cal.minText;
15420 cell.className = " fc-state-disabled";
15421 cell.title = cal.maxText;
15425 if(ddays.indexOf(d.getDay()) != -1){
15426 cell.title = ddaysText;
15427 cell.className = " fc-state-disabled";
15430 if(ddMatch && format){
15431 var fvalue = d.dateFormat(format);
15432 if(ddMatch.test(fvalue)){
15433 cell.title = ddText.replace("%0", fvalue);
15434 cell.className = " fc-state-disabled";
15438 if (!cell.initialClassName) {
15439 cell.initialClassName = cell.dom.className;
15442 cell.dom.className = cell.initialClassName + ' ' + cell.className;
15447 for(; i < startingPos; i++) {
15448 textEls[i].innerHTML = (++prevStart);
15449 d.setDate(d.getDate()+1);
15451 cells[i].className = "fc-past fc-other-month";
15452 setCellClass(this, cells[i]);
15457 for(; i < days; i++){
15458 intDay = i - startingPos + 1;
15459 textEls[i].innerHTML = (intDay);
15460 d.setDate(d.getDate()+1);
15462 cells[i].className = ''; // "x-date-active";
15463 setCellClass(this, cells[i]);
15467 for(; i < 42; i++) {
15468 textEls[i].innerHTML = (++extraDays);
15469 d.setDate(d.getDate()+1);
15471 cells[i].className = "fc-future fc-other-month";
15472 setCellClass(this, cells[i]);
15475 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
15477 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
15479 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
15480 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
15482 if(totalRows != 6){
15483 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
15484 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
15487 this.fireEvent('monthchange', this, date);
15491 if(!this.internalRender){
15492 var main = this.el.dom.firstChild;
15493 var w = main.offsetWidth;
15494 this.el.setWidth(w + this.el.getBorderWidth("lr"));
15495 Roo.fly(main).setWidth(w);
15496 this.internalRender = true;
15497 // opera does not respect the auto grow header center column
15498 // then, after it gets a width opera refuses to recalculate
15499 // without a second pass
15500 if(Roo.isOpera && !this.secondPass){
15501 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
15502 this.secondPass = true;
15503 this.update.defer(10, this, [date]);
15510 findCell : function(dt) {
15511 dt = dt.clearTime().getTime();
15513 this.cells.each(function(c){
15514 //Roo.log("check " +c.dateValue + '?=' + dt);
15515 if(c.dateValue == dt){
15525 findCells : function(ev) {
15526 var s = ev.start.clone().clearTime().getTime();
15528 var e= ev.end.clone().clearTime().getTime();
15531 this.cells.each(function(c){
15532 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
15534 if(c.dateValue > e){
15537 if(c.dateValue < s){
15546 // findBestRow: function(cells)
15550 // for (var i =0 ; i < cells.length;i++) {
15551 // ret = Math.max(cells[i].rows || 0,ret);
15558 addItem : function(ev)
15560 // look for vertical location slot in
15561 var cells = this.findCells(ev);
15563 // ev.row = this.findBestRow(cells);
15565 // work out the location.
15569 for(var i =0; i < cells.length; i++) {
15571 cells[i].row = cells[0].row;
15574 cells[i].row = cells[i].row + 1;
15584 if (crow.start.getY() == cells[i].getY()) {
15586 crow.end = cells[i];
15603 cells[0].events.push(ev);
15605 this.calevents.push(ev);
15608 clearEvents: function() {
15610 if(!this.calevents){
15614 Roo.each(this.cells.elements, function(c){
15620 Roo.each(this.calevents, function(e) {
15621 Roo.each(e.els, function(el) {
15622 el.un('mouseenter' ,this.onEventEnter, this);
15623 el.un('mouseleave' ,this.onEventLeave, this);
15628 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
15634 renderEvents: function()
15638 this.cells.each(function(c) {
15647 if(c.row != c.events.length){
15648 r = 4 - (4 - (c.row - c.events.length));
15651 c.events = ev.slice(0, r);
15652 c.more = ev.slice(r);
15654 if(c.more.length && c.more.length == 1){
15655 c.events.push(c.more.pop());
15658 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
15662 this.cells.each(function(c) {
15664 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
15667 for (var e = 0; e < c.events.length; e++){
15668 var ev = c.events[e];
15669 var rows = ev.rows;
15671 for(var i = 0; i < rows.length; i++) {
15673 // how many rows should it span..
15676 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
15677 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
15679 unselectable : "on",
15682 cls: 'fc-event-inner',
15686 // cls: 'fc-event-time',
15687 // html : cells.length > 1 ? '' : ev.time
15691 cls: 'fc-event-title',
15692 html : String.format('{0}', ev.title)
15699 cls: 'ui-resizable-handle ui-resizable-e',
15700 html : '  '
15707 cfg.cls += ' fc-event-start';
15709 if ((i+1) == rows.length) {
15710 cfg.cls += ' fc-event-end';
15713 var ctr = _this.el.select('.fc-event-container',true).first();
15714 var cg = ctr.createChild(cfg);
15716 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
15717 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
15719 var r = (c.more.length) ? 1 : 0;
15720 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
15721 cg.setWidth(ebox.right - sbox.x -2);
15723 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
15724 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
15725 cg.on('click', _this.onEventClick, _this, ev);
15736 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15737 style : 'position: absolute',
15738 unselectable : "on",
15741 cls: 'fc-event-inner',
15745 cls: 'fc-event-title',
15753 cls: 'ui-resizable-handle ui-resizable-e',
15754 html : '  '
15760 var ctr = _this.el.select('.fc-event-container',true).first();
15761 var cg = ctr.createChild(cfg);
15763 var sbox = c.select('.fc-day-content',true).first().getBox();
15764 var ebox = c.select('.fc-day-content',true).first().getBox();
15766 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15767 cg.setWidth(ebox.right - sbox.x -2);
15769 cg.on('click', _this.onMoreEventClick, _this, c.more);
15779 onEventEnter: function (e, el,event,d) {
15780 this.fireEvent('evententer', this, el, event);
15783 onEventLeave: function (e, el,event,d) {
15784 this.fireEvent('eventleave', this, el, event);
15787 onEventClick: function (e, el,event,d) {
15788 this.fireEvent('eventclick', this, el, event);
15791 onMonthChange: function () {
15795 onMoreEventClick: function(e, el, more)
15799 this.calpopover.placement = 'right';
15800 this.calpopover.setTitle('More');
15802 this.calpopover.setContent('');
15804 var ctr = this.calpopover.el.select('.popover-content', true).first();
15806 Roo.each(more, function(m){
15808 cls : 'fc-event-hori fc-event-draggable',
15811 var cg = ctr.createChild(cfg);
15813 cg.on('click', _this.onEventClick, _this, m);
15816 this.calpopover.show(el);
15821 onLoad: function ()
15823 this.calevents = [];
15826 if(this.store.getCount() > 0){
15827 this.store.data.each(function(d){
15830 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15831 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15832 time : d.data.start_time,
15833 title : d.data.title,
15834 description : d.data.description,
15835 venue : d.data.venue
15840 this.renderEvents();
15842 if(this.calevents.length && this.loadMask){
15843 this.maskEl.hide();
15847 onBeforeLoad: function()
15849 this.clearEvents();
15851 this.maskEl.show();
15865 * @class Roo.bootstrap.Popover
15866 * @extends Roo.bootstrap.Component
15867 * Bootstrap Popover class
15868 * @cfg {String} html contents of the popover (or false to use children..)
15869 * @cfg {String} title of popover (or false to hide)
15870 * @cfg {String} placement how it is placed
15871 * @cfg {String} trigger click || hover (or false to trigger manually)
15872 * @cfg {String} over what (parent or false to trigger manually.)
15873 * @cfg {Number} delay - delay before showing
15876 * Create a new Popover
15877 * @param {Object} config The config object
15880 Roo.bootstrap.Popover = function(config){
15881 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15887 * After the popover show
15889 * @param {Roo.bootstrap.Popover} this
15894 * After the popover hide
15896 * @param {Roo.bootstrap.Popover} this
15902 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
15904 title: 'Fill in a title',
15907 placement : 'right',
15908 trigger : 'hover', // hover
15914 can_build_overlaid : false,
15916 getChildContainer : function()
15918 return this.el.select('.popover-content',true).first();
15921 getAutoCreate : function(){
15924 cls : 'popover roo-dynamic',
15925 style: 'display:block',
15931 cls : 'popover-inner',
15935 cls: 'popover-title',
15939 cls : 'popover-content',
15950 setTitle: function(str)
15953 this.el.select('.popover-title',true).first().dom.innerHTML = str;
15955 setContent: function(str)
15958 this.el.select('.popover-content',true).first().dom.innerHTML = str;
15960 // as it get's added to the bottom of the page.
15961 onRender : function(ct, position)
15963 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15965 var cfg = Roo.apply({}, this.getAutoCreate());
15969 cfg.cls += ' ' + this.cls;
15972 cfg.style = this.style;
15974 //Roo.log("adding to ");
15975 this.el = Roo.get(document.body).createChild(cfg, position);
15976 // Roo.log(this.el);
15981 initEvents : function()
15983 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
15984 this.el.enableDisplayMode('block');
15986 if (this.over === false) {
15989 if (this.triggers === false) {
15992 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
15993 var triggers = this.trigger ? this.trigger.split(' ') : [];
15994 Roo.each(triggers, function(trigger) {
15996 if (trigger == 'click') {
15997 on_el.on('click', this.toggle, this);
15998 } else if (trigger != 'manual') {
15999 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16000 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16002 on_el.on(eventIn ,this.enter, this);
16003 on_el.on(eventOut, this.leave, this);
16014 toggle : function () {
16015 this.hoverState == 'in' ? this.leave() : this.enter();
16018 enter : function () {
16020 clearTimeout(this.timeout);
16022 this.hoverState = 'in';
16024 if (!this.delay || !this.delay.show) {
16029 this.timeout = setTimeout(function () {
16030 if (_t.hoverState == 'in') {
16033 }, this.delay.show)
16036 leave : function() {
16037 clearTimeout(this.timeout);
16039 this.hoverState = 'out';
16041 if (!this.delay || !this.delay.hide) {
16046 this.timeout = setTimeout(function () {
16047 if (_t.hoverState == 'out') {
16050 }, this.delay.hide)
16053 show : function (on_el)
16056 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16060 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16061 if (this.html !== false) {
16062 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16064 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16065 if (!this.title.length) {
16066 this.el.select('.popover-title',true).hide();
16069 var placement = typeof this.placement == 'function' ?
16070 this.placement.call(this, this.el, on_el) :
16073 var autoToken = /\s?auto?\s?/i;
16074 var autoPlace = autoToken.test(placement);
16076 placement = placement.replace(autoToken, '') || 'top';
16080 //this.el.setXY([0,0]);
16082 this.el.dom.style.display='block';
16083 this.el.addClass(placement);
16085 //this.el.appendTo(on_el);
16087 var p = this.getPosition();
16088 var box = this.el.getBox();
16093 var align = Roo.bootstrap.Popover.alignment[placement];
16094 this.el.alignTo(on_el, align[0],align[1]);
16095 //var arrow = this.el.select('.arrow',true).first();
16096 //arrow.set(align[2],
16098 this.el.addClass('in');
16101 if (this.el.hasClass('fade')) {
16105 this.hoverState = 'in';
16107 this.fireEvent('show', this);
16112 this.el.setXY([0,0]);
16113 this.el.removeClass('in');
16115 this.hoverState = null;
16117 this.fireEvent('hide', this);
16122 Roo.bootstrap.Popover.alignment = {
16123 'left' : ['r-l', [-10,0], 'right'],
16124 'right' : ['l-r', [10,0], 'left'],
16125 'bottom' : ['t-b', [0,10], 'top'],
16126 'top' : [ 'b-t', [0,-10], 'bottom']
16137 * @class Roo.bootstrap.Progress
16138 * @extends Roo.bootstrap.Component
16139 * Bootstrap Progress class
16140 * @cfg {Boolean} striped striped of the progress bar
16141 * @cfg {Boolean} active animated of the progress bar
16145 * Create a new Progress
16146 * @param {Object} config The config object
16149 Roo.bootstrap.Progress = function(config){
16150 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16153 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16158 getAutoCreate : function(){
16166 cfg.cls += ' progress-striped';
16170 cfg.cls += ' active';
16189 * @class Roo.bootstrap.ProgressBar
16190 * @extends Roo.bootstrap.Component
16191 * Bootstrap ProgressBar class
16192 * @cfg {Number} aria_valuenow aria-value now
16193 * @cfg {Number} aria_valuemin aria-value min
16194 * @cfg {Number} aria_valuemax aria-value max
16195 * @cfg {String} label label for the progress bar
16196 * @cfg {String} panel (success | info | warning | danger )
16197 * @cfg {String} role role of the progress bar
16198 * @cfg {String} sr_only text
16202 * Create a new ProgressBar
16203 * @param {Object} config The config object
16206 Roo.bootstrap.ProgressBar = function(config){
16207 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16210 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16214 aria_valuemax : 100,
16220 getAutoCreate : function()
16225 cls: 'progress-bar',
16226 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16238 cfg.role = this.role;
16241 if(this.aria_valuenow){
16242 cfg['aria-valuenow'] = this.aria_valuenow;
16245 if(this.aria_valuemin){
16246 cfg['aria-valuemin'] = this.aria_valuemin;
16249 if(this.aria_valuemax){
16250 cfg['aria-valuemax'] = this.aria_valuemax;
16253 if(this.label && !this.sr_only){
16254 cfg.html = this.label;
16258 cfg.cls += ' progress-bar-' + this.panel;
16264 update : function(aria_valuenow)
16266 this.aria_valuenow = aria_valuenow;
16268 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16283 * @class Roo.bootstrap.TabGroup
16284 * @extends Roo.bootstrap.Column
16285 * Bootstrap Column class
16286 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16287 * @cfg {Boolean} carousel true to make the group behave like a carousel
16288 * @cfg {Boolean} bullets show bullets for the panels
16289 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16290 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16291 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16294 * Create a new TabGroup
16295 * @param {Object} config The config object
16298 Roo.bootstrap.TabGroup = function(config){
16299 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16301 this.navId = Roo.id();
16304 Roo.bootstrap.TabGroup.register(this);
16308 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16311 transition : false,
16316 slideOnTouch : false,
16318 getAutoCreate : function()
16320 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16322 cfg.cls += ' tab-content';
16324 if (this.carousel) {
16325 cfg.cls += ' carousel slide';
16328 cls : 'carousel-inner'
16331 if(this.bullets && !Roo.isTouch){
16334 cls : 'carousel-bullets',
16338 if(this.bullets_cls){
16339 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16342 for (var i = 0; i < this.bullets; i++){
16344 cls : 'bullet bullet-' + i
16352 cfg.cn[0].cn = bullets;
16359 initEvents: function()
16361 if(Roo.isTouch && this.slideOnTouch){
16362 this.el.on("touchstart", this.onTouchStart, this);
16365 if(this.autoslide){
16368 this.slideFn = window.setInterval(function() {
16369 _this.showPanelNext();
16375 onTouchStart : function(e, el, o)
16377 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16381 this.showPanelNext();
16384 getChildContainer : function()
16386 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
16390 * register a Navigation item
16391 * @param {Roo.bootstrap.NavItem} the navitem to add
16393 register : function(item)
16395 this.tabs.push( item);
16396 item.navId = this.navId; // not really needed..
16401 getActivePanel : function()
16404 Roo.each(this.tabs, function(t) {
16414 getPanelByName : function(n)
16417 Roo.each(this.tabs, function(t) {
16418 if (t.tabId == n) {
16426 indexOfPanel : function(p)
16429 Roo.each(this.tabs, function(t,i) {
16430 if (t.tabId == p.tabId) {
16439 * show a specific panel
16440 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
16441 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
16443 showPanel : function (pan)
16445 if(this.transition || typeof(pan) == 'undefined'){
16446 Roo.log("waiting for the transitionend");
16450 if (typeof(pan) == 'number') {
16451 pan = this.tabs[pan];
16454 if (typeof(pan) == 'string') {
16455 pan = this.getPanelByName(pan);
16458 var cur = this.getActivePanel();
16461 Roo.log('pan or acitve pan is undefined');
16465 if (pan.tabId == this.getActivePanel().tabId) {
16469 if (false === cur.fireEvent('beforedeactivate')) {
16473 if(this.bullets > 0 && !Roo.isTouch){
16474 this.setActiveBullet(this.indexOfPanel(pan));
16477 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
16479 this.transition = true;
16480 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
16481 var lr = dir == 'next' ? 'left' : 'right';
16482 pan.el.addClass(dir); // or prev
16483 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
16484 cur.el.addClass(lr); // or right
16485 pan.el.addClass(lr);
16488 cur.el.on('transitionend', function() {
16489 Roo.log("trans end?");
16491 pan.el.removeClass([lr,dir]);
16492 pan.setActive(true);
16494 cur.el.removeClass([lr]);
16495 cur.setActive(false);
16497 _this.transition = false;
16499 }, this, { single: true } );
16504 cur.setActive(false);
16505 pan.setActive(true);
16510 showPanelNext : function()
16512 var i = this.indexOfPanel(this.getActivePanel());
16514 if (i >= this.tabs.length - 1 && !this.autoslide) {
16518 if (i >= this.tabs.length - 1 && this.autoslide) {
16522 this.showPanel(this.tabs[i+1]);
16525 showPanelPrev : function()
16527 var i = this.indexOfPanel(this.getActivePanel());
16529 if (i < 1 && !this.autoslide) {
16533 if (i < 1 && this.autoslide) {
16534 i = this.tabs.length;
16537 this.showPanel(this.tabs[i-1]);
16541 addBullet: function()
16543 if(!this.bullets || Roo.isTouch){
16546 var ctr = this.el.select('.carousel-bullets',true).first();
16547 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
16548 var bullet = ctr.createChild({
16549 cls : 'bullet bullet-' + i
16550 },ctr.dom.lastChild);
16555 bullet.on('click', (function(e, el, o, ii, t){
16557 e.preventDefault();
16559 this.showPanel(ii);
16561 if(this.autoslide && this.slideFn){
16562 clearInterval(this.slideFn);
16563 this.slideFn = window.setInterval(function() {
16564 _this.showPanelNext();
16568 }).createDelegate(this, [i, bullet], true));
16573 setActiveBullet : function(i)
16579 Roo.each(this.el.select('.bullet', true).elements, function(el){
16580 el.removeClass('selected');
16583 var bullet = this.el.select('.bullet-' + i, true).first();
16589 bullet.addClass('selected');
16600 Roo.apply(Roo.bootstrap.TabGroup, {
16604 * register a Navigation Group
16605 * @param {Roo.bootstrap.NavGroup} the navgroup to add
16607 register : function(navgrp)
16609 this.groups[navgrp.navId] = navgrp;
16613 * fetch a Navigation Group based on the navigation ID
16614 * if one does not exist , it will get created.
16615 * @param {string} the navgroup to add
16616 * @returns {Roo.bootstrap.NavGroup} the navgroup
16618 get: function(navId) {
16619 if (typeof(this.groups[navId]) == 'undefined') {
16620 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
16622 return this.groups[navId] ;
16637 * @class Roo.bootstrap.TabPanel
16638 * @extends Roo.bootstrap.Component
16639 * Bootstrap TabPanel class
16640 * @cfg {Boolean} active panel active
16641 * @cfg {String} html panel content
16642 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
16643 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
16647 * Create a new TabPanel
16648 * @param {Object} config The config object
16651 Roo.bootstrap.TabPanel = function(config){
16652 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
16656 * Fires when the active status changes
16657 * @param {Roo.bootstrap.TabPanel} this
16658 * @param {Boolean} state the new state
16663 * @event beforedeactivate
16664 * Fires before a tab is de-activated - can be used to do validation on a form.
16665 * @param {Roo.bootstrap.TabPanel} this
16666 * @return {Boolean} false if there is an error
16669 'beforedeactivate': true
16672 this.tabId = this.tabId || Roo.id();
16676 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
16683 getAutoCreate : function(){
16686 // item is needed for carousel - not sure if it has any effect otherwise
16687 cls: 'tab-pane item',
16688 html: this.html || ''
16692 cfg.cls += ' active';
16696 cfg.tabId = this.tabId;
16703 initEvents: function()
16705 var p = this.parent();
16706 this.navId = this.navId || p.navId;
16708 if (typeof(this.navId) != 'undefined') {
16709 // not really needed.. but just in case.. parent should be a NavGroup.
16710 var tg = Roo.bootstrap.TabGroup.get(this.navId);
16714 var i = tg.tabs.length - 1;
16716 if(this.active && tg.bullets > 0 && i < tg.bullets){
16717 tg.setActiveBullet(i);
16724 onRender : function(ct, position)
16726 // Roo.log("Call onRender: " + this.xtype);
16728 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
16736 setActive: function(state)
16738 Roo.log("panel - set active " + this.tabId + "=" + state);
16740 this.active = state;
16742 this.el.removeClass('active');
16744 } else if (!this.el.hasClass('active')) {
16745 this.el.addClass('active');
16748 this.fireEvent('changed', this, state);
16765 * @class Roo.bootstrap.DateField
16766 * @extends Roo.bootstrap.Input
16767 * Bootstrap DateField class
16768 * @cfg {Number} weekStart default 0
16769 * @cfg {String} viewMode default empty, (months|years)
16770 * @cfg {String} minViewMode default empty, (months|years)
16771 * @cfg {Number} startDate default -Infinity
16772 * @cfg {Number} endDate default Infinity
16773 * @cfg {Boolean} todayHighlight default false
16774 * @cfg {Boolean} todayBtn default false
16775 * @cfg {Boolean} calendarWeeks default false
16776 * @cfg {Object} daysOfWeekDisabled default empty
16777 * @cfg {Boolean} singleMode default false (true | false)
16779 * @cfg {Boolean} keyboardNavigation default true
16780 * @cfg {String} language default en
16783 * Create a new DateField
16784 * @param {Object} config The config object
16787 Roo.bootstrap.DateField = function(config){
16788 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16792 * Fires when this field show.
16793 * @param {Roo.bootstrap.DateField} this
16794 * @param {Mixed} date The date value
16799 * Fires when this field hide.
16800 * @param {Roo.bootstrap.DateField} this
16801 * @param {Mixed} date The date value
16806 * Fires when select a date.
16807 * @param {Roo.bootstrap.DateField} this
16808 * @param {Mixed} date The date value
16812 * @event beforeselect
16813 * Fires when before select a date.
16814 * @param {Roo.bootstrap.DateField} this
16815 * @param {Mixed} date The date value
16817 beforeselect : true
16821 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16824 * @cfg {String} format
16825 * The default date format string which can be overriden for localization support. The format must be
16826 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16830 * @cfg {String} altFormats
16831 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16832 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16834 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16842 todayHighlight : false,
16848 keyboardNavigation: true,
16850 calendarWeeks: false,
16852 startDate: -Infinity,
16856 daysOfWeekDisabled: [],
16860 singleMode : false,
16862 UTCDate: function()
16864 return new Date(Date.UTC.apply(Date, arguments));
16867 UTCToday: function()
16869 var today = new Date();
16870 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16873 getDate: function() {
16874 var d = this.getUTCDate();
16875 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16878 getUTCDate: function() {
16882 setDate: function(d) {
16883 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16886 setUTCDate: function(d) {
16888 this.setValue(this.formatDate(this.date));
16891 onRender: function(ct, position)
16894 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16896 this.language = this.language || 'en';
16897 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16898 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16900 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16901 this.format = this.format || 'm/d/y';
16902 this.isInline = false;
16903 this.isInput = true;
16904 this.component = this.el.select('.add-on', true).first() || false;
16905 this.component = (this.component && this.component.length === 0) ? false : this.component;
16906 this.hasInput = this.component && this.inputEL().length;
16908 if (typeof(this.minViewMode === 'string')) {
16909 switch (this.minViewMode) {
16911 this.minViewMode = 1;
16914 this.minViewMode = 2;
16917 this.minViewMode = 0;
16922 if (typeof(this.viewMode === 'string')) {
16923 switch (this.viewMode) {
16936 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
16938 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
16940 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16942 this.picker().on('mousedown', this.onMousedown, this);
16943 this.picker().on('click', this.onClick, this);
16945 this.picker().addClass('datepicker-dropdown');
16947 this.startViewMode = this.viewMode;
16949 if(this.singleMode){
16950 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
16951 v.setVisibilityMode(Roo.Element.DISPLAY);
16955 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16956 v.setStyle('width', '189px');
16960 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
16961 if(!this.calendarWeeks){
16966 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
16967 v.attr('colspan', function(i, val){
16968 return parseInt(val) + 1;
16973 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
16975 this.setStartDate(this.startDate);
16976 this.setEndDate(this.endDate);
16978 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
16985 if(this.isInline) {
16990 picker : function()
16992 return this.pickerEl;
16993 // return this.el.select('.datepicker', true).first();
16996 fillDow: function()
16998 var dowCnt = this.weekStart;
17007 if(this.calendarWeeks){
17015 while (dowCnt < this.weekStart + 7) {
17019 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17023 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17026 fillMonths: function()
17029 var months = this.picker().select('>.datepicker-months td', true).first();
17031 months.dom.innerHTML = '';
17037 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17040 months.createChild(month);
17047 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;
17049 if (this.date < this.startDate) {
17050 this.viewDate = new Date(this.startDate);
17051 } else if (this.date > this.endDate) {
17052 this.viewDate = new Date(this.endDate);
17054 this.viewDate = new Date(this.date);
17062 var d = new Date(this.viewDate),
17063 year = d.getUTCFullYear(),
17064 month = d.getUTCMonth(),
17065 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17066 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17067 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17068 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17069 currentDate = this.date && this.date.valueOf(),
17070 today = this.UTCToday();
17072 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17074 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17076 // this.picker.select('>tfoot th.today').
17077 // .text(dates[this.language].today)
17078 // .toggle(this.todayBtn !== false);
17080 this.updateNavArrows();
17083 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17085 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17087 prevMonth.setUTCDate(day);
17089 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17091 var nextMonth = new Date(prevMonth);
17093 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17095 nextMonth = nextMonth.valueOf();
17097 var fillMonths = false;
17099 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17101 while(prevMonth.valueOf() < nextMonth) {
17104 if (prevMonth.getUTCDay() === this.weekStart) {
17106 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17114 if(this.calendarWeeks){
17115 // ISO 8601: First week contains first thursday.
17116 // ISO also states week starts on Monday, but we can be more abstract here.
17118 // Start of current week: based on weekstart/current date
17119 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17120 // Thursday of this week
17121 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17122 // First Thursday of year, year from thursday
17123 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17124 // Calendar week: ms between thursdays, div ms per day, div 7 days
17125 calWeek = (th - yth) / 864e5 / 7 + 1;
17127 fillMonths.cn.push({
17135 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17137 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17140 if (this.todayHighlight &&
17141 prevMonth.getUTCFullYear() == today.getFullYear() &&
17142 prevMonth.getUTCMonth() == today.getMonth() &&
17143 prevMonth.getUTCDate() == today.getDate()) {
17144 clsName += ' today';
17147 if (currentDate && prevMonth.valueOf() === currentDate) {
17148 clsName += ' active';
17151 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17152 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17153 clsName += ' disabled';
17156 fillMonths.cn.push({
17158 cls: 'day ' + clsName,
17159 html: prevMonth.getDate()
17162 prevMonth.setDate(prevMonth.getDate()+1);
17165 var currentYear = this.date && this.date.getUTCFullYear();
17166 var currentMonth = this.date && this.date.getUTCMonth();
17168 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17170 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17171 v.removeClass('active');
17173 if(currentYear === year && k === currentMonth){
17174 v.addClass('active');
17177 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17178 v.addClass('disabled');
17184 year = parseInt(year/10, 10) * 10;
17186 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17188 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17191 for (var i = -1; i < 11; i++) {
17192 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17194 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17202 showMode: function(dir)
17205 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17208 Roo.each(this.picker().select('>div',true).elements, function(v){
17209 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17212 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17217 if(this.isInline) {
17221 this.picker().removeClass(['bottom', 'top']);
17223 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17225 * place to the top of element!
17229 this.picker().addClass('top');
17230 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17235 this.picker().addClass('bottom');
17237 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17240 parseDate : function(value)
17242 if(!value || value instanceof Date){
17245 var v = Date.parseDate(value, this.format);
17246 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17247 v = Date.parseDate(value, 'Y-m-d');
17249 if(!v && this.altFormats){
17250 if(!this.altFormatsArray){
17251 this.altFormatsArray = this.altFormats.split("|");
17253 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17254 v = Date.parseDate(value, this.altFormatsArray[i]);
17260 formatDate : function(date, fmt)
17262 return (!date || !(date instanceof Date)) ?
17263 date : date.dateFormat(fmt || this.format);
17266 onFocus : function()
17268 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17272 onBlur : function()
17274 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17276 var d = this.inputEl().getValue();
17285 this.picker().show();
17289 this.fireEvent('show', this, this.date);
17294 if(this.isInline) {
17297 this.picker().hide();
17298 this.viewMode = this.startViewMode;
17301 this.fireEvent('hide', this, this.date);
17305 onMousedown: function(e)
17307 e.stopPropagation();
17308 e.preventDefault();
17313 Roo.bootstrap.DateField.superclass.keyup.call(this);
17317 setValue: function(v)
17319 if(this.fireEvent('beforeselect', this, v) !== false){
17320 var d = new Date(this.parseDate(v) ).clearTime();
17322 if(isNaN(d.getTime())){
17323 this.date = this.viewDate = '';
17324 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17328 v = this.formatDate(d);
17330 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17332 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17336 this.fireEvent('select', this, this.date);
17340 getValue: function()
17342 return this.formatDate(this.date);
17345 fireKey: function(e)
17347 if (!this.picker().isVisible()){
17348 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17354 var dateChanged = false,
17356 newDate, newViewDate;
17361 e.preventDefault();
17365 if (!this.keyboardNavigation) {
17368 dir = e.keyCode == 37 ? -1 : 1;
17371 newDate = this.moveYear(this.date, dir);
17372 newViewDate = this.moveYear(this.viewDate, dir);
17373 } else if (e.shiftKey){
17374 newDate = this.moveMonth(this.date, dir);
17375 newViewDate = this.moveMonth(this.viewDate, dir);
17377 newDate = new Date(this.date);
17378 newDate.setUTCDate(this.date.getUTCDate() + dir);
17379 newViewDate = new Date(this.viewDate);
17380 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
17382 if (this.dateWithinRange(newDate)){
17383 this.date = newDate;
17384 this.viewDate = newViewDate;
17385 this.setValue(this.formatDate(this.date));
17387 e.preventDefault();
17388 dateChanged = true;
17393 if (!this.keyboardNavigation) {
17396 dir = e.keyCode == 38 ? -1 : 1;
17398 newDate = this.moveYear(this.date, dir);
17399 newViewDate = this.moveYear(this.viewDate, dir);
17400 } else if (e.shiftKey){
17401 newDate = this.moveMonth(this.date, dir);
17402 newViewDate = this.moveMonth(this.viewDate, dir);
17404 newDate = new Date(this.date);
17405 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
17406 newViewDate = new Date(this.viewDate);
17407 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
17409 if (this.dateWithinRange(newDate)){
17410 this.date = newDate;
17411 this.viewDate = newViewDate;
17412 this.setValue(this.formatDate(this.date));
17414 e.preventDefault();
17415 dateChanged = true;
17419 this.setValue(this.formatDate(this.date));
17421 e.preventDefault();
17424 this.setValue(this.formatDate(this.date));
17438 onClick: function(e)
17440 e.stopPropagation();
17441 e.preventDefault();
17443 var target = e.getTarget();
17445 if(target.nodeName.toLowerCase() === 'i'){
17446 target = Roo.get(target).dom.parentNode;
17449 var nodeName = target.nodeName;
17450 var className = target.className;
17451 var html = target.innerHTML;
17452 //Roo.log(nodeName);
17454 switch(nodeName.toLowerCase()) {
17456 switch(className) {
17462 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
17463 switch(this.viewMode){
17465 this.viewDate = this.moveMonth(this.viewDate, dir);
17469 this.viewDate = this.moveYear(this.viewDate, dir);
17475 var date = new Date();
17476 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
17478 this.setValue(this.formatDate(this.date));
17485 if (className.indexOf('disabled') < 0) {
17486 this.viewDate.setUTCDate(1);
17487 if (className.indexOf('month') > -1) {
17488 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
17490 var year = parseInt(html, 10) || 0;
17491 this.viewDate.setUTCFullYear(year);
17495 if(this.singleMode){
17496 this.setValue(this.formatDate(this.viewDate));
17507 //Roo.log(className);
17508 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
17509 var day = parseInt(html, 10) || 1;
17510 var year = this.viewDate.getUTCFullYear(),
17511 month = this.viewDate.getUTCMonth();
17513 if (className.indexOf('old') > -1) {
17520 } else if (className.indexOf('new') > -1) {
17528 //Roo.log([year,month,day]);
17529 this.date = this.UTCDate(year, month, day,0,0,0,0);
17530 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
17532 //Roo.log(this.formatDate(this.date));
17533 this.setValue(this.formatDate(this.date));
17540 setStartDate: function(startDate)
17542 this.startDate = startDate || -Infinity;
17543 if (this.startDate !== -Infinity) {
17544 this.startDate = this.parseDate(this.startDate);
17547 this.updateNavArrows();
17550 setEndDate: function(endDate)
17552 this.endDate = endDate || Infinity;
17553 if (this.endDate !== Infinity) {
17554 this.endDate = this.parseDate(this.endDate);
17557 this.updateNavArrows();
17560 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
17562 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
17563 if (typeof(this.daysOfWeekDisabled) !== 'object') {
17564 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
17566 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
17567 return parseInt(d, 10);
17570 this.updateNavArrows();
17573 updateNavArrows: function()
17575 if(this.singleMode){
17579 var d = new Date(this.viewDate),
17580 year = d.getUTCFullYear(),
17581 month = d.getUTCMonth();
17583 Roo.each(this.picker().select('.prev', true).elements, function(v){
17585 switch (this.viewMode) {
17588 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
17594 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
17601 Roo.each(this.picker().select('.next', true).elements, function(v){
17603 switch (this.viewMode) {
17606 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
17612 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
17620 moveMonth: function(date, dir)
17625 var new_date = new Date(date.valueOf()),
17626 day = new_date.getUTCDate(),
17627 month = new_date.getUTCMonth(),
17628 mag = Math.abs(dir),
17630 dir = dir > 0 ? 1 : -1;
17633 // If going back one month, make sure month is not current month
17634 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
17636 return new_date.getUTCMonth() == month;
17638 // If going forward one month, make sure month is as expected
17639 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
17641 return new_date.getUTCMonth() != new_month;
17643 new_month = month + dir;
17644 new_date.setUTCMonth(new_month);
17645 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
17646 if (new_month < 0 || new_month > 11) {
17647 new_month = (new_month + 12) % 12;
17650 // For magnitudes >1, move one month at a time...
17651 for (var i=0; i<mag; i++) {
17652 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
17653 new_date = this.moveMonth(new_date, dir);
17655 // ...then reset the day, keeping it in the new month
17656 new_month = new_date.getUTCMonth();
17657 new_date.setUTCDate(day);
17659 return new_month != new_date.getUTCMonth();
17662 // Common date-resetting loop -- if date is beyond end of month, make it
17665 new_date.setUTCDate(--day);
17666 new_date.setUTCMonth(new_month);
17671 moveYear: function(date, dir)
17673 return this.moveMonth(date, dir*12);
17676 dateWithinRange: function(date)
17678 return date >= this.startDate && date <= this.endDate;
17684 this.picker().remove();
17689 Roo.apply(Roo.bootstrap.DateField, {
17700 html: '<i class="fa fa-arrow-left"/>'
17710 html: '<i class="fa fa-arrow-right"/>'
17752 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
17753 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17754 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
17755 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17756 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17769 navFnc: 'FullYear',
17774 navFnc: 'FullYear',
17779 Roo.apply(Roo.bootstrap.DateField, {
17783 cls: 'datepicker dropdown-menu roo-dynamic',
17787 cls: 'datepicker-days',
17791 cls: 'table-condensed',
17793 Roo.bootstrap.DateField.head,
17797 Roo.bootstrap.DateField.footer
17804 cls: 'datepicker-months',
17808 cls: 'table-condensed',
17810 Roo.bootstrap.DateField.head,
17811 Roo.bootstrap.DateField.content,
17812 Roo.bootstrap.DateField.footer
17819 cls: 'datepicker-years',
17823 cls: 'table-condensed',
17825 Roo.bootstrap.DateField.head,
17826 Roo.bootstrap.DateField.content,
17827 Roo.bootstrap.DateField.footer
17846 * @class Roo.bootstrap.TimeField
17847 * @extends Roo.bootstrap.Input
17848 * Bootstrap DateField class
17852 * Create a new TimeField
17853 * @param {Object} config The config object
17856 Roo.bootstrap.TimeField = function(config){
17857 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17861 * Fires when this field show.
17862 * @param {Roo.bootstrap.DateField} thisthis
17863 * @param {Mixed} date The date value
17868 * Fires when this field hide.
17869 * @param {Roo.bootstrap.DateField} this
17870 * @param {Mixed} date The date value
17875 * Fires when select a date.
17876 * @param {Roo.bootstrap.DateField} this
17877 * @param {Mixed} date The date value
17883 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17886 * @cfg {String} format
17887 * The default time format string which can be overriden for localization support. The format must be
17888 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17892 onRender: function(ct, position)
17895 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17897 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17899 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17901 this.pop = this.picker().select('>.datepicker-time',true).first();
17902 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17904 this.picker().on('mousedown', this.onMousedown, this);
17905 this.picker().on('click', this.onClick, this);
17907 this.picker().addClass('datepicker-dropdown');
17912 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17913 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17914 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17915 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17916 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17917 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17921 fireKey: function(e){
17922 if (!this.picker().isVisible()){
17923 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17929 e.preventDefault();
17937 this.onTogglePeriod();
17940 this.onIncrementMinutes();
17943 this.onDecrementMinutes();
17952 onClick: function(e) {
17953 e.stopPropagation();
17954 e.preventDefault();
17957 picker : function()
17959 return this.el.select('.datepicker', true).first();
17962 fillTime: function()
17964 var time = this.pop.select('tbody', true).first();
17966 time.dom.innerHTML = '';
17981 cls: 'hours-up glyphicon glyphicon-chevron-up'
18001 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18022 cls: 'timepicker-hour',
18037 cls: 'timepicker-minute',
18052 cls: 'btn btn-primary period',
18074 cls: 'hours-down glyphicon glyphicon-chevron-down'
18094 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18112 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18119 var hours = this.time.getHours();
18120 var minutes = this.time.getMinutes();
18133 hours = hours - 12;
18137 hours = '0' + hours;
18141 minutes = '0' + minutes;
18144 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18145 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18146 this.pop.select('button', true).first().dom.innerHTML = period;
18152 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18154 var cls = ['bottom'];
18156 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18163 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18168 this.picker().addClass(cls.join('-'));
18172 Roo.each(cls, function(c){
18174 _this.picker().setTop(_this.inputEl().getHeight());
18178 _this.picker().setTop(0 - _this.picker().getHeight());
18183 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18187 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18194 onFocus : function()
18196 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18200 onBlur : function()
18202 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18208 this.picker().show();
18213 this.fireEvent('show', this, this.date);
18218 this.picker().hide();
18221 this.fireEvent('hide', this, this.date);
18224 setTime : function()
18227 this.setValue(this.time.format(this.format));
18229 this.fireEvent('select', this, this.date);
18234 onMousedown: function(e){
18235 e.stopPropagation();
18236 e.preventDefault();
18239 onIncrementHours: function()
18241 Roo.log('onIncrementHours');
18242 this.time = this.time.add(Date.HOUR, 1);
18247 onDecrementHours: function()
18249 Roo.log('onDecrementHours');
18250 this.time = this.time.add(Date.HOUR, -1);
18254 onIncrementMinutes: function()
18256 Roo.log('onIncrementMinutes');
18257 this.time = this.time.add(Date.MINUTE, 1);
18261 onDecrementMinutes: function()
18263 Roo.log('onDecrementMinutes');
18264 this.time = this.time.add(Date.MINUTE, -1);
18268 onTogglePeriod: function()
18270 Roo.log('onTogglePeriod');
18271 this.time = this.time.add(Date.HOUR, 12);
18278 Roo.apply(Roo.bootstrap.TimeField, {
18308 cls: 'btn btn-info ok',
18320 Roo.apply(Roo.bootstrap.TimeField, {
18324 cls: 'datepicker dropdown-menu',
18328 cls: 'datepicker-time',
18332 cls: 'table-condensed',
18334 Roo.bootstrap.TimeField.content,
18335 Roo.bootstrap.TimeField.footer
18354 * @class Roo.bootstrap.MonthField
18355 * @extends Roo.bootstrap.Input
18356 * Bootstrap MonthField class
18358 * @cfg {String} language default en
18361 * Create a new MonthField
18362 * @param {Object} config The config object
18365 Roo.bootstrap.MonthField = function(config){
18366 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
18371 * Fires when this field show.
18372 * @param {Roo.bootstrap.MonthField} this
18373 * @param {Mixed} date The date value
18378 * Fires when this field hide.
18379 * @param {Roo.bootstrap.MonthField} this
18380 * @param {Mixed} date The date value
18385 * Fires when select a date.
18386 * @param {Roo.bootstrap.MonthField} this
18387 * @param {String} oldvalue The old value
18388 * @param {String} newvalue The new value
18394 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
18396 onRender: function(ct, position)
18399 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
18401 this.language = this.language || 'en';
18402 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
18403 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
18405 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
18406 this.isInline = false;
18407 this.isInput = true;
18408 this.component = this.el.select('.add-on', true).first() || false;
18409 this.component = (this.component && this.component.length === 0) ? false : this.component;
18410 this.hasInput = this.component && this.inputEL().length;
18412 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
18414 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18416 this.picker().on('mousedown', this.onMousedown, this);
18417 this.picker().on('click', this.onClick, this);
18419 this.picker().addClass('datepicker-dropdown');
18421 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18422 v.setStyle('width', '189px');
18429 if(this.isInline) {
18435 setValue: function(v, suppressEvent)
18437 var o = this.getValue();
18439 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
18443 if(suppressEvent !== true){
18444 this.fireEvent('select', this, o, v);
18449 getValue: function()
18454 onClick: function(e)
18456 e.stopPropagation();
18457 e.preventDefault();
18459 var target = e.getTarget();
18461 if(target.nodeName.toLowerCase() === 'i'){
18462 target = Roo.get(target).dom.parentNode;
18465 var nodeName = target.nodeName;
18466 var className = target.className;
18467 var html = target.innerHTML;
18469 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
18473 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
18475 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18481 picker : function()
18483 return this.pickerEl;
18486 fillMonths: function()
18489 var months = this.picker().select('>.datepicker-months td', true).first();
18491 months.dom.innerHTML = '';
18497 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
18500 months.createChild(month);
18509 if(typeof(this.vIndex) == 'undefined' && this.value.length){
18510 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
18513 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
18514 e.removeClass('active');
18516 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
18517 e.addClass('active');
18524 if(this.isInline) {
18528 this.picker().removeClass(['bottom', 'top']);
18530 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18532 * place to the top of element!
18536 this.picker().addClass('top');
18537 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18542 this.picker().addClass('bottom');
18544 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18547 onFocus : function()
18549 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
18553 onBlur : function()
18555 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
18557 var d = this.inputEl().getValue();
18566 this.picker().show();
18567 this.picker().select('>.datepicker-months', true).first().show();
18571 this.fireEvent('show', this, this.date);
18576 if(this.isInline) {
18579 this.picker().hide();
18580 this.fireEvent('hide', this, this.date);
18584 onMousedown: function(e)
18586 e.stopPropagation();
18587 e.preventDefault();
18592 Roo.bootstrap.MonthField.superclass.keyup.call(this);
18596 fireKey: function(e)
18598 if (!this.picker().isVisible()){
18599 if (e.keyCode == 27) {// allow escape to hide and re-show picker
18610 e.preventDefault();
18614 dir = e.keyCode == 37 ? -1 : 1;
18616 this.vIndex = this.vIndex + dir;
18618 if(this.vIndex < 0){
18622 if(this.vIndex > 11){
18626 if(isNaN(this.vIndex)){
18630 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18636 dir = e.keyCode == 38 ? -1 : 1;
18638 this.vIndex = this.vIndex + dir * 4;
18640 if(this.vIndex < 0){
18644 if(this.vIndex > 11){
18648 if(isNaN(this.vIndex)){
18652 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18657 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18658 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18662 e.preventDefault();
18665 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18666 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18682 this.picker().remove();
18687 Roo.apply(Roo.bootstrap.MonthField, {
18706 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18707 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
18712 Roo.apply(Roo.bootstrap.MonthField, {
18716 cls: 'datepicker dropdown-menu roo-dynamic',
18720 cls: 'datepicker-months',
18724 cls: 'table-condensed',
18726 Roo.bootstrap.DateField.content
18746 * @class Roo.bootstrap.CheckBox
18747 * @extends Roo.bootstrap.Input
18748 * Bootstrap CheckBox class
18750 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
18751 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
18752 * @cfg {String} boxLabel The text that appears beside the checkbox
18753 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
18754 * @cfg {Boolean} checked initnal the element
18755 * @cfg {Boolean} inline inline the element (default false)
18756 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
18759 * Create a new CheckBox
18760 * @param {Object} config The config object
18763 Roo.bootstrap.CheckBox = function(config){
18764 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18769 * Fires when the element is checked or unchecked.
18770 * @param {Roo.bootstrap.CheckBox} this This input
18771 * @param {Boolean} checked The new checked value
18778 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18780 inputType: 'checkbox',
18788 getAutoCreate : function()
18790 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18796 cfg.cls = 'form-group ' + this.inputType; //input-group
18799 cfg.cls += ' ' + this.inputType + '-inline';
18805 type : this.inputType,
18806 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18807 cls : 'roo-' + this.inputType, //'form-box',
18808 placeholder : this.placeholder || ''
18812 if (this.weight) { // Validity check?
18813 cfg.cls += " " + this.inputType + "-" + this.weight;
18816 if (this.disabled) {
18817 input.disabled=true;
18821 input.checked = this.checked;
18825 input.name = this.name;
18829 input.cls += ' input-' + this.size;
18834 ['xs','sm','md','lg'].map(function(size){
18835 if (settings[size]) {
18836 cfg.cls += ' col-' + size + '-' + settings[size];
18840 var inputblock = input;
18842 if (this.before || this.after) {
18845 cls : 'input-group',
18850 inputblock.cn.push({
18852 cls : 'input-group-addon',
18857 inputblock.cn.push(input);
18860 inputblock.cn.push({
18862 cls : 'input-group-addon',
18869 if (align ==='left' && this.fieldLabel.length) {
18870 // Roo.log("left and has label");
18876 cls : 'control-label col-md-' + this.labelWidth,
18877 html : this.fieldLabel
18881 cls : "col-md-" + (12 - this.labelWidth),
18888 } else if ( this.fieldLabel.length) {
18889 // Roo.log(" label");
18893 tag: this.boxLabel ? 'span' : 'label',
18895 cls: 'control-label box-input-label',
18896 //cls : 'input-group-addon',
18897 html : this.fieldLabel
18907 // Roo.log(" no label && no align");
18908 cfg.cn = [ inputblock ] ;
18914 var boxLabelCfg = {
18916 //'for': id, // box label is handled by onclick - so no for...
18918 html: this.boxLabel
18922 boxLabelCfg.tooltip = this.tooltip;
18925 cfg.cn.push(boxLabelCfg);
18935 * return the real input element.
18937 inputEl: function ()
18939 return this.el.select('input.roo-' + this.inputType,true).first();
18942 labelEl: function()
18944 return this.el.select('label.control-label',true).first();
18946 /* depricated... */
18950 return this.labelEl();
18953 boxLabelEl: function()
18955 return this.el.select('label.box-label',true).first();
18958 initEvents : function()
18960 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
18962 this.inputEl().on('click', this.onClick, this);
18964 if (this.boxLabel) {
18965 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
18968 this.startValue = this.getValue();
18971 Roo.bootstrap.CheckBox.register(this);
18975 onClick : function()
18977 this.setChecked(!this.checked);
18980 setChecked : function(state,suppressEvent)
18982 this.startValue = this.getValue();
18984 if(this.inputType == 'radio'){
18986 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
18987 e.dom.checked = false;
18990 this.inputEl().dom.checked = true;
18992 this.inputEl().dom.value = this.inputValue;
18994 if(suppressEvent !== true){
18995 this.fireEvent('check', this, true);
19003 this.checked = state;
19005 this.inputEl().dom.checked = state;
19007 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19009 if(suppressEvent !== true){
19010 this.fireEvent('check', this, state);
19016 getValue : function()
19018 if(this.inputType == 'radio'){
19019 return this.getGroupValue();
19022 return this.inputEl().getValue();
19026 getGroupValue : function()
19028 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19032 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19035 setValue : function(v,suppressEvent)
19037 if(this.inputType == 'radio'){
19038 this.setGroupValue(v, suppressEvent);
19042 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19047 setGroupValue : function(v, suppressEvent)
19049 this.startValue = this.getValue();
19051 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19052 e.dom.checked = false;
19054 if(e.dom.value == v){
19055 e.dom.checked = true;
19059 if(suppressEvent !== true){
19060 this.fireEvent('check', this, true);
19068 validate : function()
19072 (this.inputType == 'radio' && this.validateRadio()) ||
19073 (this.inputType == 'checkbox' && this.validateCheckbox())
19079 this.markInvalid();
19083 validateRadio : function()
19087 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19088 if(!e.dom.checked){
19100 validateCheckbox : function()
19103 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19106 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19114 for(var i in group){
19119 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19126 * Mark this field as valid
19128 markValid : function()
19130 if(this.allowBlank){
19136 this.fireEvent('valid', this);
19138 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19141 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19148 if(this.inputType == 'radio'){
19149 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19150 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19151 e.findParent('.form-group', false, true).addClass(_this.validClass);
19158 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19159 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19163 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19169 for(var i in group){
19170 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19171 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19176 * Mark this field as invalid
19177 * @param {String} msg The validation message
19179 markInvalid : function(msg)
19181 if(this.allowBlank){
19187 this.fireEvent('invalid', this, msg);
19189 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19192 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19196 label.markInvalid();
19199 if(this.inputType == 'radio'){
19200 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19201 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19202 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19209 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19210 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19214 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19220 for(var i in group){
19221 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19222 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19229 Roo.apply(Roo.bootstrap.CheckBox, {
19234 * register a CheckBox Group
19235 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19237 register : function(checkbox)
19239 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19240 this.groups[checkbox.groupId] = {};
19243 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19247 this.groups[checkbox.groupId][checkbox.name] = checkbox;
19251 * fetch a CheckBox Group based on the group ID
19252 * @param {string} the group ID
19253 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
19255 get: function(groupId) {
19256 if (typeof(this.groups[groupId]) == 'undefined') {
19260 return this.groups[groupId] ;
19272 *<div class="radio">
19274 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
19275 Option one is this and that—be sure to include why it's great
19282 *<label class="radio-inline">fieldLabel</label>
19283 *<label class="radio-inline">
19284 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
19292 * @class Roo.bootstrap.Radio
19293 * @extends Roo.bootstrap.CheckBox
19294 * Bootstrap Radio class
19297 * Create a new Radio
19298 * @param {Object} config The config object
19301 Roo.bootstrap.Radio = function(config){
19302 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
19306 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
19308 inputType: 'radio',
19312 getAutoCreate : function()
19314 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19315 align = align || 'left'; // default...
19322 tag : this.inline ? 'span' : 'div',
19327 var inline = this.inline ? ' radio-inline' : '';
19331 // does not need for, as we wrap the input with it..
19333 cls : 'control-label box-label' + inline,
19336 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
19340 //cls : 'control-label' + inline,
19341 html : this.fieldLabel,
19342 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
19351 type : this.inputType,
19352 //value : (!this.checked) ? this.valueOff : this.inputValue,
19353 value : this.inputValue,
19355 placeholder : this.placeholder || '' // ?? needed????
19358 if (this.weight) { // Validity check?
19359 input.cls += " radio-" + this.weight;
19361 if (this.disabled) {
19362 input.disabled=true;
19366 input.checked = this.checked;
19370 input.name = this.name;
19374 input.cls += ' input-' + this.size;
19377 //?? can span's inline have a width??
19380 ['xs','sm','md','lg'].map(function(size){
19381 if (settings[size]) {
19382 cfg.cls += ' col-' + size + '-' + settings[size];
19386 var inputblock = input;
19388 if (this.before || this.after) {
19391 cls : 'input-group',
19396 inputblock.cn.push({
19398 cls : 'input-group-addon',
19402 inputblock.cn.push(input);
19404 inputblock.cn.push({
19406 cls : 'input-group-addon',
19414 if (this.fieldLabel && this.fieldLabel.length) {
19415 cfg.cn.push(fieldLabel);
19418 // normal bootstrap puts the input inside the label.
19419 // however with our styled version - it has to go after the input.
19421 //lbl.cn.push(inputblock);
19425 cls: 'radio' + inline,
19432 cfg.cn.push( lblwrap);
19437 html: this.boxLabel
19446 initEvents : function()
19448 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19450 this.inputEl().on('click', this.onClick, this);
19451 if (this.boxLabel) {
19452 //Roo.log('find label');
19453 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
19458 inputEl: function ()
19460 return this.el.select('input.roo-radio',true).first();
19462 onClick : function()
19465 this.setChecked(true);
19468 setChecked : function(state,suppressEvent)
19471 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19472 v.dom.checked = false;
19475 Roo.log(this.inputEl().dom);
19476 this.checked = state;
19477 this.inputEl().dom.checked = state;
19479 if(suppressEvent !== true){
19480 this.fireEvent('check', this, state);
19483 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19487 getGroupValue : function()
19490 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19491 if(v.dom.checked == true){
19492 value = v.dom.value;
19500 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19501 * @return {Mixed} value The field value
19503 getValue : function(){
19504 return this.getGroupValue();
19510 //<script type="text/javascript">
19513 * Based Ext JS Library 1.1.1
19514 * Copyright(c) 2006-2007, Ext JS, LLC.
19520 * @class Roo.HtmlEditorCore
19521 * @extends Roo.Component
19522 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
19524 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
19527 Roo.HtmlEditorCore = function(config){
19530 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
19535 * @event initialize
19536 * Fires when the editor is fully initialized (including the iframe)
19537 * @param {Roo.HtmlEditorCore} this
19542 * Fires when the editor is first receives the focus. Any insertion must wait
19543 * until after this event.
19544 * @param {Roo.HtmlEditorCore} this
19548 * @event beforesync
19549 * Fires before the textarea is updated with content from the editor iframe. Return false
19550 * to cancel the sync.
19551 * @param {Roo.HtmlEditorCore} this
19552 * @param {String} html
19556 * @event beforepush
19557 * Fires before the iframe editor is updated with content from the textarea. Return false
19558 * to cancel the push.
19559 * @param {Roo.HtmlEditorCore} this
19560 * @param {String} html
19565 * Fires when the textarea is updated with content from the editor iframe.
19566 * @param {Roo.HtmlEditorCore} this
19567 * @param {String} html
19572 * Fires when the iframe editor is updated with content from the textarea.
19573 * @param {Roo.HtmlEditorCore} this
19574 * @param {String} html
19579 * @event editorevent
19580 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19581 * @param {Roo.HtmlEditorCore} this
19587 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
19589 // defaults : white / black...
19590 this.applyBlacklists();
19597 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
19601 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
19607 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19612 * @cfg {Number} height (in pixels)
19616 * @cfg {Number} width (in pixels)
19621 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19624 stylesheets: false,
19629 // private properties
19630 validationEvent : false,
19632 initialized : false,
19634 sourceEditMode : false,
19635 onFocus : Roo.emptyFn,
19637 hideMode:'offsets',
19641 // blacklist + whitelisted elements..
19648 * Protected method that will not generally be called directly. It
19649 * is called when the editor initializes the iframe with HTML contents. Override this method if you
19650 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
19652 getDocMarkup : function(){
19656 // inherit styels from page...??
19657 if (this.stylesheets === false) {
19659 Roo.get(document.head).select('style').each(function(node) {
19660 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19663 Roo.get(document.head).select('link').each(function(node) {
19664 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19667 } else if (!this.stylesheets.length) {
19669 st = '<style type="text/css">' +
19670 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19676 st += '<style type="text/css">' +
19677 'IMG { cursor: pointer } ' +
19681 return '<html><head>' + st +
19682 //<style type="text/css">' +
19683 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19685 ' </head><body class="roo-htmleditor-body"></body></html>';
19689 onRender : function(ct, position)
19692 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
19693 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
19696 this.el.dom.style.border = '0 none';
19697 this.el.dom.setAttribute('tabIndex', -1);
19698 this.el.addClass('x-hidden hide');
19702 if(Roo.isIE){ // fix IE 1px bogus margin
19703 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
19707 this.frameId = Roo.id();
19711 var iframe = this.owner.wrap.createChild({
19713 cls: 'form-control', // bootstrap..
19715 name: this.frameId,
19716 frameBorder : 'no',
19717 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
19722 this.iframe = iframe.dom;
19724 this.assignDocWin();
19726 this.doc.designMode = 'on';
19729 this.doc.write(this.getDocMarkup());
19733 var task = { // must defer to wait for browser to be ready
19735 //console.log("run task?" + this.doc.readyState);
19736 this.assignDocWin();
19737 if(this.doc.body || this.doc.readyState == 'complete'){
19739 this.doc.designMode="on";
19743 Roo.TaskMgr.stop(task);
19744 this.initEditor.defer(10, this);
19751 Roo.TaskMgr.start(task);
19756 onResize : function(w, h)
19758 Roo.log('resize: ' +w + ',' + h );
19759 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
19763 if(typeof w == 'number'){
19765 this.iframe.style.width = w + 'px';
19767 if(typeof h == 'number'){
19769 this.iframe.style.height = h + 'px';
19771 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
19778 * Toggles the editor between standard and source edit mode.
19779 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19781 toggleSourceEdit : function(sourceEditMode){
19783 this.sourceEditMode = sourceEditMode === true;
19785 if(this.sourceEditMode){
19787 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19790 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19791 //this.iframe.className = '';
19794 //this.setSize(this.owner.wrap.getSize());
19795 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19802 * Protected method that will not generally be called directly. If you need/want
19803 * custom HTML cleanup, this is the method you should override.
19804 * @param {String} html The HTML to be cleaned
19805 * return {String} The cleaned HTML
19807 cleanHtml : function(html){
19808 html = String(html);
19809 if(html.length > 5){
19810 if(Roo.isSafari){ // strip safari nonsense
19811 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19814 if(html == ' '){
19821 * HTML Editor -> Textarea
19822 * Protected method that will not generally be called directly. Syncs the contents
19823 * of the editor iframe with the textarea.
19825 syncValue : function(){
19826 if(this.initialized){
19827 var bd = (this.doc.body || this.doc.documentElement);
19828 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19829 var html = bd.innerHTML;
19831 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19832 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19834 html = '<div style="'+m[0]+'">' + html + '</div>';
19837 html = this.cleanHtml(html);
19838 // fix up the special chars.. normaly like back quotes in word...
19839 // however we do not want to do this with chinese..
19840 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19841 var cc = b.charCodeAt();
19843 (cc >= 0x4E00 && cc < 0xA000 ) ||
19844 (cc >= 0x3400 && cc < 0x4E00 ) ||
19845 (cc >= 0xf900 && cc < 0xfb00 )
19851 if(this.owner.fireEvent('beforesync', this, html) !== false){
19852 this.el.dom.value = html;
19853 this.owner.fireEvent('sync', this, html);
19859 * Protected method that will not generally be called directly. Pushes the value of the textarea
19860 * into the iframe editor.
19862 pushValue : function(){
19863 if(this.initialized){
19864 var v = this.el.dom.value.trim();
19866 // if(v.length < 1){
19870 if(this.owner.fireEvent('beforepush', this, v) !== false){
19871 var d = (this.doc.body || this.doc.documentElement);
19873 this.cleanUpPaste();
19874 this.el.dom.value = d.innerHTML;
19875 this.owner.fireEvent('push', this, v);
19881 deferFocus : function(){
19882 this.focus.defer(10, this);
19886 focus : function(){
19887 if(this.win && !this.sourceEditMode){
19894 assignDocWin: function()
19896 var iframe = this.iframe;
19899 this.doc = iframe.contentWindow.document;
19900 this.win = iframe.contentWindow;
19902 // if (!Roo.get(this.frameId)) {
19905 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19906 // this.win = Roo.get(this.frameId).dom.contentWindow;
19908 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19912 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19913 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19918 initEditor : function(){
19919 //console.log("INIT EDITOR");
19920 this.assignDocWin();
19924 this.doc.designMode="on";
19926 this.doc.write(this.getDocMarkup());
19929 var dbody = (this.doc.body || this.doc.documentElement);
19930 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
19931 // this copies styles from the containing element into thsi one..
19932 // not sure why we need all of this..
19933 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
19935 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
19936 //ss['background-attachment'] = 'fixed'; // w3c
19937 dbody.bgProperties = 'fixed'; // ie
19938 //Roo.DomHelper.applyStyles(dbody, ss);
19939 Roo.EventManager.on(this.doc, {
19940 //'mousedown': this.onEditorEvent,
19941 'mouseup': this.onEditorEvent,
19942 'dblclick': this.onEditorEvent,
19943 'click': this.onEditorEvent,
19944 'keyup': this.onEditorEvent,
19949 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
19951 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
19952 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
19954 this.initialized = true;
19956 this.owner.fireEvent('initialize', this);
19961 onDestroy : function(){
19967 //for (var i =0; i < this.toolbars.length;i++) {
19968 // // fixme - ask toolbars for heights?
19969 // this.toolbars[i].onDestroy();
19972 //this.wrap.dom.innerHTML = '';
19973 //this.wrap.remove();
19978 onFirstFocus : function(){
19980 this.assignDocWin();
19983 this.activated = true;
19986 if(Roo.isGecko){ // prevent silly gecko errors
19988 var s = this.win.getSelection();
19989 if(!s.focusNode || s.focusNode.nodeType != 3){
19990 var r = s.getRangeAt(0);
19991 r.selectNodeContents((this.doc.body || this.doc.documentElement));
19996 this.execCmd('useCSS', true);
19997 this.execCmd('styleWithCSS', false);
20000 this.owner.fireEvent('activate', this);
20004 adjustFont: function(btn){
20005 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20006 //if(Roo.isSafari){ // safari
20009 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20010 if(Roo.isSafari){ // safari
20011 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20012 v = (v < 10) ? 10 : v;
20013 v = (v > 48) ? 48 : v;
20014 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20019 v = Math.max(1, v+adjust);
20021 this.execCmd('FontSize', v );
20024 onEditorEvent : function(e)
20026 this.owner.fireEvent('editorevent', this, e);
20027 // this.updateToolbar();
20028 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20031 insertTag : function(tg)
20033 // could be a bit smarter... -> wrap the current selected tRoo..
20034 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20036 range = this.createRange(this.getSelection());
20037 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20038 wrappingNode.appendChild(range.extractContents());
20039 range.insertNode(wrappingNode);
20046 this.execCmd("formatblock", tg);
20050 insertText : function(txt)
20054 var range = this.createRange();
20055 range.deleteContents();
20056 //alert(Sender.getAttribute('label'));
20058 range.insertNode(this.doc.createTextNode(txt));
20064 * Executes a Midas editor command on the editor document and performs necessary focus and
20065 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20066 * @param {String} cmd The Midas command
20067 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20069 relayCmd : function(cmd, value){
20071 this.execCmd(cmd, value);
20072 this.owner.fireEvent('editorevent', this);
20073 //this.updateToolbar();
20074 this.owner.deferFocus();
20078 * Executes a Midas editor command directly on the editor document.
20079 * For visual commands, you should use {@link #relayCmd} instead.
20080 * <b>This should only be called after the editor is initialized.</b>
20081 * @param {String} cmd The Midas command
20082 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20084 execCmd : function(cmd, value){
20085 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20092 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20094 * @param {String} text | dom node..
20096 insertAtCursor : function(text)
20101 if(!this.activated){
20107 var r = this.doc.selection.createRange();
20118 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20122 // from jquery ui (MIT licenced)
20124 var win = this.win;
20126 if (win.getSelection && win.getSelection().getRangeAt) {
20127 range = win.getSelection().getRangeAt(0);
20128 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20129 range.insertNode(node);
20130 } else if (win.document.selection && win.document.selection.createRange) {
20131 // no firefox support
20132 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20133 win.document.selection.createRange().pasteHTML(txt);
20135 // no firefox support
20136 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20137 this.execCmd('InsertHTML', txt);
20146 mozKeyPress : function(e){
20148 var c = e.getCharCode(), cmd;
20151 c = String.fromCharCode(c).toLowerCase();
20165 this.cleanUpPaste.defer(100, this);
20173 e.preventDefault();
20181 fixKeys : function(){ // load time branching for fastest keydown performance
20183 return function(e){
20184 var k = e.getKey(), r;
20187 r = this.doc.selection.createRange();
20190 r.pasteHTML('    ');
20197 r = this.doc.selection.createRange();
20199 var target = r.parentElement();
20200 if(!target || target.tagName.toLowerCase() != 'li'){
20202 r.pasteHTML('<br />');
20208 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20209 this.cleanUpPaste.defer(100, this);
20215 }else if(Roo.isOpera){
20216 return function(e){
20217 var k = e.getKey();
20221 this.execCmd('InsertHTML','    ');
20224 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20225 this.cleanUpPaste.defer(100, this);
20230 }else if(Roo.isSafari){
20231 return function(e){
20232 var k = e.getKey();
20236 this.execCmd('InsertText','\t');
20240 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20241 this.cleanUpPaste.defer(100, this);
20249 getAllAncestors: function()
20251 var p = this.getSelectedNode();
20254 a.push(p); // push blank onto stack..
20255 p = this.getParentElement();
20259 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
20263 a.push(this.doc.body);
20267 lastSelNode : false,
20270 getSelection : function()
20272 this.assignDocWin();
20273 return Roo.isIE ? this.doc.selection : this.win.getSelection();
20276 getSelectedNode: function()
20278 // this may only work on Gecko!!!
20280 // should we cache this!!!!
20285 var range = this.createRange(this.getSelection()).cloneRange();
20288 var parent = range.parentElement();
20290 var testRange = range.duplicate();
20291 testRange.moveToElementText(parent);
20292 if (testRange.inRange(range)) {
20295 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
20298 parent = parent.parentElement;
20303 // is ancestor a text element.
20304 var ac = range.commonAncestorContainer;
20305 if (ac.nodeType == 3) {
20306 ac = ac.parentNode;
20309 var ar = ac.childNodes;
20312 var other_nodes = [];
20313 var has_other_nodes = false;
20314 for (var i=0;i<ar.length;i++) {
20315 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
20318 // fullly contained node.
20320 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
20325 // probably selected..
20326 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
20327 other_nodes.push(ar[i]);
20331 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
20336 has_other_nodes = true;
20338 if (!nodes.length && other_nodes.length) {
20339 nodes= other_nodes;
20341 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
20347 createRange: function(sel)
20349 // this has strange effects when using with
20350 // top toolbar - not sure if it's a great idea.
20351 //this.editor.contentWindow.focus();
20352 if (typeof sel != "undefined") {
20354 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
20356 return this.doc.createRange();
20359 return this.doc.createRange();
20362 getParentElement: function()
20365 this.assignDocWin();
20366 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
20368 var range = this.createRange(sel);
20371 var p = range.commonAncestorContainer;
20372 while (p.nodeType == 3) { // text node
20383 * Range intersection.. the hard stuff...
20387 * [ -- selected range --- ]
20391 * if end is before start or hits it. fail.
20392 * if start is after end or hits it fail.
20394 * if either hits (but other is outside. - then it's not
20400 // @see http://www.thismuchiknow.co.uk/?p=64.
20401 rangeIntersectsNode : function(range, node)
20403 var nodeRange = node.ownerDocument.createRange();
20405 nodeRange.selectNode(node);
20407 nodeRange.selectNodeContents(node);
20410 var rangeStartRange = range.cloneRange();
20411 rangeStartRange.collapse(true);
20413 var rangeEndRange = range.cloneRange();
20414 rangeEndRange.collapse(false);
20416 var nodeStartRange = nodeRange.cloneRange();
20417 nodeStartRange.collapse(true);
20419 var nodeEndRange = nodeRange.cloneRange();
20420 nodeEndRange.collapse(false);
20422 return rangeStartRange.compareBoundaryPoints(
20423 Range.START_TO_START, nodeEndRange) == -1 &&
20424 rangeEndRange.compareBoundaryPoints(
20425 Range.START_TO_START, nodeStartRange) == 1;
20429 rangeCompareNode : function(range, node)
20431 var nodeRange = node.ownerDocument.createRange();
20433 nodeRange.selectNode(node);
20435 nodeRange.selectNodeContents(node);
20439 range.collapse(true);
20441 nodeRange.collapse(true);
20443 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
20444 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
20446 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
20448 var nodeIsBefore = ss == 1;
20449 var nodeIsAfter = ee == -1;
20451 if (nodeIsBefore && nodeIsAfter) {
20454 if (!nodeIsBefore && nodeIsAfter) {
20455 return 1; //right trailed.
20458 if (nodeIsBefore && !nodeIsAfter) {
20459 return 2; // left trailed.
20465 // private? - in a new class?
20466 cleanUpPaste : function()
20468 // cleans up the whole document..
20469 Roo.log('cleanuppaste');
20471 this.cleanUpChildren(this.doc.body);
20472 var clean = this.cleanWordChars(this.doc.body.innerHTML);
20473 if (clean != this.doc.body.innerHTML) {
20474 this.doc.body.innerHTML = clean;
20479 cleanWordChars : function(input) {// change the chars to hex code
20480 var he = Roo.HtmlEditorCore;
20482 var output = input;
20483 Roo.each(he.swapCodes, function(sw) {
20484 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
20486 output = output.replace(swapper, sw[1]);
20493 cleanUpChildren : function (n)
20495 if (!n.childNodes.length) {
20498 for (var i = n.childNodes.length-1; i > -1 ; i--) {
20499 this.cleanUpChild(n.childNodes[i]);
20506 cleanUpChild : function (node)
20509 //console.log(node);
20510 if (node.nodeName == "#text") {
20511 // clean up silly Windows -- stuff?
20514 if (node.nodeName == "#comment") {
20515 node.parentNode.removeChild(node);
20516 // clean up silly Windows -- stuff?
20519 var lcname = node.tagName.toLowerCase();
20520 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
20521 // whitelist of tags..
20523 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
20525 node.parentNode.removeChild(node);
20530 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
20532 // remove <a name=....> as rendering on yahoo mailer is borked with this.
20533 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
20535 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
20536 // remove_keep_children = true;
20539 if (remove_keep_children) {
20540 this.cleanUpChildren(node);
20541 // inserts everything just before this node...
20542 while (node.childNodes.length) {
20543 var cn = node.childNodes[0];
20544 node.removeChild(cn);
20545 node.parentNode.insertBefore(cn, node);
20547 node.parentNode.removeChild(node);
20551 if (!node.attributes || !node.attributes.length) {
20552 this.cleanUpChildren(node);
20556 function cleanAttr(n,v)
20559 if (v.match(/^\./) || v.match(/^\//)) {
20562 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
20565 if (v.match(/^#/)) {
20568 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
20569 node.removeAttribute(n);
20573 var cwhite = this.cwhite;
20574 var cblack = this.cblack;
20576 function cleanStyle(n,v)
20578 if (v.match(/expression/)) { //XSS?? should we even bother..
20579 node.removeAttribute(n);
20583 var parts = v.split(/;/);
20586 Roo.each(parts, function(p) {
20587 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
20591 var l = p.split(':').shift().replace(/\s+/g,'');
20592 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
20594 if ( cwhite.length && cblack.indexOf(l) > -1) {
20595 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20596 //node.removeAttribute(n);
20600 // only allow 'c whitelisted system attributes'
20601 if ( cwhite.length && cwhite.indexOf(l) < 0) {
20602 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20603 //node.removeAttribute(n);
20613 if (clean.length) {
20614 node.setAttribute(n, clean.join(';'));
20616 node.removeAttribute(n);
20622 for (var i = node.attributes.length-1; i > -1 ; i--) {
20623 var a = node.attributes[i];
20626 if (a.name.toLowerCase().substr(0,2)=='on') {
20627 node.removeAttribute(a.name);
20630 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
20631 node.removeAttribute(a.name);
20634 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
20635 cleanAttr(a.name,a.value); // fixme..
20638 if (a.name == 'style') {
20639 cleanStyle(a.name,a.value);
20642 /// clean up MS crap..
20643 // tecnically this should be a list of valid class'es..
20646 if (a.name == 'class') {
20647 if (a.value.match(/^Mso/)) {
20648 node.className = '';
20651 if (a.value.match(/body/)) {
20652 node.className = '';
20663 this.cleanUpChildren(node);
20669 * Clean up MS wordisms...
20671 cleanWord : function(node)
20676 this.cleanWord(this.doc.body);
20679 if (node.nodeName == "#text") {
20680 // clean up silly Windows -- stuff?
20683 if (node.nodeName == "#comment") {
20684 node.parentNode.removeChild(node);
20685 // clean up silly Windows -- stuff?
20689 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
20690 node.parentNode.removeChild(node);
20694 // remove - but keep children..
20695 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
20696 while (node.childNodes.length) {
20697 var cn = node.childNodes[0];
20698 node.removeChild(cn);
20699 node.parentNode.insertBefore(cn, node);
20701 node.parentNode.removeChild(node);
20702 this.iterateChildren(node, this.cleanWord);
20706 if (node.className.length) {
20708 var cn = node.className.split(/\W+/);
20710 Roo.each(cn, function(cls) {
20711 if (cls.match(/Mso[a-zA-Z]+/)) {
20716 node.className = cna.length ? cna.join(' ') : '';
20718 node.removeAttribute("class");
20722 if (node.hasAttribute("lang")) {
20723 node.removeAttribute("lang");
20726 if (node.hasAttribute("style")) {
20728 var styles = node.getAttribute("style").split(";");
20730 Roo.each(styles, function(s) {
20731 if (!s.match(/:/)) {
20734 var kv = s.split(":");
20735 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
20738 // what ever is left... we allow.
20741 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20742 if (!nstyle.length) {
20743 node.removeAttribute('style');
20746 this.iterateChildren(node, this.cleanWord);
20752 * iterateChildren of a Node, calling fn each time, using this as the scole..
20753 * @param {DomNode} node node to iterate children of.
20754 * @param {Function} fn method of this class to call on each item.
20756 iterateChildren : function(node, fn)
20758 if (!node.childNodes.length) {
20761 for (var i = node.childNodes.length-1; i > -1 ; i--) {
20762 fn.call(this, node.childNodes[i])
20768 * cleanTableWidths.
20770 * Quite often pasting from word etc.. results in tables with column and widths.
20771 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
20774 cleanTableWidths : function(node)
20779 this.cleanTableWidths(this.doc.body);
20784 if (node.nodeName == "#text" || node.nodeName == "#comment") {
20787 Roo.log(node.tagName);
20788 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
20789 this.iterateChildren(node, this.cleanTableWidths);
20792 if (node.hasAttribute('width')) {
20793 node.removeAttribute('width');
20797 if (node.hasAttribute("style")) {
20800 var styles = node.getAttribute("style").split(";");
20802 Roo.each(styles, function(s) {
20803 if (!s.match(/:/)) {
20806 var kv = s.split(":");
20807 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20810 // what ever is left... we allow.
20813 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20814 if (!nstyle.length) {
20815 node.removeAttribute('style');
20819 this.iterateChildren(node, this.cleanTableWidths);
20827 domToHTML : function(currentElement, depth, nopadtext) {
20829 depth = depth || 0;
20830 nopadtext = nopadtext || false;
20832 if (!currentElement) {
20833 return this.domToHTML(this.doc.body);
20836 //Roo.log(currentElement);
20838 var allText = false;
20839 var nodeName = currentElement.nodeName;
20840 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20842 if (nodeName == '#text') {
20844 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20849 if (nodeName != 'BODY') {
20852 // Prints the node tagName, such as <A>, <IMG>, etc
20855 for(i = 0; i < currentElement.attributes.length;i++) {
20857 var aname = currentElement.attributes.item(i).name;
20858 if (!currentElement.attributes.item(i).value.length) {
20861 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20864 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20873 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20876 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20881 // Traverse the tree
20883 var currentElementChild = currentElement.childNodes.item(i);
20884 var allText = true;
20885 var innerHTML = '';
20887 while (currentElementChild) {
20888 // Formatting code (indent the tree so it looks nice on the screen)
20889 var nopad = nopadtext;
20890 if (lastnode == 'SPAN') {
20894 if (currentElementChild.nodeName == '#text') {
20895 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20896 toadd = nopadtext ? toadd : toadd.trim();
20897 if (!nopad && toadd.length > 80) {
20898 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20900 innerHTML += toadd;
20903 currentElementChild = currentElement.childNodes.item(i);
20909 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20911 // Recursively traverse the tree structure of the child node
20912 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20913 lastnode = currentElementChild.nodeName;
20915 currentElementChild=currentElement.childNodes.item(i);
20921 // The remaining code is mostly for formatting the tree
20922 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20927 ret+= "</"+tagName+">";
20933 applyBlacklists : function()
20935 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
20936 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
20940 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
20941 if (b.indexOf(tag) > -1) {
20944 this.white.push(tag);
20948 Roo.each(w, function(tag) {
20949 if (b.indexOf(tag) > -1) {
20952 if (this.white.indexOf(tag) > -1) {
20955 this.white.push(tag);
20960 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
20961 if (w.indexOf(tag) > -1) {
20964 this.black.push(tag);
20968 Roo.each(b, function(tag) {
20969 if (w.indexOf(tag) > -1) {
20972 if (this.black.indexOf(tag) > -1) {
20975 this.black.push(tag);
20980 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
20981 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
20985 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
20986 if (b.indexOf(tag) > -1) {
20989 this.cwhite.push(tag);
20993 Roo.each(w, function(tag) {
20994 if (b.indexOf(tag) > -1) {
20997 if (this.cwhite.indexOf(tag) > -1) {
21000 this.cwhite.push(tag);
21005 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21006 if (w.indexOf(tag) > -1) {
21009 this.cblack.push(tag);
21013 Roo.each(b, function(tag) {
21014 if (w.indexOf(tag) > -1) {
21017 if (this.cblack.indexOf(tag) > -1) {
21020 this.cblack.push(tag);
21025 setStylesheets : function(stylesheets)
21027 if(typeof(stylesheets) == 'string'){
21028 Roo.get(this.iframe.contentDocument.head).createChild({
21030 rel : 'stylesheet',
21039 Roo.each(stylesheets, function(s) {
21044 Roo.get(_this.iframe.contentDocument.head).createChild({
21046 rel : 'stylesheet',
21055 removeStylesheets : function()
21059 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21064 // hide stuff that is not compatible
21078 * @event specialkey
21082 * @cfg {String} fieldClass @hide
21085 * @cfg {String} focusClass @hide
21088 * @cfg {String} autoCreate @hide
21091 * @cfg {String} inputType @hide
21094 * @cfg {String} invalidClass @hide
21097 * @cfg {String} invalidText @hide
21100 * @cfg {String} msgFx @hide
21103 * @cfg {String} validateOnBlur @hide
21107 Roo.HtmlEditorCore.white = [
21108 'area', 'br', 'img', 'input', 'hr', 'wbr',
21110 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21111 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21112 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21113 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21114 'table', 'ul', 'xmp',
21116 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21119 'dir', 'menu', 'ol', 'ul', 'dl',
21125 Roo.HtmlEditorCore.black = [
21126 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21128 'base', 'basefont', 'bgsound', 'blink', 'body',
21129 'frame', 'frameset', 'head', 'html', 'ilayer',
21130 'iframe', 'layer', 'link', 'meta', 'object',
21131 'script', 'style' ,'title', 'xml' // clean later..
21133 Roo.HtmlEditorCore.clean = [
21134 'script', 'style', 'title', 'xml'
21136 Roo.HtmlEditorCore.remove = [
21141 Roo.HtmlEditorCore.ablack = [
21145 Roo.HtmlEditorCore.aclean = [
21146 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21150 Roo.HtmlEditorCore.pwhite= [
21151 'http', 'https', 'mailto'
21154 // white listed style attributes.
21155 Roo.HtmlEditorCore.cwhite= [
21156 // 'text-align', /// default is to allow most things..
21162 // black listed style attributes.
21163 Roo.HtmlEditorCore.cblack= [
21164 // 'font-size' -- this can be set by the project
21168 Roo.HtmlEditorCore.swapCodes =[
21187 * @class Roo.bootstrap.HtmlEditor
21188 * @extends Roo.bootstrap.TextArea
21189 * Bootstrap HtmlEditor class
21192 * Create a new HtmlEditor
21193 * @param {Object} config The config object
21196 Roo.bootstrap.HtmlEditor = function(config){
21197 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21198 if (!this.toolbars) {
21199 this.toolbars = [];
21201 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21204 * @event initialize
21205 * Fires when the editor is fully initialized (including the iframe)
21206 * @param {HtmlEditor} this
21211 * Fires when the editor is first receives the focus. Any insertion must wait
21212 * until after this event.
21213 * @param {HtmlEditor} this
21217 * @event beforesync
21218 * Fires before the textarea is updated with content from the editor iframe. Return false
21219 * to cancel the sync.
21220 * @param {HtmlEditor} this
21221 * @param {String} html
21225 * @event beforepush
21226 * Fires before the iframe editor is updated with content from the textarea. Return false
21227 * to cancel the push.
21228 * @param {HtmlEditor} this
21229 * @param {String} html
21234 * Fires when the textarea is updated with content from the editor iframe.
21235 * @param {HtmlEditor} this
21236 * @param {String} html
21241 * Fires when the iframe editor is updated with content from the textarea.
21242 * @param {HtmlEditor} this
21243 * @param {String} html
21247 * @event editmodechange
21248 * Fires when the editor switches edit modes
21249 * @param {HtmlEditor} this
21250 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21252 editmodechange: true,
21254 * @event editorevent
21255 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21256 * @param {HtmlEditor} this
21260 * @event firstfocus
21261 * Fires when on first focus - needed by toolbars..
21262 * @param {HtmlEditor} this
21267 * Auto save the htmlEditor value as a file into Events
21268 * @param {HtmlEditor} this
21272 * @event savedpreview
21273 * preview the saved version of htmlEditor
21274 * @param {HtmlEditor} this
21281 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
21285 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
21290 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21295 * @cfg {Number} height (in pixels)
21299 * @cfg {Number} width (in pixels)
21304 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21307 stylesheets: false,
21312 // private properties
21313 validationEvent : false,
21315 initialized : false,
21318 onFocus : Roo.emptyFn,
21320 hideMode:'offsets',
21323 tbContainer : false,
21325 toolbarContainer :function() {
21326 return this.wrap.select('.x-html-editor-tb',true).first();
21330 * Protected method that will not generally be called directly. It
21331 * is called when the editor creates its toolbar. Override this method if you need to
21332 * add custom toolbar buttons.
21333 * @param {HtmlEditor} editor
21335 createToolbar : function(){
21337 Roo.log("create toolbars");
21339 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
21340 this.toolbars[0].render(this.toolbarContainer());
21344 // if (!editor.toolbars || !editor.toolbars.length) {
21345 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
21348 // for (var i =0 ; i < editor.toolbars.length;i++) {
21349 // editor.toolbars[i] = Roo.factory(
21350 // typeof(editor.toolbars[i]) == 'string' ?
21351 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
21352 // Roo.bootstrap.HtmlEditor);
21353 // editor.toolbars[i].init(editor);
21359 onRender : function(ct, position)
21361 // Roo.log("Call onRender: " + this.xtype);
21363 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
21365 this.wrap = this.inputEl().wrap({
21366 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
21369 this.editorcore.onRender(ct, position);
21371 if (this.resizable) {
21372 this.resizeEl = new Roo.Resizable(this.wrap, {
21376 minHeight : this.height,
21377 height: this.height,
21378 handles : this.resizable,
21381 resize : function(r, w, h) {
21382 _t.onResize(w,h); // -something
21388 this.createToolbar(this);
21391 if(!this.width && this.resizable){
21392 this.setSize(this.wrap.getSize());
21394 if (this.resizeEl) {
21395 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
21396 // should trigger onReize..
21402 onResize : function(w, h)
21404 Roo.log('resize: ' +w + ',' + h );
21405 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
21409 if(this.inputEl() ){
21410 if(typeof w == 'number'){
21411 var aw = w - this.wrap.getFrameWidth('lr');
21412 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
21415 if(typeof h == 'number'){
21416 var tbh = -11; // fixme it needs to tool bar size!
21417 for (var i =0; i < this.toolbars.length;i++) {
21418 // fixme - ask toolbars for heights?
21419 tbh += this.toolbars[i].el.getHeight();
21420 //if (this.toolbars[i].footer) {
21421 // tbh += this.toolbars[i].footer.el.getHeight();
21429 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
21430 ah -= 5; // knock a few pixes off for look..
21431 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
21435 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
21436 this.editorcore.onResize(ew,eh);
21441 * Toggles the editor between standard and source edit mode.
21442 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21444 toggleSourceEdit : function(sourceEditMode)
21446 this.editorcore.toggleSourceEdit(sourceEditMode);
21448 if(this.editorcore.sourceEditMode){
21449 Roo.log('editor - showing textarea');
21452 // Roo.log(this.syncValue());
21454 this.inputEl().removeClass(['hide', 'x-hidden']);
21455 this.inputEl().dom.removeAttribute('tabIndex');
21456 this.inputEl().focus();
21458 Roo.log('editor - hiding textarea');
21460 // Roo.log(this.pushValue());
21463 this.inputEl().addClass(['hide', 'x-hidden']);
21464 this.inputEl().dom.setAttribute('tabIndex', -1);
21465 //this.deferFocus();
21468 if(this.resizable){
21469 this.setSize(this.wrap.getSize());
21472 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
21475 // private (for BoxComponent)
21476 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21478 // private (for BoxComponent)
21479 getResizeEl : function(){
21483 // private (for BoxComponent)
21484 getPositionEl : function(){
21489 initEvents : function(){
21490 this.originalValue = this.getValue();
21494 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21497 // markInvalid : Roo.emptyFn,
21499 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21502 // clearInvalid : Roo.emptyFn,
21504 setValue : function(v){
21505 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
21506 this.editorcore.pushValue();
21511 deferFocus : function(){
21512 this.focus.defer(10, this);
21516 focus : function(){
21517 this.editorcore.focus();
21523 onDestroy : function(){
21529 for (var i =0; i < this.toolbars.length;i++) {
21530 // fixme - ask toolbars for heights?
21531 this.toolbars[i].onDestroy();
21534 this.wrap.dom.innerHTML = '';
21535 this.wrap.remove();
21540 onFirstFocus : function(){
21541 //Roo.log("onFirstFocus");
21542 this.editorcore.onFirstFocus();
21543 for (var i =0; i < this.toolbars.length;i++) {
21544 this.toolbars[i].onFirstFocus();
21550 syncValue : function()
21552 this.editorcore.syncValue();
21555 pushValue : function()
21557 this.editorcore.pushValue();
21561 // hide stuff that is not compatible
21575 * @event specialkey
21579 * @cfg {String} fieldClass @hide
21582 * @cfg {String} focusClass @hide
21585 * @cfg {String} autoCreate @hide
21588 * @cfg {String} inputType @hide
21591 * @cfg {String} invalidClass @hide
21594 * @cfg {String} invalidText @hide
21597 * @cfg {String} msgFx @hide
21600 * @cfg {String} validateOnBlur @hide
21609 Roo.namespace('Roo.bootstrap.htmleditor');
21611 * @class Roo.bootstrap.HtmlEditorToolbar1
21616 new Roo.bootstrap.HtmlEditor({
21619 new Roo.bootstrap.HtmlEditorToolbar1({
21620 disable : { fonts: 1 , format: 1, ..., ... , ...],
21626 * @cfg {Object} disable List of elements to disable..
21627 * @cfg {Array} btns List of additional buttons.
21631 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
21634 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
21637 Roo.apply(this, config);
21639 // default disabled, based on 'good practice'..
21640 this.disable = this.disable || {};
21641 Roo.applyIf(this.disable, {
21644 specialElements : true
21646 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
21648 this.editor = config.editor;
21649 this.editorcore = config.editor.editorcore;
21651 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
21653 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
21654 // dont call parent... till later.
21656 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
21661 editorcore : false,
21666 "h1","h2","h3","h4","h5","h6",
21668 "abbr", "acronym", "address", "cite", "samp", "var",
21672 onRender : function(ct, position)
21674 // Roo.log("Call onRender: " + this.xtype);
21676 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
21678 this.el.dom.style.marginBottom = '0';
21680 var editorcore = this.editorcore;
21681 var editor= this.editor;
21684 var btn = function(id,cmd , toggle, handler){
21686 var event = toggle ? 'toggle' : 'click';
21691 xns: Roo.bootstrap,
21694 enableToggle:toggle !== false,
21696 pressed : toggle ? false : null,
21699 a.listeners[toggle ? 'toggle' : 'click'] = function() {
21700 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
21709 xns: Roo.bootstrap,
21710 glyphicon : 'font',
21714 xns: Roo.bootstrap,
21718 Roo.each(this.formats, function(f) {
21719 style.menu.items.push({
21721 xns: Roo.bootstrap,
21722 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
21727 editorcore.insertTag(this.tagname);
21734 children.push(style);
21737 btn('bold',false,true);
21738 btn('italic',false,true);
21739 btn('align-left', 'justifyleft',true);
21740 btn('align-center', 'justifycenter',true);
21741 btn('align-right' , 'justifyright',true);
21742 btn('link', false, false, function(btn) {
21743 //Roo.log("create link?");
21744 var url = prompt(this.createLinkText, this.defaultLinkValue);
21745 if(url && url != 'http:/'+'/'){
21746 this.editorcore.relayCmd('createlink', url);
21749 btn('list','insertunorderedlist',true);
21750 btn('pencil', false,true, function(btn){
21753 this.toggleSourceEdit(btn.pressed);
21759 xns: Roo.bootstrap,
21764 xns: Roo.bootstrap,
21769 cog.menu.items.push({
21771 xns: Roo.bootstrap,
21772 html : Clean styles,
21777 editorcore.insertTag(this.tagname);
21786 this.xtype = 'NavSimplebar';
21788 for(var i=0;i< children.length;i++) {
21790 this.buttons.add(this.addxtypeChild(children[i]));
21794 editor.on('editorevent', this.updateToolbar, this);
21796 onBtnClick : function(id)
21798 this.editorcore.relayCmd(id);
21799 this.editorcore.focus();
21803 * Protected method that will not generally be called directly. It triggers
21804 * a toolbar update by reading the markup state of the current selection in the editor.
21806 updateToolbar: function(){
21808 if(!this.editorcore.activated){
21809 this.editor.onFirstFocus(); // is this neeed?
21813 var btns = this.buttons;
21814 var doc = this.editorcore.doc;
21815 btns.get('bold').setActive(doc.queryCommandState('bold'));
21816 btns.get('italic').setActive(doc.queryCommandState('italic'));
21817 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21819 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21820 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21821 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21823 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21824 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21827 var ans = this.editorcore.getAllAncestors();
21828 if (this.formatCombo) {
21831 var store = this.formatCombo.store;
21832 this.formatCombo.setValue("");
21833 for (var i =0; i < ans.length;i++) {
21834 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21836 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21844 // hides menus... - so this cant be on a menu...
21845 Roo.bootstrap.MenuMgr.hideAll();
21847 Roo.bootstrap.MenuMgr.hideAll();
21848 //this.editorsyncValue();
21850 onFirstFocus: function() {
21851 this.buttons.each(function(item){
21855 toggleSourceEdit : function(sourceEditMode){
21858 if(sourceEditMode){
21859 Roo.log("disabling buttons");
21860 this.buttons.each( function(item){
21861 if(item.cmd != 'pencil'){
21867 Roo.log("enabling buttons");
21868 if(this.editorcore.initialized){
21869 this.buttons.each( function(item){
21875 Roo.log("calling toggole on editor");
21876 // tell the editor that it's been pressed..
21877 this.editor.toggleSourceEdit(sourceEditMode);
21887 * @class Roo.bootstrap.Table.AbstractSelectionModel
21888 * @extends Roo.util.Observable
21889 * Abstract base class for grid SelectionModels. It provides the interface that should be
21890 * implemented by descendant classes. This class should not be directly instantiated.
21893 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21894 this.locked = false;
21895 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21899 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21900 /** @ignore Called by the grid automatically. Do not call directly. */
21901 init : function(grid){
21907 * Locks the selections.
21910 this.locked = true;
21914 * Unlocks the selections.
21916 unlock : function(){
21917 this.locked = false;
21921 * Returns true if the selections are locked.
21922 * @return {Boolean}
21924 isLocked : function(){
21925 return this.locked;
21929 * @extends Roo.bootstrap.Table.AbstractSelectionModel
21930 * @class Roo.bootstrap.Table.RowSelectionModel
21931 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
21932 * It supports multiple selections and keyboard selection/navigation.
21934 * @param {Object} config
21937 Roo.bootstrap.Table.RowSelectionModel = function(config){
21938 Roo.apply(this, config);
21939 this.selections = new Roo.util.MixedCollection(false, function(o){
21944 this.lastActive = false;
21948 * @event selectionchange
21949 * Fires when the selection changes
21950 * @param {SelectionModel} this
21952 "selectionchange" : true,
21954 * @event afterselectionchange
21955 * Fires after the selection changes (eg. by key press or clicking)
21956 * @param {SelectionModel} this
21958 "afterselectionchange" : true,
21960 * @event beforerowselect
21961 * Fires when a row is selected being selected, return false to cancel.
21962 * @param {SelectionModel} this
21963 * @param {Number} rowIndex The selected index
21964 * @param {Boolean} keepExisting False if other selections will be cleared
21966 "beforerowselect" : true,
21969 * Fires when a row is selected.
21970 * @param {SelectionModel} this
21971 * @param {Number} rowIndex The selected index
21972 * @param {Roo.data.Record} r The record
21974 "rowselect" : true,
21976 * @event rowdeselect
21977 * Fires when a row is deselected.
21978 * @param {SelectionModel} this
21979 * @param {Number} rowIndex The selected index
21981 "rowdeselect" : true
21983 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
21984 this.locked = false;
21987 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
21989 * @cfg {Boolean} singleSelect
21990 * True to allow selection of only one row at a time (defaults to false)
21992 singleSelect : false,
21995 initEvents : function(){
21997 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
21998 this.grid.on("mousedown", this.handleMouseDown, this);
21999 }else{ // allow click to work like normal
22000 this.grid.on("rowclick", this.handleDragableRowClick, this);
22003 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22004 "up" : function(e){
22006 this.selectPrevious(e.shiftKey);
22007 }else if(this.last !== false && this.lastActive !== false){
22008 var last = this.last;
22009 this.selectRange(this.last, this.lastActive-1);
22010 this.grid.getView().focusRow(this.lastActive);
22011 if(last !== false){
22015 this.selectFirstRow();
22017 this.fireEvent("afterselectionchange", this);
22019 "down" : function(e){
22021 this.selectNext(e.shiftKey);
22022 }else if(this.last !== false && this.lastActive !== false){
22023 var last = this.last;
22024 this.selectRange(this.last, this.lastActive+1);
22025 this.grid.getView().focusRow(this.lastActive);
22026 if(last !== false){
22030 this.selectFirstRow();
22032 this.fireEvent("afterselectionchange", this);
22037 var view = this.grid.view;
22038 view.on("refresh", this.onRefresh, this);
22039 view.on("rowupdated", this.onRowUpdated, this);
22040 view.on("rowremoved", this.onRemove, this);
22044 onRefresh : function(){
22045 var ds = this.grid.dataSource, i, v = this.grid.view;
22046 var s = this.selections;
22047 s.each(function(r){
22048 if((i = ds.indexOfId(r.id)) != -1){
22057 onRemove : function(v, index, r){
22058 this.selections.remove(r);
22062 onRowUpdated : function(v, index, r){
22063 if(this.isSelected(r)){
22064 v.onRowSelect(index);
22070 * @param {Array} records The records to select
22071 * @param {Boolean} keepExisting (optional) True to keep existing selections
22073 selectRecords : function(records, keepExisting){
22075 this.clearSelections();
22077 var ds = this.grid.dataSource;
22078 for(var i = 0, len = records.length; i < len; i++){
22079 this.selectRow(ds.indexOf(records[i]), true);
22084 * Gets the number of selected rows.
22087 getCount : function(){
22088 return this.selections.length;
22092 * Selects the first row in the grid.
22094 selectFirstRow : function(){
22099 * Select the last row.
22100 * @param {Boolean} keepExisting (optional) True to keep existing selections
22102 selectLastRow : function(keepExisting){
22103 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22107 * Selects the row immediately following the last selected row.
22108 * @param {Boolean} keepExisting (optional) True to keep existing selections
22110 selectNext : function(keepExisting){
22111 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
22112 this.selectRow(this.last+1, keepExisting);
22113 this.grid.getView().focusRow(this.last);
22118 * Selects the row that precedes the last selected row.
22119 * @param {Boolean} keepExisting (optional) True to keep existing selections
22121 selectPrevious : function(keepExisting){
22123 this.selectRow(this.last-1, keepExisting);
22124 this.grid.getView().focusRow(this.last);
22129 * Returns the selected records
22130 * @return {Array} Array of selected records
22132 getSelections : function(){
22133 return [].concat(this.selections.items);
22137 * Returns the first selected record.
22140 getSelected : function(){
22141 return this.selections.itemAt(0);
22146 * Clears all selections.
22148 clearSelections : function(fast){
22153 var ds = this.grid.dataSource;
22154 var s = this.selections;
22155 s.each(function(r){
22156 this.deselectRow(ds.indexOfId(r.id));
22160 this.selections.clear();
22167 * Selects all rows.
22169 selectAll : function(){
22173 this.selections.clear();
22174 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
22175 this.selectRow(i, true);
22180 * Returns True if there is a selection.
22181 * @return {Boolean}
22183 hasSelection : function(){
22184 return this.selections.length > 0;
22188 * Returns True if the specified row is selected.
22189 * @param {Number/Record} record The record or index of the record to check
22190 * @return {Boolean}
22192 isSelected : function(index){
22193 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
22194 return (r && this.selections.key(r.id) ? true : false);
22198 * Returns True if the specified record id is selected.
22199 * @param {String} id The id of record to check
22200 * @return {Boolean}
22202 isIdSelected : function(id){
22203 return (this.selections.key(id) ? true : false);
22207 handleMouseDown : function(e, t){
22208 var view = this.grid.getView(), rowIndex;
22209 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
22212 if(e.shiftKey && this.last !== false){
22213 var last = this.last;
22214 this.selectRange(last, rowIndex, e.ctrlKey);
22215 this.last = last; // reset the last
22216 view.focusRow(rowIndex);
22218 var isSelected = this.isSelected(rowIndex);
22219 if(e.button !== 0 && isSelected){
22220 view.focusRow(rowIndex);
22221 }else if(e.ctrlKey && isSelected){
22222 this.deselectRow(rowIndex);
22223 }else if(!isSelected){
22224 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22225 view.focusRow(rowIndex);
22228 this.fireEvent("afterselectionchange", this);
22231 handleDragableRowClick : function(grid, rowIndex, e)
22233 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
22234 this.selectRow(rowIndex, false);
22235 grid.view.focusRow(rowIndex);
22236 this.fireEvent("afterselectionchange", this);
22241 * Selects multiple rows.
22242 * @param {Array} rows Array of the indexes of the row to select
22243 * @param {Boolean} keepExisting (optional) True to keep existing selections
22245 selectRows : function(rows, keepExisting){
22247 this.clearSelections();
22249 for(var i = 0, len = rows.length; i < len; i++){
22250 this.selectRow(rows[i], true);
22255 * Selects a range of rows. All rows in between startRow and endRow are also selected.
22256 * @param {Number} startRow The index of the first row in the range
22257 * @param {Number} endRow The index of the last row in the range
22258 * @param {Boolean} keepExisting (optional) True to retain existing selections
22260 selectRange : function(startRow, endRow, keepExisting){
22265 this.clearSelections();
22267 if(startRow <= endRow){
22268 for(var i = startRow; i <= endRow; i++){
22269 this.selectRow(i, true);
22272 for(var i = startRow; i >= endRow; i--){
22273 this.selectRow(i, true);
22279 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
22280 * @param {Number} startRow The index of the first row in the range
22281 * @param {Number} endRow The index of the last row in the range
22283 deselectRange : function(startRow, endRow, preventViewNotify){
22287 for(var i = startRow; i <= endRow; i++){
22288 this.deselectRow(i, preventViewNotify);
22294 * @param {Number} row The index of the row to select
22295 * @param {Boolean} keepExisting (optional) True to keep existing selections
22297 selectRow : function(index, keepExisting, preventViewNotify){
22298 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
22301 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
22302 if(!keepExisting || this.singleSelect){
22303 this.clearSelections();
22305 var r = this.grid.dataSource.getAt(index);
22306 this.selections.add(r);
22307 this.last = this.lastActive = index;
22308 if(!preventViewNotify){
22309 this.grid.getView().onRowSelect(index);
22311 this.fireEvent("rowselect", this, index, r);
22312 this.fireEvent("selectionchange", this);
22318 * @param {Number} row The index of the row to deselect
22320 deselectRow : function(index, preventViewNotify){
22324 if(this.last == index){
22327 if(this.lastActive == index){
22328 this.lastActive = false;
22330 var r = this.grid.dataSource.getAt(index);
22331 this.selections.remove(r);
22332 if(!preventViewNotify){
22333 this.grid.getView().onRowDeselect(index);
22335 this.fireEvent("rowdeselect", this, index);
22336 this.fireEvent("selectionchange", this);
22340 restoreLast : function(){
22342 this.last = this._last;
22347 acceptsNav : function(row, col, cm){
22348 return !cm.isHidden(col) && cm.isCellEditable(col, row);
22352 onEditorKey : function(field, e){
22353 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
22358 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
22360 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
22362 }else if(k == e.ENTER && !e.ctrlKey){
22366 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
22368 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
22370 }else if(k == e.ESC){
22374 g.startEditing(newCell[0], newCell[1]);
22379 * Ext JS Library 1.1.1
22380 * Copyright(c) 2006-2007, Ext JS, LLC.
22382 * Originally Released Under LGPL - original licence link has changed is not relivant.
22385 * <script type="text/javascript">
22389 * @class Roo.bootstrap.PagingToolbar
22390 * @extends Roo.bootstrap.NavSimplebar
22391 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
22393 * Create a new PagingToolbar
22394 * @param {Object} config The config object
22395 * @param {Roo.data.Store} store
22397 Roo.bootstrap.PagingToolbar = function(config)
22399 // old args format still supported... - xtype is prefered..
22400 // created from xtype...
22402 this.ds = config.dataSource;
22404 if (config.store && !this.ds) {
22405 this.store= Roo.factory(config.store, Roo.data);
22406 this.ds = this.store;
22407 this.ds.xmodule = this.xmodule || false;
22410 this.toolbarItems = [];
22411 if (config.items) {
22412 this.toolbarItems = config.items;
22415 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
22420 this.bind(this.ds);
22423 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
22427 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
22429 * @cfg {Roo.data.Store} dataSource
22430 * The underlying data store providing the paged data
22433 * @cfg {String/HTMLElement/Element} container
22434 * container The id or element that will contain the toolbar
22437 * @cfg {Boolean} displayInfo
22438 * True to display the displayMsg (defaults to false)
22441 * @cfg {Number} pageSize
22442 * The number of records to display per page (defaults to 20)
22446 * @cfg {String} displayMsg
22447 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
22449 displayMsg : 'Displaying {0} - {1} of {2}',
22451 * @cfg {String} emptyMsg
22452 * The message to display when no records are found (defaults to "No data to display")
22454 emptyMsg : 'No data to display',
22456 * Customizable piece of the default paging text (defaults to "Page")
22459 beforePageText : "Page",
22461 * Customizable piece of the default paging text (defaults to "of %0")
22464 afterPageText : "of {0}",
22466 * Customizable piece of the default paging text (defaults to "First Page")
22469 firstText : "First Page",
22471 * Customizable piece of the default paging text (defaults to "Previous Page")
22474 prevText : "Previous Page",
22476 * Customizable piece of the default paging text (defaults to "Next Page")
22479 nextText : "Next Page",
22481 * Customizable piece of the default paging text (defaults to "Last Page")
22484 lastText : "Last Page",
22486 * Customizable piece of the default paging text (defaults to "Refresh")
22489 refreshText : "Refresh",
22493 onRender : function(ct, position)
22495 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
22496 this.navgroup.parentId = this.id;
22497 this.navgroup.onRender(this.el, null);
22498 // add the buttons to the navgroup
22500 if(this.displayInfo){
22501 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
22502 this.displayEl = this.el.select('.x-paging-info', true).first();
22503 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
22504 // this.displayEl = navel.el.select('span',true).first();
22510 Roo.each(_this.buttons, function(e){ // this might need to use render????
22511 Roo.factory(e).onRender(_this.el, null);
22515 Roo.each(_this.toolbarItems, function(e) {
22516 _this.navgroup.addItem(e);
22520 this.first = this.navgroup.addItem({
22521 tooltip: this.firstText,
22523 icon : 'fa fa-backward',
22525 preventDefault: true,
22526 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
22529 this.prev = this.navgroup.addItem({
22530 tooltip: this.prevText,
22532 icon : 'fa fa-step-backward',
22534 preventDefault: true,
22535 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
22537 //this.addSeparator();
22540 var field = this.navgroup.addItem( {
22542 cls : 'x-paging-position',
22544 html : this.beforePageText +
22545 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
22546 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
22549 this.field = field.el.select('input', true).first();
22550 this.field.on("keydown", this.onPagingKeydown, this);
22551 this.field.on("focus", function(){this.dom.select();});
22554 this.afterTextEl = field.el.select('.x-paging-after',true).first();
22555 //this.field.setHeight(18);
22556 //this.addSeparator();
22557 this.next = this.navgroup.addItem({
22558 tooltip: this.nextText,
22560 html : ' <i class="fa fa-step-forward">',
22562 preventDefault: true,
22563 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
22565 this.last = this.navgroup.addItem({
22566 tooltip: this.lastText,
22567 icon : 'fa fa-forward',
22570 preventDefault: true,
22571 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
22573 //this.addSeparator();
22574 this.loading = this.navgroup.addItem({
22575 tooltip: this.refreshText,
22576 icon: 'fa fa-refresh',
22577 preventDefault: true,
22578 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
22584 updateInfo : function(){
22585 if(this.displayEl){
22586 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
22587 var msg = count == 0 ?
22591 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
22593 this.displayEl.update(msg);
22598 onLoad : function(ds, r, o){
22599 this.cursor = o.params ? o.params.start : 0;
22600 var d = this.getPageData(),
22604 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
22605 this.field.dom.value = ap;
22606 this.first.setDisabled(ap == 1);
22607 this.prev.setDisabled(ap == 1);
22608 this.next.setDisabled(ap == ps);
22609 this.last.setDisabled(ap == ps);
22610 this.loading.enable();
22615 getPageData : function(){
22616 var total = this.ds.getTotalCount();
22619 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
22620 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
22625 onLoadError : function(){
22626 this.loading.enable();
22630 onPagingKeydown : function(e){
22631 var k = e.getKey();
22632 var d = this.getPageData();
22634 var v = this.field.dom.value, pageNum;
22635 if(!v || isNaN(pageNum = parseInt(v, 10))){
22636 this.field.dom.value = d.activePage;
22639 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
22640 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22643 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))
22645 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
22646 this.field.dom.value = pageNum;
22647 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
22650 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
22652 var v = this.field.dom.value, pageNum;
22653 var increment = (e.shiftKey) ? 10 : 1;
22654 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
22657 if(!v || isNaN(pageNum = parseInt(v, 10))) {
22658 this.field.dom.value = d.activePage;
22661 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
22663 this.field.dom.value = parseInt(v, 10) + increment;
22664 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
22665 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22672 beforeLoad : function(){
22674 this.loading.disable();
22679 onClick : function(which){
22688 ds.load({params:{start: 0, limit: this.pageSize}});
22691 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
22694 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
22697 var total = ds.getTotalCount();
22698 var extra = total % this.pageSize;
22699 var lastStart = extra ? (total - extra) : total-this.pageSize;
22700 ds.load({params:{start: lastStart, limit: this.pageSize}});
22703 ds.load({params:{start: this.cursor, limit: this.pageSize}});
22709 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
22710 * @param {Roo.data.Store} store The data store to unbind
22712 unbind : function(ds){
22713 ds.un("beforeload", this.beforeLoad, this);
22714 ds.un("load", this.onLoad, this);
22715 ds.un("loadexception", this.onLoadError, this);
22716 ds.un("remove", this.updateInfo, this);
22717 ds.un("add", this.updateInfo, this);
22718 this.ds = undefined;
22722 * Binds the paging toolbar to the specified {@link Roo.data.Store}
22723 * @param {Roo.data.Store} store The data store to bind
22725 bind : function(ds){
22726 ds.on("beforeload", this.beforeLoad, this);
22727 ds.on("load", this.onLoad, this);
22728 ds.on("loadexception", this.onLoadError, this);
22729 ds.on("remove", this.updateInfo, this);
22730 ds.on("add", this.updateInfo, this);
22741 * @class Roo.bootstrap.MessageBar
22742 * @extends Roo.bootstrap.Component
22743 * Bootstrap MessageBar class
22744 * @cfg {String} html contents of the MessageBar
22745 * @cfg {String} weight (info | success | warning | danger) default info
22746 * @cfg {String} beforeClass insert the bar before the given class
22747 * @cfg {Boolean} closable (true | false) default false
22748 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
22751 * Create a new Element
22752 * @param {Object} config The config object
22755 Roo.bootstrap.MessageBar = function(config){
22756 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
22759 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
22765 beforeClass: 'bootstrap-sticky-wrap',
22767 getAutoCreate : function(){
22771 cls: 'alert alert-dismissable alert-' + this.weight,
22776 html: this.html || ''
22782 cfg.cls += ' alert-messages-fixed';
22796 onRender : function(ct, position)
22798 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
22801 var cfg = Roo.apply({}, this.getAutoCreate());
22805 cfg.cls += ' ' + this.cls;
22808 cfg.style = this.style;
22810 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22812 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22815 this.el.select('>button.close').on('click', this.hide, this);
22821 if (!this.rendered) {
22827 this.fireEvent('show', this);
22833 if (!this.rendered) {
22839 this.fireEvent('hide', this);
22842 update : function()
22844 // var e = this.el.dom.firstChild;
22846 // if(this.closable){
22847 // e = e.nextSibling;
22850 // e.data = this.html || '';
22852 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22868 * @class Roo.bootstrap.Graph
22869 * @extends Roo.bootstrap.Component
22870 * Bootstrap Graph class
22874 @cfg {String} graphtype bar | vbar | pie
22875 @cfg {number} g_x coodinator | centre x (pie)
22876 @cfg {number} g_y coodinator | centre y (pie)
22877 @cfg {number} g_r radius (pie)
22878 @cfg {number} g_height height of the chart (respected by all elements in the set)
22879 @cfg {number} g_width width of the chart (respected by all elements in the set)
22880 @cfg {Object} title The title of the chart
22883 -opts (object) options for the chart
22885 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22886 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22888 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.
22889 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22891 o stretch (boolean)
22893 -opts (object) options for the pie
22896 o startAngle (number)
22897 o endAngle (number)
22901 * Create a new Input
22902 * @param {Object} config The config object
22905 Roo.bootstrap.Graph = function(config){
22906 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22912 * The img click event for the img.
22913 * @param {Roo.EventObject} e
22919 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
22930 //g_colors: this.colors,
22937 getAutoCreate : function(){
22948 onRender : function(ct,position){
22951 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
22953 if (typeof(Raphael) == 'undefined') {
22954 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
22958 this.raphael = Raphael(this.el.dom);
22960 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22961 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22962 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22963 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
22965 r.text(160, 10, "Single Series Chart").attr(txtattr);
22966 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
22967 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
22968 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
22970 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
22971 r.barchart(330, 10, 300, 220, data1);
22972 r.barchart(10, 250, 300, 220, data2, {stacked: true});
22973 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
22976 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22977 // r.barchart(30, 30, 560, 250, xdata, {
22978 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
22979 // axis : "0 0 1 1",
22980 // axisxlabels : xdata
22981 // //yvalues : cols,
22984 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
22986 // this.load(null,xdata,{
22987 // axis : "0 0 1 1",
22988 // axisxlabels : xdata
22993 load : function(graphtype,xdata,opts)
22995 this.raphael.clear();
22997 graphtype = this.graphtype;
23002 var r = this.raphael,
23003 fin = function () {
23004 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23006 fout = function () {
23007 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23009 pfin = function() {
23010 this.sector.stop();
23011 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23014 this.label[0].stop();
23015 this.label[0].attr({ r: 7.5 });
23016 this.label[1].attr({ "font-weight": 800 });
23019 pfout = function() {
23020 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23023 this.label[0].animate({ r: 5 }, 500, "bounce");
23024 this.label[1].attr({ "font-weight": 400 });
23030 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23033 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23036 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23037 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23039 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23046 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23051 setTitle: function(o)
23056 initEvents: function() {
23059 this.el.on('click', this.onClick, this);
23063 onClick : function(e)
23065 Roo.log('img onclick');
23066 this.fireEvent('click', this, e);
23078 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23081 * @class Roo.bootstrap.dash.NumberBox
23082 * @extends Roo.bootstrap.Component
23083 * Bootstrap NumberBox class
23084 * @cfg {String} headline Box headline
23085 * @cfg {String} content Box content
23086 * @cfg {String} icon Box icon
23087 * @cfg {String} footer Footer text
23088 * @cfg {String} fhref Footer href
23091 * Create a new NumberBox
23092 * @param {Object} config The config object
23096 Roo.bootstrap.dash.NumberBox = function(config){
23097 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23101 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23110 getAutoCreate : function(){
23114 cls : 'small-box ',
23122 cls : 'roo-headline',
23123 html : this.headline
23127 cls : 'roo-content',
23128 html : this.content
23142 cls : 'ion ' + this.icon
23151 cls : 'small-box-footer',
23152 href : this.fhref || '#',
23156 cfg.cn.push(footer);
23163 onRender : function(ct,position){
23164 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23171 setHeadline: function (value)
23173 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23176 setFooter: function (value, href)
23178 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23181 this.el.select('a.small-box-footer',true).first().attr('href', href);
23186 setContent: function (value)
23188 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23191 initEvents: function()
23205 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23208 * @class Roo.bootstrap.dash.TabBox
23209 * @extends Roo.bootstrap.Component
23210 * Bootstrap TabBox class
23211 * @cfg {String} title Title of the TabBox
23212 * @cfg {String} icon Icon of the TabBox
23213 * @cfg {Boolean} showtabs (true|false) show the tabs default true
23214 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
23217 * Create a new TabBox
23218 * @param {Object} config The config object
23222 Roo.bootstrap.dash.TabBox = function(config){
23223 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
23228 * When a pane is added
23229 * @param {Roo.bootstrap.dash.TabPane} pane
23233 * @event activatepane
23234 * When a pane is activated
23235 * @param {Roo.bootstrap.dash.TabPane} pane
23237 "activatepane" : true
23245 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
23250 tabScrollable : false,
23252 getChildContainer : function()
23254 return this.el.select('.tab-content', true).first();
23257 getAutoCreate : function(){
23261 cls: 'pull-left header',
23269 cls: 'fa ' + this.icon
23275 cls: 'nav nav-tabs pull-right',
23281 if(this.tabScrollable){
23288 cls: 'nav nav-tabs pull-right',
23299 cls: 'nav-tabs-custom',
23304 cls: 'tab-content no-padding',
23312 initEvents : function()
23314 //Roo.log('add add pane handler');
23315 this.on('addpane', this.onAddPane, this);
23318 * Updates the box title
23319 * @param {String} html to set the title to.
23321 setTitle : function(value)
23323 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
23325 onAddPane : function(pane)
23327 this.panes.push(pane);
23328 //Roo.log('addpane');
23330 // tabs are rendere left to right..
23331 if(!this.showtabs){
23335 var ctr = this.el.select('.nav-tabs', true).first();
23338 var existing = ctr.select('.nav-tab',true);
23339 var qty = existing.getCount();;
23342 var tab = ctr.createChild({
23344 cls : 'nav-tab' + (qty ? '' : ' active'),
23352 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
23355 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
23357 pane.el.addClass('active');
23362 onTabClick : function(ev,un,ob,pane)
23364 //Roo.log('tab - prev default');
23365 ev.preventDefault();
23368 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
23369 pane.tab.addClass('active');
23370 //Roo.log(pane.title);
23371 this.getChildContainer().select('.tab-pane',true).removeClass('active');
23372 // technically we should have a deactivate event.. but maybe add later.
23373 // and it should not de-activate the selected tab...
23374 this.fireEvent('activatepane', pane);
23375 pane.el.addClass('active');
23376 pane.fireEvent('activate');
23381 getActivePane : function()
23384 Roo.each(this.panes, function(p) {
23385 if(p.el.hasClass('active')){
23406 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23408 * @class Roo.bootstrap.TabPane
23409 * @extends Roo.bootstrap.Component
23410 * Bootstrap TabPane class
23411 * @cfg {Boolean} active (false | true) Default false
23412 * @cfg {String} title title of panel
23416 * Create a new TabPane
23417 * @param {Object} config The config object
23420 Roo.bootstrap.dash.TabPane = function(config){
23421 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
23427 * When a pane is activated
23428 * @param {Roo.bootstrap.dash.TabPane} pane
23435 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
23440 // the tabBox that this is attached to.
23443 getAutoCreate : function()
23451 cfg.cls += ' active';
23456 initEvents : function()
23458 //Roo.log('trigger add pane handler');
23459 this.parent().fireEvent('addpane', this)
23463 * Updates the tab title
23464 * @param {String} html to set the title to.
23466 setTitle: function(str)
23472 this.tab.select('a', true).first().dom.innerHTML = str;
23489 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23492 * @class Roo.bootstrap.menu.Menu
23493 * @extends Roo.bootstrap.Component
23494 * Bootstrap Menu class - container for Menu
23495 * @cfg {String} html Text of the menu
23496 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
23497 * @cfg {String} icon Font awesome icon
23498 * @cfg {String} pos Menu align to (top | bottom) default bottom
23502 * Create a new Menu
23503 * @param {Object} config The config object
23507 Roo.bootstrap.menu.Menu = function(config){
23508 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
23512 * @event beforeshow
23513 * Fires before this menu is displayed
23514 * @param {Roo.bootstrap.menu.Menu} this
23518 * @event beforehide
23519 * Fires before this menu is hidden
23520 * @param {Roo.bootstrap.menu.Menu} this
23525 * Fires after this menu is displayed
23526 * @param {Roo.bootstrap.menu.Menu} this
23531 * Fires after this menu is hidden
23532 * @param {Roo.bootstrap.menu.Menu} this
23537 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
23538 * @param {Roo.bootstrap.menu.Menu} this
23539 * @param {Roo.EventObject} e
23546 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
23550 weight : 'default',
23555 getChildContainer : function() {
23556 if(this.isSubMenu){
23560 return this.el.select('ul.dropdown-menu', true).first();
23563 getAutoCreate : function()
23568 cls : 'roo-menu-text',
23576 cls : 'fa ' + this.icon
23587 cls : 'dropdown-button btn btn-' + this.weight,
23592 cls : 'dropdown-toggle btn btn-' + this.weight,
23602 cls : 'dropdown-menu'
23608 if(this.pos == 'top'){
23609 cfg.cls += ' dropup';
23612 if(this.isSubMenu){
23615 cls : 'dropdown-menu'
23622 onRender : function(ct, position)
23624 this.isSubMenu = ct.hasClass('dropdown-submenu');
23626 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
23629 initEvents : function()
23631 if(this.isSubMenu){
23635 this.hidden = true;
23637 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
23638 this.triggerEl.on('click', this.onTriggerPress, this);
23640 this.buttonEl = this.el.select('button.dropdown-button', true).first();
23641 this.buttonEl.on('click', this.onClick, this);
23647 if(this.isSubMenu){
23651 return this.el.select('ul.dropdown-menu', true).first();
23654 onClick : function(e)
23656 this.fireEvent("click", this, e);
23659 onTriggerPress : function(e)
23661 if (this.isVisible()) {
23668 isVisible : function(){
23669 return !this.hidden;
23674 this.fireEvent("beforeshow", this);
23676 this.hidden = false;
23677 this.el.addClass('open');
23679 Roo.get(document).on("mouseup", this.onMouseUp, this);
23681 this.fireEvent("show", this);
23688 this.fireEvent("beforehide", this);
23690 this.hidden = true;
23691 this.el.removeClass('open');
23693 Roo.get(document).un("mouseup", this.onMouseUp);
23695 this.fireEvent("hide", this);
23698 onMouseUp : function()
23712 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23715 * @class Roo.bootstrap.menu.Item
23716 * @extends Roo.bootstrap.Component
23717 * Bootstrap MenuItem class
23718 * @cfg {Boolean} submenu (true | false) default false
23719 * @cfg {String} html text of the item
23720 * @cfg {String} href the link
23721 * @cfg {Boolean} disable (true | false) default false
23722 * @cfg {Boolean} preventDefault (true | false) default true
23723 * @cfg {String} icon Font awesome icon
23724 * @cfg {String} pos Submenu align to (left | right) default right
23728 * Create a new Item
23729 * @param {Object} config The config object
23733 Roo.bootstrap.menu.Item = function(config){
23734 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
23738 * Fires when the mouse is hovering over this menu
23739 * @param {Roo.bootstrap.menu.Item} this
23740 * @param {Roo.EventObject} e
23745 * Fires when the mouse exits this menu
23746 * @param {Roo.bootstrap.menu.Item} this
23747 * @param {Roo.EventObject} e
23753 * The raw click event for the entire grid.
23754 * @param {Roo.EventObject} e
23760 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
23765 preventDefault: true,
23770 getAutoCreate : function()
23775 cls : 'roo-menu-item-text',
23783 cls : 'fa ' + this.icon
23792 href : this.href || '#',
23799 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
23803 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
23805 if(this.pos == 'left'){
23806 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
23813 initEvents : function()
23815 this.el.on('mouseover', this.onMouseOver, this);
23816 this.el.on('mouseout', this.onMouseOut, this);
23818 this.el.select('a', true).first().on('click', this.onClick, this);
23822 onClick : function(e)
23824 if(this.preventDefault){
23825 e.preventDefault();
23828 this.fireEvent("click", this, e);
23831 onMouseOver : function(e)
23833 if(this.submenu && this.pos == 'left'){
23834 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23837 this.fireEvent("mouseover", this, e);
23840 onMouseOut : function(e)
23842 this.fireEvent("mouseout", this, e);
23854 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23857 * @class Roo.bootstrap.menu.Separator
23858 * @extends Roo.bootstrap.Component
23859 * Bootstrap Separator class
23862 * Create a new Separator
23863 * @param {Object} config The config object
23867 Roo.bootstrap.menu.Separator = function(config){
23868 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23871 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23873 getAutoCreate : function(){
23894 * @class Roo.bootstrap.Tooltip
23895 * Bootstrap Tooltip class
23896 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23897 * to determine which dom element triggers the tooltip.
23899 * It needs to add support for additional attributes like tooltip-position
23902 * Create a new Toolti
23903 * @param {Object} config The config object
23906 Roo.bootstrap.Tooltip = function(config){
23907 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23910 Roo.apply(Roo.bootstrap.Tooltip, {
23912 * @function init initialize tooltip monitoring.
23916 currentTip : false,
23917 currentRegion : false,
23923 Roo.get(document).on('mouseover', this.enter ,this);
23924 Roo.get(document).on('mouseout', this.leave, this);
23927 this.currentTip = new Roo.bootstrap.Tooltip();
23930 enter : function(ev)
23932 var dom = ev.getTarget();
23934 //Roo.log(['enter',dom]);
23935 var el = Roo.fly(dom);
23936 if (this.currentEl) {
23938 //Roo.log(this.currentEl);
23939 //Roo.log(this.currentEl.contains(dom));
23940 if (this.currentEl == el) {
23943 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
23949 if (this.currentTip.el) {
23950 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
23955 // you can not look for children, as if el is the body.. then everythign is the child..
23956 if (!el.attr('tooltip')) { //
23957 if (!el.select("[tooltip]").elements.length) {
23960 // is the mouse over this child...?
23961 bindEl = el.select("[tooltip]").first();
23962 var xy = ev.getXY();
23963 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
23964 //Roo.log("not in region.");
23967 //Roo.log("child element over..");
23970 this.currentEl = bindEl;
23971 this.currentTip.bind(bindEl);
23972 this.currentRegion = Roo.lib.Region.getRegion(dom);
23973 this.currentTip.enter();
23976 leave : function(ev)
23978 var dom = ev.getTarget();
23979 //Roo.log(['leave',dom]);
23980 if (!this.currentEl) {
23985 if (dom != this.currentEl.dom) {
23988 var xy = ev.getXY();
23989 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
23992 // only activate leave if mouse cursor is outside... bounding box..
23997 if (this.currentTip) {
23998 this.currentTip.leave();
24000 //Roo.log('clear currentEl');
24001 this.currentEl = false;
24006 'left' : ['r-l', [-2,0], 'right'],
24007 'right' : ['l-r', [2,0], 'left'],
24008 'bottom' : ['t-b', [0,2], 'top'],
24009 'top' : [ 'b-t', [0,-2], 'bottom']
24015 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24020 delay : null, // can be { show : 300 , hide: 500}
24024 hoverState : null, //???
24026 placement : 'bottom',
24028 getAutoCreate : function(){
24035 cls : 'tooltip-arrow'
24038 cls : 'tooltip-inner'
24045 bind : function(el)
24051 enter : function () {
24053 if (this.timeout != null) {
24054 clearTimeout(this.timeout);
24057 this.hoverState = 'in';
24058 //Roo.log("enter - show");
24059 if (!this.delay || !this.delay.show) {
24064 this.timeout = setTimeout(function () {
24065 if (_t.hoverState == 'in') {
24068 }, this.delay.show);
24072 clearTimeout(this.timeout);
24074 this.hoverState = 'out';
24075 if (!this.delay || !this.delay.hide) {
24081 this.timeout = setTimeout(function () {
24082 //Roo.log("leave - timeout");
24084 if (_t.hoverState == 'out') {
24086 Roo.bootstrap.Tooltip.currentEl = false;
24094 this.render(document.body);
24097 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24099 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24101 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24103 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24105 var placement = typeof this.placement == 'function' ?
24106 this.placement.call(this, this.el, on_el) :
24109 var autoToken = /\s?auto?\s?/i;
24110 var autoPlace = autoToken.test(placement);
24112 placement = placement.replace(autoToken, '') || 'top';
24116 //this.el.setXY([0,0]);
24118 //this.el.dom.style.display='block';
24120 //this.el.appendTo(on_el);
24122 var p = this.getPosition();
24123 var box = this.el.getBox();
24129 var align = Roo.bootstrap.Tooltip.alignment[placement];
24131 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24133 if(placement == 'top' || placement == 'bottom'){
24135 placement = 'right';
24138 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24139 placement = 'left';
24143 align = Roo.bootstrap.Tooltip.alignment[placement];
24145 this.el.alignTo(this.bindEl, align[0],align[1]);
24146 //var arrow = this.el.select('.arrow',true).first();
24147 //arrow.set(align[2],
24149 this.el.addClass(placement);
24151 this.el.addClass('in fade');
24153 this.hoverState = null;
24155 if (this.el.hasClass('fade')) {
24166 //this.el.setXY([0,0]);
24167 this.el.removeClass('in');
24183 * @class Roo.bootstrap.LocationPicker
24184 * @extends Roo.bootstrap.Component
24185 * Bootstrap LocationPicker class
24186 * @cfg {Number} latitude Position when init default 0
24187 * @cfg {Number} longitude Position when init default 0
24188 * @cfg {Number} zoom default 15
24189 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24190 * @cfg {Boolean} mapTypeControl default false
24191 * @cfg {Boolean} disableDoubleClickZoom default false
24192 * @cfg {Boolean} scrollwheel default true
24193 * @cfg {Boolean} streetViewControl default false
24194 * @cfg {Number} radius default 0
24195 * @cfg {String} locationName
24196 * @cfg {Boolean} draggable default true
24197 * @cfg {Boolean} enableAutocomplete default false
24198 * @cfg {Boolean} enableReverseGeocode default true
24199 * @cfg {String} markerTitle
24202 * Create a new LocationPicker
24203 * @param {Object} config The config object
24207 Roo.bootstrap.LocationPicker = function(config){
24209 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
24214 * Fires when the picker initialized.
24215 * @param {Roo.bootstrap.LocationPicker} this
24216 * @param {Google Location} location
24220 * @event positionchanged
24221 * Fires when the picker position changed.
24222 * @param {Roo.bootstrap.LocationPicker} this
24223 * @param {Google Location} location
24225 positionchanged : true,
24228 * Fires when the map resize.
24229 * @param {Roo.bootstrap.LocationPicker} this
24234 * Fires when the map show.
24235 * @param {Roo.bootstrap.LocationPicker} this
24240 * Fires when the map hide.
24241 * @param {Roo.bootstrap.LocationPicker} this
24246 * Fires when click the map.
24247 * @param {Roo.bootstrap.LocationPicker} this
24248 * @param {Map event} e
24252 * @event mapRightClick
24253 * Fires when right click the map.
24254 * @param {Roo.bootstrap.LocationPicker} this
24255 * @param {Map event} e
24257 mapRightClick : true,
24259 * @event markerClick
24260 * Fires when click the marker.
24261 * @param {Roo.bootstrap.LocationPicker} this
24262 * @param {Map event} e
24264 markerClick : true,
24266 * @event markerRightClick
24267 * Fires when right click the marker.
24268 * @param {Roo.bootstrap.LocationPicker} this
24269 * @param {Map event} e
24271 markerRightClick : true,
24273 * @event OverlayViewDraw
24274 * Fires when OverlayView Draw
24275 * @param {Roo.bootstrap.LocationPicker} this
24277 OverlayViewDraw : true,
24279 * @event OverlayViewOnAdd
24280 * Fires when OverlayView Draw
24281 * @param {Roo.bootstrap.LocationPicker} this
24283 OverlayViewOnAdd : true,
24285 * @event OverlayViewOnRemove
24286 * Fires when OverlayView Draw
24287 * @param {Roo.bootstrap.LocationPicker} this
24289 OverlayViewOnRemove : true,
24291 * @event OverlayViewShow
24292 * Fires when OverlayView Draw
24293 * @param {Roo.bootstrap.LocationPicker} this
24294 * @param {Pixel} cpx
24296 OverlayViewShow : true,
24298 * @event OverlayViewHide
24299 * Fires when OverlayView Draw
24300 * @param {Roo.bootstrap.LocationPicker} this
24302 OverlayViewHide : true,
24304 * @event loadexception
24305 * Fires when load google lib failed.
24306 * @param {Roo.bootstrap.LocationPicker} this
24308 loadexception : true
24313 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
24315 gMapContext: false,
24321 mapTypeControl: false,
24322 disableDoubleClickZoom: false,
24324 streetViewControl: false,
24328 enableAutocomplete: false,
24329 enableReverseGeocode: true,
24332 getAutoCreate: function()
24337 cls: 'roo-location-picker'
24343 initEvents: function(ct, position)
24345 if(!this.el.getWidth() || this.isApplied()){
24349 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24354 initial: function()
24356 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
24357 this.fireEvent('loadexception', this);
24361 if(!this.mapTypeId){
24362 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
24365 this.gMapContext = this.GMapContext();
24367 this.initOverlayView();
24369 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
24373 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
24374 _this.setPosition(_this.gMapContext.marker.position);
24377 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
24378 _this.fireEvent('mapClick', this, event);
24382 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
24383 _this.fireEvent('mapRightClick', this, event);
24387 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
24388 _this.fireEvent('markerClick', this, event);
24392 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
24393 _this.fireEvent('markerRightClick', this, event);
24397 this.setPosition(this.gMapContext.location);
24399 this.fireEvent('initial', this, this.gMapContext.location);
24402 initOverlayView: function()
24406 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
24410 _this.fireEvent('OverlayViewDraw', _this);
24415 _this.fireEvent('OverlayViewOnAdd', _this);
24418 onRemove: function()
24420 _this.fireEvent('OverlayViewOnRemove', _this);
24423 show: function(cpx)
24425 _this.fireEvent('OverlayViewShow', _this, cpx);
24430 _this.fireEvent('OverlayViewHide', _this);
24436 fromLatLngToContainerPixel: function(event)
24438 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
24441 isApplied: function()
24443 return this.getGmapContext() == false ? false : true;
24446 getGmapContext: function()
24448 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
24451 GMapContext: function()
24453 var position = new google.maps.LatLng(this.latitude, this.longitude);
24455 var _map = new google.maps.Map(this.el.dom, {
24458 mapTypeId: this.mapTypeId,
24459 mapTypeControl: this.mapTypeControl,
24460 disableDoubleClickZoom: this.disableDoubleClickZoom,
24461 scrollwheel: this.scrollwheel,
24462 streetViewControl: this.streetViewControl,
24463 locationName: this.locationName,
24464 draggable: this.draggable,
24465 enableAutocomplete: this.enableAutocomplete,
24466 enableReverseGeocode: this.enableReverseGeocode
24469 var _marker = new google.maps.Marker({
24470 position: position,
24472 title: this.markerTitle,
24473 draggable: this.draggable
24480 location: position,
24481 radius: this.radius,
24482 locationName: this.locationName,
24483 addressComponents: {
24484 formatted_address: null,
24485 addressLine1: null,
24486 addressLine2: null,
24488 streetNumber: null,
24492 stateOrProvince: null
24495 domContainer: this.el.dom,
24496 geodecoder: new google.maps.Geocoder()
24500 drawCircle: function(center, radius, options)
24502 if (this.gMapContext.circle != null) {
24503 this.gMapContext.circle.setMap(null);
24507 options = Roo.apply({}, options, {
24508 strokeColor: "#0000FF",
24509 strokeOpacity: .35,
24511 fillColor: "#0000FF",
24515 options.map = this.gMapContext.map;
24516 options.radius = radius;
24517 options.center = center;
24518 this.gMapContext.circle = new google.maps.Circle(options);
24519 return this.gMapContext.circle;
24525 setPosition: function(location)
24527 this.gMapContext.location = location;
24528 this.gMapContext.marker.setPosition(location);
24529 this.gMapContext.map.panTo(location);
24530 this.drawCircle(location, this.gMapContext.radius, {});
24534 if (this.gMapContext.settings.enableReverseGeocode) {
24535 this.gMapContext.geodecoder.geocode({
24536 latLng: this.gMapContext.location
24537 }, function(results, status) {
24539 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
24540 _this.gMapContext.locationName = results[0].formatted_address;
24541 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
24543 _this.fireEvent('positionchanged', this, location);
24550 this.fireEvent('positionchanged', this, location);
24555 google.maps.event.trigger(this.gMapContext.map, "resize");
24557 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
24559 this.fireEvent('resize', this);
24562 setPositionByLatLng: function(latitude, longitude)
24564 this.setPosition(new google.maps.LatLng(latitude, longitude));
24567 getCurrentPosition: function()
24570 latitude: this.gMapContext.location.lat(),
24571 longitude: this.gMapContext.location.lng()
24575 getAddressName: function()
24577 return this.gMapContext.locationName;
24580 getAddressComponents: function()
24582 return this.gMapContext.addressComponents;
24585 address_component_from_google_geocode: function(address_components)
24589 for (var i = 0; i < address_components.length; i++) {
24590 var component = address_components[i];
24591 if (component.types.indexOf("postal_code") >= 0) {
24592 result.postalCode = component.short_name;
24593 } else if (component.types.indexOf("street_number") >= 0) {
24594 result.streetNumber = component.short_name;
24595 } else if (component.types.indexOf("route") >= 0) {
24596 result.streetName = component.short_name;
24597 } else if (component.types.indexOf("neighborhood") >= 0) {
24598 result.city = component.short_name;
24599 } else if (component.types.indexOf("locality") >= 0) {
24600 result.city = component.short_name;
24601 } else if (component.types.indexOf("sublocality") >= 0) {
24602 result.district = component.short_name;
24603 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
24604 result.stateOrProvince = component.short_name;
24605 } else if (component.types.indexOf("country") >= 0) {
24606 result.country = component.short_name;
24610 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
24611 result.addressLine2 = "";
24615 setZoomLevel: function(zoom)
24617 this.gMapContext.map.setZoom(zoom);
24630 this.fireEvent('show', this);
24641 this.fireEvent('hide', this);
24646 Roo.apply(Roo.bootstrap.LocationPicker, {
24648 OverlayView : function(map, options)
24650 options = options || {};
24664 * @class Roo.bootstrap.Alert
24665 * @extends Roo.bootstrap.Component
24666 * Bootstrap Alert class
24667 * @cfg {String} title The title of alert
24668 * @cfg {String} html The content of alert
24669 * @cfg {String} weight ( success | info | warning | danger )
24670 * @cfg {String} faicon font-awesomeicon
24673 * Create a new alert
24674 * @param {Object} config The config object
24678 Roo.bootstrap.Alert = function(config){
24679 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
24683 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
24690 getAutoCreate : function()
24699 cls : 'roo-alert-icon'
24704 cls : 'roo-alert-title',
24709 cls : 'roo-alert-text',
24716 cfg.cn[0].cls += ' fa ' + this.faicon;
24720 cfg.cls += ' alert-' + this.weight;
24726 initEvents: function()
24728 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24731 setTitle : function(str)
24733 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
24736 setText : function(str)
24738 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
24741 setWeight : function(weight)
24744 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
24747 this.weight = weight;
24749 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
24752 setIcon : function(icon)
24755 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
24758 this.faicon = icon;
24760 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
24781 * @class Roo.bootstrap.UploadCropbox
24782 * @extends Roo.bootstrap.Component
24783 * Bootstrap UploadCropbox class
24784 * @cfg {String} emptyText show when image has been loaded
24785 * @cfg {String} rotateNotify show when image too small to rotate
24786 * @cfg {Number} errorTimeout default 3000
24787 * @cfg {Number} minWidth default 300
24788 * @cfg {Number} minHeight default 300
24789 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
24790 * @cfg {Boolean} isDocument (true|false) default false
24791 * @cfg {String} url action url
24792 * @cfg {String} paramName default 'imageUpload'
24793 * @cfg {String} method default POST
24794 * @cfg {Boolean} loadMask (true|false) default true
24795 * @cfg {Boolean} loadingText default 'Loading...'
24798 * Create a new UploadCropbox
24799 * @param {Object} config The config object
24802 Roo.bootstrap.UploadCropbox = function(config){
24803 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
24807 * @event beforeselectfile
24808 * Fire before select file
24809 * @param {Roo.bootstrap.UploadCropbox} this
24811 "beforeselectfile" : true,
24814 * Fire after initEvent
24815 * @param {Roo.bootstrap.UploadCropbox} this
24820 * Fire after initEvent
24821 * @param {Roo.bootstrap.UploadCropbox} this
24822 * @param {String} data
24827 * Fire when preparing the file data
24828 * @param {Roo.bootstrap.UploadCropbox} this
24829 * @param {Object} file
24834 * Fire when get exception
24835 * @param {Roo.bootstrap.UploadCropbox} this
24836 * @param {XMLHttpRequest} xhr
24838 "exception" : true,
24840 * @event beforeloadcanvas
24841 * Fire before load the canvas
24842 * @param {Roo.bootstrap.UploadCropbox} this
24843 * @param {String} src
24845 "beforeloadcanvas" : true,
24848 * Fire when trash image
24849 * @param {Roo.bootstrap.UploadCropbox} this
24854 * Fire when download the image
24855 * @param {Roo.bootstrap.UploadCropbox} this
24859 * @event footerbuttonclick
24860 * Fire when footerbuttonclick
24861 * @param {Roo.bootstrap.UploadCropbox} this
24862 * @param {String} type
24864 "footerbuttonclick" : true,
24868 * @param {Roo.bootstrap.UploadCropbox} this
24873 * Fire when rotate the image
24874 * @param {Roo.bootstrap.UploadCropbox} this
24875 * @param {String} pos
24880 * Fire when inspect the file
24881 * @param {Roo.bootstrap.UploadCropbox} this
24882 * @param {Object} file
24887 * Fire when xhr upload the file
24888 * @param {Roo.bootstrap.UploadCropbox} this
24889 * @param {Object} data
24894 * Fire when arrange the file data
24895 * @param {Roo.bootstrap.UploadCropbox} this
24896 * @param {Object} formData
24901 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
24904 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
24906 emptyText : 'Click to upload image',
24907 rotateNotify : 'Image is too small to rotate',
24908 errorTimeout : 3000,
24922 cropType : 'image/jpeg',
24924 canvasLoaded : false,
24925 isDocument : false,
24927 paramName : 'imageUpload',
24929 loadingText : 'Loading...',
24932 getAutoCreate : function()
24936 cls : 'roo-upload-cropbox',
24940 cls : 'roo-upload-cropbox-selector',
24945 cls : 'roo-upload-cropbox-body',
24946 style : 'cursor:pointer',
24950 cls : 'roo-upload-cropbox-preview'
24954 cls : 'roo-upload-cropbox-thumb'
24958 cls : 'roo-upload-cropbox-empty-notify',
24959 html : this.emptyText
24963 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
24964 html : this.rotateNotify
24970 cls : 'roo-upload-cropbox-footer',
24973 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
24983 onRender : function(ct, position)
24985 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
24987 if (this.buttons.length) {
24989 Roo.each(this.buttons, function(bb) {
24991 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
24993 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
24999 this.maskEl = this.el;
25003 initEvents : function()
25005 this.urlAPI = (window.createObjectURL && window) ||
25006 (window.URL && URL.revokeObjectURL && URL) ||
25007 (window.webkitURL && webkitURL);
25009 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25010 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25012 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25013 this.selectorEl.hide();
25015 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25016 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25018 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25019 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25020 this.thumbEl.hide();
25022 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25023 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25025 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25026 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25027 this.errorEl.hide();
25029 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25030 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25031 this.footerEl.hide();
25033 this.setThumbBoxSize();
25039 this.fireEvent('initial', this);
25046 window.addEventListener("resize", function() { _this.resize(); } );
25048 this.bodyEl.on('click', this.beforeSelectFile, this);
25051 this.bodyEl.on('touchstart', this.onTouchStart, this);
25052 this.bodyEl.on('touchmove', this.onTouchMove, this);
25053 this.bodyEl.on('touchend', this.onTouchEnd, this);
25057 this.bodyEl.on('mousedown', this.onMouseDown, this);
25058 this.bodyEl.on('mousemove', this.onMouseMove, this);
25059 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25060 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25061 Roo.get(document).on('mouseup', this.onMouseUp, this);
25064 this.selectorEl.on('change', this.onFileSelected, this);
25070 this.baseScale = 1;
25072 this.baseRotate = 1;
25073 this.dragable = false;
25074 this.pinching = false;
25077 this.cropData = false;
25078 this.notifyEl.dom.innerHTML = this.emptyText;
25080 this.selectorEl.dom.value = '';
25084 resize : function()
25086 if(this.fireEvent('resize', this) != false){
25087 this.setThumbBoxPosition();
25088 this.setCanvasPosition();
25092 onFooterButtonClick : function(e, el, o, type)
25095 case 'rotate-left' :
25096 this.onRotateLeft(e);
25098 case 'rotate-right' :
25099 this.onRotateRight(e);
25102 this.beforeSelectFile(e);
25117 this.fireEvent('footerbuttonclick', this, type);
25120 beforeSelectFile : function(e)
25122 e.preventDefault();
25124 if(this.fireEvent('beforeselectfile', this) != false){
25125 this.selectorEl.dom.click();
25129 onFileSelected : function(e)
25131 e.preventDefault();
25133 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25137 var file = this.selectorEl.dom.files[0];
25139 if(this.fireEvent('inspect', this, file) != false){
25140 this.prepare(file);
25145 trash : function(e)
25147 this.fireEvent('trash', this);
25150 download : function(e)
25152 this.fireEvent('download', this);
25155 loadCanvas : function(src)
25157 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25161 this.imageEl = document.createElement('img');
25165 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25167 this.imageEl.src = src;
25171 onLoadCanvas : function()
25173 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25174 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25176 this.bodyEl.un('click', this.beforeSelectFile, this);
25178 this.notifyEl.hide();
25179 this.thumbEl.show();
25180 this.footerEl.show();
25182 this.baseRotateLevel();
25184 if(this.isDocument){
25185 this.setThumbBoxSize();
25188 this.setThumbBoxPosition();
25190 this.baseScaleLevel();
25196 this.canvasLoaded = true;
25199 this.maskEl.unmask();
25204 setCanvasPosition : function()
25206 if(!this.canvasEl){
25210 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
25211 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
25213 this.previewEl.setLeft(pw);
25214 this.previewEl.setTop(ph);
25218 onMouseDown : function(e)
25222 this.dragable = true;
25223 this.pinching = false;
25225 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
25226 this.dragable = false;
25230 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25231 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25235 onMouseMove : function(e)
25239 if(!this.canvasLoaded){
25243 if (!this.dragable){
25247 var minX = Math.ceil(this.thumbEl.getLeft(true));
25248 var minY = Math.ceil(this.thumbEl.getTop(true));
25250 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
25251 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
25253 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25254 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25256 x = x - this.mouseX;
25257 y = y - this.mouseY;
25259 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
25260 var bgY = Math.ceil(y + this.previewEl.getTop(true));
25262 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
25263 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
25265 this.previewEl.setLeft(bgX);
25266 this.previewEl.setTop(bgY);
25268 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25269 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25272 onMouseUp : function(e)
25276 this.dragable = false;
25279 onMouseWheel : function(e)
25283 this.startScale = this.scale;
25285 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
25287 if(!this.zoomable()){
25288 this.scale = this.startScale;
25297 zoomable : function()
25299 var minScale = this.thumbEl.getWidth() / this.minWidth;
25301 if(this.minWidth < this.minHeight){
25302 minScale = this.thumbEl.getHeight() / this.minHeight;
25305 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
25306 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
25310 (this.rotate == 0 || this.rotate == 180) &&
25312 width > this.imageEl.OriginWidth ||
25313 height > this.imageEl.OriginHeight ||
25314 (width < this.minWidth && height < this.minHeight)
25322 (this.rotate == 90 || this.rotate == 270) &&
25324 width > this.imageEl.OriginWidth ||
25325 height > this.imageEl.OriginHeight ||
25326 (width < this.minHeight && height < this.minWidth)
25333 !this.isDocument &&
25334 (this.rotate == 0 || this.rotate == 180) &&
25336 width < this.minWidth ||
25337 width > this.imageEl.OriginWidth ||
25338 height < this.minHeight ||
25339 height > this.imageEl.OriginHeight
25346 !this.isDocument &&
25347 (this.rotate == 90 || this.rotate == 270) &&
25349 width < this.minHeight ||
25350 width > this.imageEl.OriginWidth ||
25351 height < this.minWidth ||
25352 height > this.imageEl.OriginHeight
25362 onRotateLeft : function(e)
25364 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25366 var minScale = this.thumbEl.getWidth() / this.minWidth;
25368 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25369 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25371 this.startScale = this.scale;
25373 while (this.getScaleLevel() < minScale){
25375 this.scale = this.scale + 1;
25377 if(!this.zoomable()){
25382 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25383 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25388 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25395 this.scale = this.startScale;
25397 this.onRotateFail();
25402 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25404 if(this.isDocument){
25405 this.setThumbBoxSize();
25406 this.setThumbBoxPosition();
25407 this.setCanvasPosition();
25412 this.fireEvent('rotate', this, 'left');
25416 onRotateRight : function(e)
25418 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25420 var minScale = this.thumbEl.getWidth() / this.minWidth;
25422 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25423 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25425 this.startScale = this.scale;
25427 while (this.getScaleLevel() < minScale){
25429 this.scale = this.scale + 1;
25431 if(!this.zoomable()){
25436 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25437 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25442 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25449 this.scale = this.startScale;
25451 this.onRotateFail();
25456 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25458 if(this.isDocument){
25459 this.setThumbBoxSize();
25460 this.setThumbBoxPosition();
25461 this.setCanvasPosition();
25466 this.fireEvent('rotate', this, 'right');
25469 onRotateFail : function()
25471 this.errorEl.show(true);
25475 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
25480 this.previewEl.dom.innerHTML = '';
25482 var canvasEl = document.createElement("canvas");
25484 var contextEl = canvasEl.getContext("2d");
25486 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25487 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25488 var center = this.imageEl.OriginWidth / 2;
25490 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
25491 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25492 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25493 center = this.imageEl.OriginHeight / 2;
25496 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
25498 contextEl.translate(center, center);
25499 contextEl.rotate(this.rotate * Math.PI / 180);
25501 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25503 this.canvasEl = document.createElement("canvas");
25505 this.contextEl = this.canvasEl.getContext("2d");
25507 switch (this.rotate) {
25510 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25511 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25513 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25518 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25519 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25521 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25522 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);
25526 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25531 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25532 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25534 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25535 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);
25539 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);
25544 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25545 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25547 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25548 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25552 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);
25559 this.previewEl.appendChild(this.canvasEl);
25561 this.setCanvasPosition();
25566 if(!this.canvasLoaded){
25570 var imageCanvas = document.createElement("canvas");
25572 var imageContext = imageCanvas.getContext("2d");
25574 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25575 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25577 var center = imageCanvas.width / 2;
25579 imageContext.translate(center, center);
25581 imageContext.rotate(this.rotate * Math.PI / 180);
25583 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25585 var canvas = document.createElement("canvas");
25587 var context = canvas.getContext("2d");
25589 canvas.width = this.minWidth;
25590 canvas.height = this.minHeight;
25592 switch (this.rotate) {
25595 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25596 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25598 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25599 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25601 var targetWidth = this.minWidth - 2 * x;
25602 var targetHeight = this.minHeight - 2 * y;
25606 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25607 scale = targetWidth / width;
25610 if(x > 0 && y == 0){
25611 scale = targetHeight / height;
25614 if(x > 0 && y > 0){
25615 scale = targetWidth / width;
25617 if(width < height){
25618 scale = targetHeight / height;
25622 context.scale(scale, scale);
25624 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25625 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25627 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25628 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25630 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25635 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25636 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25638 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25639 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25641 var targetWidth = this.minWidth - 2 * x;
25642 var targetHeight = this.minHeight - 2 * y;
25646 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25647 scale = targetWidth / width;
25650 if(x > 0 && y == 0){
25651 scale = targetHeight / height;
25654 if(x > 0 && y > 0){
25655 scale = targetWidth / width;
25657 if(width < height){
25658 scale = targetHeight / height;
25662 context.scale(scale, scale);
25664 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25665 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25667 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25668 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25670 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25672 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25677 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25678 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25680 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25681 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25683 var targetWidth = this.minWidth - 2 * x;
25684 var targetHeight = this.minHeight - 2 * y;
25688 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25689 scale = targetWidth / width;
25692 if(x > 0 && y == 0){
25693 scale = targetHeight / height;
25696 if(x > 0 && y > 0){
25697 scale = targetWidth / width;
25699 if(width < height){
25700 scale = targetHeight / height;
25704 context.scale(scale, scale);
25706 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25707 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25709 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25710 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25712 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25713 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25715 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25720 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25721 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25723 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25724 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25726 var targetWidth = this.minWidth - 2 * x;
25727 var targetHeight = this.minHeight - 2 * y;
25731 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25732 scale = targetWidth / width;
25735 if(x > 0 && y == 0){
25736 scale = targetHeight / height;
25739 if(x > 0 && y > 0){
25740 scale = targetWidth / width;
25742 if(width < height){
25743 scale = targetHeight / height;
25747 context.scale(scale, scale);
25749 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25750 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25752 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25753 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25755 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25757 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25764 this.cropData = canvas.toDataURL(this.cropType);
25766 if(this.fireEvent('crop', this, this.cropData) !== false){
25767 this.process(this.file, this.cropData);
25774 setThumbBoxSize : function()
25778 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
25779 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
25780 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
25782 this.minWidth = width;
25783 this.minHeight = height;
25785 if(this.rotate == 90 || this.rotate == 270){
25786 this.minWidth = height;
25787 this.minHeight = width;
25792 width = Math.ceil(this.minWidth * height / this.minHeight);
25794 if(this.minWidth > this.minHeight){
25796 height = Math.ceil(this.minHeight * width / this.minWidth);
25799 this.thumbEl.setStyle({
25800 width : width + 'px',
25801 height : height + 'px'
25808 setThumbBoxPosition : function()
25810 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
25811 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
25813 this.thumbEl.setLeft(x);
25814 this.thumbEl.setTop(y);
25818 baseRotateLevel : function()
25820 this.baseRotate = 1;
25823 typeof(this.exif) != 'undefined' &&
25824 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
25825 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
25827 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
25830 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
25834 baseScaleLevel : function()
25838 if(this.isDocument){
25840 if(this.baseRotate == 6 || this.baseRotate == 8){
25842 height = this.thumbEl.getHeight();
25843 this.baseScale = height / this.imageEl.OriginWidth;
25845 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
25846 width = this.thumbEl.getWidth();
25847 this.baseScale = width / this.imageEl.OriginHeight;
25853 height = this.thumbEl.getHeight();
25854 this.baseScale = height / this.imageEl.OriginHeight;
25856 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
25857 width = this.thumbEl.getWidth();
25858 this.baseScale = width / this.imageEl.OriginWidth;
25864 if(this.baseRotate == 6 || this.baseRotate == 8){
25866 width = this.thumbEl.getHeight();
25867 this.baseScale = width / this.imageEl.OriginHeight;
25869 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
25870 height = this.thumbEl.getWidth();
25871 this.baseScale = height / this.imageEl.OriginHeight;
25874 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25875 height = this.thumbEl.getWidth();
25876 this.baseScale = height / this.imageEl.OriginHeight;
25878 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
25879 width = this.thumbEl.getHeight();
25880 this.baseScale = width / this.imageEl.OriginWidth;
25887 width = this.thumbEl.getWidth();
25888 this.baseScale = width / this.imageEl.OriginWidth;
25890 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
25891 height = this.thumbEl.getHeight();
25892 this.baseScale = height / this.imageEl.OriginHeight;
25895 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25897 height = this.thumbEl.getHeight();
25898 this.baseScale = height / this.imageEl.OriginHeight;
25900 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
25901 width = this.thumbEl.getWidth();
25902 this.baseScale = width / this.imageEl.OriginWidth;
25910 getScaleLevel : function()
25912 return this.baseScale * Math.pow(1.1, this.scale);
25915 onTouchStart : function(e)
25917 if(!this.canvasLoaded){
25918 this.beforeSelectFile(e);
25922 var touches = e.browserEvent.touches;
25928 if(touches.length == 1){
25929 this.onMouseDown(e);
25933 if(touches.length != 2){
25939 for(var i = 0, finger; finger = touches[i]; i++){
25940 coords.push(finger.pageX, finger.pageY);
25943 var x = Math.pow(coords[0] - coords[2], 2);
25944 var y = Math.pow(coords[1] - coords[3], 2);
25946 this.startDistance = Math.sqrt(x + y);
25948 this.startScale = this.scale;
25950 this.pinching = true;
25951 this.dragable = false;
25955 onTouchMove : function(e)
25957 if(!this.pinching && !this.dragable){
25961 var touches = e.browserEvent.touches;
25968 this.onMouseMove(e);
25974 for(var i = 0, finger; finger = touches[i]; i++){
25975 coords.push(finger.pageX, finger.pageY);
25978 var x = Math.pow(coords[0] - coords[2], 2);
25979 var y = Math.pow(coords[1] - coords[3], 2);
25981 this.endDistance = Math.sqrt(x + y);
25983 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
25985 if(!this.zoomable()){
25986 this.scale = this.startScale;
25994 onTouchEnd : function(e)
25996 this.pinching = false;
25997 this.dragable = false;
26001 process : function(file, crop)
26004 this.maskEl.mask(this.loadingText);
26007 this.xhr = new XMLHttpRequest();
26009 file.xhr = this.xhr;
26011 this.xhr.open(this.method, this.url, true);
26014 "Accept": "application/json",
26015 "Cache-Control": "no-cache",
26016 "X-Requested-With": "XMLHttpRequest"
26019 for (var headerName in headers) {
26020 var headerValue = headers[headerName];
26022 this.xhr.setRequestHeader(headerName, headerValue);
26028 this.xhr.onload = function()
26030 _this.xhrOnLoad(_this.xhr);
26033 this.xhr.onerror = function()
26035 _this.xhrOnError(_this.xhr);
26038 var formData = new FormData();
26040 formData.append('returnHTML', 'NO');
26043 formData.append('crop', crop);
26046 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26047 formData.append(this.paramName, file, file.name);
26050 if(typeof(file.filename) != 'undefined'){
26051 formData.append('filename', file.filename);
26054 if(typeof(file.mimetype) != 'undefined'){
26055 formData.append('mimetype', file.mimetype);
26058 if(this.fireEvent('arrange', this, formData) != false){
26059 this.xhr.send(formData);
26063 xhrOnLoad : function(xhr)
26066 this.maskEl.unmask();
26069 if (xhr.readyState !== 4) {
26070 this.fireEvent('exception', this, xhr);
26074 var response = Roo.decode(xhr.responseText);
26076 if(!response.success){
26077 this.fireEvent('exception', this, xhr);
26081 var response = Roo.decode(xhr.responseText);
26083 this.fireEvent('upload', this, response);
26087 xhrOnError : function()
26090 this.maskEl.unmask();
26093 Roo.log('xhr on error');
26095 var response = Roo.decode(xhr.responseText);
26101 prepare : function(file)
26104 this.maskEl.mask(this.loadingText);
26110 if(typeof(file) === 'string'){
26111 this.loadCanvas(file);
26115 if(!file || !this.urlAPI){
26120 this.cropType = file.type;
26124 if(this.fireEvent('prepare', this, this.file) != false){
26126 var reader = new FileReader();
26128 reader.onload = function (e) {
26129 if (e.target.error) {
26130 Roo.log(e.target.error);
26134 var buffer = e.target.result,
26135 dataView = new DataView(buffer),
26137 maxOffset = dataView.byteLength - 4,
26141 if (dataView.getUint16(0) === 0xffd8) {
26142 while (offset < maxOffset) {
26143 markerBytes = dataView.getUint16(offset);
26145 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26146 markerLength = dataView.getUint16(offset + 2) + 2;
26147 if (offset + markerLength > dataView.byteLength) {
26148 Roo.log('Invalid meta data: Invalid segment size.');
26152 if(markerBytes == 0xffe1){
26153 _this.parseExifData(
26160 offset += markerLength;
26170 var url = _this.urlAPI.createObjectURL(_this.file);
26172 _this.loadCanvas(url);
26177 reader.readAsArrayBuffer(this.file);
26183 parseExifData : function(dataView, offset, length)
26185 var tiffOffset = offset + 10,
26189 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26190 // No Exif data, might be XMP data instead
26194 // Check for the ASCII code for "Exif" (0x45786966):
26195 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26196 // No Exif data, might be XMP data instead
26199 if (tiffOffset + 8 > dataView.byteLength) {
26200 Roo.log('Invalid Exif data: Invalid segment size.');
26203 // Check for the two null bytes:
26204 if (dataView.getUint16(offset + 8) !== 0x0000) {
26205 Roo.log('Invalid Exif data: Missing byte alignment offset.');
26208 // Check the byte alignment:
26209 switch (dataView.getUint16(tiffOffset)) {
26211 littleEndian = true;
26214 littleEndian = false;
26217 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
26220 // Check for the TIFF tag marker (0x002A):
26221 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
26222 Roo.log('Invalid Exif data: Missing TIFF marker.');
26225 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
26226 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
26228 this.parseExifTags(
26231 tiffOffset + dirOffset,
26236 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
26241 if (dirOffset + 6 > dataView.byteLength) {
26242 Roo.log('Invalid Exif data: Invalid directory offset.');
26245 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
26246 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
26247 if (dirEndOffset + 4 > dataView.byteLength) {
26248 Roo.log('Invalid Exif data: Invalid directory size.');
26251 for (i = 0; i < tagsNumber; i += 1) {
26255 dirOffset + 2 + 12 * i, // tag offset
26259 // Return the offset to the next directory:
26260 return dataView.getUint32(dirEndOffset, littleEndian);
26263 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
26265 var tag = dataView.getUint16(offset, littleEndian);
26267 this.exif[tag] = this.getExifValue(
26271 dataView.getUint16(offset + 2, littleEndian), // tag type
26272 dataView.getUint32(offset + 4, littleEndian), // tag length
26277 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
26279 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
26288 Roo.log('Invalid Exif data: Invalid tag type.');
26292 tagSize = tagType.size * length;
26293 // Determine if the value is contained in the dataOffset bytes,
26294 // or if the value at the dataOffset is a pointer to the actual data:
26295 dataOffset = tagSize > 4 ?
26296 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
26297 if (dataOffset + tagSize > dataView.byteLength) {
26298 Roo.log('Invalid Exif data: Invalid data offset.');
26301 if (length === 1) {
26302 return tagType.getValue(dataView, dataOffset, littleEndian);
26305 for (i = 0; i < length; i += 1) {
26306 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
26309 if (tagType.ascii) {
26311 // Concatenate the chars:
26312 for (i = 0; i < values.length; i += 1) {
26314 // Ignore the terminating NULL byte(s):
26315 if (c === '\u0000') {
26327 Roo.apply(Roo.bootstrap.UploadCropbox, {
26329 'Orientation': 0x0112
26333 1: 0, //'top-left',
26335 3: 180, //'bottom-right',
26336 // 4: 'bottom-left',
26338 6: 90, //'right-top',
26339 // 7: 'right-bottom',
26340 8: 270 //'left-bottom'
26344 // byte, 8-bit unsigned int:
26346 getValue: function (dataView, dataOffset) {
26347 return dataView.getUint8(dataOffset);
26351 // ascii, 8-bit byte:
26353 getValue: function (dataView, dataOffset) {
26354 return String.fromCharCode(dataView.getUint8(dataOffset));
26359 // short, 16 bit int:
26361 getValue: function (dataView, dataOffset, littleEndian) {
26362 return dataView.getUint16(dataOffset, littleEndian);
26366 // long, 32 bit int:
26368 getValue: function (dataView, dataOffset, littleEndian) {
26369 return dataView.getUint32(dataOffset, littleEndian);
26373 // rational = two long values, first is numerator, second is denominator:
26375 getValue: function (dataView, dataOffset, littleEndian) {
26376 return dataView.getUint32(dataOffset, littleEndian) /
26377 dataView.getUint32(dataOffset + 4, littleEndian);
26381 // slong, 32 bit signed int:
26383 getValue: function (dataView, dataOffset, littleEndian) {
26384 return dataView.getInt32(dataOffset, littleEndian);
26388 // srational, two slongs, first is numerator, second is denominator:
26390 getValue: function (dataView, dataOffset, littleEndian) {
26391 return dataView.getInt32(dataOffset, littleEndian) /
26392 dataView.getInt32(dataOffset + 4, littleEndian);
26402 cls : 'btn-group roo-upload-cropbox-rotate-left',
26403 action : 'rotate-left',
26407 cls : 'btn btn-default',
26408 html : '<i class="fa fa-undo"></i>'
26414 cls : 'btn-group roo-upload-cropbox-picture',
26415 action : 'picture',
26419 cls : 'btn btn-default',
26420 html : '<i class="fa fa-picture-o"></i>'
26426 cls : 'btn-group roo-upload-cropbox-rotate-right',
26427 action : 'rotate-right',
26431 cls : 'btn btn-default',
26432 html : '<i class="fa fa-repeat"></i>'
26440 cls : 'btn-group roo-upload-cropbox-rotate-left',
26441 action : 'rotate-left',
26445 cls : 'btn btn-default',
26446 html : '<i class="fa fa-undo"></i>'
26452 cls : 'btn-group roo-upload-cropbox-download',
26453 action : 'download',
26457 cls : 'btn btn-default',
26458 html : '<i class="fa fa-download"></i>'
26464 cls : 'btn-group roo-upload-cropbox-crop',
26469 cls : 'btn btn-default',
26470 html : '<i class="fa fa-crop"></i>'
26476 cls : 'btn-group roo-upload-cropbox-trash',
26481 cls : 'btn btn-default',
26482 html : '<i class="fa fa-trash"></i>'
26488 cls : 'btn-group roo-upload-cropbox-rotate-right',
26489 action : 'rotate-right',
26493 cls : 'btn btn-default',
26494 html : '<i class="fa fa-repeat"></i>'
26502 cls : 'btn-group roo-upload-cropbox-rotate-left',
26503 action : 'rotate-left',
26507 cls : 'btn btn-default',
26508 html : '<i class="fa fa-undo"></i>'
26514 cls : 'btn-group roo-upload-cropbox-rotate-right',
26515 action : 'rotate-right',
26519 cls : 'btn btn-default',
26520 html : '<i class="fa fa-repeat"></i>'
26533 * @class Roo.bootstrap.DocumentManager
26534 * @extends Roo.bootstrap.Component
26535 * Bootstrap DocumentManager class
26536 * @cfg {String} paramName default 'imageUpload'
26537 * @cfg {String} method default POST
26538 * @cfg {String} url action url
26539 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
26540 * @cfg {Boolean} multiple multiple upload default true
26541 * @cfg {Number} thumbSize default 300
26542 * @cfg {String} fieldLabel
26543 * @cfg {Number} labelWidth default 4
26544 * @cfg {String} labelAlign (left|top) default left
26545 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
26548 * Create a new DocumentManager
26549 * @param {Object} config The config object
26552 Roo.bootstrap.DocumentManager = function(config){
26553 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
26558 * Fire when initial the DocumentManager
26559 * @param {Roo.bootstrap.DocumentManager} this
26564 * inspect selected file
26565 * @param {Roo.bootstrap.DocumentManager} this
26566 * @param {File} file
26571 * Fire when xhr load exception
26572 * @param {Roo.bootstrap.DocumentManager} this
26573 * @param {XMLHttpRequest} xhr
26575 "exception" : true,
26578 * prepare the form data
26579 * @param {Roo.bootstrap.DocumentManager} this
26580 * @param {Object} formData
26585 * Fire when remove the file
26586 * @param {Roo.bootstrap.DocumentManager} this
26587 * @param {Object} file
26592 * Fire after refresh the file
26593 * @param {Roo.bootstrap.DocumentManager} this
26598 * Fire after click the image
26599 * @param {Roo.bootstrap.DocumentManager} this
26600 * @param {Object} file
26605 * Fire when upload a image and editable set to true
26606 * @param {Roo.bootstrap.DocumentManager} this
26607 * @param {Object} file
26611 * @event beforeselectfile
26612 * Fire before select file
26613 * @param {Roo.bootstrap.DocumentManager} this
26615 "beforeselectfile" : true,
26618 * Fire before process file
26619 * @param {Roo.bootstrap.DocumentManager} this
26620 * @param {Object} file
26627 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
26636 paramName : 'imageUpload',
26639 labelAlign : 'left',
26646 getAutoCreate : function()
26648 var managerWidget = {
26650 cls : 'roo-document-manager',
26654 cls : 'roo-document-manager-selector',
26659 cls : 'roo-document-manager-uploader',
26663 cls : 'roo-document-manager-upload-btn',
26664 html : '<i class="fa fa-plus"></i>'
26675 cls : 'column col-md-12',
26680 if(this.fieldLabel.length){
26685 cls : 'column col-md-12',
26686 html : this.fieldLabel
26690 cls : 'column col-md-12',
26695 if(this.labelAlign == 'left'){
26699 cls : 'column col-md-' + this.labelWidth,
26700 html : this.fieldLabel
26704 cls : 'column col-md-' + (12 - this.labelWidth),
26714 cls : 'row clearfix',
26722 initEvents : function()
26724 this.managerEl = this.el.select('.roo-document-manager', true).first();
26725 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26727 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
26728 this.selectorEl.hide();
26731 this.selectorEl.attr('multiple', 'multiple');
26734 this.selectorEl.on('change', this.onFileSelected, this);
26736 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
26737 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26739 this.uploader.on('click', this.onUploaderClick, this);
26741 this.renderProgressDialog();
26745 window.addEventListener("resize", function() { _this.refresh(); } );
26747 this.fireEvent('initial', this);
26750 renderProgressDialog : function()
26754 this.progressDialog = new Roo.bootstrap.Modal({
26755 cls : 'roo-document-manager-progress-dialog',
26756 allow_close : false,
26766 btnclick : function() {
26767 _this.uploadCancel();
26773 this.progressDialog.render(Roo.get(document.body));
26775 this.progress = new Roo.bootstrap.Progress({
26776 cls : 'roo-document-manager-progress',
26781 this.progress.render(this.progressDialog.getChildContainer());
26783 this.progressBar = new Roo.bootstrap.ProgressBar({
26784 cls : 'roo-document-manager-progress-bar',
26787 aria_valuemax : 12,
26791 this.progressBar.render(this.progress.getChildContainer());
26794 onUploaderClick : function(e)
26796 e.preventDefault();
26798 if(this.fireEvent('beforeselectfile', this) != false){
26799 this.selectorEl.dom.click();
26804 onFileSelected : function(e)
26806 e.preventDefault();
26808 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26812 Roo.each(this.selectorEl.dom.files, function(file){
26813 if(this.fireEvent('inspect', this, file) != false){
26814 this.files.push(file);
26824 this.selectorEl.dom.value = '';
26826 if(!this.files.length){
26830 if(this.boxes > 0 && this.files.length > this.boxes){
26831 this.files = this.files.slice(0, this.boxes);
26834 this.uploader.show();
26836 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26837 this.uploader.hide();
26846 Roo.each(this.files, function(file){
26848 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
26849 var f = this.renderPreview(file);
26854 if(file.type.indexOf('image') != -1){
26855 this.delegates.push(
26857 _this.process(file);
26858 }).createDelegate(this)
26866 _this.process(file);
26867 }).createDelegate(this)
26872 this.files = files;
26874 this.delegates = this.delegates.concat(docs);
26876 if(!this.delegates.length){
26881 this.progressBar.aria_valuemax = this.delegates.length;
26888 arrange : function()
26890 if(!this.delegates.length){
26891 this.progressDialog.hide();
26896 var delegate = this.delegates.shift();
26898 this.progressDialog.show();
26900 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
26902 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
26907 refresh : function()
26909 this.uploader.show();
26911 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26912 this.uploader.hide();
26915 Roo.isTouch ? this.closable(false) : this.closable(true);
26917 this.fireEvent('refresh', this);
26920 onRemove : function(e, el, o)
26922 e.preventDefault();
26924 this.fireEvent('remove', this, o);
26928 remove : function(o)
26932 Roo.each(this.files, function(file){
26933 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
26942 this.files = files;
26949 Roo.each(this.files, function(file){
26954 file.target.remove();
26963 onClick : function(e, el, o)
26965 e.preventDefault();
26967 this.fireEvent('click', this, o);
26971 closable : function(closable)
26973 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
26975 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26987 xhrOnLoad : function(xhr)
26989 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
26993 if (xhr.readyState !== 4) {
26995 this.fireEvent('exception', this, xhr);
26999 var response = Roo.decode(xhr.responseText);
27001 if(!response.success){
27003 this.fireEvent('exception', this, xhr);
27007 var file = this.renderPreview(response.data);
27009 this.files.push(file);
27015 xhrOnError : function(xhr)
27017 Roo.log('xhr on error');
27019 var response = Roo.decode(xhr.responseText);
27026 process : function(file)
27028 if(this.fireEvent('process', this, file) !== false){
27029 if(this.editable && file.type.indexOf('image') != -1){
27030 this.fireEvent('edit', this, file);
27034 this.uploadStart(file, false);
27041 uploadStart : function(file, crop)
27043 this.xhr = new XMLHttpRequest();
27045 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27050 file.xhr = this.xhr;
27052 this.managerEl.createChild({
27054 cls : 'roo-document-manager-loading',
27058 tooltip : file.name,
27059 cls : 'roo-document-manager-thumb',
27060 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27066 this.xhr.open(this.method, this.url, true);
27069 "Accept": "application/json",
27070 "Cache-Control": "no-cache",
27071 "X-Requested-With": "XMLHttpRequest"
27074 for (var headerName in headers) {
27075 var headerValue = headers[headerName];
27077 this.xhr.setRequestHeader(headerName, headerValue);
27083 this.xhr.onload = function()
27085 _this.xhrOnLoad(_this.xhr);
27088 this.xhr.onerror = function()
27090 _this.xhrOnError(_this.xhr);
27093 var formData = new FormData();
27095 formData.append('returnHTML', 'NO');
27098 formData.append('crop', crop);
27101 formData.append(this.paramName, file, file.name);
27103 if(this.fireEvent('prepare', this, formData) != false){
27104 this.xhr.send(formData);
27108 uploadCancel : function()
27115 this.delegates = [];
27117 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27124 renderPreview : function(file)
27126 if(typeof(file.target) != 'undefined' && file.target){
27130 var previewEl = this.managerEl.createChild({
27132 cls : 'roo-document-manager-preview',
27136 tooltip : file.filename,
27137 cls : 'roo-document-manager-thumb',
27138 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27143 html : '<i class="fa fa-times-circle"></i>'
27148 var close = previewEl.select('button.close', true).first();
27150 close.on('click', this.onRemove, this, file);
27152 file.target = previewEl;
27154 var image = previewEl.select('img', true).first();
27158 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27160 image.on('click', this.onClick, this, file);
27166 onPreviewLoad : function(file, image)
27168 if(typeof(file.target) == 'undefined' || !file.target){
27172 var width = image.dom.naturalWidth || image.dom.width;
27173 var height = image.dom.naturalHeight || image.dom.height;
27175 if(width > height){
27176 file.target.addClass('wide');
27180 file.target.addClass('tall');
27185 uploadFromSource : function(file, crop)
27187 this.xhr = new XMLHttpRequest();
27189 this.managerEl.createChild({
27191 cls : 'roo-document-manager-loading',
27195 tooltip : file.name,
27196 cls : 'roo-document-manager-thumb',
27197 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27203 this.xhr.open(this.method, this.url, true);
27206 "Accept": "application/json",
27207 "Cache-Control": "no-cache",
27208 "X-Requested-With": "XMLHttpRequest"
27211 for (var headerName in headers) {
27212 var headerValue = headers[headerName];
27214 this.xhr.setRequestHeader(headerName, headerValue);
27220 this.xhr.onload = function()
27222 _this.xhrOnLoad(_this.xhr);
27225 this.xhr.onerror = function()
27227 _this.xhrOnError(_this.xhr);
27230 var formData = new FormData();
27232 formData.append('returnHTML', 'NO');
27234 formData.append('crop', crop);
27236 if(typeof(file.filename) != 'undefined'){
27237 formData.append('filename', file.filename);
27240 if(typeof(file.mimetype) != 'undefined'){
27241 formData.append('mimetype', file.mimetype);
27244 if(this.fireEvent('prepare', this, formData) != false){
27245 this.xhr.send(formData);
27255 * @class Roo.bootstrap.DocumentViewer
27256 * @extends Roo.bootstrap.Component
27257 * Bootstrap DocumentViewer class
27260 * Create a new DocumentViewer
27261 * @param {Object} config The config object
27264 Roo.bootstrap.DocumentViewer = function(config){
27265 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
27270 * Fire after initEvent
27271 * @param {Roo.bootstrap.DocumentViewer} this
27277 * @param {Roo.bootstrap.DocumentViewer} this
27282 * Fire after trash button
27283 * @param {Roo.bootstrap.DocumentViewer} this
27290 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
27292 getAutoCreate : function()
27296 cls : 'roo-document-viewer',
27300 cls : 'roo-document-viewer-body',
27304 cls : 'roo-document-viewer-thumb',
27308 cls : 'roo-document-viewer-image'
27316 cls : 'roo-document-viewer-footer',
27319 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
27327 cls : 'btn btn-default roo-document-viewer-trash',
27328 html : '<i class="fa fa-trash"></i>'
27341 initEvents : function()
27344 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
27345 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27347 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
27348 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27350 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
27351 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27353 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
27354 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27356 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
27357 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27359 this.bodyEl.on('click', this.onClick, this);
27361 this.trashBtn.on('click', this.onTrash, this);
27365 initial : function()
27367 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
27370 this.fireEvent('initial', this);
27374 onClick : function(e)
27376 e.preventDefault();
27378 this.fireEvent('click', this);
27381 onTrash : function(e)
27383 e.preventDefault();
27385 this.fireEvent('trash', this);
27397 * @class Roo.bootstrap.NavProgressBar
27398 * @extends Roo.bootstrap.Component
27399 * Bootstrap NavProgressBar class
27402 * Create a new nav progress bar
27403 * @param {Object} config The config object
27406 Roo.bootstrap.NavProgressBar = function(config){
27407 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
27409 this.bullets = this.bullets || [];
27411 // Roo.bootstrap.NavProgressBar.register(this);
27415 * Fires when the active item changes
27416 * @param {Roo.bootstrap.NavProgressBar} this
27417 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
27418 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
27425 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
27430 getAutoCreate : function()
27432 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
27436 cls : 'roo-navigation-bar-group',
27440 cls : 'roo-navigation-top-bar'
27444 cls : 'roo-navigation-bullets-bar',
27448 cls : 'roo-navigation-bar'
27455 cls : 'roo-navigation-bottom-bar'
27465 initEvents: function()
27470 onRender : function(ct, position)
27472 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
27474 if(this.bullets.length){
27475 Roo.each(this.bullets, function(b){
27484 addItem : function(cfg)
27486 var item = new Roo.bootstrap.NavProgressItem(cfg);
27488 item.parentId = this.id;
27489 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
27492 var top = new Roo.bootstrap.Element({
27494 cls : 'roo-navigation-bar-text'
27497 var bottom = new Roo.bootstrap.Element({
27499 cls : 'roo-navigation-bar-text'
27502 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
27503 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
27505 var topText = new Roo.bootstrap.Element({
27507 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
27510 var bottomText = new Roo.bootstrap.Element({
27512 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
27515 topText.onRender(top.el, null);
27516 bottomText.onRender(bottom.el, null);
27519 item.bottomEl = bottom;
27522 this.barItems.push(item);
27527 getActive : function()
27529 var active = false;
27531 Roo.each(this.barItems, function(v){
27533 if (!v.isActive()) {
27545 setActiveItem : function(item)
27549 Roo.each(this.barItems, function(v){
27550 if (v.rid == item.rid) {
27554 if (v.isActive()) {
27555 v.setActive(false);
27560 item.setActive(true);
27562 this.fireEvent('changed', this, item, prev);
27565 getBarItem: function(rid)
27569 Roo.each(this.barItems, function(e) {
27570 if (e.rid != rid) {
27581 indexOfItem : function(item)
27585 Roo.each(this.barItems, function(v, i){
27587 if (v.rid != item.rid) {
27598 setActiveNext : function()
27600 var i = this.indexOfItem(this.getActive());
27602 if (i > this.barItems.length) {
27606 this.setActiveItem(this.barItems[i+1]);
27609 setActivePrev : function()
27611 var i = this.indexOfItem(this.getActive());
27617 this.setActiveItem(this.barItems[i-1]);
27620 format : function()
27622 if(!this.barItems.length){
27626 var width = 100 / this.barItems.length;
27628 Roo.each(this.barItems, function(i){
27629 i.el.setStyle('width', width + '%');
27630 i.topEl.el.setStyle('width', width + '%');
27631 i.bottomEl.el.setStyle('width', width + '%');
27640 * Nav Progress Item
27645 * @class Roo.bootstrap.NavProgressItem
27646 * @extends Roo.bootstrap.Component
27647 * Bootstrap NavProgressItem class
27648 * @cfg {String} rid the reference id
27649 * @cfg {Boolean} active (true|false) Is item active default false
27650 * @cfg {Boolean} disabled (true|false) Is item active default false
27651 * @cfg {String} html
27652 * @cfg {String} position (top|bottom) text position default bottom
27653 * @cfg {String} icon show icon instead of number
27656 * Create a new NavProgressItem
27657 * @param {Object} config The config object
27659 Roo.bootstrap.NavProgressItem = function(config){
27660 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
27665 * The raw click event for the entire grid.
27666 * @param {Roo.bootstrap.NavProgressItem} this
27667 * @param {Roo.EventObject} e
27674 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
27680 position : 'bottom',
27683 getAutoCreate : function()
27685 var iconCls = 'roo-navigation-bar-item-icon';
27687 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
27691 cls: 'roo-navigation-bar-item',
27701 cfg.cls += ' active';
27704 cfg.cls += ' disabled';
27710 disable : function()
27712 this.setDisabled(true);
27715 enable : function()
27717 this.setDisabled(false);
27720 initEvents: function()
27722 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
27724 this.iconEl.on('click', this.onClick, this);
27727 onClick : function(e)
27729 e.preventDefault();
27735 if(this.fireEvent('click', this, e) === false){
27739 this.parent().setActiveItem(this);
27742 isActive: function ()
27744 return this.active;
27747 setActive : function(state)
27749 if(this.active == state){
27753 this.active = state;
27756 this.el.addClass('active');
27760 this.el.removeClass('active');
27765 setDisabled : function(state)
27767 if(this.disabled == state){
27771 this.disabled = state;
27774 this.el.addClass('disabled');
27778 this.el.removeClass('disabled');
27781 tooltipEl : function()
27783 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
27796 * @class Roo.bootstrap.FieldLabel
27797 * @extends Roo.bootstrap.Component
27798 * Bootstrap FieldLabel class
27799 * @cfg {String} html contents of the element
27800 * @cfg {String} tag tag of the element default label
27801 * @cfg {String} cls class of the element
27802 * @cfg {String} target label target
27803 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
27804 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
27805 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
27806 * @cfg {String} iconTooltip default "This field is required"
27809 * Create a new FieldLabel
27810 * @param {Object} config The config object
27813 Roo.bootstrap.FieldLabel = function(config){
27814 Roo.bootstrap.Element.superclass.constructor.call(this, config);
27819 * Fires after the field has been marked as invalid.
27820 * @param {Roo.form.FieldLabel} this
27821 * @param {String} msg The validation message
27826 * Fires after the field has been validated with no errors.
27827 * @param {Roo.form.FieldLabel} this
27833 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
27840 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
27841 validClass : 'text-success fa fa-lg fa-check',
27842 iconTooltip : 'This field is required',
27844 getAutoCreate : function(){
27848 cls : 'roo-bootstrap-field-label ' + this.cls,
27854 tooltip : this.iconTooltip
27866 initEvents: function()
27868 Roo.bootstrap.Element.superclass.initEvents.call(this);
27870 this.iconEl = this.el.select('i', true).first();
27872 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
27874 Roo.bootstrap.FieldLabel.register(this);
27878 * Mark this field as valid
27880 markValid : function()
27882 this.iconEl.show();
27884 this.iconEl.removeClass(this.invalidClass);
27886 this.iconEl.addClass(this.validClass);
27888 this.fireEvent('valid', this);
27892 * Mark this field as invalid
27893 * @param {String} msg The validation message
27895 markInvalid : function(msg)
27897 this.iconEl.show();
27899 this.iconEl.removeClass(this.validClass);
27901 this.iconEl.addClass(this.invalidClass);
27903 this.fireEvent('invalid', this, msg);
27909 Roo.apply(Roo.bootstrap.FieldLabel, {
27914 * register a FieldLabel Group
27915 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
27917 register : function(label)
27919 if(this.groups.hasOwnProperty(label.target)){
27923 this.groups[label.target] = label;
27927 * fetch a FieldLabel Group based on the target
27928 * @param {string} target
27929 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
27931 get: function(target) {
27932 if (typeof(this.groups[target]) == 'undefined') {
27936 return this.groups[target] ;
27945 * page DateSplitField.
27951 * @class Roo.bootstrap.DateSplitField
27952 * @extends Roo.bootstrap.Component
27953 * Bootstrap DateSplitField class
27954 * @cfg {string} fieldLabel - the label associated
27955 * @cfg {Number} labelWidth set the width of label (0-12)
27956 * @cfg {String} labelAlign (top|left)
27957 * @cfg {Boolean} dayAllowBlank (true|false) default false
27958 * @cfg {Boolean} monthAllowBlank (true|false) default false
27959 * @cfg {Boolean} yearAllowBlank (true|false) default false
27960 * @cfg {string} dayPlaceholder
27961 * @cfg {string} monthPlaceholder
27962 * @cfg {string} yearPlaceholder
27963 * @cfg {string} dayFormat default 'd'
27964 * @cfg {string} monthFormat default 'm'
27965 * @cfg {string} yearFormat default 'Y'
27969 * Create a new DateSplitField
27970 * @param {Object} config The config object
27973 Roo.bootstrap.DateSplitField = function(config){
27974 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
27980 * getting the data of years
27981 * @param {Roo.bootstrap.DateSplitField} this
27982 * @param {Object} years
27987 * getting the data of days
27988 * @param {Roo.bootstrap.DateSplitField} this
27989 * @param {Object} days
27994 * Fires after the field has been marked as invalid.
27995 * @param {Roo.form.Field} this
27996 * @param {String} msg The validation message
28001 * Fires after the field has been validated with no errors.
28002 * @param {Roo.form.Field} this
28008 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28011 labelAlign : 'top',
28013 dayAllowBlank : false,
28014 monthAllowBlank : false,
28015 yearAllowBlank : false,
28016 dayPlaceholder : '',
28017 monthPlaceholder : '',
28018 yearPlaceholder : '',
28022 isFormField : true,
28024 getAutoCreate : function()
28028 cls : 'row roo-date-split-field-group',
28033 cls : 'form-hidden-field roo-date-split-field-group-value',
28039 if(this.fieldLabel){
28042 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28046 html : this.fieldLabel
28052 Roo.each(['day', 'month', 'year'], function(t){
28055 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28062 inputEl: function ()
28064 return this.el.select('.roo-date-split-field-group-value', true).first();
28067 onRender : function(ct, position)
28071 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28073 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28075 this.dayField = new Roo.bootstrap.ComboBox({
28076 allowBlank : this.dayAllowBlank,
28077 alwaysQuery : true,
28078 displayField : 'value',
28081 forceSelection : true,
28083 placeholder : this.dayPlaceholder,
28084 selectOnFocus : true,
28085 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28086 triggerAction : 'all',
28088 valueField : 'value',
28089 store : new Roo.data.SimpleStore({
28090 data : (function() {
28092 _this.fireEvent('days', _this, days);
28095 fields : [ 'value' ]
28098 select : function (_self, record, index)
28100 _this.setValue(_this.getValue());
28105 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28107 this.monthField = new Roo.bootstrap.MonthField({
28108 after : '<i class=\"fa fa-calendar\"></i>',
28109 allowBlank : this.monthAllowBlank,
28110 placeholder : this.monthPlaceholder,
28113 render : function (_self)
28115 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28116 e.preventDefault();
28120 select : function (_self, oldvalue, newvalue)
28122 _this.setValue(_this.getValue());
28127 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28129 this.yearField = new Roo.bootstrap.ComboBox({
28130 allowBlank : this.yearAllowBlank,
28131 alwaysQuery : true,
28132 displayField : 'value',
28135 forceSelection : true,
28137 placeholder : this.yearPlaceholder,
28138 selectOnFocus : true,
28139 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28140 triggerAction : 'all',
28142 valueField : 'value',
28143 store : new Roo.data.SimpleStore({
28144 data : (function() {
28146 _this.fireEvent('years', _this, years);
28149 fields : [ 'value' ]
28152 select : function (_self, record, index)
28154 _this.setValue(_this.getValue());
28159 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28162 setValue : function(v, format)
28164 this.inputEl.dom.value = v;
28166 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28168 var d = Date.parseDate(v, f);
28175 this.setDay(d.format(this.dayFormat));
28176 this.setMonth(d.format(this.monthFormat));
28177 this.setYear(d.format(this.yearFormat));
28184 setDay : function(v)
28186 this.dayField.setValue(v);
28187 this.inputEl.dom.value = this.getValue();
28192 setMonth : function(v)
28194 this.monthField.setValue(v, true);
28195 this.inputEl.dom.value = this.getValue();
28200 setYear : function(v)
28202 this.yearField.setValue(v);
28203 this.inputEl.dom.value = this.getValue();
28208 getDay : function()
28210 return this.dayField.getValue();
28213 getMonth : function()
28215 return this.monthField.getValue();
28218 getYear : function()
28220 return this.yearField.getValue();
28223 getValue : function()
28225 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
28227 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
28237 this.inputEl.dom.value = '';
28242 validate : function()
28244 var d = this.dayField.validate();
28245 var m = this.monthField.validate();
28246 var y = this.yearField.validate();
28251 (!this.dayAllowBlank && !d) ||
28252 (!this.monthAllowBlank && !m) ||
28253 (!this.yearAllowBlank && !y)
28258 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
28267 this.markInvalid();
28272 markValid : function()
28275 var label = this.el.select('label', true).first();
28276 var icon = this.el.select('i.fa-star', true).first();
28282 this.fireEvent('valid', this);
28286 * Mark this field as invalid
28287 * @param {String} msg The validation message
28289 markInvalid : function(msg)
28292 var label = this.el.select('label', true).first();
28293 var icon = this.el.select('i.fa-star', true).first();
28295 if(label && !icon){
28296 this.el.select('.roo-date-split-field-label', true).createChild({
28298 cls : 'text-danger fa fa-lg fa-star',
28299 tooltip : 'This field is required',
28300 style : 'margin-right:5px;'
28304 this.fireEvent('invalid', this, msg);
28307 clearInvalid : function()
28309 var label = this.el.select('label', true).first();
28310 var icon = this.el.select('i.fa-star', true).first();
28316 this.fireEvent('valid', this);
28319 getName: function()
28329 * http://masonry.desandro.com
28331 * The idea is to render all the bricks based on vertical width...
28333 * The original code extends 'outlayer' - we might need to use that....
28339 * @class Roo.bootstrap.LayoutMasonry
28340 * @extends Roo.bootstrap.Component
28341 * Bootstrap Layout Masonry class
28344 * Create a new Element
28345 * @param {Object} config The config object
28348 Roo.bootstrap.LayoutMasonry = function(config){
28349 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
28355 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
28358 * @cfg {Boolean} isLayoutInstant = no animation?
28360 isLayoutInstant : false, // needed?
28363 * @cfg {Number} boxWidth width of the columns
28368 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
28373 * @cfg {Number} padWidth padding below box..
28378 * @cfg {Number} gutter gutter width..
28383 * @cfg {Boolean} isAutoInitial defalut true
28385 isAutoInitial : true,
28390 * @cfg {Boolean} isHorizontal defalut false
28392 isHorizontal : false,
28394 currentSize : null,
28400 bricks: null, //CompositeElement
28404 _isLayoutInited : false,
28406 // isAlternative : false, // only use for vertical layout...
28409 * @cfg {Number} alternativePadWidth padding below box..
28411 alternativePadWidth : 50,
28413 getAutoCreate : function(){
28417 cls: 'blog-masonary-wrapper ' + this.cls,
28419 cls : 'mas-boxes masonary'
28426 getChildContainer: function( )
28428 if (this.boxesEl) {
28429 return this.boxesEl;
28432 this.boxesEl = this.el.select('.mas-boxes').first();
28434 return this.boxesEl;
28438 initEvents : function()
28442 if(this.isAutoInitial){
28443 Roo.log('hook children rendered');
28444 this.on('childrenrendered', function() {
28445 Roo.log('children rendered');
28451 initial : function()
28453 this.currentSize = this.el.getBox(true);
28455 Roo.EventManager.onWindowResize(this.resize, this);
28457 if(!this.isAutoInitial){
28465 //this.layout.defer(500,this);
28469 resize : function()
28473 var cs = this.el.getBox(true);
28475 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
28476 Roo.log("no change in with or X");
28480 this.currentSize = cs;
28486 layout : function()
28488 this._resetLayout();
28490 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
28492 this.layoutItems( isInstant );
28494 this._isLayoutInited = true;
28498 _resetLayout : function()
28500 if(this.isHorizontal){
28501 this.horizontalMeasureColumns();
28505 this.verticalMeasureColumns();
28509 verticalMeasureColumns : function()
28511 this.getContainerWidth();
28513 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28514 // this.colWidth = Math.floor(this.containerWidth * 0.8);
28518 var boxWidth = this.boxWidth + this.padWidth;
28520 if(this.containerWidth < this.boxWidth){
28521 boxWidth = this.containerWidth
28524 var containerWidth = this.containerWidth;
28526 var cols = Math.floor(containerWidth / boxWidth);
28528 this.cols = Math.max( cols, 1 );
28530 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
28532 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
28534 this.colWidth = boxWidth + avail - this.padWidth;
28536 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
28537 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
28540 horizontalMeasureColumns : function()
28542 this.getContainerWidth();
28544 var boxWidth = this.boxWidth;
28546 if(this.containerWidth < boxWidth){
28547 boxWidth = this.containerWidth;
28550 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
28552 this.el.setHeight(boxWidth);
28556 getContainerWidth : function()
28558 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
28561 layoutItems : function( isInstant )
28563 var items = Roo.apply([], this.bricks);
28565 if(this.isHorizontal){
28566 this._horizontalLayoutItems( items , isInstant );
28570 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28571 // this._verticalAlternativeLayoutItems( items , isInstant );
28575 this._verticalLayoutItems( items , isInstant );
28579 _verticalLayoutItems : function ( items , isInstant)
28581 if ( !items || !items.length ) {
28586 ['xs', 'xs', 'xs', 'tall'],
28587 ['xs', 'xs', 'tall'],
28588 ['xs', 'xs', 'sm'],
28589 ['xs', 'xs', 'xs'],
28595 ['sm', 'xs', 'xs'],
28599 ['tall', 'xs', 'xs', 'xs'],
28600 ['tall', 'xs', 'xs'],
28612 Roo.each(items, function(item, k){
28614 switch (item.size) {
28615 // these layouts take up a full box,
28626 boxes.push([item]);
28649 var filterPattern = function(box, length)
28657 var pattern = box.slice(0, length);
28661 Roo.each(pattern, function(i){
28662 format.push(i.size);
28665 Roo.each(standard, function(s){
28667 if(String(s) != String(format)){
28676 if(!match && length == 1){
28681 filterPattern(box, length - 1);
28685 queue.push(pattern);
28687 box = box.slice(length, box.length);
28689 filterPattern(box, 4);
28695 Roo.each(boxes, function(box, k){
28701 if(box.length == 1){
28706 filterPattern(box, 4);
28710 this._processVerticalLayoutQueue( queue, isInstant );
28714 // _verticalAlternativeLayoutItems : function( items , isInstant )
28716 // if ( !items || !items.length ) {
28720 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
28724 _horizontalLayoutItems : function ( items , isInstant)
28726 if ( !items || !items.length || items.length < 3) {
28732 var eItems = items.slice(0, 3);
28734 items = items.slice(3, items.length);
28737 ['xs', 'xs', 'xs', 'wide'],
28738 ['xs', 'xs', 'wide'],
28739 ['xs', 'xs', 'sm'],
28740 ['xs', 'xs', 'xs'],
28746 ['sm', 'xs', 'xs'],
28750 ['wide', 'xs', 'xs', 'xs'],
28751 ['wide', 'xs', 'xs'],
28764 Roo.each(items, function(item, k){
28766 switch (item.size) {
28777 boxes.push([item]);
28801 var filterPattern = function(box, length)
28809 var pattern = box.slice(0, length);
28813 Roo.each(pattern, function(i){
28814 format.push(i.size);
28817 Roo.each(standard, function(s){
28819 if(String(s) != String(format)){
28828 if(!match && length == 1){
28833 filterPattern(box, length - 1);
28837 queue.push(pattern);
28839 box = box.slice(length, box.length);
28841 filterPattern(box, 4);
28847 Roo.each(boxes, function(box, k){
28853 if(box.length == 1){
28858 filterPattern(box, 4);
28865 var pos = this.el.getBox(true);
28869 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
28871 var hit_end = false;
28873 Roo.each(queue, function(box){
28877 Roo.each(box, function(b){
28879 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28889 Roo.each(box, function(b){
28891 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28894 mx = Math.max(mx, b.x);
28898 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
28902 Roo.each(box, function(b){
28904 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28918 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
28921 /** Sets position of item in DOM
28922 * @param {Element} item
28923 * @param {Number} x - horizontal position
28924 * @param {Number} y - vertical position
28925 * @param {Boolean} isInstant - disables transitions
28927 _processVerticalLayoutQueue : function( queue, isInstant )
28929 var pos = this.el.getBox(true);
28934 for (var i = 0; i < this.cols; i++){
28938 Roo.each(queue, function(box, k){
28940 var col = k % this.cols;
28942 Roo.each(box, function(b,kk){
28944 b.el.position('absolute');
28946 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
28947 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
28949 if(b.size == 'md-left' || b.size == 'md-right'){
28950 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
28951 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
28954 b.el.setWidth(width);
28955 b.el.setHeight(height);
28959 for (var i = 0; i < this.cols; i++){
28961 if(maxY[i] < maxY[col]){
28966 col = Math.min(col, i);
28970 x = pos.x + col * (this.colWidth + this.padWidth);
28974 var positions = [];
28976 switch (box.length){
28978 positions = this.getVerticalOneBoxColPositions(x, y, box);
28981 positions = this.getVerticalTwoBoxColPositions(x, y, box);
28984 positions = this.getVerticalThreeBoxColPositions(x, y, box);
28987 positions = this.getVerticalFourBoxColPositions(x, y, box);
28993 Roo.each(box, function(b,kk){
28995 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
28997 var sz = b.el.getSize();
28999 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29007 for (var i = 0; i < this.cols; i++){
29008 mY = Math.max(mY, maxY[i]);
29011 this.el.setHeight(mY - pos.y);
29015 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29017 // var pos = this.el.getBox(true);
29020 // var maxX = pos.right;
29022 // var maxHeight = 0;
29024 // Roo.each(items, function(item, k){
29028 // item.el.position('absolute');
29030 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29032 // item.el.setWidth(width);
29034 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29036 // item.el.setHeight(height);
29039 // item.el.setXY([x, y], isInstant ? false : true);
29041 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29044 // y = y + height + this.alternativePadWidth;
29046 // maxHeight = maxHeight + height + this.alternativePadWidth;
29050 // this.el.setHeight(maxHeight);
29054 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29056 var pos = this.el.getBox(true);
29061 var maxX = pos.right;
29063 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29065 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29067 Roo.each(queue, function(box, k){
29069 Roo.each(box, function(b, kk){
29071 b.el.position('absolute');
29073 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29074 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29076 if(b.size == 'md-left' || b.size == 'md-right'){
29077 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29078 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29081 b.el.setWidth(width);
29082 b.el.setHeight(height);
29090 var positions = [];
29092 switch (box.length){
29094 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29097 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29100 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29103 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29109 Roo.each(box, function(b,kk){
29111 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29113 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29121 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29123 Roo.each(eItems, function(b,k){
29125 b.size = (k == 0) ? 'sm' : 'xs';
29126 b.x = (k == 0) ? 2 : 1;
29127 b.y = (k == 0) ? 2 : 1;
29129 b.el.position('absolute');
29131 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29133 b.el.setWidth(width);
29135 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29137 b.el.setHeight(height);
29141 var positions = [];
29144 x : maxX - this.unitWidth * 2 - this.gutter,
29149 x : maxX - this.unitWidth,
29150 y : minY + (this.unitWidth + this.gutter) * 2
29154 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29158 Roo.each(eItems, function(b,k){
29160 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29166 getVerticalOneBoxColPositions : function(x, y, box)
29170 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29172 if(box[0].size == 'md-left'){
29176 if(box[0].size == 'md-right'){
29181 x : x + (this.unitWidth + this.gutter) * rand,
29188 getVerticalTwoBoxColPositions : function(x, y, box)
29192 if(box[0].size == 'xs'){
29196 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
29200 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
29214 x : x + (this.unitWidth + this.gutter) * 2,
29215 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
29222 getVerticalThreeBoxColPositions : function(x, y, box)
29226 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29234 x : x + (this.unitWidth + this.gutter) * 1,
29239 x : x + (this.unitWidth + this.gutter) * 2,
29247 if(box[0].size == 'xs' && box[1].size == 'xs'){
29256 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
29260 x : x + (this.unitWidth + this.gutter) * 1,
29274 x : x + (this.unitWidth + this.gutter) * 2,
29279 x : x + (this.unitWidth + this.gutter) * 2,
29280 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
29287 getVerticalFourBoxColPositions : function(x, y, box)
29291 if(box[0].size == 'xs'){
29300 y : y + (this.unitHeight + this.gutter) * 1
29305 y : y + (this.unitHeight + this.gutter) * 2
29309 x : x + (this.unitWidth + this.gutter) * 1,
29323 x : x + (this.unitWidth + this.gutter) * 2,
29328 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
29329 y : y + (this.unitHeight + this.gutter) * 1
29333 x : x + (this.unitWidth + this.gutter) * 2,
29334 y : y + (this.unitWidth + this.gutter) * 2
29341 getHorizontalOneBoxColPositions : function(maxX, minY, box)
29345 if(box[0].size == 'md-left'){
29347 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29354 if(box[0].size == 'md-right'){
29356 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29357 y : minY + (this.unitWidth + this.gutter) * 1
29363 var rand = Math.floor(Math.random() * (4 - box[0].y));
29366 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29367 y : minY + (this.unitWidth + this.gutter) * rand
29374 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
29378 if(box[0].size == 'xs'){
29381 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29386 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29387 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
29395 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29400 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29401 y : minY + (this.unitWidth + this.gutter) * 2
29408 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
29412 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29415 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29420 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29421 y : minY + (this.unitWidth + this.gutter) * 1
29425 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29426 y : minY + (this.unitWidth + this.gutter) * 2
29433 if(box[0].size == 'xs' && box[1].size == 'xs'){
29436 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29441 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29446 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29447 y : minY + (this.unitWidth + this.gutter) * 1
29455 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29460 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29461 y : minY + (this.unitWidth + this.gutter) * 2
29465 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29466 y : minY + (this.unitWidth + this.gutter) * 2
29473 getHorizontalFourBoxColPositions : function(maxX, minY, box)
29477 if(box[0].size == 'xs'){
29480 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29485 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29490 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),
29495 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
29496 y : minY + (this.unitWidth + this.gutter) * 1
29504 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29509 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29510 y : minY + (this.unitWidth + this.gutter) * 2
29514 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29515 y : minY + (this.unitWidth + this.gutter) * 2
29519 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),
29520 y : minY + (this.unitWidth + this.gutter) * 2
29534 * http://masonry.desandro.com
29536 * The idea is to render all the bricks based on vertical width...
29538 * The original code extends 'outlayer' - we might need to use that....
29544 * @class Roo.bootstrap.LayoutMasonryAuto
29545 * @extends Roo.bootstrap.Component
29546 * Bootstrap Layout Masonry class
29549 * Create a new Element
29550 * @param {Object} config The config object
29553 Roo.bootstrap.LayoutMasonryAuto = function(config){
29554 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
29557 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
29560 * @cfg {Boolean} isFitWidth - resize the width..
29562 isFitWidth : false, // options..
29564 * @cfg {Boolean} isOriginLeft = left align?
29566 isOriginLeft : true,
29568 * @cfg {Boolean} isOriginTop = top align?
29570 isOriginTop : false,
29572 * @cfg {Boolean} isLayoutInstant = no animation?
29574 isLayoutInstant : false, // needed?
29576 * @cfg {Boolean} isResizingContainer = not sure if this is used..
29578 isResizingContainer : true,
29580 * @cfg {Number} columnWidth width of the columns
29585 * @cfg {Number} padHeight padding below box..
29591 * @cfg {Boolean} isAutoInitial defalut true
29594 isAutoInitial : true,
29600 initialColumnWidth : 0,
29601 currentSize : null,
29603 colYs : null, // array.
29610 bricks: null, //CompositeElement
29611 cols : 0, // array?
29612 // element : null, // wrapped now this.el
29613 _isLayoutInited : null,
29616 getAutoCreate : function(){
29620 cls: 'blog-masonary-wrapper ' + this.cls,
29622 cls : 'mas-boxes masonary'
29629 getChildContainer: function( )
29631 if (this.boxesEl) {
29632 return this.boxesEl;
29635 this.boxesEl = this.el.select('.mas-boxes').first();
29637 return this.boxesEl;
29641 initEvents : function()
29645 if(this.isAutoInitial){
29646 Roo.log('hook children rendered');
29647 this.on('childrenrendered', function() {
29648 Roo.log('children rendered');
29655 initial : function()
29657 this.reloadItems();
29659 this.currentSize = this.el.getBox(true);
29661 /// was window resize... - let's see if this works..
29662 Roo.EventManager.onWindowResize(this.resize, this);
29664 if(!this.isAutoInitial){
29669 this.layout.defer(500,this);
29672 reloadItems: function()
29674 this.bricks = this.el.select('.masonry-brick', true);
29676 this.bricks.each(function(b) {
29677 //Roo.log(b.getSize());
29678 if (!b.attr('originalwidth')) {
29679 b.attr('originalwidth', b.getSize().width);
29684 Roo.log(this.bricks.elements.length);
29687 resize : function()
29690 var cs = this.el.getBox(true);
29692 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29693 Roo.log("no change in with or X");
29696 this.currentSize = cs;
29700 layout : function()
29703 this._resetLayout();
29704 //this._manageStamps();
29706 // don't animate first layout
29707 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29708 this.layoutItems( isInstant );
29710 // flag for initalized
29711 this._isLayoutInited = true;
29714 layoutItems : function( isInstant )
29716 //var items = this._getItemsForLayout( this.items );
29717 // original code supports filtering layout items.. we just ignore it..
29719 this._layoutItems( this.bricks , isInstant );
29721 this._postLayout();
29723 _layoutItems : function ( items , isInstant)
29725 //this.fireEvent( 'layout', this, items );
29728 if ( !items || !items.elements.length ) {
29729 // no items, emit event with empty array
29734 items.each(function(item) {
29735 Roo.log("layout item");
29737 // get x/y object from method
29738 var position = this._getItemLayoutPosition( item );
29740 position.item = item;
29741 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
29742 queue.push( position );
29745 this._processLayoutQueue( queue );
29747 /** Sets position of item in DOM
29748 * @param {Element} item
29749 * @param {Number} x - horizontal position
29750 * @param {Number} y - vertical position
29751 * @param {Boolean} isInstant - disables transitions
29753 _processLayoutQueue : function( queue )
29755 for ( var i=0, len = queue.length; i < len; i++ ) {
29756 var obj = queue[i];
29757 obj.item.position('absolute');
29758 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
29764 * Any logic you want to do after each layout,
29765 * i.e. size the container
29767 _postLayout : function()
29769 this.resizeContainer();
29772 resizeContainer : function()
29774 if ( !this.isResizingContainer ) {
29777 var size = this._getContainerSize();
29779 this.el.setSize(size.width,size.height);
29780 this.boxesEl.setSize(size.width,size.height);
29786 _resetLayout : function()
29788 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
29789 this.colWidth = this.el.getWidth();
29790 //this.gutter = this.el.getWidth();
29792 this.measureColumns();
29798 this.colYs.push( 0 );
29804 measureColumns : function()
29806 this.getContainerWidth();
29807 // if columnWidth is 0, default to outerWidth of first item
29808 if ( !this.columnWidth ) {
29809 var firstItem = this.bricks.first();
29810 Roo.log(firstItem);
29811 this.columnWidth = this.containerWidth;
29812 if (firstItem && firstItem.attr('originalwidth') ) {
29813 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
29815 // columnWidth fall back to item of first element
29816 Roo.log("set column width?");
29817 this.initialColumnWidth = this.columnWidth ;
29819 // if first elem has no width, default to size of container
29824 if (this.initialColumnWidth) {
29825 this.columnWidth = this.initialColumnWidth;
29830 // column width is fixed at the top - however if container width get's smaller we should
29833 // this bit calcs how man columns..
29835 var columnWidth = this.columnWidth += this.gutter;
29837 // calculate columns
29838 var containerWidth = this.containerWidth + this.gutter;
29840 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
29841 // fix rounding errors, typically with gutters
29842 var excess = columnWidth - containerWidth % columnWidth;
29845 // if overshoot is less than a pixel, round up, otherwise floor it
29846 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
29847 cols = Math[ mathMethod ]( cols );
29848 this.cols = Math.max( cols, 1 );
29851 // padding positioning..
29852 var totalColWidth = this.cols * this.columnWidth;
29853 var padavail = this.containerWidth - totalColWidth;
29854 // so for 2 columns - we need 3 'pads'
29856 var padNeeded = (1+this.cols) * this.padWidth;
29858 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
29860 this.columnWidth += padExtra
29861 //this.padWidth = Math.floor(padavail / ( this.cols));
29863 // adjust colum width so that padding is fixed??
29865 // we have 3 columns ... total = width * 3
29866 // we have X left over... that should be used by
29868 //if (this.expandC) {
29876 getContainerWidth : function()
29878 /* // container is parent if fit width
29879 var container = this.isFitWidth ? this.element.parentNode : this.element;
29880 // check that this.size and size are there
29881 // IE8 triggers resize on body size change, so they might not be
29883 var size = getSize( container ); //FIXME
29884 this.containerWidth = size && size.innerWidth; //FIXME
29887 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29891 _getItemLayoutPosition : function( item ) // what is item?
29893 // we resize the item to our columnWidth..
29895 item.setWidth(this.columnWidth);
29896 item.autoBoxAdjust = false;
29898 var sz = item.getSize();
29900 // how many columns does this brick span
29901 var remainder = this.containerWidth % this.columnWidth;
29903 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
29904 // round if off by 1 pixel, otherwise use ceil
29905 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
29906 colSpan = Math.min( colSpan, this.cols );
29908 // normally this should be '1' as we dont' currently allow multi width columns..
29910 var colGroup = this._getColGroup( colSpan );
29911 // get the minimum Y value from the columns
29912 var minimumY = Math.min.apply( Math, colGroup );
29913 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
29915 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
29917 // position the brick
29919 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
29920 y: this.currentSize.y + minimumY + this.padHeight
29924 // apply setHeight to necessary columns
29925 var setHeight = minimumY + sz.height + this.padHeight;
29926 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
29928 var setSpan = this.cols + 1 - colGroup.length;
29929 for ( var i = 0; i < setSpan; i++ ) {
29930 this.colYs[ shortColIndex + i ] = setHeight ;
29937 * @param {Number} colSpan - number of columns the element spans
29938 * @returns {Array} colGroup
29940 _getColGroup : function( colSpan )
29942 if ( colSpan < 2 ) {
29943 // if brick spans only one column, use all the column Ys
29948 // how many different places could this brick fit horizontally
29949 var groupCount = this.cols + 1 - colSpan;
29950 // for each group potential horizontal position
29951 for ( var i = 0; i < groupCount; i++ ) {
29952 // make an array of colY values for that one group
29953 var groupColYs = this.colYs.slice( i, i + colSpan );
29954 // and get the max value of the array
29955 colGroup[i] = Math.max.apply( Math, groupColYs );
29960 _manageStamp : function( stamp )
29962 var stampSize = stamp.getSize();
29963 var offset = stamp.getBox();
29964 // get the columns that this stamp affects
29965 var firstX = this.isOriginLeft ? offset.x : offset.right;
29966 var lastX = firstX + stampSize.width;
29967 var firstCol = Math.floor( firstX / this.columnWidth );
29968 firstCol = Math.max( 0, firstCol );
29970 var lastCol = Math.floor( lastX / this.columnWidth );
29971 // lastCol should not go over if multiple of columnWidth #425
29972 lastCol -= lastX % this.columnWidth ? 0 : 1;
29973 lastCol = Math.min( this.cols - 1, lastCol );
29975 // set colYs to bottom of the stamp
29976 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
29979 for ( var i = firstCol; i <= lastCol; i++ ) {
29980 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
29985 _getContainerSize : function()
29987 this.maxY = Math.max.apply( Math, this.colYs );
29992 if ( this.isFitWidth ) {
29993 size.width = this._getContainerFitWidth();
29999 _getContainerFitWidth : function()
30001 var unusedCols = 0;
30002 // count unused columns
30005 if ( this.colYs[i] !== 0 ) {
30010 // fit container to columns that have been used
30011 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30014 needsResizeLayout : function()
30016 var previousWidth = this.containerWidth;
30017 this.getContainerWidth();
30018 return previousWidth !== this.containerWidth;
30033 * @class Roo.bootstrap.MasonryBrick
30034 * @extends Roo.bootstrap.Component
30035 * Bootstrap MasonryBrick class
30038 * Create a new MasonryBrick
30039 * @param {Object} config The config object
30042 Roo.bootstrap.MasonryBrick = function(config){
30043 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30049 * When a MasonryBrick is clcik
30050 * @param {Roo.bootstrap.MasonryBrick} this
30051 * @param {Roo.EventObject} e
30057 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30060 * @cfg {String} title
30064 * @cfg {String} html
30068 * @cfg {String} bgimage
30072 * @cfg {String} cls
30076 * @cfg {String} href
30080 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30085 * @cfg {String} (center|bottom) placetitle
30089 getAutoCreate : function()
30091 var cls = 'masonry-brick';
30093 if(this.href.length){
30094 cls += ' masonry-brick-link';
30097 if(this.bgimage.length){
30098 cls += ' masonry-brick-image';
30102 cls += ' masonry-' + this.size + '-brick';
30105 if(this.placetitle.length){
30107 switch (this.placetitle) {
30109 cls += ' masonry-center-title';
30112 cls += ' masonry-bottom-title';
30119 if(!this.html.length && !this.bgimage.length){
30120 cls += ' masonry-center-title';
30123 if(!this.html.length && this.bgimage.length){
30124 cls += ' masonry-bottom-title';
30129 cls += ' ' + this.cls;
30133 tag: (this.href.length) ? 'a' : 'div',
30138 cls: 'masonry-brick-paragraph',
30144 if(this.href.length){
30145 cfg.href = this.href;
30148 var cn = cfg.cn[0].cn;
30150 if(this.title.length){
30153 cls: 'masonry-brick-title',
30158 if(this.html.length){
30161 cls: 'masonry-brick-text',
30166 if(this.bgimage.length){
30169 cls: 'masonry-brick-image-view',
30178 initEvents: function()
30180 switch (this.size) {
30182 // this.intSize = 1;
30187 // this.intSize = 2;
30194 // this.intSize = 3;
30199 // this.intSize = 3;
30204 // this.intSize = 3;
30209 // this.intSize = 3;
30221 this.el.on('touchstart', this.onTouchStart, this);
30222 this.el.on('touchmove', this.onTouchMove, this);
30223 this.el.on('touchend', this.onTouchEnd, this);
30225 this.el.on('mouseenter' ,this.enter, this);
30226 this.el.on('mouseleave', this.leave, this);
30229 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
30230 this.parent().bricks.push(this);
30235 onClick: function(e, el)
30243 var time = this.endTimer - this.startTimer;
30251 e.preventDefault();
30254 enter: function(e, el)
30256 e.preventDefault();
30258 if(this.bgimage.length && this.html.length){
30259 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30263 leave: function(e, el)
30265 e.preventDefault();
30267 if(this.bgimage.length && this.html.length){
30268 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30272 onTouchStart: function(e, el)
30274 // e.preventDefault();
30276 if(!this.bgimage.length || !this.html.length){
30280 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30282 this.timer = new Date().getTime();
30284 this.touchmoved = false;
30287 onTouchMove: function(e, el)
30289 this.touchmoved = true;
30292 onTouchEnd: function(e, el)
30294 // e.preventDefault();
30296 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
30300 if(!this.bgimage.length || !this.html.length){
30302 if(this.href.length){
30303 window.location.href = this.href;
30309 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30311 window.location.href = this.href;
30326 * @class Roo.bootstrap.Brick
30327 * @extends Roo.bootstrap.Component
30328 * Bootstrap Brick class
30331 * Create a new Brick
30332 * @param {Object} config The config object
30335 Roo.bootstrap.Brick = function(config){
30336 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
30342 * When a Brick is click
30343 * @param {Roo.bootstrap.Brick} this
30344 * @param {Roo.EventObject} e
30350 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
30353 * @cfg {String} title
30357 * @cfg {String} html
30361 * @cfg {String} bgimage
30365 * @cfg {String} cls
30369 * @cfg {String} href
30373 * @cfg {String} video
30377 * @cfg {Boolean} square
30381 getAutoCreate : function()
30383 var cls = 'roo-brick';
30385 if(this.href.length){
30386 cls += ' roo-brick-link';
30389 if(this.bgimage.length){
30390 cls += ' roo-brick-image';
30393 if(!this.html.length && !this.bgimage.length){
30394 cls += ' roo-brick-center-title';
30397 if(!this.html.length && this.bgimage.length){
30398 cls += ' roo-brick-bottom-title';
30402 cls += ' ' + this.cls;
30406 tag: (this.href.length) ? 'a' : 'div',
30411 cls: 'roo-brick-paragraph',
30417 if(this.href.length){
30418 cfg.href = this.href;
30421 var cn = cfg.cn[0].cn;
30423 if(this.title.length){
30426 cls: 'roo-brick-title',
30431 if(this.html.length){
30434 cls: 'roo-brick-text',
30439 if(this.bgimage.length){
30442 cls: 'roo-brick-image-view',
30450 initEvents: function()
30452 if(this.title.length || this.html.length){
30453 this.el.on('mouseenter' ,this.enter, this);
30454 this.el.on('mouseleave', this.leave, this);
30458 Roo.EventManager.onWindowResize(this.resize, this);
30463 resize : function()
30465 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
30467 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
30468 // paragraph.setHeight(paragraph.getWidth());
30470 if(this.bgimage.length){
30471 var image = this.el.select('.roo-brick-image-view', true).first();
30472 image.setWidth(paragraph.getWidth());
30473 image.setHeight(paragraph.getWidth());
30478 enter: function(e, el)
30480 e.preventDefault();
30482 if(this.bgimage.length){
30483 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
30484 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
30488 leave: function(e, el)
30490 e.preventDefault();
30492 if(this.bgimage.length){
30493 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
30494 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
30504 * Ext JS Library 1.1.1
30505 * Copyright(c) 2006-2007, Ext JS, LLC.
30507 * Originally Released Under LGPL - original licence link has changed is not relivant.
30510 * <script type="text/javascript">
30515 * @class Roo.bootstrap.SplitBar
30516 * @extends Roo.util.Observable
30517 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
30521 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
30522 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
30523 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
30524 split.minSize = 100;
30525 split.maxSize = 600;
30526 split.animate = true;
30527 split.on('moved', splitterMoved);
30530 * Create a new SplitBar
30531 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
30532 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
30533 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30534 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
30535 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
30536 position of the SplitBar).
30538 Roo.bootstrap.SplitBar = function(cfg){
30543 // dragElement : elm
30544 // resizingElement: el,
30546 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
30547 // placement : Roo.bootstrap.SplitBar.LEFT ,
30548 // existingProxy ???
30551 this.el = Roo.get(cfg.dragElement, true);
30552 this.el.dom.unselectable = "on";
30554 this.resizingEl = Roo.get(cfg.resizingElement, true);
30558 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30559 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
30562 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
30565 * The minimum size of the resizing element. (Defaults to 0)
30571 * The maximum size of the resizing element. (Defaults to 2000)
30574 this.maxSize = 2000;
30577 * Whether to animate the transition to the new size
30580 this.animate = false;
30583 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
30586 this.useShim = false;
30591 if(!cfg.existingProxy){
30593 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
30595 this.proxy = Roo.get(cfg.existingProxy).dom;
30598 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
30601 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
30604 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
30607 this.dragSpecs = {};
30610 * @private The adapter to use to positon and resize elements
30612 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30613 this.adapter.init(this);
30615 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30617 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
30618 this.el.addClass("roo-splitbar-h");
30621 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
30622 this.el.addClass("roo-splitbar-v");
30628 * Fires when the splitter is moved (alias for {@link #event-moved})
30629 * @param {Roo.bootstrap.SplitBar} this
30630 * @param {Number} newSize the new width or height
30635 * Fires when the splitter is moved
30636 * @param {Roo.bootstrap.SplitBar} this
30637 * @param {Number} newSize the new width or height
30641 * @event beforeresize
30642 * Fires before the splitter is dragged
30643 * @param {Roo.bootstrap.SplitBar} this
30645 "beforeresize" : true,
30647 "beforeapply" : true
30650 Roo.util.Observable.call(this);
30653 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
30654 onStartProxyDrag : function(x, y){
30655 this.fireEvent("beforeresize", this);
30657 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
30659 o.enableDisplayMode("block");
30660 // all splitbars share the same overlay
30661 Roo.bootstrap.SplitBar.prototype.overlay = o;
30663 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30664 this.overlay.show();
30665 Roo.get(this.proxy).setDisplayed("block");
30666 var size = this.adapter.getElementSize(this);
30667 this.activeMinSize = this.getMinimumSize();;
30668 this.activeMaxSize = this.getMaximumSize();;
30669 var c1 = size - this.activeMinSize;
30670 var c2 = Math.max(this.activeMaxSize - size, 0);
30671 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30672 this.dd.resetConstraints();
30673 this.dd.setXConstraint(
30674 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
30675 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
30677 this.dd.setYConstraint(0, 0);
30679 this.dd.resetConstraints();
30680 this.dd.setXConstraint(0, 0);
30681 this.dd.setYConstraint(
30682 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
30683 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
30686 this.dragSpecs.startSize = size;
30687 this.dragSpecs.startPoint = [x, y];
30688 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
30692 * @private Called after the drag operation by the DDProxy
30694 onEndProxyDrag : function(e){
30695 Roo.get(this.proxy).setDisplayed(false);
30696 var endPoint = Roo.lib.Event.getXY(e);
30698 this.overlay.hide();
30701 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30702 newSize = this.dragSpecs.startSize +
30703 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
30704 endPoint[0] - this.dragSpecs.startPoint[0] :
30705 this.dragSpecs.startPoint[0] - endPoint[0]
30708 newSize = this.dragSpecs.startSize +
30709 (this.placement == Roo.bootstrap.SplitBar.TOP ?
30710 endPoint[1] - this.dragSpecs.startPoint[1] :
30711 this.dragSpecs.startPoint[1] - endPoint[1]
30714 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
30715 if(newSize != this.dragSpecs.startSize){
30716 if(this.fireEvent('beforeapply', this, newSize) !== false){
30717 this.adapter.setElementSize(this, newSize);
30718 this.fireEvent("moved", this, newSize);
30719 this.fireEvent("resize", this, newSize);
30725 * Get the adapter this SplitBar uses
30726 * @return The adapter object
30728 getAdapter : function(){
30729 return this.adapter;
30733 * Set the adapter this SplitBar uses
30734 * @param {Object} adapter A SplitBar adapter object
30736 setAdapter : function(adapter){
30737 this.adapter = adapter;
30738 this.adapter.init(this);
30742 * Gets the minimum size for the resizing element
30743 * @return {Number} The minimum size
30745 getMinimumSize : function(){
30746 return this.minSize;
30750 * Sets the minimum size for the resizing element
30751 * @param {Number} minSize The minimum size
30753 setMinimumSize : function(minSize){
30754 this.minSize = minSize;
30758 * Gets the maximum size for the resizing element
30759 * @return {Number} The maximum size
30761 getMaximumSize : function(){
30762 return this.maxSize;
30766 * Sets the maximum size for the resizing element
30767 * @param {Number} maxSize The maximum size
30769 setMaximumSize : function(maxSize){
30770 this.maxSize = maxSize;
30774 * Sets the initialize size for the resizing element
30775 * @param {Number} size The initial size
30777 setCurrentSize : function(size){
30778 var oldAnimate = this.animate;
30779 this.animate = false;
30780 this.adapter.setElementSize(this, size);
30781 this.animate = oldAnimate;
30785 * Destroy this splitbar.
30786 * @param {Boolean} removeEl True to remove the element
30788 destroy : function(removeEl){
30790 this.shim.remove();
30793 this.proxy.parentNode.removeChild(this.proxy);
30801 * @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.
30803 Roo.bootstrap.SplitBar.createProxy = function(dir){
30804 var proxy = new Roo.Element(document.createElement("div"));
30805 proxy.unselectable();
30806 var cls = 'roo-splitbar-proxy';
30807 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
30808 document.body.appendChild(proxy.dom);
30813 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
30814 * Default Adapter. It assumes the splitter and resizing element are not positioned
30815 * elements and only gets/sets the width of the element. Generally used for table based layouts.
30817 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
30820 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
30821 // do nothing for now
30822 init : function(s){
30826 * Called before drag operations to get the current size of the resizing element.
30827 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30829 getElementSize : function(s){
30830 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30831 return s.resizingEl.getWidth();
30833 return s.resizingEl.getHeight();
30838 * Called after drag operations to set the size of the resizing element.
30839 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30840 * @param {Number} newSize The new size to set
30841 * @param {Function} onComplete A function to be invoked when resizing is complete
30843 setElementSize : function(s, newSize, onComplete){
30844 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30846 s.resizingEl.setWidth(newSize);
30848 onComplete(s, newSize);
30851 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
30856 s.resizingEl.setHeight(newSize);
30858 onComplete(s, newSize);
30861 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
30868 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
30869 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
30870 * Adapter that moves the splitter element to align with the resized sizing element.
30871 * Used with an absolute positioned SplitBar.
30872 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
30873 * document.body, make sure you assign an id to the body element.
30875 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
30876 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30877 this.container = Roo.get(container);
30880 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
30881 init : function(s){
30882 this.basic.init(s);
30885 getElementSize : function(s){
30886 return this.basic.getElementSize(s);
30889 setElementSize : function(s, newSize, onComplete){
30890 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
30893 moveSplitter : function(s){
30894 var yes = Roo.bootstrap.SplitBar;
30895 switch(s.placement){
30897 s.el.setX(s.resizingEl.getRight());
30900 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
30903 s.el.setY(s.resizingEl.getBottom());
30906 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
30913 * Orientation constant - Create a vertical SplitBar
30917 Roo.bootstrap.SplitBar.VERTICAL = 1;
30920 * Orientation constant - Create a horizontal SplitBar
30924 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
30927 * Placement constant - The resizing element is to the left of the splitter element
30931 Roo.bootstrap.SplitBar.LEFT = 1;
30934 * Placement constant - The resizing element is to the right of the splitter element
30938 Roo.bootstrap.SplitBar.RIGHT = 2;
30941 * Placement constant - The resizing element is positioned above the splitter element
30945 Roo.bootstrap.SplitBar.TOP = 3;
30948 * Placement constant - The resizing element is positioned under splitter element
30952 Roo.bootstrap.SplitBar.BOTTOM = 4;
30953 Roo.namespace("Roo.bootstrap.layout");/*
30955 * Ext JS Library 1.1.1
30956 * Copyright(c) 2006-2007, Ext JS, LLC.
30958 * Originally Released Under LGPL - original licence link has changed is not relivant.
30961 * <script type="text/javascript">
30965 * @class Roo.bootstrap.layout.Manager
30966 * @extends Roo.util.Observable
30967 * Base class for layout managers.
30969 Roo.bootstrap.layout.Manager = function(config)
30971 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
30972 this.el = Roo.get(config.el);
30973 // ie scrollbar fix
30974 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
30975 document.body.scroll = "no";
30976 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
30977 this.el.position('relative');
30980 this.id = this.el.id;
30981 this.el.addClass("roo-layout-container");
30982 /** false to disable window resize monitoring @type Boolean */
30983 this.monitorWindowResize = true;
30988 * Fires when a layout is performed.
30989 * @param {Roo.LayoutManager} this
30993 * @event regionresized
30994 * Fires when the user resizes a region.
30995 * @param {Roo.LayoutRegion} region The resized region
30996 * @param {Number} newSize The new size (width for east/west, height for north/south)
30998 "regionresized" : true,
31000 * @event regioncollapsed
31001 * Fires when a region is collapsed.
31002 * @param {Roo.LayoutRegion} region The collapsed region
31004 "regioncollapsed" : true,
31006 * @event regionexpanded
31007 * Fires when a region is expanded.
31008 * @param {Roo.LayoutRegion} region The expanded region
31010 "regionexpanded" : true
31012 this.updating = false;
31013 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31016 Roo.extend(Roo.bootstrap.layout.Manager, Roo.util.Observable, {
31021 monitorWindowResize : true,
31027 * Returns true if this layout is currently being updated
31028 * @return {Boolean}
31030 isUpdating : function(){
31031 return this.updating;
31035 * Suspend the LayoutManager from doing auto-layouts while
31036 * making multiple add or remove calls
31038 beginUpdate : function(){
31039 this.updating = true;
31043 * Restore auto-layouts and optionally disable the manager from performing a layout
31044 * @param {Boolean} noLayout true to disable a layout update
31046 endUpdate : function(noLayout){
31047 this.updating = false;
31053 layout: function(){
31057 onRegionResized : function(region, newSize){
31058 this.fireEvent("regionresized", region, newSize);
31062 onRegionCollapsed : function(region){
31063 this.fireEvent("regioncollapsed", region);
31066 onRegionExpanded : function(region){
31067 this.fireEvent("regionexpanded", region);
31071 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31072 * performs box-model adjustments.
31073 * @return {Object} The size as an object {width: (the width), height: (the height)}
31075 getViewSize : function()
31078 if(this.el.dom != document.body){
31079 size = this.el.getSize();
31081 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31083 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31084 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31089 * Returns the Element this layout is bound to.
31090 * @return {Roo.Element}
31092 getEl : function(){
31097 * Returns the specified region.
31098 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31099 * @return {Roo.LayoutRegion}
31101 getRegion : function(target){
31102 return this.regions[target.toLowerCase()];
31105 onWindowResize : function(){
31106 if(this.monitorWindowResize){
31112 * Ext JS Library 1.1.1
31113 * Copyright(c) 2006-2007, Ext JS, LLC.
31115 * Originally Released Under LGPL - original licence link has changed is not relivant.
31118 * <script type="text/javascript">
31121 * @class Roo.bootstrap.layout.Border
31122 * @extends Roo.bootstrap.layout.Manager
31123 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
31124 * please see: examples/bootstrap/nested.html<br><br>
31126 <b>The container the layout is rendered into can be either the body element or any other element.
31127 If it is not the body element, the container needs to either be an absolute positioned element,
31128 or you will need to add "position:relative" to the css of the container. You will also need to specify
31129 the container size if it is not the body element.</b>
31132 * Create a new Border
31133 * @param {Object} config Configuration options
31135 Roo.bootstrap.layout.Border = function(config){
31136 config = config || {};
31137 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
31141 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
31142 if(config[region]){
31143 config[region].region = region;
31144 this.addRegion(config[region]);
31150 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
31152 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
31154 * Creates and adds a new region if it doesn't already exist.
31155 * @param {String} target The target region key (north, south, east, west or center).
31156 * @param {Object} config The regions config object
31157 * @return {BorderLayoutRegion} The new region
31159 addRegion : function(config)
31161 if(!this.regions[config.region]){
31162 var r = this.factory(config);
31163 this.bindRegion(r);
31165 return this.regions[config.region];
31169 bindRegion : function(r){
31170 this.regions[r.config.region] = r;
31172 r.on("visibilitychange", this.layout, this);
31173 r.on("paneladded", this.layout, this);
31174 r.on("panelremoved", this.layout, this);
31175 r.on("invalidated", this.layout, this);
31176 r.on("resized", this.onRegionResized, this);
31177 r.on("collapsed", this.onRegionCollapsed, this);
31178 r.on("expanded", this.onRegionExpanded, this);
31182 * Performs a layout update.
31184 layout : function()
31186 if(this.updating) {
31189 var size = this.getViewSize();
31190 var w = size.width;
31191 var h = size.height;
31196 //var x = 0, y = 0;
31198 var rs = this.regions;
31199 var north = rs["north"];
31200 var south = rs["south"];
31201 var west = rs["west"];
31202 var east = rs["east"];
31203 var center = rs["center"];
31204 //if(this.hideOnLayout){ // not supported anymore
31205 //c.el.setStyle("display", "none");
31207 if(north && north.isVisible()){
31208 var b = north.getBox();
31209 var m = north.getMargins();
31210 b.width = w - (m.left+m.right);
31213 centerY = b.height + b.y + m.bottom;
31214 centerH -= centerY;
31215 north.updateBox(this.safeBox(b));
31217 if(south && south.isVisible()){
31218 var b = south.getBox();
31219 var m = south.getMargins();
31220 b.width = w - (m.left+m.right);
31222 var totalHeight = (b.height + m.top + m.bottom);
31223 b.y = h - totalHeight + m.top;
31224 centerH -= totalHeight;
31225 south.updateBox(this.safeBox(b));
31227 if(west && west.isVisible()){
31228 var b = west.getBox();
31229 var m = west.getMargins();
31230 b.height = centerH - (m.top+m.bottom);
31232 b.y = centerY + m.top;
31233 var totalWidth = (b.width + m.left + m.right);
31234 centerX += totalWidth;
31235 centerW -= totalWidth;
31236 west.updateBox(this.safeBox(b));
31238 if(east && east.isVisible()){
31239 var b = east.getBox();
31240 var m = east.getMargins();
31241 b.height = centerH - (m.top+m.bottom);
31242 var totalWidth = (b.width + m.left + m.right);
31243 b.x = w - totalWidth + m.left;
31244 b.y = centerY + m.top;
31245 centerW -= totalWidth;
31246 east.updateBox(this.safeBox(b));
31249 var m = center.getMargins();
31251 x: centerX + m.left,
31252 y: centerY + m.top,
31253 width: centerW - (m.left+m.right),
31254 height: centerH - (m.top+m.bottom)
31256 //if(this.hideOnLayout){
31257 //center.el.setStyle("display", "block");
31259 center.updateBox(this.safeBox(centerBox));
31262 this.fireEvent("layout", this);
31266 safeBox : function(box){
31267 box.width = Math.max(0, box.width);
31268 box.height = Math.max(0, box.height);
31273 * Adds a ContentPanel (or subclass) to this layout.
31274 * @param {String} target The target region key (north, south, east, west or center).
31275 * @param {Roo.ContentPanel} panel The panel to add
31276 * @return {Roo.ContentPanel} The added panel
31278 add : function(target, panel){
31280 target = target.toLowerCase();
31281 return this.regions[target].add(panel);
31285 * Remove a ContentPanel (or subclass) to this layout.
31286 * @param {String} target The target region key (north, south, east, west or center).
31287 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
31288 * @return {Roo.ContentPanel} The removed panel
31290 remove : function(target, panel){
31291 target = target.toLowerCase();
31292 return this.regions[target].remove(panel);
31296 * Searches all regions for a panel with the specified id
31297 * @param {String} panelId
31298 * @return {Roo.ContentPanel} The panel or null if it wasn't found
31300 findPanel : function(panelId){
31301 var rs = this.regions;
31302 for(var target in rs){
31303 if(typeof rs[target] != "function"){
31304 var p = rs[target].getPanel(panelId);
31314 * Searches all regions for a panel with the specified id and activates (shows) it.
31315 * @param {String/ContentPanel} panelId The panels id or the panel itself
31316 * @return {Roo.ContentPanel} The shown panel or null
31318 showPanel : function(panelId) {
31319 var rs = this.regions;
31320 for(var target in rs){
31321 var r = rs[target];
31322 if(typeof r != "function"){
31323 if(r.hasPanel(panelId)){
31324 return r.showPanel(panelId);
31332 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
31333 * @param {Roo.state.Provider} provider (optional) An alternate state provider
31336 restoreState : function(provider){
31338 provider = Roo.state.Manager;
31340 var sm = new Roo.LayoutStateManager();
31341 sm.init(this, provider);
31347 * Adds a xtype elements to the layout.
31351 xtype : 'ContentPanel',
31358 xtype : 'NestedLayoutPanel',
31364 items : [ ... list of content panels or nested layout panels.. ]
31368 * @param {Object} cfg Xtype definition of item to add.
31370 addxtype : function(cfg)
31372 // basically accepts a pannel...
31373 // can accept a layout region..!?!?
31374 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
31377 // theory? children can only be panels??
31379 //if (!cfg.xtype.match(/Panel$/)) {
31384 if (typeof(cfg.region) == 'undefined') {
31385 Roo.log("Failed to add Panel, region was not set");
31389 var region = cfg.region;
31395 xitems = cfg.items;
31402 case 'Content': // ContentPanel (el, cfg)
31403 case 'Scroll': // ContentPanel (el, cfg)
31405 cfg.autoCreate = true;
31406 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31408 // var el = this.el.createChild();
31409 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
31412 this.add(region, ret);
31416 case 'TreePanel': // our new panel!
31417 cfg.el = this.el.createChild();
31418 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31419 this.add(region, ret);
31424 // create a new Layout (which is a Border Layout...
31426 var clayout = cfg.layout;
31427 clayout.el = this.el.createChild();
31428 clayout.items = clayout.items || [];
31432 // replace this exitems with the clayout ones..
31433 xitems = clayout.items;
31435 // force background off if it's in center...
31436 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
31437 cfg.background = false;
31439 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
31442 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31443 //console.log('adding nested layout panel ' + cfg.toSource());
31444 this.add(region, ret);
31445 nb = {}; /// find first...
31450 // needs grid and region
31452 //var el = this.getRegion(region).el.createChild();
31453 var el = this.el.createChild();
31454 // create the grid first...
31456 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
31458 if (region == 'center' && this.active ) {
31459 cfg.background = false;
31461 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
31463 this.add(region, ret);
31464 if (cfg.background) {
31465 ret.on('activate', function(gp) {
31466 if (!gp.grid.rendered) {
31476 case 'Border': // it can get called on it'self...
31486 if (typeof(Roo[cfg.xtype]) != 'undefined') {
31488 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31489 this.add(region, ret);
31493 throw "Can not add '" + cfg.xtype + "' to Border";
31497 // GridPanel (grid, cfg)
31500 this.beginUpdate();
31504 Roo.each(xitems, function(i) {
31505 region = nb && i.region ? i.region : false;
31507 var add = ret.addxtype(i);
31510 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
31511 if (!i.background) {
31512 abn[region] = nb[region] ;
31519 // make the last non-background panel active..
31520 //if (nb) { Roo.log(abn); }
31523 for(var r in abn) {
31524 region = this.getRegion(r);
31526 // tried using nb[r], but it does not work..
31528 region.showPanel(abn[r]);
31539 factory : function(cfg)
31542 var validRegions = Roo.bootstrap.layout.Border.regions;
31544 var target = cfg.region;
31547 var r = Roo.bootstrap.layout;
31551 return new r.North(cfg);
31553 return new r.South(cfg);
31555 return new r.East(cfg);
31557 return new r.West(cfg);
31559 return new r.Center(cfg);
31561 throw 'Layout region "'+target+'" not supported.';
31568 * Ext JS Library 1.1.1
31569 * Copyright(c) 2006-2007, Ext JS, LLC.
31571 * Originally Released Under LGPL - original licence link has changed is not relivant.
31574 * <script type="text/javascript">
31578 * @class Roo.bootstrap.layout.Basic
31579 * @extends Roo.util.Observable
31580 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
31581 * and does not have a titlebar, tabs or any other features. All it does is size and position
31582 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
31583 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31584 * @cfg {string} region the region that it inhabits..
31585 * @cfg {bool} skipConfig skip config?
31589 Roo.bootstrap.layout.Basic = function(config){
31591 this.mgr = config.mgr;
31593 this.position = config.region;
31595 var skipConfig = config.skipConfig;
31599 * @scope Roo.BasicLayoutRegion
31603 * @event beforeremove
31604 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
31605 * @param {Roo.LayoutRegion} this
31606 * @param {Roo.ContentPanel} panel The panel
31607 * @param {Object} e The cancel event object
31609 "beforeremove" : true,
31611 * @event invalidated
31612 * Fires when the layout for this region is changed.
31613 * @param {Roo.LayoutRegion} this
31615 "invalidated" : true,
31617 * @event visibilitychange
31618 * Fires when this region is shown or hidden
31619 * @param {Roo.LayoutRegion} this
31620 * @param {Boolean} visibility true or false
31622 "visibilitychange" : true,
31624 * @event paneladded
31625 * Fires when a panel is added.
31626 * @param {Roo.LayoutRegion} this
31627 * @param {Roo.ContentPanel} panel The panel
31629 "paneladded" : true,
31631 * @event panelremoved
31632 * Fires when a panel is removed.
31633 * @param {Roo.LayoutRegion} this
31634 * @param {Roo.ContentPanel} panel The panel
31636 "panelremoved" : true,
31638 * @event beforecollapse
31639 * Fires when this region before collapse.
31640 * @param {Roo.LayoutRegion} this
31642 "beforecollapse" : true,
31645 * Fires when this region is collapsed.
31646 * @param {Roo.LayoutRegion} this
31648 "collapsed" : true,
31651 * Fires when this region is expanded.
31652 * @param {Roo.LayoutRegion} this
31657 * Fires when this region is slid into view.
31658 * @param {Roo.LayoutRegion} this
31660 "slideshow" : true,
31663 * Fires when this region slides out of view.
31664 * @param {Roo.LayoutRegion} this
31666 "slidehide" : true,
31668 * @event panelactivated
31669 * Fires when a panel is activated.
31670 * @param {Roo.LayoutRegion} this
31671 * @param {Roo.ContentPanel} panel The activated panel
31673 "panelactivated" : true,
31676 * Fires when the user resizes this region.
31677 * @param {Roo.LayoutRegion} this
31678 * @param {Number} newSize The new size (width for east/west, height for north/south)
31682 /** A collection of panels in this region. @type Roo.util.MixedCollection */
31683 this.panels = new Roo.util.MixedCollection();
31684 this.panels.getKey = this.getPanelId.createDelegate(this);
31686 this.activePanel = null;
31687 // ensure listeners are added...
31689 if (config.listeners || config.events) {
31690 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
31691 listeners : config.listeners || {},
31692 events : config.events || {}
31696 if(skipConfig !== true){
31697 this.applyConfig(config);
31701 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
31703 getPanelId : function(p){
31707 applyConfig : function(config){
31708 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
31709 this.config = config;
31714 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
31715 * the width, for horizontal (north, south) the height.
31716 * @param {Number} newSize The new width or height
31718 resizeTo : function(newSize){
31719 var el = this.el ? this.el :
31720 (this.activePanel ? this.activePanel.getEl() : null);
31722 switch(this.position){
31725 el.setWidth(newSize);
31726 this.fireEvent("resized", this, newSize);
31730 el.setHeight(newSize);
31731 this.fireEvent("resized", this, newSize);
31737 getBox : function(){
31738 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
31741 getMargins : function(){
31742 return this.margins;
31745 updateBox : function(box){
31747 var el = this.activePanel.getEl();
31748 el.dom.style.left = box.x + "px";
31749 el.dom.style.top = box.y + "px";
31750 this.activePanel.setSize(box.width, box.height);
31754 * Returns the container element for this region.
31755 * @return {Roo.Element}
31757 getEl : function(){
31758 return this.activePanel;
31762 * Returns true if this region is currently visible.
31763 * @return {Boolean}
31765 isVisible : function(){
31766 return this.activePanel ? true : false;
31769 setActivePanel : function(panel){
31770 panel = this.getPanel(panel);
31771 if(this.activePanel && this.activePanel != panel){
31772 this.activePanel.setActiveState(false);
31773 this.activePanel.getEl().setLeftTop(-10000,-10000);
31775 this.activePanel = panel;
31776 panel.setActiveState(true);
31778 panel.setSize(this.box.width, this.box.height);
31780 this.fireEvent("panelactivated", this, panel);
31781 this.fireEvent("invalidated");
31785 * Show the specified panel.
31786 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
31787 * @return {Roo.ContentPanel} The shown panel or null
31789 showPanel : function(panel){
31790 panel = this.getPanel(panel);
31792 this.setActivePanel(panel);
31798 * Get the active panel for this region.
31799 * @return {Roo.ContentPanel} The active panel or null
31801 getActivePanel : function(){
31802 return this.activePanel;
31806 * Add the passed ContentPanel(s)
31807 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
31808 * @return {Roo.ContentPanel} The panel added (if only one was added)
31810 add : function(panel){
31811 if(arguments.length > 1){
31812 for(var i = 0, len = arguments.length; i < len; i++) {
31813 this.add(arguments[i]);
31817 if(this.hasPanel(panel)){
31818 this.showPanel(panel);
31821 var el = panel.getEl();
31822 if(el.dom.parentNode != this.mgr.el.dom){
31823 this.mgr.el.dom.appendChild(el.dom);
31825 if(panel.setRegion){
31826 panel.setRegion(this);
31828 this.panels.add(panel);
31829 el.setStyle("position", "absolute");
31830 if(!panel.background){
31831 this.setActivePanel(panel);
31832 if(this.config.initialSize && this.panels.getCount()==1){
31833 this.resizeTo(this.config.initialSize);
31836 this.fireEvent("paneladded", this, panel);
31841 * Returns true if the panel is in this region.
31842 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31843 * @return {Boolean}
31845 hasPanel : function(panel){
31846 if(typeof panel == "object"){ // must be panel obj
31847 panel = panel.getId();
31849 return this.getPanel(panel) ? true : false;
31853 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
31854 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31855 * @param {Boolean} preservePanel Overrides the config preservePanel option
31856 * @return {Roo.ContentPanel} The panel that was removed
31858 remove : function(panel, preservePanel){
31859 panel = this.getPanel(panel);
31864 this.fireEvent("beforeremove", this, panel, e);
31865 if(e.cancel === true){
31868 var panelId = panel.getId();
31869 this.panels.removeKey(panelId);
31874 * Returns the panel specified or null if it's not in this region.
31875 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31876 * @return {Roo.ContentPanel}
31878 getPanel : function(id){
31879 if(typeof id == "object"){ // must be panel obj
31882 return this.panels.get(id);
31886 * Returns this regions position (north/south/east/west/center).
31889 getPosition: function(){
31890 return this.position;
31894 * Ext JS Library 1.1.1
31895 * Copyright(c) 2006-2007, Ext JS, LLC.
31897 * Originally Released Under LGPL - original licence link has changed is not relivant.
31900 * <script type="text/javascript">
31904 * @class Roo.bootstrap.layout.Region
31905 * @extends Roo.bootstrap.layout.Basic
31906 * This class represents a region in a layout manager.
31908 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
31909 * @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})
31910 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
31911 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
31912 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
31913 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
31914 * @cfg {String} title The title for the region (overrides panel titles)
31915 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
31916 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
31917 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
31918 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
31919 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
31920 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
31921 * the space available, similar to FireFox 1.5 tabs (defaults to false)
31922 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
31923 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
31924 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
31926 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
31927 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
31928 * @cfg {Boolean} disableTabTips True to disable tab tooltips
31929 * @cfg {Number} width For East/West panels
31930 * @cfg {Number} height For North/South panels
31931 * @cfg {Boolean} split To show the splitter
31932 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
31934 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31935 * @cfg {string} region the region that it inhabits..
31938 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
31939 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
31941 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
31942 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
31943 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
31945 Roo.bootstrap.layout.Region = function(config)
31948 var mgr = config.mgr;
31949 var pos = config.region;
31950 config.skipConfig = true;
31951 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
31952 var dh = Roo.DomHelper;
31953 /** This region's container element
31954 * @type Roo.Element */
31955 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "roo-layout-region roo-layout-panel roo-layout-panel-" + this.position}, true);
31956 /** This region's title element
31957 * @type Roo.Element */
31959 this.titleEl = dh.append(this.el.dom,
31962 unselectable: "on",
31963 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
31965 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
31966 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
31969 this.titleEl.enableDisplayMode();
31970 /** This region's title text element
31971 * @type HTMLElement */
31972 this.titleTextEl = this.titleEl.dom.firstChild;
31973 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
31975 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
31976 this.closeBtn.enableDisplayMode();
31977 this.closeBtn.on("click", this.closeClicked, this);
31978 this.closeBtn.hide();
31980 this.createBody(config);
31981 this.visible = true;
31982 this.collapsed = false;
31984 if(config.hideWhenEmpty){
31986 this.on("paneladded", this.validateVisibility, this);
31987 this.on("panelremoved", this.validateVisibility, this);
31989 this.applyConfig(config);
31992 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
31996 createBody : function(){
31997 /** This region's body element
31998 * @type Roo.Element */
31999 this.bodyEl = this.el.createChild({
32001 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32005 applyConfig : function(c)
32008 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32009 var dh = Roo.DomHelper;
32010 if(c.titlebar !== false){
32011 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32012 this.collapseBtn.on("click", this.collapse, this);
32013 this.collapseBtn.enableDisplayMode();
32015 if(c.showPin === true || this.showPin){
32016 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32017 this.stickBtn.enableDisplayMode();
32018 this.stickBtn.on("click", this.expand, this);
32019 this.stickBtn.hide();
32024 /** This region's collapsed element
32025 * @type Roo.Element */
32028 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32029 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32032 if(c.floatable !== false){
32033 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32034 this.collapsedEl.on("click", this.collapseClick, this);
32037 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32038 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32039 id: "message", unselectable: "on", style:{"float":"left"}});
32040 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32042 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32043 this.expandBtn.on("click", this.expand, this);
32047 if(this.collapseBtn){
32048 this.collapseBtn.setVisible(c.collapsible == true);
32051 this.cmargins = c.cmargins || this.cmargins ||
32052 (this.position == "west" || this.position == "east" ?
32053 {top: 0, left: 2, right:2, bottom: 0} :
32054 {top: 2, left: 0, right:0, bottom: 2});
32056 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32059 this.bottomTabs = c.tabPosition != "top";
32061 this.autoScroll = c.autoScroll || false;
32064 if(this.autoScroll){
32065 this.bodyEl.setStyle("overflow", "auto");
32067 this.bodyEl.setStyle("overflow", c.overflow || 'hidden');
32069 //if(c.titlebar !== false){
32070 if((!c.titlebar && !c.title) || c.titlebar === false){
32071 this.titleEl.hide();
32073 this.titleEl.show();
32075 this.titleTextEl.innerHTML = c.title;
32079 this.duration = c.duration || .30;
32080 this.slideDuration = c.slideDuration || .45;
32083 this.collapse(true);
32090 * Returns true if this region is currently visible.
32091 * @return {Boolean}
32093 isVisible : function(){
32094 return this.visible;
32098 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
32099 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
32101 //setCollapsedTitle : function(title){
32102 // title = title || " ";
32103 // if(this.collapsedTitleTextEl){
32104 // this.collapsedTitleTextEl.innerHTML = title;
32108 getBox : function(){
32110 // if(!this.collapsed){
32111 b = this.el.getBox(false, true);
32113 // b = this.collapsedEl.getBox(false, true);
32118 getMargins : function(){
32119 return this.margins;
32120 //return this.collapsed ? this.cmargins : this.margins;
32123 highlight : function(){
32124 this.el.addClass("x-layout-panel-dragover");
32127 unhighlight : function(){
32128 this.el.removeClass("x-layout-panel-dragover");
32131 updateBox : function(box)
32134 if(!this.collapsed){
32135 this.el.dom.style.left = box.x + "px";
32136 this.el.dom.style.top = box.y + "px";
32137 this.updateBody(box.width, box.height);
32139 this.collapsedEl.dom.style.left = box.x + "px";
32140 this.collapsedEl.dom.style.top = box.y + "px";
32141 this.collapsedEl.setSize(box.width, box.height);
32144 this.tabs.autoSizeTabs();
32148 updateBody : function(w, h)
32151 this.el.setWidth(w);
32152 w -= this.el.getBorderWidth("rl");
32153 if(this.config.adjustments){
32154 w += this.config.adjustments[0];
32158 this.el.setHeight(h);
32159 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
32160 h -= this.el.getBorderWidth("tb");
32161 if(this.config.adjustments){
32162 h += this.config.adjustments[1];
32164 this.bodyEl.setHeight(h);
32166 h = this.tabs.syncHeight(h);
32169 if(this.panelSize){
32170 w = w !== null ? w : this.panelSize.width;
32171 h = h !== null ? h : this.panelSize.height;
32173 if(this.activePanel){
32174 var el = this.activePanel.getEl();
32175 w = w !== null ? w : el.getWidth();
32176 h = h !== null ? h : el.getHeight();
32177 this.panelSize = {width: w, height: h};
32178 this.activePanel.setSize(w, h);
32180 if(Roo.isIE && this.tabs){
32181 this.tabs.el.repaint();
32186 * Returns the container element for this region.
32187 * @return {Roo.Element}
32189 getEl : function(){
32194 * Hides this region.
32197 //if(!this.collapsed){
32198 this.el.dom.style.left = "-2000px";
32201 // this.collapsedEl.dom.style.left = "-2000px";
32202 // this.collapsedEl.hide();
32204 this.visible = false;
32205 this.fireEvent("visibilitychange", this, false);
32209 * Shows this region if it was previously hidden.
32212 //if(!this.collapsed){
32215 // this.collapsedEl.show();
32217 this.visible = true;
32218 this.fireEvent("visibilitychange", this, true);
32221 closeClicked : function(){
32222 if(this.activePanel){
32223 this.remove(this.activePanel);
32227 collapseClick : function(e){
32229 e.stopPropagation();
32232 e.stopPropagation();
32238 * Collapses this region.
32239 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
32242 collapse : function(skipAnim, skipCheck = false){
32243 if(this.collapsed) {
32247 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
32249 this.collapsed = true;
32251 this.split.el.hide();
32253 if(this.config.animate && skipAnim !== true){
32254 this.fireEvent("invalidated", this);
32255 this.animateCollapse();
32257 this.el.setLocation(-20000,-20000);
32259 this.collapsedEl.show();
32260 this.fireEvent("collapsed", this);
32261 this.fireEvent("invalidated", this);
32267 animateCollapse : function(){
32272 * Expands this region if it was previously collapsed.
32273 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
32274 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
32277 expand : function(e, skipAnim){
32279 e.stopPropagation();
32281 if(!this.collapsed || this.el.hasActiveFx()) {
32285 this.afterSlideIn();
32288 this.collapsed = false;
32289 if(this.config.animate && skipAnim !== true){
32290 this.animateExpand();
32294 this.split.el.show();
32296 this.collapsedEl.setLocation(-2000,-2000);
32297 this.collapsedEl.hide();
32298 this.fireEvent("invalidated", this);
32299 this.fireEvent("expanded", this);
32303 animateExpand : function(){
32307 initTabs : function()
32309 this.bodyEl.setStyle("overflow", "hidden");
32310 var ts = new Roo.bootstrap.panel.Tabs({
32311 el: this.bodyEl.dom,
32312 tabPosition: this.bottomTabs ? 'bottom' : 'top',
32313 disableTooltips: this.config.disableTabTips,
32314 toolbar : this.config.toolbar
32317 if(this.config.hideTabs){
32318 ts.stripWrap.setDisplayed(false);
32321 ts.resizeTabs = this.config.resizeTabs === true;
32322 ts.minTabWidth = this.config.minTabWidth || 40;
32323 ts.maxTabWidth = this.config.maxTabWidth || 250;
32324 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
32325 ts.monitorResize = false;
32326 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32327 ts.bodyEl.addClass('roo-layout-tabs-body');
32328 this.panels.each(this.initPanelAsTab, this);
32331 initPanelAsTab : function(panel){
32332 var ti = this.tabs.addTab(
32334 panel.getTitle(), null,
32335 this.config.closeOnTab && panel.isClosable()
32337 if(panel.tabTip !== undefined){
32338 ti.setTooltip(panel.tabTip);
32340 ti.on("activate", function(){
32341 this.setActivePanel(panel);
32344 if(this.config.closeOnTab){
32345 ti.on("beforeclose", function(t, e){
32347 this.remove(panel);
32353 updatePanelTitle : function(panel, title)
32355 if(this.activePanel == panel){
32356 this.updateTitle(title);
32359 var ti = this.tabs.getTab(panel.getEl().id);
32361 if(panel.tabTip !== undefined){
32362 ti.setTooltip(panel.tabTip);
32367 updateTitle : function(title){
32368 if(this.titleTextEl && !this.config.title){
32369 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
32373 setActivePanel : function(panel)
32375 panel = this.getPanel(panel);
32376 if(this.activePanel && this.activePanel != panel){
32377 this.activePanel.setActiveState(false);
32379 this.activePanel = panel;
32380 panel.setActiveState(true);
32381 if(this.panelSize){
32382 panel.setSize(this.panelSize.width, this.panelSize.height);
32385 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
32387 this.updateTitle(panel.getTitle());
32389 this.fireEvent("invalidated", this);
32391 this.fireEvent("panelactivated", this, panel);
32395 * Shows the specified panel.
32396 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
32397 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
32399 showPanel : function(panel)
32401 panel = this.getPanel(panel);
32404 var tab = this.tabs.getTab(panel.getEl().id);
32405 if(tab.isHidden()){
32406 this.tabs.unhideTab(tab.id);
32410 this.setActivePanel(panel);
32417 * Get the active panel for this region.
32418 * @return {Roo.ContentPanel} The active panel or null
32420 getActivePanel : function(){
32421 return this.activePanel;
32424 validateVisibility : function(){
32425 if(this.panels.getCount() < 1){
32426 this.updateTitle(" ");
32427 this.closeBtn.hide();
32430 if(!this.isVisible()){
32437 * Adds the passed ContentPanel(s) to this region.
32438 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32439 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
32441 add : function(panel){
32442 if(arguments.length > 1){
32443 for(var i = 0, len = arguments.length; i < len; i++) {
32444 this.add(arguments[i]);
32448 if(this.hasPanel(panel)){
32449 this.showPanel(panel);
32452 panel.setRegion(this);
32453 this.panels.add(panel);
32454 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
32455 this.bodyEl.dom.appendChild(panel.getEl().dom);
32456 if(panel.background !== true){
32457 this.setActivePanel(panel);
32459 this.fireEvent("paneladded", this, panel);
32465 this.initPanelAsTab(panel);
32469 if(panel.background !== true){
32470 this.tabs.activate(panel.getEl().id);
32472 this.fireEvent("paneladded", this, panel);
32477 * Hides the tab for the specified panel.
32478 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32480 hidePanel : function(panel){
32481 if(this.tabs && (panel = this.getPanel(panel))){
32482 this.tabs.hideTab(panel.getEl().id);
32487 * Unhides the tab for a previously hidden panel.
32488 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32490 unhidePanel : function(panel){
32491 if(this.tabs && (panel = this.getPanel(panel))){
32492 this.tabs.unhideTab(panel.getEl().id);
32496 clearPanels : function(){
32497 while(this.panels.getCount() > 0){
32498 this.remove(this.panels.first());
32503 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32504 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32505 * @param {Boolean} preservePanel Overrides the config preservePanel option
32506 * @return {Roo.ContentPanel} The panel that was removed
32508 remove : function(panel, preservePanel)
32510 panel = this.getPanel(panel);
32515 this.fireEvent("beforeremove", this, panel, e);
32516 if(e.cancel === true){
32519 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
32520 var panelId = panel.getId();
32521 this.panels.removeKey(panelId);
32523 document.body.appendChild(panel.getEl().dom);
32526 this.tabs.removeTab(panel.getEl().id);
32527 }else if (!preservePanel){
32528 this.bodyEl.dom.removeChild(panel.getEl().dom);
32530 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
32531 var p = this.panels.first();
32532 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
32533 tempEl.appendChild(p.getEl().dom);
32534 this.bodyEl.update("");
32535 this.bodyEl.dom.appendChild(p.getEl().dom);
32537 this.updateTitle(p.getTitle());
32539 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32540 this.setActivePanel(p);
32542 panel.setRegion(null);
32543 if(this.activePanel == panel){
32544 this.activePanel = null;
32546 if(this.config.autoDestroy !== false && preservePanel !== true){
32547 try{panel.destroy();}catch(e){}
32549 this.fireEvent("panelremoved", this, panel);
32554 * Returns the TabPanel component used by this region
32555 * @return {Roo.TabPanel}
32557 getTabs : function(){
32561 createTool : function(parentEl, className){
32562 var btn = Roo.DomHelper.append(parentEl, {
32564 cls: "x-layout-tools-button",
32567 cls: "roo-layout-tools-button-inner " + className,
32571 btn.addClassOnOver("roo-layout-tools-button-over");
32576 * Ext JS Library 1.1.1
32577 * Copyright(c) 2006-2007, Ext JS, LLC.
32579 * Originally Released Under LGPL - original licence link has changed is not relivant.
32582 * <script type="text/javascript">
32588 * @class Roo.SplitLayoutRegion
32589 * @extends Roo.LayoutRegion
32590 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
32592 Roo.bootstrap.layout.Split = function(config){
32593 this.cursor = config.cursor;
32594 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
32597 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
32599 splitTip : "Drag to resize.",
32600 collapsibleSplitTip : "Drag to resize. Double click to hide.",
32601 useSplitTips : false,
32603 applyConfig : function(config){
32604 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
32610 var splitEl = Roo.DomHelper.append(this.mgr.el.dom, {
32612 id: this.el.id + "-split",
32613 cls: "roo-layout-split roo-layout-split-"+this.position,
32616 /** The SplitBar for this region
32617 * @type Roo.SplitBar */
32618 // does not exist yet...
32619 Roo.log([this.position, this.orientation]);
32621 this.split = new Roo.bootstrap.SplitBar({
32622 dragElement : splitEl,
32623 resizingElement: this.el,
32624 orientation : this.orientation
32627 this.split.on("moved", this.onSplitMove, this);
32628 this.split.useShim = config.useShim === true;
32629 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
32630 if(this.useSplitTips){
32631 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
32633 //if(config.collapsible){
32634 // this.split.el.on("dblclick", this.collapse, this);
32637 if(typeof config.minSize != "undefined"){
32638 this.split.minSize = config.minSize;
32640 if(typeof config.maxSize != "undefined"){
32641 this.split.maxSize = config.maxSize;
32643 if(config.hideWhenEmpty || config.hidden || config.collapsed){
32644 this.hideSplitter();
32649 getHMaxSize : function(){
32650 var cmax = this.config.maxSize || 10000;
32651 var center = this.mgr.getRegion("center");
32652 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
32655 getVMaxSize : function(){
32656 var cmax = this.config.maxSize || 10000;
32657 var center = this.mgr.getRegion("center");
32658 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
32661 onSplitMove : function(split, newSize){
32662 this.fireEvent("resized", this, newSize);
32666 * Returns the {@link Roo.SplitBar} for this region.
32667 * @return {Roo.SplitBar}
32669 getSplitBar : function(){
32674 this.hideSplitter();
32675 Roo.bootstrap.layout.Split.superclass.hide.call(this);
32678 hideSplitter : function(){
32680 this.split.el.setLocation(-2000,-2000);
32681 this.split.el.hide();
32687 this.split.el.show();
32689 Roo.bootstrap.layout.Split.superclass.show.call(this);
32692 beforeSlide: function(){
32693 if(Roo.isGecko){// firefox overflow auto bug workaround
32694 this.bodyEl.clip();
32696 this.tabs.bodyEl.clip();
32698 if(this.activePanel){
32699 this.activePanel.getEl().clip();
32701 if(this.activePanel.beforeSlide){
32702 this.activePanel.beforeSlide();
32708 afterSlide : function(){
32709 if(Roo.isGecko){// firefox overflow auto bug workaround
32710 this.bodyEl.unclip();
32712 this.tabs.bodyEl.unclip();
32714 if(this.activePanel){
32715 this.activePanel.getEl().unclip();
32716 if(this.activePanel.afterSlide){
32717 this.activePanel.afterSlide();
32723 initAutoHide : function(){
32724 if(this.autoHide !== false){
32725 if(!this.autoHideHd){
32726 var st = new Roo.util.DelayedTask(this.slideIn, this);
32727 this.autoHideHd = {
32728 "mouseout": function(e){
32729 if(!e.within(this.el, true)){
32733 "mouseover" : function(e){
32739 this.el.on(this.autoHideHd);
32743 clearAutoHide : function(){
32744 if(this.autoHide !== false){
32745 this.el.un("mouseout", this.autoHideHd.mouseout);
32746 this.el.un("mouseover", this.autoHideHd.mouseover);
32750 clearMonitor : function(){
32751 Roo.get(document).un("click", this.slideInIf, this);
32754 // these names are backwards but not changed for compat
32755 slideOut : function(){
32756 if(this.isSlid || this.el.hasActiveFx()){
32759 this.isSlid = true;
32760 if(this.collapseBtn){
32761 this.collapseBtn.hide();
32763 this.closeBtnState = this.closeBtn.getStyle('display');
32764 this.closeBtn.hide();
32766 this.stickBtn.show();
32769 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
32770 this.beforeSlide();
32771 this.el.setStyle("z-index", 10001);
32772 this.el.slideIn(this.getSlideAnchor(), {
32773 callback: function(){
32775 this.initAutoHide();
32776 Roo.get(document).on("click", this.slideInIf, this);
32777 this.fireEvent("slideshow", this);
32784 afterSlideIn : function(){
32785 this.clearAutoHide();
32786 this.isSlid = false;
32787 this.clearMonitor();
32788 this.el.setStyle("z-index", "");
32789 if(this.collapseBtn){
32790 this.collapseBtn.show();
32792 this.closeBtn.setStyle('display', this.closeBtnState);
32794 this.stickBtn.hide();
32796 this.fireEvent("slidehide", this);
32799 slideIn : function(cb){
32800 if(!this.isSlid || this.el.hasActiveFx()){
32804 this.isSlid = false;
32805 this.beforeSlide();
32806 this.el.slideOut(this.getSlideAnchor(), {
32807 callback: function(){
32808 this.el.setLeftTop(-10000, -10000);
32810 this.afterSlideIn();
32818 slideInIf : function(e){
32819 if(!e.within(this.el)){
32824 animateCollapse : function(){
32825 this.beforeSlide();
32826 this.el.setStyle("z-index", 20000);
32827 var anchor = this.getSlideAnchor();
32828 this.el.slideOut(anchor, {
32829 callback : function(){
32830 this.el.setStyle("z-index", "");
32831 this.collapsedEl.slideIn(anchor, {duration:.3});
32833 this.el.setLocation(-10000,-10000);
32835 this.fireEvent("collapsed", this);
32842 animateExpand : function(){
32843 this.beforeSlide();
32844 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
32845 this.el.setStyle("z-index", 20000);
32846 this.collapsedEl.hide({
32849 this.el.slideIn(this.getSlideAnchor(), {
32850 callback : function(){
32851 this.el.setStyle("z-index", "");
32854 this.split.el.show();
32856 this.fireEvent("invalidated", this);
32857 this.fireEvent("expanded", this);
32885 getAnchor : function(){
32886 return this.anchors[this.position];
32889 getCollapseAnchor : function(){
32890 return this.canchors[this.position];
32893 getSlideAnchor : function(){
32894 return this.sanchors[this.position];
32897 getAlignAdj : function(){
32898 var cm = this.cmargins;
32899 switch(this.position){
32915 getExpandAdj : function(){
32916 var c = this.collapsedEl, cm = this.cmargins;
32917 switch(this.position){
32919 return [-(cm.right+c.getWidth()+cm.left), 0];
32922 return [cm.right+c.getWidth()+cm.left, 0];
32925 return [0, -(cm.top+cm.bottom+c.getHeight())];
32928 return [0, cm.top+cm.bottom+c.getHeight()];
32934 * Ext JS Library 1.1.1
32935 * Copyright(c) 2006-2007, Ext JS, LLC.
32937 * Originally Released Under LGPL - original licence link has changed is not relivant.
32940 * <script type="text/javascript">
32943 * These classes are private internal classes
32945 Roo.bootstrap.layout.Center = function(config){
32946 config.region = "center";
32947 Roo.bootstrap.layout.Region.call(this, config);
32948 this.visible = true;
32949 this.minWidth = config.minWidth || 20;
32950 this.minHeight = config.minHeight || 20;
32953 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
32955 // center panel can't be hidden
32959 // center panel can't be hidden
32962 getMinWidth: function(){
32963 return this.minWidth;
32966 getMinHeight: function(){
32967 return this.minHeight;
32980 Roo.bootstrap.layout.North = function(config)
32982 config.region = 'north';
32983 config.cursor = 'n-resize';
32985 Roo.bootstrap.layout.Split.call(this, config);
32987 this.split.placement = Roo.bootstrap.SplitBar.TOP;
32988 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
32989 this.split.el.addClass("roo-layout-split-v");
32991 var size = config.initialSize || config.height;
32992 if(typeof size != "undefined"){
32993 this.el.setHeight(size);
32996 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
32998 orientation: Roo.bootstrap.SplitBar.VERTICAL,
32999 getBox : function(){
33000 if(this.collapsed){
33001 return this.collapsedEl.getBox();
33003 var box = this.el.getBox();
33005 box.height += this.split.el.getHeight();
33010 updateBox : function(box){
33011 if(this.split && !this.collapsed){
33012 box.height -= this.split.el.getHeight();
33013 this.split.el.setLeft(box.x);
33014 this.split.el.setTop(box.y+box.height);
33015 this.split.el.setWidth(box.width);
33017 if(this.collapsed){
33018 this.updateBody(box.width, null);
33020 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33028 Roo.bootstrap.layout.South = function(config){
33029 config.region = 'south';
33030 config.cursor = 's-resize';
33031 Roo.bootstrap.layout.Split.call(this, config);
33033 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33034 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33035 this.split.el.addClass("roo-layout-split-v");
33037 var size = config.initialSize || config.height;
33038 if(typeof size != "undefined"){
33039 this.el.setHeight(size);
33043 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33044 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33045 getBox : function(){
33046 if(this.collapsed){
33047 return this.collapsedEl.getBox();
33049 var box = this.el.getBox();
33051 var sh = this.split.el.getHeight();
33058 updateBox : function(box){
33059 if(this.split && !this.collapsed){
33060 var sh = this.split.el.getHeight();
33063 this.split.el.setLeft(box.x);
33064 this.split.el.setTop(box.y-sh);
33065 this.split.el.setWidth(box.width);
33067 if(this.collapsed){
33068 this.updateBody(box.width, null);
33070 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33074 Roo.bootstrap.layout.East = function(config){
33075 config.region = "east";
33076 config.cursor = "e-resize";
33077 Roo.bootstrap.layout.Split.call(this, config);
33079 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
33080 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33081 this.split.el.addClass("roo-layout-split-h");
33083 var size = config.initialSize || config.width;
33084 if(typeof size != "undefined"){
33085 this.el.setWidth(size);
33088 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
33089 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33090 getBox : function(){
33091 if(this.collapsed){
33092 return this.collapsedEl.getBox();
33094 var box = this.el.getBox();
33096 var sw = this.split.el.getWidth();
33103 updateBox : function(box){
33104 if(this.split && !this.collapsed){
33105 var sw = this.split.el.getWidth();
33107 this.split.el.setLeft(box.x);
33108 this.split.el.setTop(box.y);
33109 this.split.el.setHeight(box.height);
33112 if(this.collapsed){
33113 this.updateBody(null, box.height);
33115 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33119 Roo.bootstrap.layout.West = function(config){
33120 config.region = "west";
33121 config.cursor = "w-resize";
33123 Roo.bootstrap.layout.Split.call(this, config);
33125 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
33126 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33127 this.split.el.addClass("roo-layout-split-h");
33129 var size = config.initialSize || config.width;
33130 if(typeof size != "undefined"){
33131 this.el.setWidth(size);
33134 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
33135 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33136 getBox : function(){
33137 if(this.collapsed){
33138 return this.collapsedEl.getBox();
33140 var box = this.el.getBox();
33142 box.width += this.split.el.getWidth();
33147 updateBox : function(box){
33148 if(this.split && !this.collapsed){
33149 var sw = this.split.el.getWidth();
33151 this.split.el.setLeft(box.x+box.width);
33152 this.split.el.setTop(box.y);
33153 this.split.el.setHeight(box.height);
33155 if(this.collapsed){
33156 this.updateBody(null, box.height);
33158 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33161 Roo.namespace("Roo.bootstrap.panel");/*
33163 * Ext JS Library 1.1.1
33164 * Copyright(c) 2006-2007, Ext JS, LLC.
33166 * Originally Released Under LGPL - original licence link has changed is not relivant.
33169 * <script type="text/javascript">
33172 * @class Roo.ContentPanel
33173 * @extends Roo.util.Observable
33174 * A basic ContentPanel element.
33175 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
33176 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
33177 * @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
33178 * @cfg {Boolean} closable True if the panel can be closed/removed
33179 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
33180 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
33181 * @cfg {Toolbar} toolbar A toolbar for this panel
33182 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
33183 * @cfg {String} title The title for this panel
33184 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
33185 * @cfg {String} url Calls {@link #setUrl} with this value
33186 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
33187 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
33188 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
33189 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
33192 * Create a new ContentPanel.
33193 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
33194 * @param {String/Object} config A string to set only the title or a config object
33195 * @param {String} content (optional) Set the HTML content for this panel
33196 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
33198 Roo.bootstrap.panel.Content = function( config){
33200 var el = config.el;
33201 var content = config.content;
33203 if(config.autoCreate){ // xtype is available if this is called from factory
33206 this.el = Roo.get(el);
33207 if(!this.el && config && config.autoCreate){
33208 if(typeof config.autoCreate == "object"){
33209 if(!config.autoCreate.id){
33210 config.autoCreate.id = config.id||el;
33212 this.el = Roo.DomHelper.append(document.body,
33213 config.autoCreate, true);
33215 var elcfg = { tag: "div",
33216 cls: "roo-layout-inactive-content",
33220 elcfg.html = config.html;
33224 this.el = Roo.DomHelper.append(document.body, elcfg , true);
33227 this.closable = false;
33228 this.loaded = false;
33229 this.active = false;
33230 if(typeof config == "string"){
33231 this.title = config;
33233 Roo.apply(this, config);
33236 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
33237 this.wrapEl = this.el.wrap();
33238 this.toolbar.container = this.el.insertSibling(false, 'before');
33239 this.toolbar = new Roo.Toolbar(this.toolbar);
33242 // xtype created footer. - not sure if will work as we normally have to render first..
33243 if (this.footer && !this.footer.el && this.footer.xtype) {
33244 if (!this.wrapEl) {
33245 this.wrapEl = this.el.wrap();
33248 this.footer.container = this.wrapEl.createChild();
33250 this.footer = Roo.factory(this.footer, Roo);
33255 this.resizeEl = Roo.get(this.resizeEl, true);
33257 this.resizeEl = this.el;
33259 // handle view.xtype
33267 * Fires when this panel is activated.
33268 * @param {Roo.ContentPanel} this
33272 * @event deactivate
33273 * Fires when this panel is activated.
33274 * @param {Roo.ContentPanel} this
33276 "deactivate" : true,
33280 * Fires when this panel is resized if fitToFrame is true.
33281 * @param {Roo.ContentPanel} this
33282 * @param {Number} width The width after any component adjustments
33283 * @param {Number} height The height after any component adjustments
33289 * Fires when this tab is created
33290 * @param {Roo.ContentPanel} this
33301 if(this.autoScroll){
33302 this.resizeEl.setStyle("overflow", "auto");
33304 // fix randome scrolling
33305 this.el.on('scroll', function() {
33306 Roo.log('fix random scolling');
33307 this.scrollTo('top',0);
33310 content = content || this.content;
33312 this.setContent(content);
33314 if(config && config.url){
33315 this.setUrl(this.url, this.params, this.loadOnce);
33320 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
33322 if (this.view && typeof(this.view.xtype) != 'undefined') {
33323 this.view.el = this.el.appendChild(document.createElement("div"));
33324 this.view = Roo.factory(this.view);
33325 this.view.render && this.view.render(false, '');
33329 this.fireEvent('render', this);
33332 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
33334 setRegion : function(region){
33335 this.region = region;
33337 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
33339 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
33344 * Returns the toolbar for this Panel if one was configured.
33345 * @return {Roo.Toolbar}
33347 getToolbar : function(){
33348 return this.toolbar;
33351 setActiveState : function(active){
33352 this.active = active;
33354 this.fireEvent("deactivate", this);
33356 this.fireEvent("activate", this);
33360 * Updates this panel's element
33361 * @param {String} content The new content
33362 * @param {Boolean} loadScripts (optional) true to look for and process scripts
33364 setContent : function(content, loadScripts){
33365 this.el.update(content, loadScripts);
33368 ignoreResize : function(w, h){
33369 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
33372 this.lastSize = {width: w, height: h};
33377 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
33378 * @return {Roo.UpdateManager} The UpdateManager
33380 getUpdateManager : function(){
33381 return this.el.getUpdateManager();
33384 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
33385 * @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:
33388 url: "your-url.php",
33389 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
33390 callback: yourFunction,
33391 scope: yourObject, //(optional scope)
33394 text: "Loading...",
33399 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
33400 * 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.
33401 * @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}
33402 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
33403 * @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.
33404 * @return {Roo.ContentPanel} this
33407 var um = this.el.getUpdateManager();
33408 um.update.apply(um, arguments);
33414 * 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.
33415 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
33416 * @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)
33417 * @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)
33418 * @return {Roo.UpdateManager} The UpdateManager
33420 setUrl : function(url, params, loadOnce){
33421 if(this.refreshDelegate){
33422 this.removeListener("activate", this.refreshDelegate);
33424 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
33425 this.on("activate", this.refreshDelegate);
33426 return this.el.getUpdateManager();
33429 _handleRefresh : function(url, params, loadOnce){
33430 if(!loadOnce || !this.loaded){
33431 var updater = this.el.getUpdateManager();
33432 updater.update(url, params, this._setLoaded.createDelegate(this));
33436 _setLoaded : function(){
33437 this.loaded = true;
33441 * Returns this panel's id
33444 getId : function(){
33449 * Returns this panel's element - used by regiosn to add.
33450 * @return {Roo.Element}
33452 getEl : function(){
33453 return this.wrapEl || this.el;
33458 adjustForComponents : function(width, height)
33460 //Roo.log('adjustForComponents ');
33461 if(this.resizeEl != this.el){
33462 width -= this.el.getFrameWidth('lr');
33463 height -= this.el.getFrameWidth('tb');
33466 var te = this.toolbar.getEl();
33467 height -= te.getHeight();
33468 te.setWidth(width);
33471 var te = this.footer.getEl();
33472 Roo.log("footer:" + te.getHeight());
33474 height -= te.getHeight();
33475 te.setWidth(width);
33479 if(this.adjustments){
33480 width += this.adjustments[0];
33481 height += this.adjustments[1];
33483 return {"width": width, "height": height};
33486 setSize : function(width, height){
33487 if(this.fitToFrame && !this.ignoreResize(width, height)){
33488 if(this.fitContainer && this.resizeEl != this.el){
33489 this.el.setSize(width, height);
33491 var size = this.adjustForComponents(width, height);
33492 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
33493 this.fireEvent('resize', this, size.width, size.height);
33498 * Returns this panel's title
33501 getTitle : function(){
33506 * Set this panel's title
33507 * @param {String} title
33509 setTitle : function(title){
33510 this.title = title;
33512 this.region.updatePanelTitle(this, title);
33517 * Returns true is this panel was configured to be closable
33518 * @return {Boolean}
33520 isClosable : function(){
33521 return this.closable;
33524 beforeSlide : function(){
33526 this.resizeEl.clip();
33529 afterSlide : function(){
33531 this.resizeEl.unclip();
33535 * Force a content refresh from the URL specified in the {@link #setUrl} method.
33536 * Will fail silently if the {@link #setUrl} method has not been called.
33537 * This does not activate the panel, just updates its content.
33539 refresh : function(){
33540 if(this.refreshDelegate){
33541 this.loaded = false;
33542 this.refreshDelegate();
33547 * Destroys this panel
33549 destroy : function(){
33550 this.el.removeAllListeners();
33551 var tempEl = document.createElement("span");
33552 tempEl.appendChild(this.el.dom);
33553 tempEl.innerHTML = "";
33559 * form - if the content panel contains a form - this is a reference to it.
33560 * @type {Roo.form.Form}
33564 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
33565 * This contains a reference to it.
33571 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
33581 * @param {Object} cfg Xtype definition of item to add.
33585 getChildContainer: function () {
33586 return this.getEl();
33591 var ret = new Roo.factory(cfg);
33596 if (cfg.xtype.match(/^Form$/)) {
33599 //if (this.footer) {
33600 // el = this.footer.container.insertSibling(false, 'before');
33602 el = this.el.createChild();
33605 this.form = new Roo.form.Form(cfg);
33608 if ( this.form.allItems.length) {
33609 this.form.render(el.dom);
33613 // should only have one of theses..
33614 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
33615 // views.. should not be just added - used named prop 'view''
33617 cfg.el = this.el.appendChild(document.createElement("div"));
33620 var ret = new Roo.factory(cfg);
33622 ret.render && ret.render(false, ''); // render blank..
33632 * @class Roo.bootstrap.panel.Nest
33633 * @extends Roo.bootstrap.panel.Content
33635 * Create a new Panel, that can contain a layout.Border.
33638 * @param {Roo.BorderLayout} layout The layout for this panel
33639 * @param {String/Object} config A string to set only the title or a config object
33641 Roo.bootstrap.panel.Nest = function(config)
33643 // construct with only one argument..
33644 /* FIXME - implement nicer consturctors
33645 if (layout.layout) {
33647 layout = config.layout;
33648 delete config.layout;
33650 if (layout.xtype && !layout.getEl) {
33651 // then layout needs constructing..
33652 layout = Roo.factory(layout, Roo);
33656 config.el = config.layout.getEl();
33658 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
33660 config.layout.monitorWindowResize = false; // turn off autosizing
33661 this.layout = config.layout;
33662 this.layout.getEl().addClass("roo-layout-nested-layout");
33669 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
33671 setSize : function(width, height){
33672 if(!this.ignoreResize(width, height)){
33673 var size = this.adjustForComponents(width, height);
33674 var el = this.layout.getEl();
33675 el.setSize(size.width, size.height);
33676 var touch = el.dom.offsetWidth;
33677 this.layout.layout();
33678 // ie requires a double layout on the first pass
33679 if(Roo.isIE && !this.initialized){
33680 this.initialized = true;
33681 this.layout.layout();
33686 // activate all subpanels if not currently active..
33688 setActiveState : function(active){
33689 this.active = active;
33691 this.fireEvent("deactivate", this);
33695 this.fireEvent("activate", this);
33696 // not sure if this should happen before or after..
33697 if (!this.layout) {
33698 return; // should not happen..
33701 for (var r in this.layout.regions) {
33702 reg = this.layout.getRegion(r);
33703 if (reg.getActivePanel()) {
33704 //reg.showPanel(reg.getActivePanel()); // force it to activate..
33705 reg.setActivePanel(reg.getActivePanel());
33708 if (!reg.panels.length) {
33711 reg.showPanel(reg.getPanel(0));
33720 * Returns the nested BorderLayout for this panel
33721 * @return {Roo.BorderLayout}
33723 getLayout : function(){
33724 return this.layout;
33728 * Adds a xtype elements to the layout of the nested panel
33732 xtype : 'ContentPanel',
33739 xtype : 'NestedLayoutPanel',
33745 items : [ ... list of content panels or nested layout panels.. ]
33749 * @param {Object} cfg Xtype definition of item to add.
33751 addxtype : function(cfg) {
33752 return this.layout.addxtype(cfg);
33757 * Ext JS Library 1.1.1
33758 * Copyright(c) 2006-2007, Ext JS, LLC.
33760 * Originally Released Under LGPL - original licence link has changed is not relivant.
33763 * <script type="text/javascript">
33766 * @class Roo.TabPanel
33767 * @extends Roo.util.Observable
33768 * A lightweight tab container.
33772 // basic tabs 1, built from existing content
33773 var tabs = new Roo.TabPanel("tabs1");
33774 tabs.addTab("script", "View Script");
33775 tabs.addTab("markup", "View Markup");
33776 tabs.activate("script");
33778 // more advanced tabs, built from javascript
33779 var jtabs = new Roo.TabPanel("jtabs");
33780 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
33782 // set up the UpdateManager
33783 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
33784 var updater = tab2.getUpdateManager();
33785 updater.setDefaultUrl("ajax1.htm");
33786 tab2.on('activate', updater.refresh, updater, true);
33788 // Use setUrl for Ajax loading
33789 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
33790 tab3.setUrl("ajax2.htm", null, true);
33793 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
33796 jtabs.activate("jtabs-1");
33799 * Create a new TabPanel.
33800 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
33801 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
33803 Roo.bootstrap.panel.Tabs = function(config){
33805 * The container element for this TabPanel.
33806 * @type Roo.Element
33808 this.el = Roo.get(config.el);
33811 if(typeof config == "boolean"){
33812 this.tabPosition = config ? "bottom" : "top";
33814 Roo.apply(this, config);
33818 if(this.tabPosition == "bottom"){
33819 this.bodyEl = Roo.get(this.createBody(this.el.dom));
33820 this.el.addClass("roo-tabs-bottom");
33822 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
33823 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
33824 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
33826 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
33828 if(this.tabPosition != "bottom"){
33829 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
33830 * @type Roo.Element
33832 this.bodyEl = Roo.get(this.createBody(this.el.dom));
33833 this.el.addClass("roo-tabs-top");
33837 this.bodyEl.setStyle("position", "relative");
33839 this.active = null;
33840 this.activateDelegate = this.activate.createDelegate(this);
33845 * Fires when the active tab changes
33846 * @param {Roo.TabPanel} this
33847 * @param {Roo.TabPanelItem} activePanel The new active tab
33851 * @event beforetabchange
33852 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
33853 * @param {Roo.TabPanel} this
33854 * @param {Object} e Set cancel to true on this object to cancel the tab change
33855 * @param {Roo.TabPanelItem} tab The tab being changed to
33857 "beforetabchange" : true
33860 Roo.EventManager.onWindowResize(this.onResize, this);
33861 this.cpad = this.el.getPadding("lr");
33862 this.hiddenCount = 0;
33865 // toolbar on the tabbar support...
33866 if (this.toolbar) {
33867 alert("no toolbar support yet");
33868 this.toolbar = false;
33870 var tcfg = this.toolbar;
33871 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
33872 this.toolbar = new Roo.Toolbar(tcfg);
33873 if (Roo.isSafari) {
33874 var tbl = tcfg.container.child('table', true);
33875 tbl.setAttribute('width', '100%');
33883 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
33886 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
33888 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
33890 tabPosition : "top",
33892 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
33894 currentTabWidth : 0,
33896 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
33900 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
33904 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
33906 preferredTabWidth : 175,
33908 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
33910 resizeTabs : false,
33912 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
33914 monitorResize : true,
33916 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
33921 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
33922 * @param {String} id The id of the div to use <b>or create</b>
33923 * @param {String} text The text for the tab
33924 * @param {String} content (optional) Content to put in the TabPanelItem body
33925 * @param {Boolean} closable (optional) True to create a close icon on the tab
33926 * @return {Roo.TabPanelItem} The created TabPanelItem
33928 addTab : function(id, text, content, closable)
33930 var item = new Roo.bootstrap.panel.TabItem({
33934 closable : closable
33936 this.addTabItem(item);
33938 item.setContent(content);
33944 * Returns the {@link Roo.TabPanelItem} with the specified id/index
33945 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
33946 * @return {Roo.TabPanelItem}
33948 getTab : function(id){
33949 return this.items[id];
33953 * Hides the {@link Roo.TabPanelItem} with the specified id/index
33954 * @param {String/Number} id The id or index of the TabPanelItem to hide.
33956 hideTab : function(id){
33957 var t = this.items[id];
33960 this.hiddenCount++;
33961 this.autoSizeTabs();
33966 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
33967 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
33969 unhideTab : function(id){
33970 var t = this.items[id];
33972 t.setHidden(false);
33973 this.hiddenCount--;
33974 this.autoSizeTabs();
33979 * Adds an existing {@link Roo.TabPanelItem}.
33980 * @param {Roo.TabPanelItem} item The TabPanelItem to add
33982 addTabItem : function(item){
33983 this.items[item.id] = item;
33984 this.items.push(item);
33985 // if(this.resizeTabs){
33986 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
33987 // this.autoSizeTabs();
33989 // item.autoSize();
33994 * Removes a {@link Roo.TabPanelItem}.
33995 * @param {String/Number} id The id or index of the TabPanelItem to remove.
33997 removeTab : function(id){
33998 var items = this.items;
33999 var tab = items[id];
34000 if(!tab) { return; }
34001 var index = items.indexOf(tab);
34002 if(this.active == tab && items.length > 1){
34003 var newTab = this.getNextAvailable(index);
34008 this.stripEl.dom.removeChild(tab.pnode.dom);
34009 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
34010 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
34012 items.splice(index, 1);
34013 delete this.items[tab.id];
34014 tab.fireEvent("close", tab);
34015 tab.purgeListeners();
34016 this.autoSizeTabs();
34019 getNextAvailable : function(start){
34020 var items = this.items;
34022 // look for a next tab that will slide over to
34023 // replace the one being removed
34024 while(index < items.length){
34025 var item = items[++index];
34026 if(item && !item.isHidden()){
34030 // if one isn't found select the previous tab (on the left)
34033 var item = items[--index];
34034 if(item && !item.isHidden()){
34042 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
34043 * @param {String/Number} id The id or index of the TabPanelItem to disable.
34045 disableTab : function(id){
34046 var tab = this.items[id];
34047 if(tab && this.active != tab){
34053 * Enables a {@link Roo.TabPanelItem} that is disabled.
34054 * @param {String/Number} id The id or index of the TabPanelItem to enable.
34056 enableTab : function(id){
34057 var tab = this.items[id];
34062 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
34063 * @param {String/Number} id The id or index of the TabPanelItem to activate.
34064 * @return {Roo.TabPanelItem} The TabPanelItem.
34066 activate : function(id){
34067 var tab = this.items[id];
34071 if(tab == this.active || tab.disabled){
34075 this.fireEvent("beforetabchange", this, e, tab);
34076 if(e.cancel !== true && !tab.disabled){
34078 this.active.hide();
34080 this.active = this.items[id];
34081 this.active.show();
34082 this.fireEvent("tabchange", this, this.active);
34088 * Gets the active {@link Roo.TabPanelItem}.
34089 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
34091 getActiveTab : function(){
34092 return this.active;
34096 * Updates the tab body element to fit the height of the container element
34097 * for overflow scrolling
34098 * @param {Number} targetHeight (optional) Override the starting height from the elements height
34100 syncHeight : function(targetHeight){
34101 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34102 var bm = this.bodyEl.getMargins();
34103 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
34104 this.bodyEl.setHeight(newHeight);
34108 onResize : function(){
34109 if(this.monitorResize){
34110 this.autoSizeTabs();
34115 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
34117 beginUpdate : function(){
34118 this.updating = true;
34122 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
34124 endUpdate : function(){
34125 this.updating = false;
34126 this.autoSizeTabs();
34130 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
34132 autoSizeTabs : function(){
34133 var count = this.items.length;
34134 var vcount = count - this.hiddenCount;
34135 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
34138 var w = Math.max(this.el.getWidth() - this.cpad, 10);
34139 var availWidth = Math.floor(w / vcount);
34140 var b = this.stripBody;
34141 if(b.getWidth() > w){
34142 var tabs = this.items;
34143 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
34144 if(availWidth < this.minTabWidth){
34145 /*if(!this.sleft){ // incomplete scrolling code
34146 this.createScrollButtons();
34149 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
34152 if(this.currentTabWidth < this.preferredTabWidth){
34153 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
34159 * Returns the number of tabs in this TabPanel.
34162 getCount : function(){
34163 return this.items.length;
34167 * Resizes all the tabs to the passed width
34168 * @param {Number} The new width
34170 setTabWidth : function(width){
34171 this.currentTabWidth = width;
34172 for(var i = 0, len = this.items.length; i < len; i++) {
34173 if(!this.items[i].isHidden()) {
34174 this.items[i].setWidth(width);
34180 * Destroys this TabPanel
34181 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
34183 destroy : function(removeEl){
34184 Roo.EventManager.removeResizeListener(this.onResize, this);
34185 for(var i = 0, len = this.items.length; i < len; i++){
34186 this.items[i].purgeListeners();
34188 if(removeEl === true){
34189 this.el.update("");
34194 createStrip : function(container)
34196 var strip = document.createElement("nav");
34197 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
34198 container.appendChild(strip);
34202 createStripList : function(strip)
34204 // div wrapper for retard IE
34205 // returns the "tr" element.
34206 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
34207 //'<div class="x-tabs-strip-wrap">'+
34208 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
34209 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
34210 return strip.firstChild; //.firstChild.firstChild.firstChild;
34212 createBody : function(container)
34214 var body = document.createElement("div");
34215 Roo.id(body, "tab-body");
34216 //Roo.fly(body).addClass("x-tabs-body");
34217 Roo.fly(body).addClass("tab-content");
34218 container.appendChild(body);
34221 createItemBody :function(bodyEl, id){
34222 var body = Roo.getDom(id);
34224 body = document.createElement("div");
34227 //Roo.fly(body).addClass("x-tabs-item-body");
34228 Roo.fly(body).addClass("tab-pane");
34229 bodyEl.insertBefore(body, bodyEl.firstChild);
34233 createStripElements : function(stripEl, text, closable)
34235 var td = document.createElement("li"); // was td..
34236 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
34237 //stripEl.appendChild(td);
34239 td.className = "x-tabs-closable";
34240 if(!this.closeTpl){
34241 this.closeTpl = new Roo.Template(
34242 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34243 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
34244 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
34247 var el = this.closeTpl.overwrite(td, {"text": text});
34248 var close = el.getElementsByTagName("div")[0];
34249 var inner = el.getElementsByTagName("em")[0];
34250 return {"el": el, "close": close, "inner": inner};
34253 // not sure what this is..
34255 //this.tabTpl = new Roo.Template(
34256 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34257 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
34259 this.tabTpl = new Roo.Template(
34261 '<span unselectable="on"' +
34262 (this.disableTooltips ? '' : ' title="{text}"') +
34263 ' >{text}</span></span></a>'
34267 var el = this.tabTpl.overwrite(td, {"text": text});
34268 var inner = el.getElementsByTagName("span")[0];
34269 return {"el": el, "inner": inner};
34277 * @class Roo.TabPanelItem
34278 * @extends Roo.util.Observable
34279 * Represents an individual item (tab plus body) in a TabPanel.
34280 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
34281 * @param {String} id The id of this TabPanelItem
34282 * @param {String} text The text for the tab of this TabPanelItem
34283 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
34285 Roo.bootstrap.panel.TabItem = function(config){
34287 * The {@link Roo.TabPanel} this TabPanelItem belongs to
34288 * @type Roo.TabPanel
34290 this.tabPanel = config.panel;
34292 * The id for this TabPanelItem
34295 this.id = config.id;
34297 this.disabled = false;
34299 this.text = config.text;
34301 this.loaded = false;
34302 this.closable = config.closable;
34305 * The body element for this TabPanelItem.
34306 * @type Roo.Element
34308 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
34309 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
34310 this.bodyEl.setStyle("display", "block");
34311 this.bodyEl.setStyle("zoom", "1");
34312 //this.hideAction();
34314 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
34316 this.el = Roo.get(els.el);
34317 this.inner = Roo.get(els.inner, true);
34318 this.textEl = Roo.get(this.el.dom.firstChild, true);
34319 this.pnode = Roo.get(els.el.parentNode, true);
34320 this.el.on("mousedown", this.onTabMouseDown, this);
34321 this.el.on("click", this.onTabClick, this);
34323 if(config.closable){
34324 var c = Roo.get(els.close, true);
34325 c.dom.title = this.closeText;
34326 c.addClassOnOver("close-over");
34327 c.on("click", this.closeClick, this);
34333 * Fires when this tab becomes the active tab.
34334 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34335 * @param {Roo.TabPanelItem} this
34339 * @event beforeclose
34340 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
34341 * @param {Roo.TabPanelItem} this
34342 * @param {Object} e Set cancel to true on this object to cancel the close.
34344 "beforeclose": true,
34347 * Fires when this tab is closed.
34348 * @param {Roo.TabPanelItem} this
34352 * @event deactivate
34353 * Fires when this tab is no longer the active tab.
34354 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34355 * @param {Roo.TabPanelItem} this
34357 "deactivate" : true
34359 this.hidden = false;
34361 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
34364 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
34366 purgeListeners : function(){
34367 Roo.util.Observable.prototype.purgeListeners.call(this);
34368 this.el.removeAllListeners();
34371 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
34374 this.pnode.addClass("active");
34377 this.tabPanel.stripWrap.repaint();
34379 this.fireEvent("activate", this.tabPanel, this);
34383 * Returns true if this tab is the active tab.
34384 * @return {Boolean}
34386 isActive : function(){
34387 return this.tabPanel.getActiveTab() == this;
34391 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
34394 this.pnode.removeClass("active");
34396 this.fireEvent("deactivate", this.tabPanel, this);
34399 hideAction : function(){
34400 this.bodyEl.hide();
34401 this.bodyEl.setStyle("position", "absolute");
34402 this.bodyEl.setLeft("-20000px");
34403 this.bodyEl.setTop("-20000px");
34406 showAction : function(){
34407 this.bodyEl.setStyle("position", "relative");
34408 this.bodyEl.setTop("");
34409 this.bodyEl.setLeft("");
34410 this.bodyEl.show();
34414 * Set the tooltip for the tab.
34415 * @param {String} tooltip The tab's tooltip
34417 setTooltip : function(text){
34418 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
34419 this.textEl.dom.qtip = text;
34420 this.textEl.dom.removeAttribute('title');
34422 this.textEl.dom.title = text;
34426 onTabClick : function(e){
34427 e.preventDefault();
34428 this.tabPanel.activate(this.id);
34431 onTabMouseDown : function(e){
34432 e.preventDefault();
34433 this.tabPanel.activate(this.id);
34436 getWidth : function(){
34437 return this.inner.getWidth();
34440 setWidth : function(width){
34441 var iwidth = width - this.pnode.getPadding("lr");
34442 this.inner.setWidth(iwidth);
34443 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
34444 this.pnode.setWidth(width);
34448 * Show or hide the tab
34449 * @param {Boolean} hidden True to hide or false to show.
34451 setHidden : function(hidden){
34452 this.hidden = hidden;
34453 this.pnode.setStyle("display", hidden ? "none" : "");
34457 * Returns true if this tab is "hidden"
34458 * @return {Boolean}
34460 isHidden : function(){
34461 return this.hidden;
34465 * Returns the text for this tab
34468 getText : function(){
34472 autoSize : function(){
34473 //this.el.beginMeasure();
34474 this.textEl.setWidth(1);
34476 * #2804 [new] Tabs in Roojs
34477 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
34479 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
34480 //this.el.endMeasure();
34484 * Sets the text for the tab (Note: this also sets the tooltip text)
34485 * @param {String} text The tab's text and tooltip
34487 setText : function(text){
34489 this.textEl.update(text);
34490 this.setTooltip(text);
34491 //if(!this.tabPanel.resizeTabs){
34492 // this.autoSize();
34496 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
34498 activate : function(){
34499 this.tabPanel.activate(this.id);
34503 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
34505 disable : function(){
34506 if(this.tabPanel.active != this){
34507 this.disabled = true;
34508 this.pnode.addClass("disabled");
34513 * Enables this TabPanelItem if it was previously disabled.
34515 enable : function(){
34516 this.disabled = false;
34517 this.pnode.removeClass("disabled");
34521 * Sets the content for this TabPanelItem.
34522 * @param {String} content The content
34523 * @param {Boolean} loadScripts true to look for and load scripts
34525 setContent : function(content, loadScripts){
34526 this.bodyEl.update(content, loadScripts);
34530 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
34531 * @return {Roo.UpdateManager} The UpdateManager
34533 getUpdateManager : function(){
34534 return this.bodyEl.getUpdateManager();
34538 * Set a URL to be used to load the content for this TabPanelItem.
34539 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
34540 * @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)
34541 * @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)
34542 * @return {Roo.UpdateManager} The UpdateManager
34544 setUrl : function(url, params, loadOnce){
34545 if(this.refreshDelegate){
34546 this.un('activate', this.refreshDelegate);
34548 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34549 this.on("activate", this.refreshDelegate);
34550 return this.bodyEl.getUpdateManager();
34554 _handleRefresh : function(url, params, loadOnce){
34555 if(!loadOnce || !this.loaded){
34556 var updater = this.bodyEl.getUpdateManager();
34557 updater.update(url, params, this._setLoaded.createDelegate(this));
34562 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
34563 * Will fail silently if the setUrl method has not been called.
34564 * This does not activate the panel, just updates its content.
34566 refresh : function(){
34567 if(this.refreshDelegate){
34568 this.loaded = false;
34569 this.refreshDelegate();
34574 _setLoaded : function(){
34575 this.loaded = true;
34579 closeClick : function(e){
34582 this.fireEvent("beforeclose", this, o);
34583 if(o.cancel !== true){
34584 this.tabPanel.removeTab(this.id);
34588 * The text displayed in the tooltip for the close icon.
34591 closeText : "Close this tab"