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);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
394 Roo.bootstrap.Body.superclass.constructor.call(this, config);
395 this.el = Roo.get(document.body);
396 if (this.cls && this.cls.length) {
397 Roo.get(document.body).addClass(this.cls);
401 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
403 is_body : true,// just to make sure it's constructed?
408 onRender : function(ct, position)
410 /* Roo.log("Roo.bootstrap.Body - onRender");
411 if (this.cls && this.cls.length) {
412 Roo.get(document.body).addClass(this.cls);
432 * @class Roo.bootstrap.ButtonGroup
433 * @extends Roo.bootstrap.Component
434 * Bootstrap ButtonGroup class
435 * @cfg {String} size lg | sm | xs (default empty normal)
436 * @cfg {String} align vertical | justified (default none)
437 * @cfg {String} direction up | down (default down)
438 * @cfg {Boolean} toolbar false | true
439 * @cfg {Boolean} btn true | false
444 * @param {Object} config The config object
447 Roo.bootstrap.ButtonGroup = function(config){
448 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
451 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
459 getAutoCreate : function(){
465 cfg.html = this.html || cfg.html;
476 if (['vertical','justified'].indexOf(this.align)!==-1) {
477 cfg.cls = 'btn-group-' + this.align;
479 if (this.align == 'justified') {
480 console.log(this.items);
484 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
485 cfg.cls += ' btn-group-' + this.size;
488 if (this.direction == 'up') {
489 cfg.cls += ' dropup' ;
505 * @class Roo.bootstrap.Button
506 * @extends Roo.bootstrap.Component
507 * Bootstrap Button class
508 * @cfg {String} html The button content
509 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
510 * @cfg {String} size ( lg | sm | xs)
511 * @cfg {String} tag ( a | input | submit)
512 * @cfg {String} href empty or href
513 * @cfg {Boolean} disabled default false;
514 * @cfg {Boolean} isClose default false;
515 * @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)
516 * @cfg {String} badge text for badge
517 * @cfg {String} theme default
518 * @cfg {Boolean} inverse
519 * @cfg {Boolean} toggle
520 * @cfg {String} ontext text for on toggle state
521 * @cfg {String} offtext text for off toggle state
522 * @cfg {Boolean} defaulton
523 * @cfg {Boolean} preventDefault default true
524 * @cfg {Boolean} removeClass remove the standard class..
525 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
528 * Create a new button
529 * @param {Object} config The config object
533 Roo.bootstrap.Button = function(config){
534 Roo.bootstrap.Button.superclass.constructor.call(this, config);
539 * When a butotn is pressed
540 * @param {Roo.bootstrap.Button} this
541 * @param {Roo.EventObject} e
546 * After the button has been toggles
547 * @param {Roo.EventObject} e
548 * @param {boolean} pressed (also available as button.pressed)
554 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
572 preventDefault: true,
581 getAutoCreate : function(){
589 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
590 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
595 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
597 if (this.toggle == true) {
600 cls: 'slider-frame roo-button',
605 'data-off-text':'OFF',
606 cls: 'slider-button',
612 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
613 cfg.cls += ' '+this.weight;
622 cfg["aria-hidden"] = true;
624 cfg.html = "×";
630 if (this.theme==='default') {
631 cfg.cls = 'btn roo-button';
633 //if (this.parentType != 'Navbar') {
634 this.weight = this.weight.length ? this.weight : 'default';
636 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
638 cfg.cls += ' btn-' + this.weight;
640 } else if (this.theme==='glow') {
643 cfg.cls = 'btn-glow roo-button';
645 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
647 cfg.cls += ' ' + this.weight;
653 this.cls += ' inverse';
658 cfg.cls += ' active';
662 cfg.disabled = 'disabled';
666 Roo.log('changing to ul' );
668 this.glyphicon = 'caret';
671 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
673 //gsRoo.log(this.parentType);
674 if (this.parentType === 'Navbar' && !this.parent().bar) {
675 Roo.log('changing to li?');
684 href : this.href || '#'
687 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
688 cfg.cls += ' dropdown';
695 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
697 if (this.glyphicon) {
698 cfg.html = ' ' + cfg.html;
703 cls: 'glyphicon glyphicon-' + this.glyphicon
713 // cfg.cls='btn roo-button';
717 var value = cfg.html;
722 cls: 'glyphicon glyphicon-' + this.glyphicon,
741 cfg.cls += ' dropdown';
742 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
745 if (cfg.tag !== 'a' && this.href !== '') {
746 throw "Tag must be a to set href.";
747 } else if (this.href.length > 0) {
748 cfg.href = this.href;
751 if(this.removeClass){
756 cfg.target = this.target;
761 initEvents: function() {
762 // Roo.log('init events?');
763 // Roo.log(this.el.dom);
766 if (typeof (this.menu) != 'undefined') {
767 this.menu.parentType = this.xtype;
768 this.menu.triggerEl = this.el;
769 this.addxtype(Roo.apply({}, this.menu));
773 if (this.el.hasClass('roo-button')) {
774 this.el.on('click', this.onClick, this);
776 this.el.select('.roo-button').on('click', this.onClick, this);
779 if(this.removeClass){
780 this.el.on('click', this.onClick, this);
783 this.el.enableDisplayMode();
786 onClick : function(e)
793 Roo.log('button on click ');
794 if(this.preventDefault){
797 if (this.pressed === true || this.pressed === false) {
798 this.pressed = !this.pressed;
799 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
800 this.fireEvent('toggle', this, e, this.pressed);
804 this.fireEvent('click', this, e);
808 * Enables this button
812 this.disabled = false;
813 this.el.removeClass('disabled');
817 * Disable this button
821 this.disabled = true;
822 this.el.addClass('disabled');
825 * sets the active state on/off,
826 * @param {Boolean} state (optional) Force a particular state
828 setActive : function(v) {
830 this.el[v ? 'addClass' : 'removeClass']('active');
833 * toggles the current active state
835 toggleActive : function()
837 var active = this.el.hasClass('active');
838 this.setActive(!active);
842 setText : function(str)
844 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
848 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
871 * @class Roo.bootstrap.Column
872 * @extends Roo.bootstrap.Component
873 * Bootstrap Column class
874 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
875 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
876 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
877 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
878 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
879 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
880 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
881 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
884 * @cfg {Boolean} hidden (true|false) hide the element
885 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
886 * @cfg {String} fa (ban|check|...) font awesome icon
887 * @cfg {Number} fasize (1|2|....) font awsome size
889 * @cfg {String} icon (info-sign|check|...) glyphicon name
891 * @cfg {String} html content of column.
894 * Create a new Column
895 * @param {Object} config The config object
898 Roo.bootstrap.Column = function(config){
899 Roo.bootstrap.Column.superclass.constructor.call(this, config);
902 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
920 getAutoCreate : function(){
921 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
929 ['xs','sm','md','lg'].map(function(size){
930 //Roo.log( size + ':' + settings[size]);
932 if (settings[size+'off'] !== false) {
933 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
936 if (settings[size] === false) {
940 if (!settings[size]) { // 0 = hidden
941 cfg.cls += ' hidden-' + size;
944 cfg.cls += ' col-' + size + '-' + settings[size];
949 cfg.cls += ' hidden';
952 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
953 cfg.cls +=' alert alert-' + this.alert;
957 if (this.html.length) {
958 cfg.html = this.html;
962 if (this.fasize > 1) {
963 fasize = ' fa-' + this.fasize + 'x';
965 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
970 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
989 * @class Roo.bootstrap.Container
990 * @extends Roo.bootstrap.Component
991 * Bootstrap Container class
992 * @cfg {Boolean} jumbotron is it a jumbotron element
993 * @cfg {String} html content of element
994 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
995 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
996 * @cfg {String} header content of header (for panel)
997 * @cfg {String} footer content of footer (for panel)
998 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
999 * @cfg {String} tag (header|aside|section) type of HTML tag.
1000 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1001 * @cfg {String} fa font awesome icon
1002 * @cfg {String} icon (info-sign|check|...) glyphicon name
1003 * @cfg {Boolean} hidden (true|false) hide the element
1004 * @cfg {Boolean} expandable (true|false) default false
1005 * @cfg {Boolean} expanded (true|false) default true
1006 * @cfg {String} rheader contet on the right of header
1007 * @cfg {Boolean} clickable (true|false) default false
1011 * Create a new Container
1012 * @param {Object} config The config object
1015 Roo.bootstrap.Container = function(config){
1016 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1022 * After the panel has been expand
1024 * @param {Roo.bootstrap.Container} this
1029 * After the panel has been collapsed
1031 * @param {Roo.bootstrap.Container} this
1036 * When a element is chick
1037 * @param {Roo.bootstrap.Container} this
1038 * @param {Roo.EventObject} e
1044 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1062 getChildContainer : function() {
1068 if (this.panel.length) {
1069 return this.el.select('.panel-body',true).first();
1076 getAutoCreate : function(){
1079 tag : this.tag || 'div',
1083 if (this.jumbotron) {
1084 cfg.cls = 'jumbotron';
1089 // - this is applied by the parent..
1091 // cfg.cls = this.cls + '';
1094 if (this.sticky.length) {
1096 var bd = Roo.get(document.body);
1097 if (!bd.hasClass('bootstrap-sticky')) {
1098 bd.addClass('bootstrap-sticky');
1099 Roo.select('html',true).setStyle('height', '100%');
1102 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1106 if (this.well.length) {
1107 switch (this.well) {
1110 cfg.cls +=' well well-' +this.well;
1119 cfg.cls += ' hidden';
1123 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1124 cfg.cls +=' alert alert-' + this.alert;
1129 if (this.panel.length) {
1130 cfg.cls += ' panel panel-' + this.panel;
1132 if (this.header.length) {
1136 if(this.expandable){
1138 cfg.cls = cfg.cls + ' expandable';
1142 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1150 cls : 'panel-title',
1151 html : (this.expandable ? ' ' : '') + this.header
1155 cls: 'panel-header-right',
1161 cls : 'panel-heading',
1162 style : this.expandable ? 'cursor: pointer' : '',
1170 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1175 if (this.footer.length) {
1177 cls : 'panel-footer',
1186 body.html = this.html || cfg.html;
1187 // prefix with the icons..
1189 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1192 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1197 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1198 cfg.cls = 'container';
1204 initEvents: function()
1206 if(this.expandable){
1207 var headerEl = this.headerEl();
1210 headerEl.on('click', this.onToggleClick, this);
1215 this.el.on('click', this.onClick, this);
1220 onToggleClick : function()
1222 var headerEl = this.headerEl();
1238 if(this.fireEvent('expand', this)) {
1240 this.expanded = true;
1242 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1244 this.el.select('.panel-body',true).first().removeClass('hide');
1246 var toggleEl = this.toggleEl();
1252 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1257 collapse : function()
1259 if(this.fireEvent('collapse', this)) {
1261 this.expanded = false;
1263 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1264 this.el.select('.panel-body',true).first().addClass('hide');
1266 var toggleEl = this.toggleEl();
1272 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1276 toggleEl : function()
1278 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1282 return this.el.select('.panel-heading .fa',true).first();
1285 headerEl : function()
1287 if(!this.el || !this.panel.length || !this.header.length){
1291 return this.el.select('.panel-heading',true).first()
1294 titleEl : function()
1296 if(!this.el || !this.panel.length || !this.header.length){
1300 return this.el.select('.panel-title',true).first();
1303 setTitle : function(v)
1305 var titleEl = this.titleEl();
1311 titleEl.dom.innerHTML = v;
1314 getTitle : function()
1317 var titleEl = this.titleEl();
1323 return titleEl.dom.innerHTML;
1326 setRightTitle : function(v)
1328 var t = this.el.select('.panel-header-right',true).first();
1334 t.dom.innerHTML = v;
1337 onClick : function(e)
1341 this.fireEvent('click', this, e);
1355 * @class Roo.bootstrap.Img
1356 * @extends Roo.bootstrap.Component
1357 * Bootstrap Img class
1358 * @cfg {Boolean} imgResponsive false | true
1359 * @cfg {String} border rounded | circle | thumbnail
1360 * @cfg {String} src image source
1361 * @cfg {String} alt image alternative text
1362 * @cfg {String} href a tag href
1363 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1364 * @cfg {String} xsUrl xs image source
1365 * @cfg {String} smUrl sm image source
1366 * @cfg {String} mdUrl md image source
1367 * @cfg {String} lgUrl lg image source
1370 * Create a new Input
1371 * @param {Object} config The config object
1374 Roo.bootstrap.Img = function(config){
1375 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1381 * The img click event for the img.
1382 * @param {Roo.EventObject} e
1388 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1390 imgResponsive: true,
1400 getAutoCreate : function()
1402 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1403 return this.createSingleImg();
1408 cls: 'roo-image-responsive-group',
1413 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1415 if(!_this[size + 'Url']){
1421 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1422 html: _this.html || cfg.html,
1423 src: _this[size + 'Url']
1426 img.cls += ' roo-image-responsive-' + size;
1428 var s = ['xs', 'sm', 'md', 'lg'];
1430 s.splice(s.indexOf(size), 1);
1432 Roo.each(s, function(ss){
1433 img.cls += ' hidden-' + ss;
1436 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1437 cfg.cls += ' img-' + _this.border;
1441 cfg.alt = _this.alt;
1454 a.target = _this.target;
1458 cfg.cn.push((_this.href) ? a : img);
1465 createSingleImg : function()
1469 cls: (this.imgResponsive) ? 'img-responsive' : '',
1471 src : 'about:blank' // just incase src get's set to undefined?!?
1474 cfg.html = this.html || cfg.html;
1476 cfg.src = this.src || cfg.src;
1478 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1479 cfg.cls += ' img-' + this.border;
1496 a.target = this.target;
1501 return (this.href) ? a : cfg;
1504 initEvents: function()
1507 this.el.on('click', this.onClick, this);
1512 onClick : function(e)
1514 Roo.log('img onclick');
1515 this.fireEvent('click', this, e);
1529 * @class Roo.bootstrap.Link
1530 * @extends Roo.bootstrap.Component
1531 * Bootstrap Link Class
1532 * @cfg {String} alt image alternative text
1533 * @cfg {String} href a tag href
1534 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1535 * @cfg {String} html the content of the link.
1536 * @cfg {String} anchor name for the anchor link
1537 * @cfg {String} fa - favicon
1539 * @cfg {Boolean} preventDefault (true | false) default false
1543 * Create a new Input
1544 * @param {Object} config The config object
1547 Roo.bootstrap.Link = function(config){
1548 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1554 * The img click event for the img.
1555 * @param {Roo.EventObject} e
1561 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1565 preventDefault: false,
1571 getAutoCreate : function()
1573 var html = this.html || '';
1575 if (this.fa !== false) {
1576 html = '<i class="fa fa-' + this.fa + '"></i>';
1581 // anchor's do not require html/href...
1582 if (this.anchor === false) {
1584 cfg.href = this.href || '#';
1586 cfg.name = this.anchor;
1587 if (this.html !== false || this.fa !== false) {
1590 if (this.href !== false) {
1591 cfg.href = this.href;
1595 if(this.alt !== false){
1600 if(this.target !== false) {
1601 cfg.target = this.target;
1607 initEvents: function() {
1609 if(!this.href || this.preventDefault){
1610 this.el.on('click', this.onClick, this);
1614 onClick : function(e)
1616 if(this.preventDefault){
1619 //Roo.log('img onclick');
1620 this.fireEvent('click', this, e);
1633 * @class Roo.bootstrap.Header
1634 * @extends Roo.bootstrap.Component
1635 * Bootstrap Header class
1636 * @cfg {String} html content of header
1637 * @cfg {Number} level (1|2|3|4|5|6) default 1
1640 * Create a new Header
1641 * @param {Object} config The config object
1645 Roo.bootstrap.Header = function(config){
1646 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1649 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1657 getAutoCreate : function(){
1662 tag: 'h' + (1 *this.level),
1663 html: this.html || ''
1675 * Ext JS Library 1.1.1
1676 * Copyright(c) 2006-2007, Ext JS, LLC.
1678 * Originally Released Under LGPL - original licence link has changed is not relivant.
1681 * <script type="text/javascript">
1685 * @class Roo.bootstrap.MenuMgr
1686 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1689 Roo.bootstrap.MenuMgr = function(){
1690 var menus, active, groups = {}, attached = false, lastShow = new Date();
1692 // private - called when first menu is created
1695 active = new Roo.util.MixedCollection();
1696 Roo.get(document).addKeyListener(27, function(){
1697 if(active.length > 0){
1705 if(active && active.length > 0){
1706 var c = active.clone();
1716 if(active.length < 1){
1717 Roo.get(document).un("mouseup", onMouseDown);
1725 var last = active.last();
1726 lastShow = new Date();
1729 Roo.get(document).on("mouseup", onMouseDown);
1734 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1735 m.parentMenu.activeChild = m;
1736 }else if(last && last.isVisible()){
1737 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1742 function onBeforeHide(m){
1744 m.activeChild.hide();
1746 if(m.autoHideTimer){
1747 clearTimeout(m.autoHideTimer);
1748 delete m.autoHideTimer;
1753 function onBeforeShow(m){
1754 var pm = m.parentMenu;
1755 if(!pm && !m.allowOtherMenus){
1757 }else if(pm && pm.activeChild && active != m){
1758 pm.activeChild.hide();
1762 // private this should really trigger on mouseup..
1763 function onMouseDown(e){
1764 Roo.log("on Mouse Up");
1766 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1767 Roo.log("MenuManager hideAll");
1776 function onBeforeCheck(mi, state){
1778 var g = groups[mi.group];
1779 for(var i = 0, l = g.length; i < l; i++){
1781 g[i].setChecked(false);
1790 * Hides all menus that are currently visible
1792 hideAll : function(){
1797 register : function(menu){
1801 menus[menu.id] = menu;
1802 menu.on("beforehide", onBeforeHide);
1803 menu.on("hide", onHide);
1804 menu.on("beforeshow", onBeforeShow);
1805 menu.on("show", onShow);
1807 if(g && menu.events["checkchange"]){
1811 groups[g].push(menu);
1812 menu.on("checkchange", onCheck);
1817 * Returns a {@link Roo.menu.Menu} object
1818 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1819 * be used to generate and return a new Menu instance.
1821 get : function(menu){
1822 if(typeof menu == "string"){ // menu id
1824 }else if(menu.events){ // menu instance
1827 /*else if(typeof menu.length == 'number'){ // array of menu items?
1828 return new Roo.bootstrap.Menu({items:menu});
1829 }else{ // otherwise, must be a config
1830 return new Roo.bootstrap.Menu(menu);
1837 unregister : function(menu){
1838 delete menus[menu.id];
1839 menu.un("beforehide", onBeforeHide);
1840 menu.un("hide", onHide);
1841 menu.un("beforeshow", onBeforeShow);
1842 menu.un("show", onShow);
1844 if(g && menu.events["checkchange"]){
1845 groups[g].remove(menu);
1846 menu.un("checkchange", onCheck);
1851 registerCheckable : function(menuItem){
1852 var g = menuItem.group;
1857 groups[g].push(menuItem);
1858 menuItem.on("beforecheckchange", onBeforeCheck);
1863 unregisterCheckable : function(menuItem){
1864 var g = menuItem.group;
1866 groups[g].remove(menuItem);
1867 menuItem.un("beforecheckchange", onBeforeCheck);
1879 * @class Roo.bootstrap.Menu
1880 * @extends Roo.bootstrap.Component
1881 * Bootstrap Menu class - container for MenuItems
1882 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1883 * @cfg {bool} hidden if the menu should be hidden when rendered.
1884 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1885 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1889 * @param {Object} config The config object
1893 Roo.bootstrap.Menu = function(config){
1894 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1895 if (this.registerMenu && this.type != 'treeview') {
1896 Roo.bootstrap.MenuMgr.register(this);
1901 * Fires before this menu is displayed
1902 * @param {Roo.menu.Menu} this
1907 * Fires before this menu is hidden
1908 * @param {Roo.menu.Menu} this
1913 * Fires after this menu is displayed
1914 * @param {Roo.menu.Menu} this
1919 * Fires after this menu is hidden
1920 * @param {Roo.menu.Menu} this
1925 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1926 * @param {Roo.menu.Menu} this
1927 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1928 * @param {Roo.EventObject} e
1933 * Fires when the mouse is hovering over this menu
1934 * @param {Roo.menu.Menu} this
1935 * @param {Roo.EventObject} e
1936 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1941 * Fires when the mouse exits this menu
1942 * @param {Roo.menu.Menu} this
1943 * @param {Roo.EventObject} e
1944 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1949 * Fires when a menu item contained in this menu is clicked
1950 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1951 * @param {Roo.EventObject} e
1955 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1958 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1962 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1965 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1967 registerMenu : true,
1969 menuItems :false, // stores the menu items..
1979 getChildContainer : function() {
1983 getAutoCreate : function(){
1985 //if (['right'].indexOf(this.align)!==-1) {
1986 // cfg.cn[1].cls += ' pull-right'
1992 cls : 'dropdown-menu' ,
1993 style : 'z-index:1000'
1997 if (this.type === 'submenu') {
1998 cfg.cls = 'submenu active';
2000 if (this.type === 'treeview') {
2001 cfg.cls = 'treeview-menu';
2006 initEvents : function() {
2008 // Roo.log("ADD event");
2009 // Roo.log(this.triggerEl.dom);
2011 this.triggerEl.on('click', this.onTriggerClick, this);
2013 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2015 this.triggerEl.addClass('dropdown-toggle');
2018 this.el.on('touchstart' , this.onTouch, this);
2020 this.el.on('click' , this.onClick, this);
2022 this.el.on("mouseover", this.onMouseOver, this);
2023 this.el.on("mouseout", this.onMouseOut, this);
2027 findTargetItem : function(e)
2029 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2033 //Roo.log(t); Roo.log(t.id);
2035 //Roo.log(this.menuitems);
2036 return this.menuitems.get(t.id);
2038 //return this.items.get(t.menuItemId);
2044 onTouch : function(e)
2046 Roo.log("menu.onTouch");
2047 //e.stopEvent(); this make the user popdown broken
2051 onClick : function(e)
2053 Roo.log("menu.onClick");
2055 var t = this.findTargetItem(e);
2056 if(!t || t.isContainer){
2061 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2062 if(t == this.activeItem && t.shouldDeactivate(e)){
2063 this.activeItem.deactivate();
2064 delete this.activeItem;
2068 this.setActiveItem(t, true);
2076 Roo.log('pass click event');
2080 this.fireEvent("click", this, t, e);
2084 (function() { _this.hide(); }).defer(500);
2087 onMouseOver : function(e){
2088 var t = this.findTargetItem(e);
2091 // if(t.canActivate && !t.disabled){
2092 // this.setActiveItem(t, true);
2096 this.fireEvent("mouseover", this, e, t);
2098 isVisible : function(){
2099 return !this.hidden;
2101 onMouseOut : function(e){
2102 var t = this.findTargetItem(e);
2105 // if(t == this.activeItem && t.shouldDeactivate(e)){
2106 // this.activeItem.deactivate();
2107 // delete this.activeItem;
2110 this.fireEvent("mouseout", this, e, t);
2115 * Displays this menu relative to another element
2116 * @param {String/HTMLElement/Roo.Element} element The element to align to
2117 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2118 * the element (defaults to this.defaultAlign)
2119 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2121 show : function(el, pos, parentMenu){
2122 this.parentMenu = parentMenu;
2126 this.fireEvent("beforeshow", this);
2127 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2130 * Displays this menu at a specific xy position
2131 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2132 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2134 showAt : function(xy, parentMenu, /* private: */_e){
2135 this.parentMenu = parentMenu;
2140 this.fireEvent("beforeshow", this);
2141 //xy = this.el.adjustForConstraints(xy);
2145 this.hideMenuItems();
2146 this.hidden = false;
2147 this.triggerEl.addClass('open');
2149 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2150 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2153 if(this.el.getStyle('top').slice(-1) != "%"){
2158 this.fireEvent("show", this);
2164 this.doFocus.defer(50, this);
2168 doFocus : function(){
2170 this.focusEl.focus();
2175 * Hides this menu and optionally all parent menus
2176 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2178 hide : function(deep)
2181 this.hideMenuItems();
2182 if(this.el && this.isVisible()){
2183 this.fireEvent("beforehide", this);
2184 if(this.activeItem){
2185 this.activeItem.deactivate();
2186 this.activeItem = null;
2188 this.triggerEl.removeClass('open');;
2190 this.fireEvent("hide", this);
2192 if(deep === true && this.parentMenu){
2193 this.parentMenu.hide(true);
2197 onTriggerClick : function(e)
2199 Roo.log('trigger click');
2201 var target = e.getTarget();
2203 Roo.log(target.nodeName.toLowerCase());
2205 if(target.nodeName.toLowerCase() === 'i'){
2211 onTriggerPress : function(e)
2213 Roo.log('trigger press');
2214 //Roo.log(e.getTarget());
2215 // Roo.log(this.triggerEl.dom);
2217 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2218 var pel = Roo.get(e.getTarget());
2219 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2220 Roo.log('is treeview or dropdown?');
2224 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2228 if (this.isVisible()) {
2233 this.show(this.triggerEl, false, false);
2236 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2243 hideMenuItems : function()
2245 Roo.log("hide Menu Items");
2249 //$(backdrop).remove()
2250 this.el.select('.open',true).each(function(aa) {
2252 aa.removeClass('open');
2253 //var parent = getParent($(this))
2254 //var relatedTarget = { relatedTarget: this }
2256 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2257 //if (e.isDefaultPrevented()) return
2258 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2261 addxtypeChild : function (tree, cntr) {
2262 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2264 this.menuitems.add(comp);
2285 * @class Roo.bootstrap.MenuItem
2286 * @extends Roo.bootstrap.Component
2287 * Bootstrap MenuItem class
2288 * @cfg {String} html the menu label
2289 * @cfg {String} href the link
2290 * @cfg {Boolean} preventDefault do not trigger A href on clicks.
2291 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2292 * @cfg {Boolean} active used on sidebars to highlight active itesm
2293 * @cfg {String} fa favicon to show on left of menu item.
2294 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2298 * Create a new MenuItem
2299 * @param {Object} config The config object
2303 Roo.bootstrap.MenuItem = function(config){
2304 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2309 * The raw click event for the entire grid.
2310 * @param {Roo.bootstrap.MenuItem} this
2311 * @param {Roo.EventObject} e
2317 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2321 preventDefault: true,
2322 isContainer : false,
2326 getAutoCreate : function(){
2328 if(this.isContainer){
2331 cls: 'dropdown-menu-item'
2345 if (this.fa !== false) {
2348 cls : 'fa fa-' + this.fa
2357 cls: 'dropdown-menu-item',
2360 if (this.parent().type == 'treeview') {
2361 cfg.cls = 'treeview-menu';
2364 cfg.cls += ' active';
2369 anc.href = this.href || cfg.cn[0].href ;
2370 ctag.html = this.html || cfg.cn[0].html ;
2374 initEvents: function()
2376 if (this.parent().type == 'treeview') {
2377 this.el.select('a').on('click', this.onClick, this);
2380 this.menu.parentType = this.xtype;
2381 this.menu.triggerEl = this.el;
2382 this.menu = this.addxtype(Roo.apply({}, this.menu));
2386 onClick : function(e)
2388 Roo.log('item on click ');
2389 //if(this.preventDefault){
2390 // e.preventDefault();
2392 //this.parent().hideMenuItems();
2394 this.fireEvent('click', this, e);
2413 * @class Roo.bootstrap.MenuSeparator
2414 * @extends Roo.bootstrap.Component
2415 * Bootstrap MenuSeparator class
2418 * Create a new MenuItem
2419 * @param {Object} config The config object
2423 Roo.bootstrap.MenuSeparator = function(config){
2424 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2427 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2429 getAutoCreate : function(){
2448 * @class Roo.bootstrap.Modal
2449 * @extends Roo.bootstrap.Component
2450 * Bootstrap Modal class
2451 * @cfg {String} title Title of dialog
2452 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2453 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2454 * @cfg {Boolean} specificTitle default false
2455 * @cfg {Array} buttons Array of buttons or standard button set..
2456 * @cfg {String} buttonPosition (left|right|center) default right
2457 * @cfg {Boolean} animate default true
2458 * @cfg {Boolean} allow_close default true
2461 * Create a new Modal Dialog
2462 * @param {Object} config The config object
2465 Roo.bootstrap.Modal = function(config){
2466 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2471 * The raw btnclick event for the button
2472 * @param {Roo.EventObject} e
2476 this.buttons = this.buttons || [];
2479 this.tmpl = Roo.factory(this.tmpl);
2484 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2486 title : 'test dialog',
2496 specificTitle: false,
2498 buttonPosition: 'right',
2512 onRender : function(ct, position)
2514 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2517 var cfg = Roo.apply({}, this.getAutoCreate());
2520 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2522 //if (!cfg.name.length) {
2526 cfg.cls += ' ' + this.cls;
2529 cfg.style = this.style;
2531 this.el = Roo.get(document.body).createChild(cfg, position);
2533 //var type = this.el.dom.type;
2536 if(this.tabIndex !== undefined){
2537 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2541 this.bodyEl = this.el.select('.modal-body',true).first();
2542 this.closeEl = this.el.select('.modal-header .close', true).first();
2543 this.footerEl = this.el.select('.modal-footer',true).first();
2544 this.titleEl = this.el.select('.modal-title',true).first();
2548 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2549 this.maskEl.enableDisplayMode("block");
2551 //this.el.addClass("x-dlg-modal");
2553 if (this.buttons.length) {
2554 Roo.each(this.buttons, function(bb) {
2555 var b = Roo.apply({}, bb);
2556 b.xns = b.xns || Roo.bootstrap;
2557 b.xtype = b.xtype || 'Button';
2558 if (typeof(b.listeners) == 'undefined') {
2559 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2562 var btn = Roo.factory(b);
2564 btn.render(this.el.select('.modal-footer div').first());
2568 // render the children.
2571 if(typeof(this.items) != 'undefined'){
2572 var items = this.items;
2575 for(var i =0;i < items.length;i++) {
2576 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2580 this.items = nitems;
2582 // where are these used - they used to be body/close/footer
2586 //this.el.addClass([this.fieldClass, this.cls]);
2590 getAutoCreate : function(){
2595 html : this.html || ''
2600 cls : 'modal-title',
2604 if(this.specificTitle){
2610 if (this.allow_close) {
2621 style : 'display: none',
2624 cls: "modal-dialog",
2627 cls : "modal-content",
2630 cls : 'modal-header',
2635 cls : 'modal-footer',
2639 cls: 'btn-' + this.buttonPosition
2656 modal.cls += ' fade';
2662 getChildContainer : function() {
2667 getButtonContainer : function() {
2668 return this.el.select('.modal-footer div',true).first();
2671 initEvents : function()
2673 if (this.allow_close) {
2674 this.closeEl.on('click', this.hide, this);
2679 window.addEventListener("resize", function() { _this.resize(); } );
2685 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2690 if (!this.rendered) {
2694 this.el.setStyle('display', 'block');
2696 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2699 this.el.addClass('in');
2702 this.el.addClass('in');
2706 // not sure how we can show data in here..
2708 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2711 Roo.get(document.body).addClass("x-body-masked");
2712 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2714 this.el.setStyle('zIndex', '10001');
2716 this.fireEvent('show', this);
2724 Roo.get(document.body).removeClass("x-body-masked");
2725 this.el.removeClass('in');
2726 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2728 if(this.animate){ // why
2730 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2732 this.el.setStyle('display', 'none');
2735 this.fireEvent('hide', this);
2738 addButton : function(str, cb)
2742 var b = Roo.apply({}, { html : str } );
2743 b.xns = b.xns || Roo.bootstrap;
2744 b.xtype = b.xtype || 'Button';
2745 if (typeof(b.listeners) == 'undefined') {
2746 b.listeners = { click : cb.createDelegate(this) };
2749 var btn = Roo.factory(b);
2751 btn.render(this.el.select('.modal-footer div').first());
2757 setDefaultButton : function(btn)
2759 //this.el.select('.modal-footer').()
2763 resizeTo: function(w,h)
2767 this.el.select('.modal-dialog',true).first().setWidth(w);
2768 if (this.diff === false) {
2769 this.diff = this.el.select('.modal-dialog',true).first().getHeight() - this.el.select('.modal-body',true).first().getHeight();
2772 this.el.select('.modal-body',true).first().setHeight(h-this.diff);
2776 setContentSize : function(w, h)
2780 onButtonClick: function(btn,e)
2783 this.fireEvent('btnclick', btn.name, e);
2786 * Set the title of the Dialog
2787 * @param {String} str new Title
2789 setTitle: function(str) {
2790 this.titleEl.dom.innerHTML = str;
2793 * Set the body of the Dialog
2794 * @param {String} str new Title
2796 setBody: function(str) {
2797 this.bodyEl.dom.innerHTML = str;
2800 * Set the body of the Dialog using the template
2801 * @param {Obj} data - apply this data to the template and replace the body contents.
2803 applyBody: function(obj)
2806 Roo.log("Error - using apply Body without a template");
2809 this.tmpl.overwrite(this.bodyEl, obj);
2815 Roo.apply(Roo.bootstrap.Modal, {
2817 * Button config that displays a single OK button
2826 * Button config that displays Yes and No buttons
2842 * Button config that displays OK and Cancel buttons
2857 * Button config that displays Yes, No and Cancel buttons
2880 * messagebox - can be used as a replace
2884 * @class Roo.MessageBox
2885 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2889 Roo.Msg.alert('Status', 'Changes saved successfully.');
2891 // Prompt for user data:
2892 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2894 // process text value...
2898 // Show a dialog using config options:
2900 title:'Save Changes?',
2901 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2902 buttons: Roo.Msg.YESNOCANCEL,
2909 Roo.bootstrap.MessageBox = function(){
2910 var dlg, opt, mask, waitTimer;
2911 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2912 var buttons, activeTextEl, bwidth;
2916 var handleButton = function(button){
2918 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2922 var handleHide = function(){
2924 dlg.el.removeClass(opt.cls);
2927 // Roo.TaskMgr.stop(waitTimer);
2928 // waitTimer = null;
2933 var updateButtons = function(b){
2936 buttons["ok"].hide();
2937 buttons["cancel"].hide();
2938 buttons["yes"].hide();
2939 buttons["no"].hide();
2940 //dlg.footer.dom.style.display = 'none';
2943 dlg.footerEl.dom.style.display = '';
2944 for(var k in buttons){
2945 if(typeof buttons[k] != "function"){
2948 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2949 width += buttons[k].el.getWidth()+15;
2959 var handleEsc = function(d, k, e){
2960 if(opt && opt.closable !== false){
2970 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2971 * @return {Roo.BasicDialog} The BasicDialog element
2973 getDialog : function(){
2975 dlg = new Roo.bootstrap.Modal( {
2978 //constraintoviewport:false,
2980 //collapsible : false,
2985 //buttonAlign:"center",
2986 closeClick : function(){
2987 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2990 handleButton("cancel");
2995 dlg.on("hide", handleHide);
2997 //dlg.addKeyListener(27, handleEsc);
2999 this.buttons = buttons;
3000 var bt = this.buttonText;
3001 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3002 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3003 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3004 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3006 bodyEl = dlg.bodyEl.createChild({
3008 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3009 '<textarea class="roo-mb-textarea"></textarea>' +
3010 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3012 msgEl = bodyEl.dom.firstChild;
3013 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3014 textboxEl.enableDisplayMode();
3015 textboxEl.addKeyListener([10,13], function(){
3016 if(dlg.isVisible() && opt && opt.buttons){
3019 }else if(opt.buttons.yes){
3020 handleButton("yes");
3024 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3025 textareaEl.enableDisplayMode();
3026 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3027 progressEl.enableDisplayMode();
3028 var pf = progressEl.dom.firstChild;
3030 pp = Roo.get(pf.firstChild);
3031 pp.setHeight(pf.offsetHeight);
3039 * Updates the message box body text
3040 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3041 * the XHTML-compliant non-breaking space character '&#160;')
3042 * @return {Roo.MessageBox} This message box
3044 updateText : function(text){
3045 if(!dlg.isVisible() && !opt.width){
3046 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3048 msgEl.innerHTML = text || ' ';
3050 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3051 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3053 Math.min(opt.width || cw , this.maxWidth),
3054 Math.max(opt.minWidth || this.minWidth, bwidth)
3057 activeTextEl.setWidth(w);
3059 if(dlg.isVisible()){
3060 dlg.fixedcenter = false;
3062 // to big, make it scroll. = But as usual stupid IE does not support
3065 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3066 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3067 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3069 bodyEl.dom.style.height = '';
3070 bodyEl.dom.style.overflowY = '';
3073 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3075 bodyEl.dom.style.overflowX = '';
3078 dlg.setContentSize(w, bodyEl.getHeight());
3079 if(dlg.isVisible()){
3080 dlg.fixedcenter = true;
3086 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3087 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3088 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3089 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3090 * @return {Roo.MessageBox} This message box
3092 updateProgress : function(value, text){
3094 this.updateText(text);
3096 if (pp) { // weird bug on my firefox - for some reason this is not defined
3097 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3103 * Returns true if the message box is currently displayed
3104 * @return {Boolean} True if the message box is visible, else false
3106 isVisible : function(){
3107 return dlg && dlg.isVisible();
3111 * Hides the message box if it is displayed
3114 if(this.isVisible()){
3120 * Displays a new message box, or reinitializes an existing message box, based on the config options
3121 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3122 * The following config object properties are supported:
3124 Property Type Description
3125 ---------- --------------- ------------------------------------------------------------------------------------
3126 animEl String/Element An id or Element from which the message box should animate as it opens and
3127 closes (defaults to undefined)
3128 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3129 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3130 closable Boolean False to hide the top-right close button (defaults to true). Note that
3131 progress and wait dialogs will ignore this property and always hide the
3132 close button as they can only be closed programmatically.
3133 cls String A custom CSS class to apply to the message box element
3134 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3135 displayed (defaults to 75)
3136 fn Function A callback function to execute after closing the dialog. The arguments to the
3137 function will be btn (the name of the button that was clicked, if applicable,
3138 e.g. "ok"), and text (the value of the active text field, if applicable).
3139 Progress and wait dialogs will ignore this option since they do not respond to
3140 user actions and can only be closed programmatically, so any required function
3141 should be called by the same code after it closes the dialog.
3142 icon String A CSS class that provides a background image to be used as an icon for
3143 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3144 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3145 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3146 modal Boolean False to allow user interaction with the page while the message box is
3147 displayed (defaults to true)
3148 msg String A string that will replace the existing message box body text (defaults
3149 to the XHTML-compliant non-breaking space character ' ')
3150 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3151 progress Boolean True to display a progress bar (defaults to false)
3152 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3153 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3154 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3155 title String The title text
3156 value String The string value to set into the active textbox element if displayed
3157 wait Boolean True to display a progress bar (defaults to false)
3158 width Number The width of the dialog in pixels
3165 msg: 'Please enter your address:',
3167 buttons: Roo.MessageBox.OKCANCEL,
3170 animEl: 'addAddressBtn'
3173 * @param {Object} config Configuration options
3174 * @return {Roo.MessageBox} This message box
3176 show : function(options)
3179 // this causes nightmares if you show one dialog after another
3180 // especially on callbacks..
3182 if(this.isVisible()){
3185 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3186 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3187 Roo.log("New Dialog Message:" + options.msg )
3188 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3189 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3192 var d = this.getDialog();
3194 d.setTitle(opt.title || " ");
3195 d.closeEl.setDisplayed(opt.closable !== false);
3196 activeTextEl = textboxEl;
3197 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3202 textareaEl.setHeight(typeof opt.multiline == "number" ?
3203 opt.multiline : this.defaultTextHeight);
3204 activeTextEl = textareaEl;
3213 progressEl.setDisplayed(opt.progress === true);
3214 this.updateProgress(0);
3215 activeTextEl.dom.value = opt.value || "";
3217 dlg.setDefaultButton(activeTextEl);
3219 var bs = opt.buttons;
3223 }else if(bs && bs.yes){
3224 db = buttons["yes"];
3226 dlg.setDefaultButton(db);
3228 bwidth = updateButtons(opt.buttons);
3229 this.updateText(opt.msg);
3231 d.el.addClass(opt.cls);
3233 d.proxyDrag = opt.proxyDrag === true;
3234 d.modal = opt.modal !== false;
3235 d.mask = opt.modal !== false ? mask : false;
3237 // force it to the end of the z-index stack so it gets a cursor in FF
3238 document.body.appendChild(dlg.el.dom);
3239 d.animateTarget = null;
3240 d.show(options.animEl);
3246 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3247 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3248 * and closing the message box when the process is complete.
3249 * @param {String} title The title bar text
3250 * @param {String} msg The message box body text
3251 * @return {Roo.MessageBox} This message box
3253 progress : function(title, msg){
3260 minWidth: this.minProgressWidth,
3267 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3268 * If a callback function is passed it will be called after the user clicks the button, and the
3269 * id of the button that was clicked will be passed as the only parameter to the callback
3270 * (could also be the top-right close button).
3271 * @param {String} title The title bar text
3272 * @param {String} msg The message box body text
3273 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3274 * @param {Object} scope (optional) The scope of the callback function
3275 * @return {Roo.MessageBox} This message box
3277 alert : function(title, msg, fn, scope){
3290 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3291 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3292 * You are responsible for closing the message box when the process is complete.
3293 * @param {String} msg The message box body text
3294 * @param {String} title (optional) The title bar text
3295 * @return {Roo.MessageBox} This message box
3297 wait : function(msg, title){
3308 waitTimer = Roo.TaskMgr.start({
3310 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3318 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3319 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3320 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3321 * @param {String} title The title bar text
3322 * @param {String} msg The message box body text
3323 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3324 * @param {Object} scope (optional) The scope of the callback function
3325 * @return {Roo.MessageBox} This message box
3327 confirm : function(title, msg, fn, scope){
3331 buttons: this.YESNO,
3340 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3341 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3342 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3343 * (could also be the top-right close button) and the text that was entered will be passed as the two
3344 * parameters to the callback.
3345 * @param {String} title The title bar text
3346 * @param {String} msg The message box body text
3347 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3348 * @param {Object} scope (optional) The scope of the callback function
3349 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3350 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3351 * @return {Roo.MessageBox} This message box
3353 prompt : function(title, msg, fn, scope, multiline){
3357 buttons: this.OKCANCEL,
3362 multiline: multiline,
3369 * Button config that displays a single OK button
3374 * Button config that displays Yes and No buttons
3377 YESNO : {yes:true, no:true},
3379 * Button config that displays OK and Cancel buttons
3382 OKCANCEL : {ok:true, cancel:true},
3384 * Button config that displays Yes, No and Cancel buttons
3387 YESNOCANCEL : {yes:true, no:true, cancel:true},
3390 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3393 defaultTextHeight : 75,
3395 * The maximum width in pixels of the message box (defaults to 600)
3400 * The minimum width in pixels of the message box (defaults to 100)
3405 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3406 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3409 minProgressWidth : 250,
3411 * An object containing the default button text strings that can be overriden for localized language support.
3412 * Supported properties are: ok, cancel, yes and no.
3413 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3426 * Shorthand for {@link Roo.MessageBox}
3428 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3429 Roo.Msg = Roo.Msg || Roo.MessageBox;
3438 * @class Roo.bootstrap.Navbar
3439 * @extends Roo.bootstrap.Component
3440 * Bootstrap Navbar class
3443 * Create a new Navbar
3444 * @param {Object} config The config object
3448 Roo.bootstrap.Navbar = function(config){
3449 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3453 * @event beforetoggle
3454 * Fire before toggle the menu
3455 * @param {Roo.EventObject} e
3457 "beforetoggle" : true
3461 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3470 getAutoCreate : function(){
3473 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3477 initEvents :function ()
3479 //Roo.log(this.el.select('.navbar-toggle',true));
3480 this.el.select('.navbar-toggle',true).on('click', function() {
3481 if(this.fireEvent('beforetoggle', this) !== false){
3482 this.el.select('.navbar-collapse',true).toggleClass('in');
3492 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3494 var size = this.el.getSize();
3495 this.maskEl.setSize(size.width, size.height);
3496 this.maskEl.enableDisplayMode("block");
3505 getChildContainer : function()
3507 if (this.el.select('.collapse').getCount()) {
3508 return this.el.select('.collapse',true).first();
3541 * @class Roo.bootstrap.NavSimplebar
3542 * @extends Roo.bootstrap.Navbar
3543 * Bootstrap Sidebar class
3545 * @cfg {Boolean} inverse is inverted color
3547 * @cfg {String} type (nav | pills | tabs)
3548 * @cfg {Boolean} arrangement stacked | justified
3549 * @cfg {String} align (left | right) alignment
3551 * @cfg {Boolean} main (true|false) main nav bar? default false
3552 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3554 * @cfg {String} tag (header|footer|nav|div) default is nav
3560 * Create a new Sidebar
3561 * @param {Object} config The config object
3565 Roo.bootstrap.NavSimplebar = function(config){
3566 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3569 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3585 getAutoCreate : function(){
3589 tag : this.tag || 'div',
3602 this.type = this.type || 'nav';
3603 if (['tabs','pills'].indexOf(this.type)!==-1) {
3604 cfg.cn[0].cls += ' nav-' + this.type
3608 if (this.type!=='nav') {
3609 Roo.log('nav type must be nav/tabs/pills')
3611 cfg.cn[0].cls += ' navbar-nav'
3617 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3618 cfg.cn[0].cls += ' nav-' + this.arrangement;
3622 if (this.align === 'right') {
3623 cfg.cn[0].cls += ' navbar-right';
3627 cfg.cls += ' navbar-inverse';
3654 * @class Roo.bootstrap.NavHeaderbar
3655 * @extends Roo.bootstrap.NavSimplebar
3656 * Bootstrap Sidebar class
3658 * @cfg {String} brand what is brand
3659 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3660 * @cfg {String} brand_href href of the brand
3661 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3662 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3663 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3664 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3667 * Create a new Sidebar
3668 * @param {Object} config The config object
3672 Roo.bootstrap.NavHeaderbar = function(config){
3673 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3677 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3684 desktopCenter : false,
3687 getAutoCreate : function(){
3690 tag: this.nav || 'nav',
3697 if (this.desktopCenter) {
3698 cn.push({cls : 'container', cn : []});
3705 cls: 'navbar-header',
3710 cls: 'navbar-toggle',
3711 'data-toggle': 'collapse',
3716 html: 'Toggle navigation'
3738 cls: 'collapse navbar-collapse',
3742 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3744 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3745 cfg.cls += ' navbar-' + this.position;
3747 // tag can override this..
3749 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3752 if (this.brand !== '') {
3755 href: this.brand_href ? this.brand_href : '#',
3756 cls: 'navbar-brand',
3764 cfg.cls += ' main-nav';
3772 getHeaderChildContainer : function()
3774 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3775 return this.el.select('.navbar-header',true).first();
3778 return this.getChildContainer();
3782 initEvents : function()
3784 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3786 if (this.autohide) {
3791 Roo.get(document).on('scroll',function(e) {
3792 var ns = Roo.get(document).getScroll().top;
3793 var os = prevScroll;
3797 ft.removeClass('slideDown');
3798 ft.addClass('slideUp');
3801 ft.removeClass('slideUp');
3802 ft.addClass('slideDown');
3823 * @class Roo.bootstrap.NavSidebar
3824 * @extends Roo.bootstrap.Navbar
3825 * Bootstrap Sidebar class
3828 * Create a new Sidebar
3829 * @param {Object} config The config object
3833 Roo.bootstrap.NavSidebar = function(config){
3834 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3837 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3839 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3841 getAutoCreate : function(){
3846 cls: 'sidebar sidebar-nav'
3868 * @class Roo.bootstrap.NavGroup
3869 * @extends Roo.bootstrap.Component
3870 * Bootstrap NavGroup class
3871 * @cfg {String} align (left|right)
3872 * @cfg {Boolean} inverse
3873 * @cfg {String} type (nav|pills|tab) default nav
3874 * @cfg {String} navId - reference Id for navbar.
3878 * Create a new nav group
3879 * @param {Object} config The config object
3882 Roo.bootstrap.NavGroup = function(config){
3883 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3886 Roo.bootstrap.NavGroup.register(this);
3890 * Fires when the active item changes
3891 * @param {Roo.bootstrap.NavGroup} this
3892 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3893 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3900 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3911 getAutoCreate : function()
3913 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3920 if (['tabs','pills'].indexOf(this.type)!==-1) {
3921 cfg.cls += ' nav-' + this.type
3923 if (this.type!=='nav') {
3924 Roo.log('nav type must be nav/tabs/pills')
3926 cfg.cls += ' navbar-nav'
3929 if (this.parent().sidebar) {
3932 cls: 'dashboard-menu sidebar-menu'
3938 if (this.form === true) {
3944 if (this.align === 'right') {
3945 cfg.cls += ' navbar-right';
3947 cfg.cls += ' navbar-left';
3951 if (this.align === 'right') {
3952 cfg.cls += ' navbar-right';
3956 cfg.cls += ' navbar-inverse';
3964 * sets the active Navigation item
3965 * @param {Roo.bootstrap.NavItem} the new current navitem
3967 setActiveItem : function(item)
3970 Roo.each(this.navItems, function(v){
3975 v.setActive(false, true);
3982 item.setActive(true, true);
3983 this.fireEvent('changed', this, item, prev);
3988 * gets the active Navigation item
3989 * @return {Roo.bootstrap.NavItem} the current navitem
3991 getActive : function()
3995 Roo.each(this.navItems, function(v){
4006 indexOfNav : function()
4010 Roo.each(this.navItems, function(v,i){
4021 * adds a Navigation item
4022 * @param {Roo.bootstrap.NavItem} the navitem to add
4024 addItem : function(cfg)
4026 var cn = new Roo.bootstrap.NavItem(cfg);
4028 cn.parentId = this.id;
4029 cn.onRender(this.el, null);
4033 * register a Navigation item
4034 * @param {Roo.bootstrap.NavItem} the navitem to add
4036 register : function(item)
4038 this.navItems.push( item);
4039 item.navId = this.navId;
4044 * clear all the Navigation item
4047 clearAll : function()
4050 this.el.dom.innerHTML = '';
4053 getNavItem: function(tabId)
4056 Roo.each(this.navItems, function(e) {
4057 if (e.tabId == tabId) {
4067 setActiveNext : function()
4069 var i = this.indexOfNav(this.getActive());
4070 if (i > this.navItems.length) {
4073 this.setActiveItem(this.navItems[i+1]);
4075 setActivePrev : function()
4077 var i = this.indexOfNav(this.getActive());
4081 this.setActiveItem(this.navItems[i-1]);
4083 clearWasActive : function(except) {
4084 Roo.each(this.navItems, function(e) {
4085 if (e.tabId != except.tabId && e.was_active) {
4086 e.was_active = false;
4093 getWasActive : function ()
4096 Roo.each(this.navItems, function(e) {
4111 Roo.apply(Roo.bootstrap.NavGroup, {
4115 * register a Navigation Group
4116 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4118 register : function(navgrp)
4120 this.groups[navgrp.navId] = navgrp;
4124 * fetch a Navigation Group based on the navigation ID
4125 * @param {string} the navgroup to add
4126 * @returns {Roo.bootstrap.NavGroup} the navgroup
4128 get: function(navId) {
4129 if (typeof(this.groups[navId]) == 'undefined') {
4131 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4133 return this.groups[navId] ;
4148 * @class Roo.bootstrap.NavItem
4149 * @extends Roo.bootstrap.Component
4150 * Bootstrap Navbar.NavItem class
4151 * @cfg {String} href link to
4152 * @cfg {String} html content of button
4153 * @cfg {String} badge text inside badge
4154 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4155 * @cfg {String} glyphicon name of glyphicon
4156 * @cfg {String} icon name of font awesome icon
4157 * @cfg {Boolean} active Is item active
4158 * @cfg {Boolean} disabled Is item disabled
4160 * @cfg {Boolean} preventDefault (true | false) default false
4161 * @cfg {String} tabId the tab that this item activates.
4162 * @cfg {String} tagtype (a|span) render as a href or span?
4163 * @cfg {Boolean} animateRef (true|false) link to element default false
4166 * Create a new Navbar Item
4167 * @param {Object} config The config object
4169 Roo.bootstrap.NavItem = function(config){
4170 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4175 * The raw click event for the entire grid.
4176 * @param {Roo.EventObject} e
4181 * Fires when the active item active state changes
4182 * @param {Roo.bootstrap.NavItem} this
4183 * @param {boolean} state the new state
4189 * Fires when scroll to element
4190 * @param {Roo.bootstrap.NavItem} this
4191 * @param {Object} options
4192 * @param {Roo.EventObject} e
4200 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4208 preventDefault : false,
4215 getAutoCreate : function(){
4224 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4226 if (this.disabled) {
4227 cfg.cls += ' disabled';
4230 if (this.href || this.html || this.glyphicon || this.icon) {
4234 href : this.href || "#",
4235 html: this.html || ''
4240 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4243 if(this.glyphicon) {
4244 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4249 cfg.cn[0].html += " <span class='caret'></span>";
4253 if (this.badge !== '') {
4255 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4263 initEvents: function()
4265 if (typeof (this.menu) != 'undefined') {
4266 this.menu.parentType = this.xtype;
4267 this.menu.triggerEl = this.el;
4268 this.menu = this.addxtype(Roo.apply({}, this.menu));
4271 this.el.select('a',true).on('click', this.onClick, this);
4273 if(this.tagtype == 'span'){
4274 this.el.select('span',true).on('click', this.onClick, this);
4277 // at this point parent should be available..
4278 this.parent().register(this);
4281 onClick : function(e)
4283 if (e.getTarget('.dropdown-menu-item')) {
4284 // did you click on a menu itemm.... - then don't trigger onclick..
4289 this.preventDefault ||
4292 Roo.log("NavItem - prevent Default?");
4296 if (this.disabled) {
4300 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4301 if (tg && tg.transition) {
4302 Roo.log("waiting for the transitionend");
4308 //Roo.log("fire event clicked");
4309 if(this.fireEvent('click', this, e) === false){
4313 if(this.tagtype == 'span'){
4317 //Roo.log(this.href);
4318 var ael = this.el.select('a',true).first();
4321 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4322 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4323 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4324 return; // ignore... - it's a 'hash' to another page.
4326 Roo.log("NavItem - prevent Default?");
4328 this.scrollToElement(e);
4332 var p = this.parent();
4334 if (['tabs','pills'].indexOf(p.type)!==-1) {
4335 if (typeof(p.setActiveItem) !== 'undefined') {
4336 p.setActiveItem(this);
4340 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4341 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4342 // remove the collapsed menu expand...
4343 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4347 isActive: function () {
4350 setActive : function(state, fire, is_was_active)
4352 if (this.active && !state && this.navId) {
4353 this.was_active = true;
4354 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4356 nv.clearWasActive(this);
4360 this.active = state;
4363 this.el.removeClass('active');
4364 } else if (!this.el.hasClass('active')) {
4365 this.el.addClass('active');
4368 this.fireEvent('changed', this, state);
4371 // show a panel if it's registered and related..
4373 if (!this.navId || !this.tabId || !state || is_was_active) {
4377 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4381 var pan = tg.getPanelByName(this.tabId);
4385 // if we can not flip to new panel - go back to old nav highlight..
4386 if (false == tg.showPanel(pan)) {
4387 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4389 var onav = nv.getWasActive();
4391 onav.setActive(true, false, true);
4400 // this should not be here...
4401 setDisabled : function(state)
4403 this.disabled = state;
4405 this.el.removeClass('disabled');
4406 } else if (!this.el.hasClass('disabled')) {
4407 this.el.addClass('disabled');
4413 * Fetch the element to display the tooltip on.
4414 * @return {Roo.Element} defaults to this.el
4416 tooltipEl : function()
4418 return this.el.select('' + this.tagtype + '', true).first();
4421 scrollToElement : function(e)
4423 var c = document.body;
4426 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4428 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4429 c = document.documentElement;
4432 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4438 var o = target.calcOffsetsTo(c);
4445 this.fireEvent('scrollto', this, options, e);
4447 Roo.get(c).scrollTo('top', options.value, true);
4460 * <span> icon </span>
4461 * <span> text </span>
4462 * <span>badge </span>
4466 * @class Roo.bootstrap.NavSidebarItem
4467 * @extends Roo.bootstrap.NavItem
4468 * Bootstrap Navbar.NavSidebarItem class
4469 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4470 * {bool} open is the menu open
4472 * Create a new Navbar Button
4473 * @param {Object} config The config object
4475 Roo.bootstrap.NavSidebarItem = function(config){
4476 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4481 * The raw click event for the entire grid.
4482 * @param {Roo.EventObject} e
4487 * Fires when the active item active state changes
4488 * @param {Roo.bootstrap.NavSidebarItem} this
4489 * @param {boolean} state the new state
4497 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4499 badgeWeight : 'default',
4503 getAutoCreate : function(){
4508 href : this.href || '#',
4520 html : this.html || ''
4525 cfg.cls += ' active';
4528 if (this.disabled) {
4529 cfg.cls += ' disabled';
4532 cfg.cls += ' open x-open';
4535 if (this.glyphicon || this.icon) {
4536 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4537 a.cn.push({ tag : 'i', cls : c }) ;
4542 if (this.badge !== '') {
4544 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4548 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4549 a.cls += 'dropdown-toggle treeview' ;
4557 initEvents : function()
4559 if (typeof (this.menu) != 'undefined') {
4560 this.menu.parentType = this.xtype;
4561 this.menu.triggerEl = this.el;
4562 this.menu = this.addxtype(Roo.apply({}, this.menu));
4565 this.el.on('click', this.onClick, this);
4568 if(this.badge !== ''){
4570 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4575 onClick : function(e)
4582 if(this.preventDefault){
4586 this.fireEvent('click', this);
4589 disable : function()
4591 this.setDisabled(true);
4596 this.setDisabled(false);
4599 setDisabled : function(state)
4601 if(this.disabled == state){
4605 this.disabled = state;
4608 this.el.addClass('disabled');
4612 this.el.removeClass('disabled');
4617 setActive : function(state)
4619 if(this.active == state){
4623 this.active = state;
4626 this.el.addClass('active');
4630 this.el.removeClass('active');
4635 isActive: function ()
4640 setBadge : function(str)
4646 this.badgeEl.dom.innerHTML = str;
4663 * @class Roo.bootstrap.Row
4664 * @extends Roo.bootstrap.Component
4665 * Bootstrap Row class (contains columns...)
4669 * @param {Object} config The config object
4672 Roo.bootstrap.Row = function(config){
4673 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4676 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4678 getAutoCreate : function(){
4697 * @class Roo.bootstrap.Element
4698 * @extends Roo.bootstrap.Component
4699 * Bootstrap Element class
4700 * @cfg {String} html contents of the element
4701 * @cfg {String} tag tag of the element
4702 * @cfg {String} cls class of the element
4703 * @cfg {Boolean} preventDefault (true|false) default false
4704 * @cfg {Boolean} clickable (true|false) default false
4707 * Create a new Element
4708 * @param {Object} config The config object
4711 Roo.bootstrap.Element = function(config){
4712 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4718 * When a element is chick
4719 * @param {Roo.bootstrap.Element} this
4720 * @param {Roo.EventObject} e
4726 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4731 preventDefault: false,
4734 getAutoCreate : function(){
4745 initEvents: function()
4747 Roo.bootstrap.Element.superclass.initEvents.call(this);
4750 this.el.on('click', this.onClick, this);
4755 onClick : function(e)
4757 if(this.preventDefault){
4761 this.fireEvent('click', this, e);
4764 getValue : function()
4766 return this.el.dom.innerHTML;
4769 setValue : function(value)
4771 this.el.dom.innerHTML = value;
4786 * @class Roo.bootstrap.Pagination
4787 * @extends Roo.bootstrap.Component
4788 * Bootstrap Pagination class
4789 * @cfg {String} size xs | sm | md | lg
4790 * @cfg {Boolean} inverse false | true
4793 * Create a new Pagination
4794 * @param {Object} config The config object
4797 Roo.bootstrap.Pagination = function(config){
4798 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4801 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4807 getAutoCreate : function(){
4813 cfg.cls += ' inverse';
4819 cfg.cls += " " + this.cls;
4837 * @class Roo.bootstrap.PaginationItem
4838 * @extends Roo.bootstrap.Component
4839 * Bootstrap PaginationItem class
4840 * @cfg {String} html text
4841 * @cfg {String} href the link
4842 * @cfg {Boolean} preventDefault (true | false) default true
4843 * @cfg {Boolean} active (true | false) default false
4844 * @cfg {Boolean} disabled default false
4848 * Create a new PaginationItem
4849 * @param {Object} config The config object
4853 Roo.bootstrap.PaginationItem = function(config){
4854 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4859 * The raw click event for the entire grid.
4860 * @param {Roo.EventObject} e
4866 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4870 preventDefault: true,
4875 getAutoCreate : function(){
4881 href : this.href ? this.href : '#',
4882 html : this.html ? this.html : ''
4892 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4896 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4902 initEvents: function() {
4904 this.el.on('click', this.onClick, this);
4907 onClick : function(e)
4909 Roo.log('PaginationItem on click ');
4910 if(this.preventDefault){
4918 this.fireEvent('click', this, e);
4934 * @class Roo.bootstrap.Slider
4935 * @extends Roo.bootstrap.Component
4936 * Bootstrap Slider class
4939 * Create a new Slider
4940 * @param {Object} config The config object
4943 Roo.bootstrap.Slider = function(config){
4944 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4947 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4949 getAutoCreate : function(){
4953 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4957 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4969 * Ext JS Library 1.1.1
4970 * Copyright(c) 2006-2007, Ext JS, LLC.
4972 * Originally Released Under LGPL - original licence link has changed is not relivant.
4975 * <script type="text/javascript">
4980 * @class Roo.grid.ColumnModel
4981 * @extends Roo.util.Observable
4982 * This is the default implementation of a ColumnModel used by the Grid. It defines
4983 * the columns in the grid.
4986 var colModel = new Roo.grid.ColumnModel([
4987 {header: "Ticker", width: 60, sortable: true, locked: true},
4988 {header: "Company Name", width: 150, sortable: true},
4989 {header: "Market Cap.", width: 100, sortable: true},
4990 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4991 {header: "Employees", width: 100, sortable: true, resizable: false}
4996 * The config options listed for this class are options which may appear in each
4997 * individual column definition.
4998 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5000 * @param {Object} config An Array of column config objects. See this class's
5001 * config objects for details.
5003 Roo.grid.ColumnModel = function(config){
5005 * The config passed into the constructor
5007 this.config = config;
5010 // if no id, create one
5011 // if the column does not have a dataIndex mapping,
5012 // map it to the order it is in the config
5013 for(var i = 0, len = config.length; i < len; i++){
5015 if(typeof c.dataIndex == "undefined"){
5018 if(typeof c.renderer == "string"){
5019 c.renderer = Roo.util.Format[c.renderer];
5021 if(typeof c.id == "undefined"){
5024 if(c.editor && c.editor.xtype){
5025 c.editor = Roo.factory(c.editor, Roo.grid);
5027 if(c.editor && c.editor.isFormField){
5028 c.editor = new Roo.grid.GridEditor(c.editor);
5030 this.lookup[c.id] = c;
5034 * The width of columns which have no width specified (defaults to 100)
5037 this.defaultWidth = 100;
5040 * Default sortable of columns which have no sortable specified (defaults to false)
5043 this.defaultSortable = false;
5047 * @event widthchange
5048 * Fires when the width of a column changes.
5049 * @param {ColumnModel} this
5050 * @param {Number} columnIndex The column index
5051 * @param {Number} newWidth The new width
5053 "widthchange": true,
5055 * @event headerchange
5056 * Fires when the text of a header changes.
5057 * @param {ColumnModel} this
5058 * @param {Number} columnIndex The column index
5059 * @param {Number} newText The new header text
5061 "headerchange": true,
5063 * @event hiddenchange
5064 * Fires when a column is hidden or "unhidden".
5065 * @param {ColumnModel} this
5066 * @param {Number} columnIndex The column index
5067 * @param {Boolean} hidden true if hidden, false otherwise
5069 "hiddenchange": true,
5071 * @event columnmoved
5072 * Fires when a column is moved.
5073 * @param {ColumnModel} this
5074 * @param {Number} oldIndex
5075 * @param {Number} newIndex
5077 "columnmoved" : true,
5079 * @event columlockchange
5080 * Fires when a column's locked state is changed
5081 * @param {ColumnModel} this
5082 * @param {Number} colIndex
5083 * @param {Boolean} locked true if locked
5085 "columnlockchange" : true
5087 Roo.grid.ColumnModel.superclass.constructor.call(this);
5089 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5091 * @cfg {String} header The header text to display in the Grid view.
5094 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5095 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5096 * specified, the column's index is used as an index into the Record's data Array.
5099 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5100 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5103 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5104 * Defaults to the value of the {@link #defaultSortable} property.
5105 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5108 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5111 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5114 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5117 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5120 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5121 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5122 * default renderer uses the raw data value. If an object is returned (bootstrap only)
5123 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5126 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5129 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5132 * @cfg {String} cursor (Optional)
5135 * @cfg {String} tooltip (Optional)
5138 * @cfg {Number} xs (Optional)
5141 * @cfg {Number} sm (Optional)
5144 * @cfg {Number} md (Optional)
5147 * @cfg {Number} lg (Optional)
5150 * Returns the id of the column at the specified index.
5151 * @param {Number} index The column index
5152 * @return {String} the id
5154 getColumnId : function(index){
5155 return this.config[index].id;
5159 * Returns the column for a specified id.
5160 * @param {String} id The column id
5161 * @return {Object} the column
5163 getColumnById : function(id){
5164 return this.lookup[id];
5169 * Returns the column for a specified dataIndex.
5170 * @param {String} dataIndex The column dataIndex
5171 * @return {Object|Boolean} the column or false if not found
5173 getColumnByDataIndex: function(dataIndex){
5174 var index = this.findColumnIndex(dataIndex);
5175 return index > -1 ? this.config[index] : false;
5179 * Returns the index for a specified column id.
5180 * @param {String} id The column id
5181 * @return {Number} the index, or -1 if not found
5183 getIndexById : function(id){
5184 for(var i = 0, len = this.config.length; i < len; i++){
5185 if(this.config[i].id == id){
5193 * Returns the index for a specified column dataIndex.
5194 * @param {String} dataIndex The column dataIndex
5195 * @return {Number} the index, or -1 if not found
5198 findColumnIndex : function(dataIndex){
5199 for(var i = 0, len = this.config.length; i < len; i++){
5200 if(this.config[i].dataIndex == dataIndex){
5208 moveColumn : function(oldIndex, newIndex){
5209 var c = this.config[oldIndex];
5210 this.config.splice(oldIndex, 1);
5211 this.config.splice(newIndex, 0, c);
5212 this.dataMap = null;
5213 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5216 isLocked : function(colIndex){
5217 return this.config[colIndex].locked === true;
5220 setLocked : function(colIndex, value, suppressEvent){
5221 if(this.isLocked(colIndex) == value){
5224 this.config[colIndex].locked = value;
5226 this.fireEvent("columnlockchange", this, colIndex, value);
5230 getTotalLockedWidth : function(){
5232 for(var i = 0; i < this.config.length; i++){
5233 if(this.isLocked(i) && !this.isHidden(i)){
5234 this.totalWidth += this.getColumnWidth(i);
5240 getLockedCount : function(){
5241 for(var i = 0, len = this.config.length; i < len; i++){
5242 if(!this.isLocked(i)){
5247 return this.config.length;
5251 * Returns the number of columns.
5254 getColumnCount : function(visibleOnly){
5255 if(visibleOnly === true){
5257 for(var i = 0, len = this.config.length; i < len; i++){
5258 if(!this.isHidden(i)){
5264 return this.config.length;
5268 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5269 * @param {Function} fn
5270 * @param {Object} scope (optional)
5271 * @return {Array} result
5273 getColumnsBy : function(fn, scope){
5275 for(var i = 0, len = this.config.length; i < len; i++){
5276 var c = this.config[i];
5277 if(fn.call(scope||this, c, i) === true){
5285 * Returns true if the specified column is sortable.
5286 * @param {Number} col The column index
5289 isSortable : function(col){
5290 if(typeof this.config[col].sortable == "undefined"){
5291 return this.defaultSortable;
5293 return this.config[col].sortable;
5297 * Returns the rendering (formatting) function defined for the column.
5298 * @param {Number} col The column index.
5299 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5301 getRenderer : function(col){
5302 if(!this.config[col].renderer){
5303 return Roo.grid.ColumnModel.defaultRenderer;
5305 return this.config[col].renderer;
5309 * Sets the rendering (formatting) function for a column.
5310 * @param {Number} col The column index
5311 * @param {Function} fn The function to use to process the cell's raw data
5312 * to return HTML markup for the grid view. The render function is called with
5313 * the following parameters:<ul>
5314 * <li>Data value.</li>
5315 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5316 * <li>css A CSS style string to apply to the table cell.</li>
5317 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5318 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5319 * <li>Row index</li>
5320 * <li>Column index</li>
5321 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5323 setRenderer : function(col, fn){
5324 this.config[col].renderer = fn;
5328 * Returns the width for the specified column.
5329 * @param {Number} col The column index
5332 getColumnWidth : function(col){
5333 return this.config[col].width * 1 || this.defaultWidth;
5337 * Sets the width for a column.
5338 * @param {Number} col The column index
5339 * @param {Number} width The new width
5341 setColumnWidth : function(col, width, suppressEvent){
5342 this.config[col].width = width;
5343 this.totalWidth = null;
5345 this.fireEvent("widthchange", this, col, width);
5350 * Returns the total width of all columns.
5351 * @param {Boolean} includeHidden True to include hidden column widths
5354 getTotalWidth : function(includeHidden){
5355 if(!this.totalWidth){
5356 this.totalWidth = 0;
5357 for(var i = 0, len = this.config.length; i < len; i++){
5358 if(includeHidden || !this.isHidden(i)){
5359 this.totalWidth += this.getColumnWidth(i);
5363 return this.totalWidth;
5367 * Returns the header for the specified column.
5368 * @param {Number} col The column index
5371 getColumnHeader : function(col){
5372 return this.config[col].header;
5376 * Sets the header for a column.
5377 * @param {Number} col The column index
5378 * @param {String} header The new header
5380 setColumnHeader : function(col, header){
5381 this.config[col].header = header;
5382 this.fireEvent("headerchange", this, col, header);
5386 * Returns the tooltip for the specified column.
5387 * @param {Number} col The column index
5390 getColumnTooltip : function(col){
5391 return this.config[col].tooltip;
5394 * Sets the tooltip for a column.
5395 * @param {Number} col The column index
5396 * @param {String} tooltip The new tooltip
5398 setColumnTooltip : function(col, tooltip){
5399 this.config[col].tooltip = tooltip;
5403 * Returns the dataIndex for the specified column.
5404 * @param {Number} col The column index
5407 getDataIndex : function(col){
5408 return this.config[col].dataIndex;
5412 * Sets the dataIndex for a column.
5413 * @param {Number} col The column index
5414 * @param {Number} dataIndex The new dataIndex
5416 setDataIndex : function(col, dataIndex){
5417 this.config[col].dataIndex = dataIndex;
5423 * Returns true if the cell is editable.
5424 * @param {Number} colIndex The column index
5425 * @param {Number} rowIndex The row index - this is nto actually used..?
5428 isCellEditable : function(colIndex, rowIndex){
5429 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5433 * Returns the editor defined for the cell/column.
5434 * return false or null to disable editing.
5435 * @param {Number} colIndex The column index
5436 * @param {Number} rowIndex The row index
5439 getCellEditor : function(colIndex, rowIndex){
5440 return this.config[colIndex].editor;
5444 * Sets if a column is editable.
5445 * @param {Number} col The column index
5446 * @param {Boolean} editable True if the column is editable
5448 setEditable : function(col, editable){
5449 this.config[col].editable = editable;
5454 * Returns true if the column is hidden.
5455 * @param {Number} colIndex The column index
5458 isHidden : function(colIndex){
5459 return this.config[colIndex].hidden;
5464 * Returns true if the column width cannot be changed
5466 isFixed : function(colIndex){
5467 return this.config[colIndex].fixed;
5471 * Returns true if the column can be resized
5474 isResizable : function(colIndex){
5475 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5478 * Sets if a column is hidden.
5479 * @param {Number} colIndex The column index
5480 * @param {Boolean} hidden True if the column is hidden
5482 setHidden : function(colIndex, hidden){
5483 this.config[colIndex].hidden = hidden;
5484 this.totalWidth = null;
5485 this.fireEvent("hiddenchange", this, colIndex, hidden);
5489 * Sets the editor for a column.
5490 * @param {Number} col The column index
5491 * @param {Object} editor The editor object
5493 setEditor : function(col, editor){
5494 this.config[col].editor = editor;
5498 Roo.grid.ColumnModel.defaultRenderer = function(value){
5499 if(typeof value == "string" && value.length < 1){
5505 // Alias for backwards compatibility
5506 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5509 * Ext JS Library 1.1.1
5510 * Copyright(c) 2006-2007, Ext JS, LLC.
5512 * Originally Released Under LGPL - original licence link has changed is not relivant.
5515 * <script type="text/javascript">
5519 * @class Roo.LoadMask
5520 * A simple utility class for generically masking elements while loading data. If the element being masked has
5521 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5522 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5523 * element's UpdateManager load indicator and will be destroyed after the initial load.
5525 * Create a new LoadMask
5526 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5527 * @param {Object} config The config object
5529 Roo.LoadMask = function(el, config){
5530 this.el = Roo.get(el);
5531 Roo.apply(this, config);
5533 this.store.on('beforeload', this.onBeforeLoad, this);
5534 this.store.on('load', this.onLoad, this);
5535 this.store.on('loadexception', this.onLoadException, this);
5536 this.removeMask = false;
5538 var um = this.el.getUpdateManager();
5539 um.showLoadIndicator = false; // disable the default indicator
5540 um.on('beforeupdate', this.onBeforeLoad, this);
5541 um.on('update', this.onLoad, this);
5542 um.on('failure', this.onLoad, this);
5543 this.removeMask = true;
5547 Roo.LoadMask.prototype = {
5549 * @cfg {Boolean} removeMask
5550 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5551 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5555 * The text to display in a centered loading message box (defaults to 'Loading...')
5559 * @cfg {String} msgCls
5560 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5562 msgCls : 'x-mask-loading',
5565 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5571 * Disables the mask to prevent it from being displayed
5573 disable : function(){
5574 this.disabled = true;
5578 * Enables the mask so that it can be displayed
5580 enable : function(){
5581 this.disabled = false;
5584 onLoadException : function()
5588 if (typeof(arguments[3]) != 'undefined') {
5589 Roo.MessageBox.alert("Error loading",arguments[3]);
5593 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5594 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5603 this.el.unmask(this.removeMask);
5608 this.el.unmask(this.removeMask);
5612 onBeforeLoad : function(){
5614 this.el.mask(this.msg, this.msgCls);
5619 destroy : function(){
5621 this.store.un('beforeload', this.onBeforeLoad, this);
5622 this.store.un('load', this.onLoad, this);
5623 this.store.un('loadexception', this.onLoadException, this);
5625 var um = this.el.getUpdateManager();
5626 um.un('beforeupdate', this.onBeforeLoad, this);
5627 um.un('update', this.onLoad, this);
5628 um.un('failure', this.onLoad, this);
5639 * @class Roo.bootstrap.Table
5640 * @extends Roo.bootstrap.Component
5641 * Bootstrap Table class
5642 * @cfg {String} cls table class
5643 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5644 * @cfg {String} bgcolor Specifies the background color for a table
5645 * @cfg {Number} border Specifies whether the table cells should have borders or not
5646 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5647 * @cfg {Number} cellspacing Specifies the space between cells
5648 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5649 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5650 * @cfg {String} sortable Specifies that the table should be sortable
5651 * @cfg {String} summary Specifies a summary of the content of a table
5652 * @cfg {Number} width Specifies the width of a table
5653 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5655 * @cfg {boolean} striped Should the rows be alternative striped
5656 * @cfg {boolean} bordered Add borders to the table
5657 * @cfg {boolean} hover Add hover highlighting
5658 * @cfg {boolean} condensed Format condensed
5659 * @cfg {boolean} responsive Format condensed
5660 * @cfg {Boolean} loadMask (true|false) default false
5661 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5662 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5663 * @cfg {Boolean} rowSelection (true|false) default false
5664 * @cfg {Boolean} cellSelection (true|false) default false
5665 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5666 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5670 * Create a new Table
5671 * @param {Object} config The config object
5674 Roo.bootstrap.Table = function(config){
5675 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5677 if (config.container) {
5678 // ctor'ed from a Border/panel.grid
5679 this.container = Roo.get(config.container);
5680 this.container.update("");
5681 this.container.setStyle("overflow", "hidden");
5682 this.container.addClass('x-grid-container');
5687 this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
5688 this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
5689 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5690 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5694 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5695 this.sm = this.selModel;
5696 this.sm.xmodule = this.xmodule || false;
5698 if (this.cm && typeof(this.cm.config) == 'undefined') {
5699 this.colModel = new Roo.grid.ColumnModel(this.cm);
5700 this.cm = this.colModel;
5701 this.cm.xmodule = this.xmodule || false;
5704 this.store= Roo.factory(this.store, Roo.data);
5705 this.ds = this.store;
5706 this.ds.xmodule = this.xmodule || false;
5709 if (this.footer && this.store) {
5710 this.footer.dataSource = this.ds;
5711 this.footer = Roo.factory(this.footer);
5718 * Fires when a cell is clicked
5719 * @param {Roo.bootstrap.Table} this
5720 * @param {Roo.Element} el
5721 * @param {Number} rowIndex
5722 * @param {Number} columnIndex
5723 * @param {Roo.EventObject} e
5727 * @event celldblclick
5728 * Fires when a cell is double clicked
5729 * @param {Roo.bootstrap.Table} this
5730 * @param {Roo.Element} el
5731 * @param {Number} rowIndex
5732 * @param {Number} columnIndex
5733 * @param {Roo.EventObject} e
5735 "celldblclick" : true,
5738 * Fires when a row is clicked
5739 * @param {Roo.bootstrap.Table} this
5740 * @param {Roo.Element} el
5741 * @param {Number} rowIndex
5742 * @param {Roo.EventObject} e
5746 * @event rowdblclick
5747 * Fires when a row is double clicked
5748 * @param {Roo.bootstrap.Table} this
5749 * @param {Roo.Element} el
5750 * @param {Number} rowIndex
5751 * @param {Roo.EventObject} e
5753 "rowdblclick" : true,
5756 * Fires when a mouseover occur
5757 * @param {Roo.bootstrap.Table} this
5758 * @param {Roo.Element} el
5759 * @param {Number} rowIndex
5760 * @param {Number} columnIndex
5761 * @param {Roo.EventObject} e
5766 * Fires when a mouseout occur
5767 * @param {Roo.bootstrap.Table} this
5768 * @param {Roo.Element} el
5769 * @param {Number} rowIndex
5770 * @param {Number} columnIndex
5771 * @param {Roo.EventObject} e
5776 * Fires when a row is rendered, so you can change add a style to it.
5777 * @param {Roo.bootstrap.Table} this
5778 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5782 * @event rowsrendered
5783 * Fires when all the rows have been rendered
5784 * @param {Roo.bootstrap.Table} this
5786 'rowsrendered' : true,
5788 * @event contextmenu
5789 * The raw contextmenu event for the entire grid.
5790 * @param {Roo.EventObject} e
5792 "contextmenu" : true,
5794 * @event rowcontextmenu
5795 * Fires when a row is right clicked
5796 * @param {Roo.bootstrap.Table} this
5797 * @param {Number} rowIndex
5798 * @param {Roo.EventObject} e
5800 "rowcontextmenu" : true,
5802 * @event cellcontextmenu
5803 * Fires when a cell is right clicked
5804 * @param {Roo.bootstrap.Table} this
5805 * @param {Number} rowIndex
5806 * @param {Number} cellIndex
5807 * @param {Roo.EventObject} e
5809 "cellcontextmenu" : true,
5811 * @event headercontextmenu
5812 * Fires when a header is right clicked
5813 * @param {Roo.bootstrap.Table} this
5814 * @param {Number} columnIndex
5815 * @param {Roo.EventObject} e
5817 "headercontextmenu" : true
5821 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5847 rowSelection : false,
5848 cellSelection : false,
5851 // Roo.Element - the tbody
5853 // Roo.Element - thead element
5856 container: false, // used by gridpanel...
5858 getAutoCreate : function()
5860 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5867 if (this.scrollBody) {
5868 cfg.cls += ' table-body-fixed';
5871 cfg.cls += ' table-striped';
5875 cfg.cls += ' table-hover';
5877 if (this.bordered) {
5878 cfg.cls += ' table-bordered';
5880 if (this.condensed) {
5881 cfg.cls += ' table-condensed';
5883 if (this.responsive) {
5884 cfg.cls += ' table-responsive';
5888 cfg.cls+= ' ' +this.cls;
5891 // this lot should be simplifed...
5894 cfg.align=this.align;
5897 cfg.bgcolor=this.bgcolor;
5900 cfg.border=this.border;
5902 if (this.cellpadding) {
5903 cfg.cellpadding=this.cellpadding;
5905 if (this.cellspacing) {
5906 cfg.cellspacing=this.cellspacing;
5909 cfg.frame=this.frame;
5912 cfg.rules=this.rules;
5914 if (this.sortable) {
5915 cfg.sortable=this.sortable;
5918 cfg.summary=this.summary;
5921 cfg.width=this.width;
5924 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5927 if(this.store || this.cm){
5928 if(this.headerShow){
5929 cfg.cn.push(this.renderHeader());
5932 cfg.cn.push(this.renderBody());
5934 if(this.footerShow){
5935 cfg.cn.push(this.renderFooter());
5937 // where does this come from?
5938 //cfg.cls+= ' TableGrid';
5941 return { cn : [ cfg ] };
5944 initEvents : function()
5946 if(!this.store || !this.cm){
5950 //Roo.log('initEvents with ds!!!!');
5952 this.mainBody = this.el.select('tbody', true).first();
5953 this.mainHead = this.el.select('thead', true).first();
5959 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5960 e.on('click', _this.sort, _this);
5963 this.el.on("click", this.onClick, this);
5964 this.el.on("dblclick", this.onDblClick, this);
5966 // why is this done????? = it breaks dialogs??
5967 //this.parent().el.setStyle('position', 'relative');
5971 this.footer.parentId = this.id;
5972 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5975 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5977 this.store.on('load', this.onLoad, this);
5978 this.store.on('beforeload', this.onBeforeLoad, this);
5979 this.store.on('update', this.onUpdate, this);
5980 this.store.on('add', this.onAdd, this);
5982 this.el.on("contextmenu", this.onContextMenu, this);
5984 this.mainBody.on('scroll', this.onBodyScroll, this);
5989 onContextMenu : function(e, t)
5991 this.processEvent("contextmenu", e);
5994 processEvent : function(name, e)
5996 if (name != 'touchstart' ) {
5997 this.fireEvent(name, e);
6000 var t = e.getTarget();
6002 var cell = Roo.get(t);
6008 if(cell.findParent('tfoot', false, true)){
6012 if(cell.findParent('thead', false, true)){
6014 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6015 cell = Roo.get(t).findParent('th', false, true);
6017 Roo.log("failed to find th in thead?");
6018 Roo.log(e.getTarget());
6023 var cellIndex = cell.dom.cellIndex;
6025 var ename = name == 'touchstart' ? 'click' : name;
6026 this.fireEvent("header" + ename, this, cellIndex, e);
6031 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6032 cell = Roo.get(t).findParent('td', false, true);
6034 Roo.log("failed to find th in tbody?");
6035 Roo.log(e.getTarget());
6040 var row = cell.findParent('tr', false, true);
6041 var cellIndex = cell.dom.cellIndex;
6042 var rowIndex = row.dom.rowIndex - 1;
6046 this.fireEvent("row" + name, this, rowIndex, e);
6050 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6056 onMouseover : function(e, el)
6058 var cell = Roo.get(el);
6064 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6065 cell = cell.findParent('td', false, true);
6068 var row = cell.findParent('tr', false, true);
6069 var cellIndex = cell.dom.cellIndex;
6070 var rowIndex = row.dom.rowIndex - 1; // start from 0
6072 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6076 onMouseout : function(e, el)
6078 var cell = Roo.get(el);
6084 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6085 cell = cell.findParent('td', false, true);
6088 var row = cell.findParent('tr', false, true);
6089 var cellIndex = cell.dom.cellIndex;
6090 var rowIndex = row.dom.rowIndex - 1; // start from 0
6092 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6096 onClick : function(e, el)
6098 var cell = Roo.get(el);
6100 if(!cell || (!this.cellSelection && !this.rowSelection)){
6104 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6105 cell = cell.findParent('td', false, true);
6108 if(!cell || typeof(cell) == 'undefined'){
6112 var row = cell.findParent('tr', false, true);
6114 if(!row || typeof(row) == 'undefined'){
6118 var cellIndex = cell.dom.cellIndex;
6119 var rowIndex = this.getRowIndex(row);
6121 // why??? - should these not be based on SelectionModel?
6122 if(this.cellSelection){
6123 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6126 if(this.rowSelection){
6127 this.fireEvent('rowclick', this, row, rowIndex, e);
6133 onDblClick : function(e,el)
6135 var cell = Roo.get(el);
6137 if(!cell || (!this.CellSelection && !this.RowSelection)){
6141 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6142 cell = cell.findParent('td', false, true);
6145 if(!cell || typeof(cell) == 'undefined'){
6149 var row = cell.findParent('tr', false, true);
6151 if(!row || typeof(row) == 'undefined'){
6155 var cellIndex = cell.dom.cellIndex;
6156 var rowIndex = this.getRowIndex(row);
6158 if(this.CellSelection){
6159 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6162 if(this.RowSelection){
6163 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6167 sort : function(e,el)
6169 var col = Roo.get(el);
6171 if(!col.hasClass('sortable')){
6175 var sort = col.attr('sort');
6178 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6182 this.store.sortInfo = {field : sort, direction : dir};
6185 Roo.log("calling footer first");
6186 this.footer.onClick('first');
6189 this.store.load({ params : { start : 0 } });
6193 renderHeader : function()
6201 this.totalWidth = 0;
6203 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6205 var config = cm.config[i];
6210 html: cm.getColumnHeader(i)
6215 if(typeof(config.sortable) != 'undefined' && config.sortable){
6217 c.html = '<i class="glyphicon"></i>' + c.html;
6220 if(typeof(config.lgHeader) != 'undefined'){
6221 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6224 if(typeof(config.mdHeader) != 'undefined'){
6225 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6228 if(typeof(config.smHeader) != 'undefined'){
6229 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6232 if(typeof(config.xsHeader) != 'undefined'){
6233 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6240 if(typeof(config.tooltip) != 'undefined'){
6241 c.tooltip = config.tooltip;
6244 if(typeof(config.colspan) != 'undefined'){
6245 c.colspan = config.colspan;
6248 if(typeof(config.hidden) != 'undefined' && config.hidden){
6249 c.style += ' display:none;';
6252 if(typeof(config.dataIndex) != 'undefined'){
6253 c.sort = config.dataIndex;
6258 if(typeof(config.align) != 'undefined' && config.align.length){
6259 c.style += ' text-align:' + config.align + ';';
6262 if(typeof(config.width) != 'undefined'){
6263 c.style += ' width:' + config.width + 'px;';
6264 this.totalWidth += config.width;
6266 this.totalWidth += 100; // assume minimum of 100 per column?
6269 if(typeof(config.cls) != 'undefined'){
6270 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6273 ['xs','sm','md','lg'].map(function(size){
6275 if(typeof(config[size]) == 'undefined'){
6279 if (!config[size]) { // 0 = hidden
6280 c.cls += ' hidden-' + size;
6284 c.cls += ' col-' + size + '-' + config[size];
6294 renderBody : function()
6304 colspan : this.cm.getColumnCount()
6314 renderFooter : function()
6324 colspan : this.cm.getColumnCount()
6338 // Roo.log('ds onload');
6343 var ds = this.store;
6345 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6346 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6347 if (_this.store.sortInfo) {
6349 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6350 e.select('i', true).addClass(['glyphicon-arrow-up']);
6353 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6354 e.select('i', true).addClass(['glyphicon-arrow-down']);
6359 var tbody = this.mainBody;
6361 if(ds.getCount() > 0){
6362 ds.data.each(function(d,rowIndex){
6363 var row = this.renderRow(cm, ds, rowIndex);
6365 tbody.createChild(row);
6369 if(row.cellObjects.length){
6370 Roo.each(row.cellObjects, function(r){
6371 _this.renderCellObject(r);
6378 Roo.each(this.el.select('tbody td', true).elements, function(e){
6379 e.on('mouseover', _this.onMouseover, _this);
6382 Roo.each(this.el.select('tbody td', true).elements, function(e){
6383 e.on('mouseout', _this.onMouseout, _this);
6385 this.fireEvent('rowsrendered', this);
6386 //if(this.loadMask){
6387 // this.maskEl.hide();
6394 onUpdate : function(ds,record)
6396 this.refreshRow(record);
6399 onRemove : function(ds, record, index, isUpdate){
6400 if(isUpdate !== true){
6401 this.fireEvent("beforerowremoved", this, index, record);
6403 var bt = this.mainBody.dom;
6405 var rows = this.el.select('tbody > tr', true).elements;
6407 if(typeof(rows[index]) != 'undefined'){
6408 bt.removeChild(rows[index].dom);
6411 // if(bt.rows[index]){
6412 // bt.removeChild(bt.rows[index]);
6415 if(isUpdate !== true){
6416 //this.stripeRows(index);
6417 //this.syncRowHeights(index, index);
6419 this.fireEvent("rowremoved", this, index, record);
6423 onAdd : function(ds, records, rowIndex)
6425 //Roo.log('on Add called');
6426 // - note this does not handle multiple adding very well..
6427 var bt = this.mainBody.dom;
6428 for (var i =0 ; i < records.length;i++) {
6429 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6430 //Roo.log(records[i]);
6431 //Roo.log(this.store.getAt(rowIndex+i));
6432 this.insertRow(this.store, rowIndex + i, false);
6439 refreshRow : function(record){
6440 var ds = this.store, index;
6441 if(typeof record == 'number'){
6443 record = ds.getAt(index);
6445 index = ds.indexOf(record);
6447 this.insertRow(ds, index, true);
6448 this.onRemove(ds, record, index+1, true);
6449 //this.syncRowHeights(index, index);
6451 this.fireEvent("rowupdated", this, index, record);
6454 insertRow : function(dm, rowIndex, isUpdate){
6457 this.fireEvent("beforerowsinserted", this, rowIndex);
6459 //var s = this.getScrollState();
6460 var row = this.renderRow(this.cm, this.store, rowIndex);
6461 // insert before rowIndex..
6462 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6466 if(row.cellObjects.length){
6467 Roo.each(row.cellObjects, function(r){
6468 _this.renderCellObject(r);
6473 this.fireEvent("rowsinserted", this, rowIndex);
6474 //this.syncRowHeights(firstRow, lastRow);
6475 //this.stripeRows(firstRow);
6482 getRowDom : function(rowIndex)
6484 var rows = this.el.select('tbody > tr', true).elements;
6486 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6489 // returns the object tree for a tr..
6492 renderRow : function(cm, ds, rowIndex)
6495 var d = ds.getAt(rowIndex);
6502 var cellObjects = [];
6504 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6505 var config = cm.config[i];
6507 var renderer = cm.getRenderer(i);
6511 if(typeof(renderer) !== 'undefined'){
6512 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6514 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6515 // and are rendered into the cells after the row is rendered - using the id for the element.
6517 if(typeof(value) === 'object'){
6527 rowIndex : rowIndex,
6532 this.fireEvent('rowclass', this, rowcfg);
6536 cls : rowcfg.rowClass,
6538 html: (typeof(value) === 'object') ? '' : value
6545 if(typeof(config.colspan) != 'undefined'){
6546 td.colspan = config.colspan;
6549 if(typeof(config.hidden) != 'undefined' && config.hidden){
6550 td.style += ' display:none;';
6553 if(typeof(config.align) != 'undefined' && config.align.length){
6554 td.style += ' text-align:' + config.align + ';';
6557 if(typeof(config.width) != 'undefined'){
6558 td.style += ' width:' + config.width + 'px;';
6561 if(typeof(config.cursor) != 'undefined'){
6562 td.style += ' cursor:' + config.cursor + ';';
6565 if(typeof(config.cls) != 'undefined'){
6566 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6569 ['xs','sm','md','lg'].map(function(size){
6571 if(typeof(config[size]) == 'undefined'){
6575 if (!config[size]) { // 0 = hidden
6576 td.cls += ' hidden-' + size;
6580 td.cls += ' col-' + size + '-' + config[size];
6588 row.cellObjects = cellObjects;
6596 onBeforeLoad : function()
6598 //Roo.log('ds onBeforeLoad');
6602 //if(this.loadMask){
6603 // this.maskEl.show();
6611 this.el.select('tbody', true).first().dom.innerHTML = '';
6614 * Show or hide a row.
6615 * @param {Number} rowIndex to show or hide
6616 * @param {Boolean} state hide
6618 setRowVisibility : function(rowIndex, state)
6620 var bt = this.mainBody.dom;
6622 var rows = this.el.select('tbody > tr', true).elements;
6624 if(typeof(rows[rowIndex]) == 'undefined'){
6627 rows[rowIndex].dom.style.display = state ? '' : 'none';
6631 getSelectionModel : function(){
6633 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6635 return this.selModel;
6638 * Render the Roo.bootstrap object from renderder
6640 renderCellObject : function(r)
6644 var t = r.cfg.render(r.container);
6647 Roo.each(r.cfg.cn, function(c){
6649 container: t.getChildContainer(),
6652 _this.renderCellObject(child);
6657 getRowIndex : function(row)
6661 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6672 * Returns the grid's underlying element = used by panel.Grid
6673 * @return {Element} The element
6675 getGridEl : function(){
6676 return this.container;
6679 * Forces a resize - used by panel.Grid
6680 * @return {Element} The element
6682 autoSize : function(){
6683 var ctr = Roo.get(this.container.dom.parentElement);
6685 var thd = this.getGridEl().select('thead',true).first();
6686 var tbd = this.getGridEl().select('tbody', true).first();
6689 var cw = ctr.getWidth();
6693 tbd.setSize(ctr.getWidth(), ctr.getHeight() - thd.getHeight());
6694 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6697 cw = Math.max(cw, this.totalWidth);
6698 this.getGridEl().select('tr',true).setWidth(cw);
6700 return; // we doe not have a view in this design..
6703 if(this.view.adjustForScroll){
6704 this.view.adjustForScroll();
6708 onBodyScroll: function()
6711 Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6712 this.mainHead.setStyle({
6713 'position' : 'relative',
6714 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6731 * @class Roo.bootstrap.TableCell
6732 * @extends Roo.bootstrap.Component
6733 * Bootstrap TableCell class
6734 * @cfg {String} html cell contain text
6735 * @cfg {String} cls cell class
6736 * @cfg {String} tag cell tag (td|th) default td
6737 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6738 * @cfg {String} align Aligns the content in a cell
6739 * @cfg {String} axis Categorizes cells
6740 * @cfg {String} bgcolor Specifies the background color of a cell
6741 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6742 * @cfg {Number} colspan Specifies the number of columns a cell should span
6743 * @cfg {String} headers Specifies one or more header cells a cell is related to
6744 * @cfg {Number} height Sets the height of a cell
6745 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6746 * @cfg {Number} rowspan Sets the number of rows a cell should span
6747 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6748 * @cfg {String} valign Vertical aligns the content in a cell
6749 * @cfg {Number} width Specifies the width of a cell
6752 * Create a new TableCell
6753 * @param {Object} config The config object
6756 Roo.bootstrap.TableCell = function(config){
6757 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6760 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6780 getAutoCreate : function(){
6781 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6801 cfg.align=this.align
6807 cfg.bgcolor=this.bgcolor
6810 cfg.charoff=this.charoff
6813 cfg.colspan=this.colspan
6816 cfg.headers=this.headers
6819 cfg.height=this.height
6822 cfg.nowrap=this.nowrap
6825 cfg.rowspan=this.rowspan
6828 cfg.scope=this.scope
6831 cfg.valign=this.valign
6834 cfg.width=this.width
6853 * @class Roo.bootstrap.TableRow
6854 * @extends Roo.bootstrap.Component
6855 * Bootstrap TableRow class
6856 * @cfg {String} cls row class
6857 * @cfg {String} align Aligns the content in a table row
6858 * @cfg {String} bgcolor Specifies a background color for a table row
6859 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6860 * @cfg {String} valign Vertical aligns the content in a table row
6863 * Create a new TableRow
6864 * @param {Object} config The config object
6867 Roo.bootstrap.TableRow = function(config){
6868 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6871 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6879 getAutoCreate : function(){
6880 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6890 cfg.align = this.align;
6893 cfg.bgcolor = this.bgcolor;
6896 cfg.charoff = this.charoff;
6899 cfg.valign = this.valign;
6917 * @class Roo.bootstrap.TableBody
6918 * @extends Roo.bootstrap.Component
6919 * Bootstrap TableBody class
6920 * @cfg {String} cls element class
6921 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6922 * @cfg {String} align Aligns the content inside the element
6923 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6924 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6927 * Create a new TableBody
6928 * @param {Object} config The config object
6931 Roo.bootstrap.TableBody = function(config){
6932 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6935 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6943 getAutoCreate : function(){
6944 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6958 cfg.align = this.align;
6961 cfg.charoff = this.charoff;
6964 cfg.valign = this.valign;
6971 // initEvents : function()
6978 // this.store = Roo.factory(this.store, Roo.data);
6979 // this.store.on('load', this.onLoad, this);
6981 // this.store.load();
6985 // onLoad: function ()
6987 // this.fireEvent('load', this);
6997 * Ext JS Library 1.1.1
6998 * Copyright(c) 2006-2007, Ext JS, LLC.
7000 * Originally Released Under LGPL - original licence link has changed is not relivant.
7003 * <script type="text/javascript">
7006 // as we use this in bootstrap.
7007 Roo.namespace('Roo.form');
7009 * @class Roo.form.Action
7010 * Internal Class used to handle form actions
7012 * @param {Roo.form.BasicForm} el The form element or its id
7013 * @param {Object} config Configuration options
7018 // define the action interface
7019 Roo.form.Action = function(form, options){
7021 this.options = options || {};
7024 * Client Validation Failed
7027 Roo.form.Action.CLIENT_INVALID = 'client';
7029 * Server Validation Failed
7032 Roo.form.Action.SERVER_INVALID = 'server';
7034 * Connect to Server Failed
7037 Roo.form.Action.CONNECT_FAILURE = 'connect';
7039 * Reading Data from Server Failed
7042 Roo.form.Action.LOAD_FAILURE = 'load';
7044 Roo.form.Action.prototype = {
7046 failureType : undefined,
7047 response : undefined,
7051 run : function(options){
7056 success : function(response){
7061 handleResponse : function(response){
7065 // default connection failure
7066 failure : function(response){
7068 this.response = response;
7069 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7070 this.form.afterAction(this, false);
7073 processResponse : function(response){
7074 this.response = response;
7075 if(!response.responseText){
7078 this.result = this.handleResponse(response);
7082 // utility functions used internally
7083 getUrl : function(appendParams){
7084 var url = this.options.url || this.form.url || this.form.el.dom.action;
7086 var p = this.getParams();
7088 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7094 getMethod : function(){
7095 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7098 getParams : function(){
7099 var bp = this.form.baseParams;
7100 var p = this.options.params;
7102 if(typeof p == "object"){
7103 p = Roo.urlEncode(Roo.applyIf(p, bp));
7104 }else if(typeof p == 'string' && bp){
7105 p += '&' + Roo.urlEncode(bp);
7108 p = Roo.urlEncode(bp);
7113 createCallback : function(){
7115 success: this.success,
7116 failure: this.failure,
7118 timeout: (this.form.timeout*1000),
7119 upload: this.form.fileUpload ? this.success : undefined
7124 Roo.form.Action.Submit = function(form, options){
7125 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7128 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7131 haveProgress : false,
7132 uploadComplete : false,
7134 // uploadProgress indicator.
7135 uploadProgress : function()
7137 if (!this.form.progressUrl) {
7141 if (!this.haveProgress) {
7142 Roo.MessageBox.progress("Uploading", "Uploading");
7144 if (this.uploadComplete) {
7145 Roo.MessageBox.hide();
7149 this.haveProgress = true;
7151 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7153 var c = new Roo.data.Connection();
7155 url : this.form.progressUrl,
7160 success : function(req){
7161 //console.log(data);
7165 rdata = Roo.decode(req.responseText)
7167 Roo.log("Invalid data from server..");
7171 if (!rdata || !rdata.success) {
7173 Roo.MessageBox.alert(Roo.encode(rdata));
7176 var data = rdata.data;
7178 if (this.uploadComplete) {
7179 Roo.MessageBox.hide();
7184 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7185 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7188 this.uploadProgress.defer(2000,this);
7191 failure: function(data) {
7192 Roo.log('progress url failed ');
7203 // run get Values on the form, so it syncs any secondary forms.
7204 this.form.getValues();
7206 var o = this.options;
7207 var method = this.getMethod();
7208 var isPost = method == 'POST';
7209 if(o.clientValidation === false || this.form.isValid()){
7211 if (this.form.progressUrl) {
7212 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7213 (new Date() * 1) + '' + Math.random());
7218 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7219 form:this.form.el.dom,
7220 url:this.getUrl(!isPost),
7222 params:isPost ? this.getParams() : null,
7223 isUpload: this.form.fileUpload
7226 this.uploadProgress();
7228 }else if (o.clientValidation !== false){ // client validation failed
7229 this.failureType = Roo.form.Action.CLIENT_INVALID;
7230 this.form.afterAction(this, false);
7234 success : function(response)
7236 this.uploadComplete= true;
7237 if (this.haveProgress) {
7238 Roo.MessageBox.hide();
7242 var result = this.processResponse(response);
7243 if(result === true || result.success){
7244 this.form.afterAction(this, true);
7248 this.form.markInvalid(result.errors);
7249 this.failureType = Roo.form.Action.SERVER_INVALID;
7251 this.form.afterAction(this, false);
7253 failure : function(response)
7255 this.uploadComplete= true;
7256 if (this.haveProgress) {
7257 Roo.MessageBox.hide();
7260 this.response = response;
7261 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7262 this.form.afterAction(this, false);
7265 handleResponse : function(response){
7266 if(this.form.errorReader){
7267 var rs = this.form.errorReader.read(response);
7270 for(var i = 0, len = rs.records.length; i < len; i++) {
7271 var r = rs.records[i];
7275 if(errors.length < 1){
7279 success : rs.success,
7285 ret = Roo.decode(response.responseText);
7289 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7299 Roo.form.Action.Load = function(form, options){
7300 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7301 this.reader = this.form.reader;
7304 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7309 Roo.Ajax.request(Roo.apply(
7310 this.createCallback(), {
7311 method:this.getMethod(),
7312 url:this.getUrl(false),
7313 params:this.getParams()
7317 success : function(response){
7319 var result = this.processResponse(response);
7320 if(result === true || !result.success || !result.data){
7321 this.failureType = Roo.form.Action.LOAD_FAILURE;
7322 this.form.afterAction(this, false);
7325 this.form.clearInvalid();
7326 this.form.setValues(result.data);
7327 this.form.afterAction(this, true);
7330 handleResponse : function(response){
7331 if(this.form.reader){
7332 var rs = this.form.reader.read(response);
7333 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7335 success : rs.success,
7339 return Roo.decode(response.responseText);
7343 Roo.form.Action.ACTION_TYPES = {
7344 'load' : Roo.form.Action.Load,
7345 'submit' : Roo.form.Action.Submit
7354 * @class Roo.bootstrap.Form
7355 * @extends Roo.bootstrap.Component
7356 * Bootstrap Form class
7357 * @cfg {String} method GET | POST (default POST)
7358 * @cfg {String} labelAlign top | left (default top)
7359 * @cfg {String} align left | right - for navbars
7360 * @cfg {Boolean} loadMask load mask when submit (default true)
7365 * @param {Object} config The config object
7369 Roo.bootstrap.Form = function(config){
7370 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7373 * @event clientvalidation
7374 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7375 * @param {Form} this
7376 * @param {Boolean} valid true if the form has passed client-side validation
7378 clientvalidation: true,
7380 * @event beforeaction
7381 * Fires before any action is performed. Return false to cancel the action.
7382 * @param {Form} this
7383 * @param {Action} action The action to be performed
7387 * @event actionfailed
7388 * Fires when an action fails.
7389 * @param {Form} this
7390 * @param {Action} action The action that failed
7392 actionfailed : true,
7394 * @event actioncomplete
7395 * Fires when an action is completed.
7396 * @param {Form} this
7397 * @param {Action} action The action that completed
7399 actioncomplete : true
7404 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7407 * @cfg {String} method
7408 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7413 * The URL to use for form actions if one isn't supplied in the action options.
7416 * @cfg {Boolean} fileUpload
7417 * Set to true if this form is a file upload.
7421 * @cfg {Object} baseParams
7422 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7426 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7430 * @cfg {Sting} align (left|right) for navbar forms
7435 activeAction : null,
7438 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7439 * element by passing it or its id or mask the form itself by passing in true.
7442 waitMsgTarget : false,
7446 getAutoCreate : function(){
7450 method : this.method || 'POST',
7451 id : this.id || Roo.id(),
7454 if (this.parent().xtype.match(/^Nav/)) {
7455 cfg.cls = 'navbar-form navbar-' + this.align;
7459 if (this.labelAlign == 'left' ) {
7460 cfg.cls += ' form-horizontal';
7466 initEvents : function()
7468 this.el.on('submit', this.onSubmit, this);
7469 // this was added as random key presses on the form where triggering form submit.
7470 this.el.on('keypress', function(e) {
7471 if (e.getCharCode() != 13) {
7474 // we might need to allow it for textareas.. and some other items.
7475 // check e.getTarget().
7477 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7481 Roo.log("keypress blocked");
7489 onSubmit : function(e){
7494 * Returns true if client-side validation on the form is successful.
7497 isValid : function(){
7498 var items = this.getItems();
7500 items.each(function(f){
7509 * Returns true if any fields in this form have changed since their original load.
7512 isDirty : function(){
7514 var items = this.getItems();
7515 items.each(function(f){
7525 * Performs a predefined action (submit or load) or custom actions you define on this form.
7526 * @param {String} actionName The name of the action type
7527 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7528 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7529 * accept other config options):
7531 Property Type Description
7532 ---------------- --------------- ----------------------------------------------------------------------------------
7533 url String The url for the action (defaults to the form's url)
7534 method String The form method to use (defaults to the form's method, or POST if not defined)
7535 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7536 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7537 validate the form on the client (defaults to false)
7539 * @return {BasicForm} this
7541 doAction : function(action, options){
7542 if(typeof action == 'string'){
7543 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7545 if(this.fireEvent('beforeaction', this, action) !== false){
7546 this.beforeAction(action);
7547 action.run.defer(100, action);
7553 beforeAction : function(action){
7554 var o = action.options;
7557 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7559 // not really supported yet.. ??
7561 //if(this.waitMsgTarget === true){
7562 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7563 //}else if(this.waitMsgTarget){
7564 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7565 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7567 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7573 afterAction : function(action, success){
7574 this.activeAction = null;
7575 var o = action.options;
7577 //if(this.waitMsgTarget === true){
7579 //}else if(this.waitMsgTarget){
7580 // this.waitMsgTarget.unmask();
7582 // Roo.MessageBox.updateProgress(1);
7583 // Roo.MessageBox.hide();
7590 Roo.callback(o.success, o.scope, [this, action]);
7591 this.fireEvent('actioncomplete', this, action);
7595 // failure condition..
7596 // we have a scenario where updates need confirming.
7597 // eg. if a locking scenario exists..
7598 // we look for { errors : { needs_confirm : true }} in the response.
7600 (typeof(action.result) != 'undefined') &&
7601 (typeof(action.result.errors) != 'undefined') &&
7602 (typeof(action.result.errors.needs_confirm) != 'undefined')
7605 Roo.log("not supported yet");
7608 Roo.MessageBox.confirm(
7609 "Change requires confirmation",
7610 action.result.errorMsg,
7615 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7625 Roo.callback(o.failure, o.scope, [this, action]);
7626 // show an error message if no failed handler is set..
7627 if (!this.hasListener('actionfailed')) {
7628 Roo.log("need to add dialog support");
7630 Roo.MessageBox.alert("Error",
7631 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7632 action.result.errorMsg :
7633 "Saving Failed, please check your entries or try again"
7638 this.fireEvent('actionfailed', this, action);
7643 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7644 * @param {String} id The value to search for
7647 findField : function(id){
7648 var items = this.getItems();
7649 var field = items.get(id);
7651 items.each(function(f){
7652 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7659 return field || null;
7662 * Mark fields in this form invalid in bulk.
7663 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7664 * @return {BasicForm} this
7666 markInvalid : function(errors){
7667 if(errors instanceof Array){
7668 for(var i = 0, len = errors.length; i < len; i++){
7669 var fieldError = errors[i];
7670 var f = this.findField(fieldError.id);
7672 f.markInvalid(fieldError.msg);
7678 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7679 field.markInvalid(errors[id]);
7683 //Roo.each(this.childForms || [], function (f) {
7684 // f.markInvalid(errors);
7691 * Set values for fields in this form in bulk.
7692 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7693 * @return {BasicForm} this
7695 setValues : function(values){
7696 if(values instanceof Array){ // array of objects
7697 for(var i = 0, len = values.length; i < len; i++){
7699 var f = this.findField(v.id);
7701 f.setValue(v.value);
7702 if(this.trackResetOnLoad){
7703 f.originalValue = f.getValue();
7707 }else{ // object hash
7710 if(typeof values[id] != 'function' && (field = this.findField(id))){
7712 if (field.setFromData &&
7714 field.displayField &&
7715 // combos' with local stores can
7716 // be queried via setValue()
7717 // to set their value..
7718 (field.store && !field.store.isLocal)
7722 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7723 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7724 field.setFromData(sd);
7727 field.setValue(values[id]);
7731 if(this.trackResetOnLoad){
7732 field.originalValue = field.getValue();
7738 //Roo.each(this.childForms || [], function (f) {
7739 // f.setValues(values);
7746 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7747 * they are returned as an array.
7748 * @param {Boolean} asString
7751 getValues : function(asString){
7752 //if (this.childForms) {
7753 // copy values from the child forms
7754 // Roo.each(this.childForms, function (f) {
7755 // this.setValues(f.getValues());
7761 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7762 if(asString === true){
7765 return Roo.urlDecode(fs);
7769 * Returns the fields in this form as an object with key/value pairs.
7770 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7773 getFieldValues : function(with_hidden)
7775 var items = this.getItems();
7777 items.each(function(f){
7781 var v = f.getValue();
7782 if (f.inputType =='radio') {
7783 if (typeof(ret[f.getName()]) == 'undefined') {
7784 ret[f.getName()] = ''; // empty..
7787 if (!f.el.dom.checked) {
7795 // not sure if this supported any more..
7796 if ((typeof(v) == 'object') && f.getRawValue) {
7797 v = f.getRawValue() ; // dates..
7799 // combo boxes where name != hiddenName...
7800 if (f.name != f.getName()) {
7801 ret[f.name] = f.getRawValue();
7803 ret[f.getName()] = v;
7810 * Clears all invalid messages in this form.
7811 * @return {BasicForm} this
7813 clearInvalid : function(){
7814 var items = this.getItems();
7816 items.each(function(f){
7827 * @return {BasicForm} this
7830 var items = this.getItems();
7831 items.each(function(f){
7835 Roo.each(this.childForms || [], function (f) {
7842 getItems : function()
7844 var r=new Roo.util.MixedCollection(false, function(o){
7845 return o.id || (o.id = Roo.id());
7847 var iter = function(el) {
7854 Roo.each(el.items,function(e) {
7874 * Ext JS Library 1.1.1
7875 * Copyright(c) 2006-2007, Ext JS, LLC.
7877 * Originally Released Under LGPL - original licence link has changed is not relivant.
7880 * <script type="text/javascript">
7883 * @class Roo.form.VTypes
7884 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7887 Roo.form.VTypes = function(){
7888 // closure these in so they are only created once.
7889 var alpha = /^[a-zA-Z_]+$/;
7890 var alphanum = /^[a-zA-Z0-9_]+$/;
7891 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7892 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7894 // All these messages and functions are configurable
7897 * The function used to validate email addresses
7898 * @param {String} value The email address
7900 'email' : function(v){
7901 return email.test(v);
7904 * The error text to display when the email validation function returns false
7907 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7909 * The keystroke filter mask to be applied on email input
7912 'emailMask' : /[a-z0-9_\.\-@]/i,
7915 * The function used to validate URLs
7916 * @param {String} value The URL
7918 'url' : function(v){
7922 * The error text to display when the url validation function returns false
7925 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7928 * The function used to validate alpha values
7929 * @param {String} value The value
7931 'alpha' : function(v){
7932 return alpha.test(v);
7935 * The error text to display when the alpha validation function returns false
7938 'alphaText' : 'This field should only contain letters and _',
7940 * The keystroke filter mask to be applied on alpha input
7943 'alphaMask' : /[a-z_]/i,
7946 * The function used to validate alphanumeric values
7947 * @param {String} value The value
7949 'alphanum' : function(v){
7950 return alphanum.test(v);
7953 * The error text to display when the alphanumeric validation function returns false
7956 'alphanumText' : 'This field should only contain letters, numbers and _',
7958 * The keystroke filter mask to be applied on alphanumeric input
7961 'alphanumMask' : /[a-z0-9_]/i
7971 * @class Roo.bootstrap.Input
7972 * @extends Roo.bootstrap.Component
7973 * Bootstrap Input class
7974 * @cfg {Boolean} disabled is it disabled
7975 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7976 * @cfg {String} name name of the input
7977 * @cfg {string} fieldLabel - the label associated
7978 * @cfg {string} placeholder - placeholder to put in text.
7979 * @cfg {string} before - input group add on before
7980 * @cfg {string} after - input group add on after
7981 * @cfg {string} size - (lg|sm) or leave empty..
7982 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7983 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7984 * @cfg {Number} md colspan out of 12 for computer-sized screens
7985 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7986 * @cfg {string} value default value of the input
7987 * @cfg {Number} labelWidth set the width of label (0-12)
7988 * @cfg {String} labelAlign (top|left)
7989 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7990 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7992 * @cfg {String} align (left|center|right) Default left
7993 * @cfg {Boolean} forceFeedback (true|false) Default false
7999 * Create a new Input
8000 * @param {Object} config The config object
8003 Roo.bootstrap.Input = function(config){
8004 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8009 * Fires when this field receives input focus.
8010 * @param {Roo.form.Field} this
8015 * Fires when this field loses input focus.
8016 * @param {Roo.form.Field} this
8021 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8022 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8023 * @param {Roo.form.Field} this
8024 * @param {Roo.EventObject} e The event object
8029 * Fires just before the field blurs if the field value has changed.
8030 * @param {Roo.form.Field} this
8031 * @param {Mixed} newValue The new value
8032 * @param {Mixed} oldValue The original value
8037 * Fires after the field has been marked as invalid.
8038 * @param {Roo.form.Field} this
8039 * @param {String} msg The validation message
8044 * Fires after the field has been validated with no errors.
8045 * @param {Roo.form.Field} this
8050 * Fires after the key up
8051 * @param {Roo.form.Field} this
8052 * @param {Roo.EventObject} e The event Object
8058 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8060 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8061 automatic validation (defaults to "keyup").
8063 validationEvent : "keyup",
8065 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8067 validateOnBlur : true,
8069 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8071 validationDelay : 250,
8073 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8075 focusClass : "x-form-focus", // not needed???
8079 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8081 invalidClass : "has-warning",
8084 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8086 validClass : "has-success",
8089 * @cfg {Boolean} hasFeedback (true|false) default true
8094 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8096 invalidFeedbackClass : "glyphicon-warning-sign",
8099 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8101 validFeedbackClass : "glyphicon-ok",
8104 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8106 selectOnFocus : false,
8109 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8113 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8118 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8120 disableKeyFilter : false,
8123 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8127 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8131 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8133 blankText : "This field is required",
8136 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8140 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8142 maxLength : Number.MAX_VALUE,
8144 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8146 minLengthText : "The minimum length for this field is {0}",
8148 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8150 maxLengthText : "The maximum length for this field is {0}",
8154 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8155 * If available, this function will be called only after the basic validators all return true, and will be passed the
8156 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8160 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8161 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8162 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8166 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8170 autocomplete: false,
8189 formatedValue : false,
8190 forceFeedback : false,
8192 parentLabelAlign : function()
8195 while (parent.parent()) {
8196 parent = parent.parent();
8197 if (typeof(parent.labelAlign) !='undefined') {
8198 return parent.labelAlign;
8205 getAutoCreate : function(){
8207 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8215 if(this.inputType != 'hidden'){
8216 cfg.cls = 'form-group' //input-group
8222 type : this.inputType,
8224 cls : 'form-control',
8225 placeholder : this.placeholder || '',
8226 autocomplete : this.autocomplete || 'new-password'
8231 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8234 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8235 input.maxLength = this.maxLength;
8238 if (this.disabled) {
8239 input.disabled=true;
8242 if (this.readOnly) {
8243 input.readonly=true;
8247 input.name = this.name;
8250 input.cls += ' input-' + this.size;
8253 ['xs','sm','md','lg'].map(function(size){
8254 if (settings[size]) {
8255 cfg.cls += ' col-' + size + '-' + settings[size];
8259 var inputblock = input;
8263 cls: 'glyphicon form-control-feedback'
8266 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8269 cls : 'has-feedback',
8277 if (this.before || this.after) {
8280 cls : 'input-group',
8284 if (this.before && typeof(this.before) == 'string') {
8286 inputblock.cn.push({
8288 cls : 'roo-input-before input-group-addon',
8292 if (this.before && typeof(this.before) == 'object') {
8293 this.before = Roo.factory(this.before);
8295 inputblock.cn.push({
8297 cls : 'roo-input-before input-group-' +
8298 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8302 inputblock.cn.push(input);
8304 if (this.after && typeof(this.after) == 'string') {
8305 inputblock.cn.push({
8307 cls : 'roo-input-after input-group-addon',
8311 if (this.after && typeof(this.after) == 'object') {
8312 this.after = Roo.factory(this.after);
8314 inputblock.cn.push({
8316 cls : 'roo-input-after input-group-' +
8317 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8321 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8322 inputblock.cls += ' has-feedback';
8323 inputblock.cn.push(feedback);
8327 if (align ==='left' && this.fieldLabel.length) {
8334 cls : 'control-label col-sm-' + this.labelWidth,
8335 html : this.fieldLabel
8339 cls : "col-sm-" + (12 - this.labelWidth),
8346 } else if ( this.fieldLabel.length) {
8352 //cls : 'input-group-addon',
8353 html : this.fieldLabel
8372 if (this.parentType === 'Navbar' && this.parent().bar) {
8373 cfg.cls += ' navbar-form';
8375 if (this.parentType === 'NavGroup') {
8376 cfg.cls += ' navbar-form';
8383 * return the real input element.
8385 inputEl: function ()
8387 return this.el.select('input.form-control',true).first();
8390 tooltipEl : function()
8392 return this.inputEl();
8395 setDisabled : function(v)
8397 var i = this.inputEl().dom;
8399 i.removeAttribute('disabled');
8403 i.setAttribute('disabled','true');
8405 initEvents : function()
8408 this.inputEl().on("keydown" , this.fireKey, this);
8409 this.inputEl().on("focus", this.onFocus, this);
8410 this.inputEl().on("blur", this.onBlur, this);
8412 this.inputEl().relayEvent('keyup', this);
8414 // reference to original value for reset
8415 this.originalValue = this.getValue();
8416 //Roo.form.TextField.superclass.initEvents.call(this);
8417 if(this.validationEvent == 'keyup'){
8418 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8419 this.inputEl().on('keyup', this.filterValidation, this);
8421 else if(this.validationEvent !== false){
8422 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8425 if(this.selectOnFocus){
8426 this.on("focus", this.preFocus, this);
8429 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8430 this.inputEl().on("keypress", this.filterKeys, this);
8433 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8434 this.el.on("click", this.autoSize, this);
8437 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8438 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8441 if (typeof(this.before) == 'object') {
8442 this.before.render(this.el.select('.roo-input-before',true).first());
8444 if (typeof(this.after) == 'object') {
8445 this.after.render(this.el.select('.roo-input-after',true).first());
8450 filterValidation : function(e){
8451 if(!e.isNavKeyPress()){
8452 this.validationTask.delay(this.validationDelay);
8456 * Validates the field value
8457 * @return {Boolean} True if the value is valid, else false
8459 validate : function(){
8460 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8461 if(this.disabled || this.validateValue(this.getRawValue())){
8472 * Validates a value according to the field's validation rules and marks the field as invalid
8473 * if the validation fails
8474 * @param {Mixed} value The value to validate
8475 * @return {Boolean} True if the value is valid, else false
8477 validateValue : function(value){
8478 if(value.length < 1) { // if it's blank
8479 if(this.allowBlank){
8485 if(value.length < this.minLength){
8488 if(value.length > this.maxLength){
8492 var vt = Roo.form.VTypes;
8493 if(!vt[this.vtype](value, this)){
8497 if(typeof this.validator == "function"){
8498 var msg = this.validator(value);
8504 if(this.regex && !this.regex.test(value)){
8514 fireKey : function(e){
8515 //Roo.log('field ' + e.getKey());
8516 if(e.isNavKeyPress()){
8517 this.fireEvent("specialkey", this, e);
8520 focus : function (selectText){
8522 this.inputEl().focus();
8523 if(selectText === true){
8524 this.inputEl().dom.select();
8530 onFocus : function(){
8531 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8532 // this.el.addClass(this.focusClass);
8535 this.hasFocus = true;
8536 this.startValue = this.getValue();
8537 this.fireEvent("focus", this);
8541 beforeBlur : Roo.emptyFn,
8545 onBlur : function(){
8547 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8548 //this.el.removeClass(this.focusClass);
8550 this.hasFocus = false;
8551 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8554 var v = this.getValue();
8555 if(String(v) !== String(this.startValue)){
8556 this.fireEvent('change', this, v, this.startValue);
8558 this.fireEvent("blur", this);
8562 * Resets the current field value to the originally loaded value and clears any validation messages
8565 this.setValue(this.originalValue);
8569 * Returns the name of the field
8570 * @return {Mixed} name The name field
8572 getName: function(){
8576 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8577 * @return {Mixed} value The field value
8579 getValue : function(){
8581 var v = this.inputEl().getValue();
8586 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8587 * @return {Mixed} value The field value
8589 getRawValue : function(){
8590 var v = this.inputEl().getValue();
8596 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8597 * @param {Mixed} value The value to set
8599 setRawValue : function(v){
8600 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8603 selectText : function(start, end){
8604 var v = this.getRawValue();
8606 start = start === undefined ? 0 : start;
8607 end = end === undefined ? v.length : end;
8608 var d = this.inputEl().dom;
8609 if(d.setSelectionRange){
8610 d.setSelectionRange(start, end);
8611 }else if(d.createTextRange){
8612 var range = d.createTextRange();
8613 range.moveStart("character", start);
8614 range.moveEnd("character", v.length-end);
8621 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8622 * @param {Mixed} value The value to set
8624 setValue : function(v){
8627 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8633 processValue : function(value){
8634 if(this.stripCharsRe){
8635 var newValue = value.replace(this.stripCharsRe, '');
8636 if(newValue !== value){
8637 this.setRawValue(newValue);
8644 preFocus : function(){
8646 if(this.selectOnFocus){
8647 this.inputEl().dom.select();
8650 filterKeys : function(e){
8652 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8655 var c = e.getCharCode(), cc = String.fromCharCode(c);
8656 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8659 if(!this.maskRe.test(cc)){
8664 * Clear any invalid styles/messages for this field
8666 clearInvalid : function(){
8668 if(!this.el || this.preventMark){ // not rendered
8672 var label = this.el.select('label', true).first();
8673 var icon = this.el.select('i.fa-star', true).first();
8679 this.el.removeClass(this.invalidClass);
8681 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8683 var feedback = this.el.select('.form-control-feedback', true).first();
8686 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8691 this.fireEvent('valid', this);
8695 * Mark this field as valid
8697 markValid : function()
8699 if(!this.el || this.preventMark){ // not rendered
8703 this.el.removeClass([this.invalidClass, this.validClass]);
8705 var feedback = this.el.select('.form-control-feedback', true).first();
8708 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8711 if(this.disabled || this.allowBlank){
8715 var formGroup = this.el.findParent('.form-group', false, true);
8719 var label = formGroup.select('label', true).first();
8720 var icon = formGroup.select('i.fa-star', true).first();
8727 this.el.addClass(this.validClass);
8729 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8731 var feedback = this.el.select('.form-control-feedback', true).first();
8734 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8735 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8740 this.fireEvent('valid', this);
8744 * Mark this field as invalid
8745 * @param {String} msg The validation message
8747 markInvalid : function(msg)
8749 if(!this.el || this.preventMark){ // not rendered
8753 this.el.removeClass([this.invalidClass, this.validClass]);
8755 var feedback = this.el.select('.form-control-feedback', true).first();
8758 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8761 if(this.disabled || this.allowBlank){
8765 var formGroup = this.el.findParent('.form-group', false, true);
8768 var label = formGroup.select('label', true).first();
8769 var icon = formGroup.select('i.fa-star', true).first();
8771 if(!this.getValue().length && label && !icon){
8772 this.el.findParent('.form-group', false, true).createChild({
8774 cls : 'text-danger fa fa-lg fa-star',
8775 tooltip : 'This field is required',
8776 style : 'margin-right:5px;'
8782 this.el.addClass(this.invalidClass);
8784 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8786 var feedback = this.el.select('.form-control-feedback', true).first();
8789 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8791 if(this.getValue().length || this.forceFeedback){
8792 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8799 this.fireEvent('invalid', this, msg);
8802 SafariOnKeyDown : function(event)
8804 // this is a workaround for a password hang bug on chrome/ webkit.
8806 var isSelectAll = false;
8808 if(this.inputEl().dom.selectionEnd > 0){
8809 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8811 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8812 event.preventDefault();
8817 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8819 event.preventDefault();
8820 // this is very hacky as keydown always get's upper case.
8822 var cc = String.fromCharCode(event.getCharCode());
8823 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8827 adjustWidth : function(tag, w){
8828 tag = tag.toLowerCase();
8829 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8830 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8834 if(tag == 'textarea'){
8837 }else if(Roo.isOpera){
8841 if(tag == 'textarea'){
8860 * @class Roo.bootstrap.TextArea
8861 * @extends Roo.bootstrap.Input
8862 * Bootstrap TextArea class
8863 * @cfg {Number} cols Specifies the visible width of a text area
8864 * @cfg {Number} rows Specifies the visible number of lines in a text area
8865 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8866 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8867 * @cfg {string} html text
8870 * Create a new TextArea
8871 * @param {Object} config The config object
8874 Roo.bootstrap.TextArea = function(config){
8875 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8879 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8889 getAutoCreate : function(){
8891 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8902 value : this.value || '',
8903 html: this.html || '',
8904 cls : 'form-control',
8905 placeholder : this.placeholder || ''
8909 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8910 input.maxLength = this.maxLength;
8914 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8918 input.cols = this.cols;
8921 if (this.readOnly) {
8922 input.readonly = true;
8926 input.name = this.name;
8930 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8934 ['xs','sm','md','lg'].map(function(size){
8935 if (settings[size]) {
8936 cfg.cls += ' col-' + size + '-' + settings[size];
8940 var inputblock = input;
8942 if(this.hasFeedback && !this.allowBlank){
8946 cls: 'glyphicon form-control-feedback'
8950 cls : 'has-feedback',
8959 if (this.before || this.after) {
8962 cls : 'input-group',
8966 inputblock.cn.push({
8968 cls : 'input-group-addon',
8973 inputblock.cn.push(input);
8975 if(this.hasFeedback && !this.allowBlank){
8976 inputblock.cls += ' has-feedback';
8977 inputblock.cn.push(feedback);
8981 inputblock.cn.push({
8983 cls : 'input-group-addon',
8990 if (align ==='left' && this.fieldLabel.length) {
8991 // Roo.log("left and has label");
8997 cls : 'control-label col-sm-' + this.labelWidth,
8998 html : this.fieldLabel
9002 cls : "col-sm-" + (12 - this.labelWidth),
9009 } else if ( this.fieldLabel.length) {
9010 // Roo.log(" label");
9015 //cls : 'input-group-addon',
9016 html : this.fieldLabel
9026 // Roo.log(" no label && no align");
9036 if (this.disabled) {
9037 input.disabled=true;
9044 * return the real textarea element.
9046 inputEl: function ()
9048 return this.el.select('textarea.form-control',true).first();
9052 * Clear any invalid styles/messages for this field
9054 clearInvalid : function()
9057 if(!this.el || this.preventMark){ // not rendered
9061 var label = this.el.select('label', true).first();
9062 var icon = this.el.select('i.fa-star', true).first();
9068 this.el.removeClass(this.invalidClass);
9070 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9072 var feedback = this.el.select('.form-control-feedback', true).first();
9075 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9080 this.fireEvent('valid', this);
9084 * Mark this field as valid
9086 markValid : function()
9088 if(!this.el || this.preventMark){ // not rendered
9092 this.el.removeClass([this.invalidClass, this.validClass]);
9094 var feedback = this.el.select('.form-control-feedback', true).first();
9097 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9100 if(this.disabled || this.allowBlank){
9104 var label = this.el.select('label', true).first();
9105 var icon = this.el.select('i.fa-star', true).first();
9111 this.el.addClass(this.validClass);
9113 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9115 var feedback = this.el.select('.form-control-feedback', true).first();
9118 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9119 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9124 this.fireEvent('valid', this);
9128 * Mark this field as invalid
9129 * @param {String} msg The validation message
9131 markInvalid : function(msg)
9133 if(!this.el || this.preventMark){ // not rendered
9137 this.el.removeClass([this.invalidClass, this.validClass]);
9139 var feedback = this.el.select('.form-control-feedback', true).first();
9142 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9145 if(this.disabled || this.allowBlank){
9149 var label = this.el.select('label', true).first();
9150 var icon = this.el.select('i.fa-star', true).first();
9152 if(!this.getValue().length && label && !icon){
9153 this.el.createChild({
9155 cls : 'text-danger fa fa-lg fa-star',
9156 tooltip : 'This field is required',
9157 style : 'margin-right:5px;'
9161 this.el.addClass(this.invalidClass);
9163 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9165 var feedback = this.el.select('.form-control-feedback', true).first();
9168 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9170 if(this.getValue().length || this.forceFeedback){
9171 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9178 this.fireEvent('invalid', this, msg);
9186 * trigger field - base class for combo..
9191 * @class Roo.bootstrap.TriggerField
9192 * @extends Roo.bootstrap.Input
9193 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9194 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9195 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9196 * for which you can provide a custom implementation. For example:
9198 var trigger = new Roo.bootstrap.TriggerField();
9199 trigger.onTriggerClick = myTriggerFn;
9200 trigger.applyTo('my-field');
9203 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9204 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9205 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9206 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9207 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9210 * Create a new TriggerField.
9211 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9212 * to the base TextField)
9214 Roo.bootstrap.TriggerField = function(config){
9215 this.mimicing = false;
9216 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9219 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9221 * @cfg {String} triggerClass A CSS class to apply to the trigger
9224 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9229 * @cfg {Boolean} removable (true|false) special filter default false
9233 /** @cfg {Boolean} grow @hide */
9234 /** @cfg {Number} growMin @hide */
9235 /** @cfg {Number} growMax @hide */
9241 autoSize: Roo.emptyFn,
9248 actionMode : 'wrap',
9253 getAutoCreate : function(){
9255 var align = this.labelAlign || this.parentLabelAlign();
9260 cls: 'form-group' //input-group
9267 type : this.inputType,
9268 cls : 'form-control',
9269 autocomplete: 'new-password',
9270 placeholder : this.placeholder || ''
9274 input.name = this.name;
9277 input.cls += ' input-' + this.size;
9280 if (this.disabled) {
9281 input.disabled=true;
9284 var inputblock = input;
9286 if(this.hasFeedback && !this.allowBlank){
9290 cls: 'glyphicon form-control-feedback'
9293 if(this.removable && !this.editable && !this.tickable){
9295 cls : 'has-feedback',
9301 cls : 'roo-combo-removable-btn close'
9308 cls : 'has-feedback',
9317 if(this.removable && !this.editable && !this.tickable){
9319 cls : 'roo-removable',
9325 cls : 'roo-combo-removable-btn close'
9332 if (this.before || this.after) {
9335 cls : 'input-group',
9339 inputblock.cn.push({
9341 cls : 'input-group-addon',
9346 inputblock.cn.push(input);
9348 if(this.hasFeedback && !this.allowBlank){
9349 inputblock.cls += ' has-feedback';
9350 inputblock.cn.push(feedback);
9354 inputblock.cn.push({
9356 cls : 'input-group-addon',
9369 cls: 'form-hidden-field'
9383 cls: 'form-hidden-field'
9387 cls: 'roo-select2-choices',
9391 cls: 'roo-select2-search-field',
9404 cls: 'roo-select2-container input-group',
9409 // cls: 'typeahead typeahead-long dropdown-menu',
9410 // style: 'display:none'
9415 if(!this.multiple && this.showToggleBtn){
9421 if (this.caret != false) {
9424 cls: 'fa fa-' + this.caret
9431 cls : 'input-group-addon btn dropdown-toggle',
9436 cls: 'combobox-clear',
9450 combobox.cls += ' roo-select2-container-multi';
9453 if (align ==='left' && this.fieldLabel.length) {
9455 // Roo.log("left and has label");
9461 cls : 'control-label col-sm-' + this.labelWidth,
9462 html : this.fieldLabel
9466 cls : "col-sm-" + (12 - this.labelWidth),
9473 } else if ( this.fieldLabel.length) {
9474 // Roo.log(" label");
9479 //cls : 'input-group-addon',
9480 html : this.fieldLabel
9490 // Roo.log(" no label && no align");
9497 ['xs','sm','md','lg'].map(function(size){
9498 if (settings[size]) {
9499 cfg.cls += ' col-' + size + '-' + settings[size];
9510 onResize : function(w, h){
9511 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9512 // if(typeof w == 'number'){
9513 // var x = w - this.trigger.getWidth();
9514 // this.inputEl().setWidth(this.adjustWidth('input', x));
9515 // this.trigger.setStyle('left', x+'px');
9520 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9523 getResizeEl : function(){
9524 return this.inputEl();
9528 getPositionEl : function(){
9529 return this.inputEl();
9533 alignErrorIcon : function(){
9534 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9538 initEvents : function(){
9542 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9543 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9544 if(!this.multiple && this.showToggleBtn){
9545 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9546 if(this.hideTrigger){
9547 this.trigger.setDisplayed(false);
9549 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9553 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9556 if(this.removable && !this.editable && !this.tickable){
9557 var close = this.closeTriggerEl();
9560 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9561 close.on('click', this.removeBtnClick, this, close);
9565 //this.trigger.addClassOnOver('x-form-trigger-over');
9566 //this.trigger.addClassOnClick('x-form-trigger-click');
9569 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9573 closeTriggerEl : function()
9575 var close = this.el.select('.roo-combo-removable-btn', true).first();
9576 return close ? close : false;
9579 removeBtnClick : function(e, h, el)
9583 if(this.fireEvent("remove", this) !== false){
9585 this.fireEvent("afterremove", this)
9589 createList : function()
9591 this.list = Roo.get(document.body).createChild({
9593 cls: 'typeahead typeahead-long dropdown-menu',
9594 style: 'display:none'
9597 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9602 initTrigger : function(){
9607 onDestroy : function(){
9609 this.trigger.removeAllListeners();
9610 // this.trigger.remove();
9613 // this.wrap.remove();
9615 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9619 onFocus : function(){
9620 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9623 this.wrap.addClass('x-trigger-wrap-focus');
9624 this.mimicing = true;
9625 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9626 if(this.monitorTab){
9627 this.el.on("keydown", this.checkTab, this);
9634 checkTab : function(e){
9635 if(e.getKey() == e.TAB){
9641 onBlur : function(){
9646 mimicBlur : function(e, t){
9648 if(!this.wrap.contains(t) && this.validateBlur()){
9655 triggerBlur : function(){
9656 this.mimicing = false;
9657 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9658 if(this.monitorTab){
9659 this.el.un("keydown", this.checkTab, this);
9661 //this.wrap.removeClass('x-trigger-wrap-focus');
9662 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9666 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9667 validateBlur : function(e, t){
9672 onDisable : function(){
9673 this.inputEl().dom.disabled = true;
9674 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9676 // this.wrap.addClass('x-item-disabled');
9681 onEnable : function(){
9682 this.inputEl().dom.disabled = false;
9683 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9685 // this.el.removeClass('x-item-disabled');
9690 onShow : function(){
9691 var ae = this.getActionEl();
9694 ae.dom.style.display = '';
9695 ae.dom.style.visibility = 'visible';
9701 onHide : function(){
9702 var ae = this.getActionEl();
9703 ae.dom.style.display = 'none';
9707 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9708 * by an implementing function.
9710 * @param {EventObject} e
9712 onTriggerClick : Roo.emptyFn
9716 * Ext JS Library 1.1.1
9717 * Copyright(c) 2006-2007, Ext JS, LLC.
9719 * Originally Released Under LGPL - original licence link has changed is not relivant.
9722 * <script type="text/javascript">
9727 * @class Roo.data.SortTypes
9729 * Defines the default sorting (casting?) comparison functions used when sorting data.
9731 Roo.data.SortTypes = {
9733 * Default sort that does nothing
9734 * @param {Mixed} s The value being converted
9735 * @return {Mixed} The comparison value
9742 * The regular expression used to strip tags
9746 stripTagsRE : /<\/?[^>]+>/gi,
9749 * Strips all HTML tags to sort on text only
9750 * @param {Mixed} s The value being converted
9751 * @return {String} The comparison value
9753 asText : function(s){
9754 return String(s).replace(this.stripTagsRE, "");
9758 * Strips all HTML tags to sort on text only - Case insensitive
9759 * @param {Mixed} s The value being converted
9760 * @return {String} The comparison value
9762 asUCText : function(s){
9763 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9767 * Case insensitive string
9768 * @param {Mixed} s The value being converted
9769 * @return {String} The comparison value
9771 asUCString : function(s) {
9772 return String(s).toUpperCase();
9777 * @param {Mixed} s The value being converted
9778 * @return {Number} The comparison value
9780 asDate : function(s) {
9784 if(s instanceof Date){
9787 return Date.parse(String(s));
9792 * @param {Mixed} s The value being converted
9793 * @return {Float} The comparison value
9795 asFloat : function(s) {
9796 var val = parseFloat(String(s).replace(/,/g, ""));
9805 * @param {Mixed} s The value being converted
9806 * @return {Number} The comparison value
9808 asInt : function(s) {
9809 var val = parseInt(String(s).replace(/,/g, ""));
9817 * Ext JS Library 1.1.1
9818 * Copyright(c) 2006-2007, Ext JS, LLC.
9820 * Originally Released Under LGPL - original licence link has changed is not relivant.
9823 * <script type="text/javascript">
9827 * @class Roo.data.Record
9828 * Instances of this class encapsulate both record <em>definition</em> information, and record
9829 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9830 * to access Records cached in an {@link Roo.data.Store} object.<br>
9832 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9833 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9836 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9838 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9839 * {@link #create}. The parameters are the same.
9840 * @param {Array} data An associative Array of data values keyed by the field name.
9841 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9842 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9843 * not specified an integer id is generated.
9845 Roo.data.Record = function(data, id){
9846 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9851 * Generate a constructor for a specific record layout.
9852 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9853 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9854 * Each field definition object may contain the following properties: <ul>
9855 * <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,
9856 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9857 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9858 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9859 * is being used, then this is a string containing the javascript expression to reference the data relative to
9860 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9861 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9862 * this may be omitted.</p></li>
9863 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9864 * <ul><li>auto (Default, implies no conversion)</li>
9869 * <li>date</li></ul></p></li>
9870 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9871 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9872 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9873 * by the Reader into an object that will be stored in the Record. It is passed the
9874 * following parameters:<ul>
9875 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9877 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9879 * <br>usage:<br><pre><code>
9880 var TopicRecord = Roo.data.Record.create(
9881 {name: 'title', mapping: 'topic_title'},
9882 {name: 'author', mapping: 'username'},
9883 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9884 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9885 {name: 'lastPoster', mapping: 'user2'},
9886 {name: 'excerpt', mapping: 'post_text'}
9889 var myNewRecord = new TopicRecord({
9890 title: 'Do my job please',
9893 lastPost: new Date(),
9894 lastPoster: 'Animal',
9895 excerpt: 'No way dude!'
9897 myStore.add(myNewRecord);
9902 Roo.data.Record.create = function(o){
9904 f.superclass.constructor.apply(this, arguments);
9906 Roo.extend(f, Roo.data.Record);
9907 var p = f.prototype;
9908 p.fields = new Roo.util.MixedCollection(false, function(field){
9911 for(var i = 0, len = o.length; i < len; i++){
9912 p.fields.add(new Roo.data.Field(o[i]));
9914 f.getField = function(name){
9915 return p.fields.get(name);
9920 Roo.data.Record.AUTO_ID = 1000;
9921 Roo.data.Record.EDIT = 'edit';
9922 Roo.data.Record.REJECT = 'reject';
9923 Roo.data.Record.COMMIT = 'commit';
9925 Roo.data.Record.prototype = {
9927 * Readonly flag - true if this record has been modified.
9936 join : function(store){
9941 * Set the named field to the specified value.
9942 * @param {String} name The name of the field to set.
9943 * @param {Object} value The value to set the field to.
9945 set : function(name, value){
9946 if(this.data[name] == value){
9953 if(typeof this.modified[name] == 'undefined'){
9954 this.modified[name] = this.data[name];
9956 this.data[name] = value;
9957 if(!this.editing && this.store){
9958 this.store.afterEdit(this);
9963 * Get the value of the named field.
9964 * @param {String} name The name of the field to get the value of.
9965 * @return {Object} The value of the field.
9967 get : function(name){
9968 return this.data[name];
9972 beginEdit : function(){
9973 this.editing = true;
9978 cancelEdit : function(){
9979 this.editing = false;
9980 delete this.modified;
9984 endEdit : function(){
9985 this.editing = false;
9986 if(this.dirty && this.store){
9987 this.store.afterEdit(this);
9992 * Usually called by the {@link Roo.data.Store} which owns the Record.
9993 * Rejects all changes made to the Record since either creation, or the last commit operation.
9994 * Modified fields are reverted to their original values.
9996 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9997 * of reject operations.
9999 reject : function(){
10000 var m = this.modified;
10002 if(typeof m[n] != "function"){
10003 this.data[n] = m[n];
10006 this.dirty = false;
10007 delete this.modified;
10008 this.editing = false;
10010 this.store.afterReject(this);
10015 * Usually called by the {@link Roo.data.Store} which owns the Record.
10016 * Commits all changes made to the Record since either creation, or the last commit operation.
10018 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10019 * of commit operations.
10021 commit : function(){
10022 this.dirty = false;
10023 delete this.modified;
10024 this.editing = false;
10026 this.store.afterCommit(this);
10031 hasError : function(){
10032 return this.error != null;
10036 clearError : function(){
10041 * Creates a copy of this record.
10042 * @param {String} id (optional) A new record id if you don't want to use this record's id
10045 copy : function(newId) {
10046 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10050 * Ext JS Library 1.1.1
10051 * Copyright(c) 2006-2007, Ext JS, LLC.
10053 * Originally Released Under LGPL - original licence link has changed is not relivant.
10056 * <script type="text/javascript">
10062 * @class Roo.data.Store
10063 * @extends Roo.util.Observable
10064 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10065 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10067 * 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
10068 * has no knowledge of the format of the data returned by the Proxy.<br>
10070 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10071 * instances from the data object. These records are cached and made available through accessor functions.
10073 * Creates a new Store.
10074 * @param {Object} config A config object containing the objects needed for the Store to access data,
10075 * and read the data into Records.
10077 Roo.data.Store = function(config){
10078 this.data = new Roo.util.MixedCollection(false);
10079 this.data.getKey = function(o){
10082 this.baseParams = {};
10084 this.paramNames = {
10089 "multisort" : "_multisort"
10092 if(config && config.data){
10093 this.inlineData = config.data;
10094 delete config.data;
10097 Roo.apply(this, config);
10099 if(this.reader){ // reader passed
10100 this.reader = Roo.factory(this.reader, Roo.data);
10101 this.reader.xmodule = this.xmodule || false;
10102 if(!this.recordType){
10103 this.recordType = this.reader.recordType;
10105 if(this.reader.onMetaChange){
10106 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10110 if(this.recordType){
10111 this.fields = this.recordType.prototype.fields;
10113 this.modified = [];
10117 * @event datachanged
10118 * Fires when the data cache has changed, and a widget which is using this Store
10119 * as a Record cache should refresh its view.
10120 * @param {Store} this
10122 datachanged : true,
10124 * @event metachange
10125 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10126 * @param {Store} this
10127 * @param {Object} meta The JSON metadata
10132 * Fires when Records have been added to the Store
10133 * @param {Store} this
10134 * @param {Roo.data.Record[]} records The array of Records added
10135 * @param {Number} index The index at which the record(s) were added
10140 * Fires when a Record has been removed from the Store
10141 * @param {Store} this
10142 * @param {Roo.data.Record} record The Record that was removed
10143 * @param {Number} index The index at which the record was removed
10148 * Fires when a Record has been updated
10149 * @param {Store} this
10150 * @param {Roo.data.Record} record The Record that was updated
10151 * @param {String} operation The update operation being performed. Value may be one of:
10153 Roo.data.Record.EDIT
10154 Roo.data.Record.REJECT
10155 Roo.data.Record.COMMIT
10161 * Fires when the data cache has been cleared.
10162 * @param {Store} this
10166 * @event beforeload
10167 * Fires before a request is made for a new data object. If the beforeload handler returns false
10168 * the load action will be canceled.
10169 * @param {Store} this
10170 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10174 * @event beforeloadadd
10175 * Fires after a new set of Records has been loaded.
10176 * @param {Store} this
10177 * @param {Roo.data.Record[]} records The Records that were loaded
10178 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10180 beforeloadadd : true,
10183 * Fires after a new set of Records has been loaded, before they are added to the store.
10184 * @param {Store} this
10185 * @param {Roo.data.Record[]} records The Records that were loaded
10186 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10187 * @params {Object} return from reader
10191 * @event loadexception
10192 * Fires if an exception occurs in the Proxy during loading.
10193 * Called with the signature of the Proxy's "loadexception" event.
10194 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10197 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10198 * @param {Object} load options
10199 * @param {Object} jsonData from your request (normally this contains the Exception)
10201 loadexception : true
10205 this.proxy = Roo.factory(this.proxy, Roo.data);
10206 this.proxy.xmodule = this.xmodule || false;
10207 this.relayEvents(this.proxy, ["loadexception"]);
10209 this.sortToggle = {};
10210 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10212 Roo.data.Store.superclass.constructor.call(this);
10214 if(this.inlineData){
10215 this.loadData(this.inlineData);
10216 delete this.inlineData;
10220 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10222 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10223 * without a remote query - used by combo/forms at present.
10227 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10230 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10233 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10234 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10237 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10238 * on any HTTP request
10241 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10244 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10248 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10249 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10251 remoteSort : false,
10254 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10255 * loaded or when a record is removed. (defaults to false).
10257 pruneModifiedRecords : false,
10260 lastOptions : null,
10263 * Add Records to the Store and fires the add event.
10264 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10266 add : function(records){
10267 records = [].concat(records);
10268 for(var i = 0, len = records.length; i < len; i++){
10269 records[i].join(this);
10271 var index = this.data.length;
10272 this.data.addAll(records);
10273 this.fireEvent("add", this, records, index);
10277 * Remove a Record from the Store and fires the remove event.
10278 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10280 remove : function(record){
10281 var index = this.data.indexOf(record);
10282 this.data.removeAt(index);
10283 if(this.pruneModifiedRecords){
10284 this.modified.remove(record);
10286 this.fireEvent("remove", this, record, index);
10290 * Remove all Records from the Store and fires the clear event.
10292 removeAll : function(){
10294 if(this.pruneModifiedRecords){
10295 this.modified = [];
10297 this.fireEvent("clear", this);
10301 * Inserts Records to the Store at the given index and fires the add event.
10302 * @param {Number} index The start index at which to insert the passed Records.
10303 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10305 insert : function(index, records){
10306 records = [].concat(records);
10307 for(var i = 0, len = records.length; i < len; i++){
10308 this.data.insert(index, records[i]);
10309 records[i].join(this);
10311 this.fireEvent("add", this, records, index);
10315 * Get the index within the cache of the passed Record.
10316 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10317 * @return {Number} The index of the passed Record. Returns -1 if not found.
10319 indexOf : function(record){
10320 return this.data.indexOf(record);
10324 * Get the index within the cache of the Record with the passed id.
10325 * @param {String} id The id of the Record to find.
10326 * @return {Number} The index of the Record. Returns -1 if not found.
10328 indexOfId : function(id){
10329 return this.data.indexOfKey(id);
10333 * Get the Record with the specified id.
10334 * @param {String} id The id of the Record to find.
10335 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10337 getById : function(id){
10338 return this.data.key(id);
10342 * Get the Record at the specified index.
10343 * @param {Number} index The index of the Record to find.
10344 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10346 getAt : function(index){
10347 return this.data.itemAt(index);
10351 * Returns a range of Records between specified indices.
10352 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10353 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10354 * @return {Roo.data.Record[]} An array of Records
10356 getRange : function(start, end){
10357 return this.data.getRange(start, end);
10361 storeOptions : function(o){
10362 o = Roo.apply({}, o);
10365 this.lastOptions = o;
10369 * Loads the Record cache from the configured Proxy using the configured Reader.
10371 * If using remote paging, then the first load call must specify the <em>start</em>
10372 * and <em>limit</em> properties in the options.params property to establish the initial
10373 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10375 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10376 * and this call will return before the new data has been loaded. Perform any post-processing
10377 * in a callback function, or in a "load" event handler.</strong>
10379 * @param {Object} options An object containing properties which control loading options:<ul>
10380 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10381 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10382 * passed the following arguments:<ul>
10383 * <li>r : Roo.data.Record[]</li>
10384 * <li>options: Options object from the load call</li>
10385 * <li>success: Boolean success indicator</li></ul></li>
10386 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10387 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10390 load : function(options){
10391 options = options || {};
10392 if(this.fireEvent("beforeload", this, options) !== false){
10393 this.storeOptions(options);
10394 var p = Roo.apply(options.params || {}, this.baseParams);
10395 // if meta was not loaded from remote source.. try requesting it.
10396 if (!this.reader.metaFromRemote) {
10397 p._requestMeta = 1;
10399 if(this.sortInfo && this.remoteSort){
10400 var pn = this.paramNames;
10401 p[pn["sort"]] = this.sortInfo.field;
10402 p[pn["dir"]] = this.sortInfo.direction;
10404 if (this.multiSort) {
10405 var pn = this.paramNames;
10406 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10409 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10414 * Reloads the Record cache from the configured Proxy using the configured Reader and
10415 * the options from the last load operation performed.
10416 * @param {Object} options (optional) An object containing properties which may override the options
10417 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10418 * the most recently used options are reused).
10420 reload : function(options){
10421 this.load(Roo.applyIf(options||{}, this.lastOptions));
10425 // Called as a callback by the Reader during a load operation.
10426 loadRecords : function(o, options, success){
10427 if(!o || success === false){
10428 if(success !== false){
10429 this.fireEvent("load", this, [], options, o);
10431 if(options.callback){
10432 options.callback.call(options.scope || this, [], options, false);
10436 // if data returned failure - throw an exception.
10437 if (o.success === false) {
10438 // show a message if no listener is registered.
10439 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10440 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10442 // loadmask wil be hooked into this..
10443 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10446 var r = o.records, t = o.totalRecords || r.length;
10448 this.fireEvent("beforeloadadd", this, r, options, o);
10450 if(!options || options.add !== true){
10451 if(this.pruneModifiedRecords){
10452 this.modified = [];
10454 for(var i = 0, len = r.length; i < len; i++){
10458 this.data = this.snapshot;
10459 delete this.snapshot;
10462 this.data.addAll(r);
10463 this.totalLength = t;
10465 this.fireEvent("datachanged", this);
10467 this.totalLength = Math.max(t, this.data.length+r.length);
10470 this.fireEvent("load", this, r, options, o);
10471 if(options.callback){
10472 options.callback.call(options.scope || this, r, options, true);
10478 * Loads data from a passed data block. A Reader which understands the format of the data
10479 * must have been configured in the constructor.
10480 * @param {Object} data The data block from which to read the Records. The format of the data expected
10481 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10482 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10484 loadData : function(o, append){
10485 var r = this.reader.readRecords(o);
10486 this.loadRecords(r, {add: append}, true);
10490 * Gets the number of cached records.
10492 * <em>If using paging, this may not be the total size of the dataset. If the data object
10493 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10494 * the data set size</em>
10496 getCount : function(){
10497 return this.data.length || 0;
10501 * Gets the total number of records in the dataset as returned by the server.
10503 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10504 * the dataset size</em>
10506 getTotalCount : function(){
10507 return this.totalLength || 0;
10511 * Returns the sort state of the Store as an object with two properties:
10513 field {String} The name of the field by which the Records are sorted
10514 direction {String} The sort order, "ASC" or "DESC"
10517 getSortState : function(){
10518 return this.sortInfo;
10522 applySort : function(){
10523 if(this.sortInfo && !this.remoteSort){
10524 var s = this.sortInfo, f = s.field;
10525 var st = this.fields.get(f).sortType;
10526 var fn = function(r1, r2){
10527 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10528 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10530 this.data.sort(s.direction, fn);
10531 if(this.snapshot && this.snapshot != this.data){
10532 this.snapshot.sort(s.direction, fn);
10538 * Sets the default sort column and order to be used by the next load operation.
10539 * @param {String} fieldName The name of the field to sort by.
10540 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10542 setDefaultSort : function(field, dir){
10543 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10547 * Sort the Records.
10548 * If remote sorting is used, the sort is performed on the server, and the cache is
10549 * reloaded. If local sorting is used, the cache is sorted internally.
10550 * @param {String} fieldName The name of the field to sort by.
10551 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10553 sort : function(fieldName, dir){
10554 var f = this.fields.get(fieldName);
10556 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10558 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10559 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10564 this.sortToggle[f.name] = dir;
10565 this.sortInfo = {field: f.name, direction: dir};
10566 if(!this.remoteSort){
10568 this.fireEvent("datachanged", this);
10570 this.load(this.lastOptions);
10575 * Calls the specified function for each of the Records in the cache.
10576 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10577 * Returning <em>false</em> aborts and exits the iteration.
10578 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10580 each : function(fn, scope){
10581 this.data.each(fn, scope);
10585 * Gets all records modified since the last commit. Modified records are persisted across load operations
10586 * (e.g., during paging).
10587 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10589 getModifiedRecords : function(){
10590 return this.modified;
10594 createFilterFn : function(property, value, anyMatch){
10595 if(!value.exec){ // not a regex
10596 value = String(value);
10597 if(value.length == 0){
10600 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10602 return function(r){
10603 return value.test(r.data[property]);
10608 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10609 * @param {String} property A field on your records
10610 * @param {Number} start The record index to start at (defaults to 0)
10611 * @param {Number} end The last record index to include (defaults to length - 1)
10612 * @return {Number} The sum
10614 sum : function(property, start, end){
10615 var rs = this.data.items, v = 0;
10616 start = start || 0;
10617 end = (end || end === 0) ? end : rs.length-1;
10619 for(var i = start; i <= end; i++){
10620 v += (rs[i].data[property] || 0);
10626 * Filter the records by a specified property.
10627 * @param {String} field A field on your records
10628 * @param {String/RegExp} value Either a string that the field
10629 * should start with or a RegExp to test against the field
10630 * @param {Boolean} anyMatch True to match any part not just the beginning
10632 filter : function(property, value, anyMatch){
10633 var fn = this.createFilterFn(property, value, anyMatch);
10634 return fn ? this.filterBy(fn) : this.clearFilter();
10638 * Filter by a function. The specified function will be called with each
10639 * record in this data source. If the function returns true the record is included,
10640 * otherwise it is filtered.
10641 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10642 * @param {Object} scope (optional) The scope of the function (defaults to this)
10644 filterBy : function(fn, scope){
10645 this.snapshot = this.snapshot || this.data;
10646 this.data = this.queryBy(fn, scope||this);
10647 this.fireEvent("datachanged", this);
10651 * Query the records by a specified property.
10652 * @param {String} field A field on your records
10653 * @param {String/RegExp} value Either a string that the field
10654 * should start with or a RegExp to test against the field
10655 * @param {Boolean} anyMatch True to match any part not just the beginning
10656 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10658 query : function(property, value, anyMatch){
10659 var fn = this.createFilterFn(property, value, anyMatch);
10660 return fn ? this.queryBy(fn) : this.data.clone();
10664 * Query by a function. The specified function will be called with each
10665 * record in this data source. If the function returns true the record is included
10667 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10668 * @param {Object} scope (optional) The scope of the function (defaults to this)
10669 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10671 queryBy : function(fn, scope){
10672 var data = this.snapshot || this.data;
10673 return data.filterBy(fn, scope||this);
10677 * Collects unique values for a particular dataIndex from this store.
10678 * @param {String} dataIndex The property to collect
10679 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10680 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10681 * @return {Array} An array of the unique values
10683 collect : function(dataIndex, allowNull, bypassFilter){
10684 var d = (bypassFilter === true && this.snapshot) ?
10685 this.snapshot.items : this.data.items;
10686 var v, sv, r = [], l = {};
10687 for(var i = 0, len = d.length; i < len; i++){
10688 v = d[i].data[dataIndex];
10690 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10699 * Revert to a view of the Record cache with no filtering applied.
10700 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10702 clearFilter : function(suppressEvent){
10703 if(this.snapshot && this.snapshot != this.data){
10704 this.data = this.snapshot;
10705 delete this.snapshot;
10706 if(suppressEvent !== true){
10707 this.fireEvent("datachanged", this);
10713 afterEdit : function(record){
10714 if(this.modified.indexOf(record) == -1){
10715 this.modified.push(record);
10717 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10721 afterReject : function(record){
10722 this.modified.remove(record);
10723 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10727 afterCommit : function(record){
10728 this.modified.remove(record);
10729 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10733 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10734 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10736 commitChanges : function(){
10737 var m = this.modified.slice(0);
10738 this.modified = [];
10739 for(var i = 0, len = m.length; i < len; i++){
10745 * Cancel outstanding changes on all changed records.
10747 rejectChanges : function(){
10748 var m = this.modified.slice(0);
10749 this.modified = [];
10750 for(var i = 0, len = m.length; i < len; i++){
10755 onMetaChange : function(meta, rtype, o){
10756 this.recordType = rtype;
10757 this.fields = rtype.prototype.fields;
10758 delete this.snapshot;
10759 this.sortInfo = meta.sortInfo || this.sortInfo;
10760 this.modified = [];
10761 this.fireEvent('metachange', this, this.reader.meta);
10764 moveIndex : function(data, type)
10766 var index = this.indexOf(data);
10768 var newIndex = index + type;
10772 this.insert(newIndex, data);
10777 * Ext JS Library 1.1.1
10778 * Copyright(c) 2006-2007, Ext JS, LLC.
10780 * Originally Released Under LGPL - original licence link has changed is not relivant.
10783 * <script type="text/javascript">
10787 * @class Roo.data.SimpleStore
10788 * @extends Roo.data.Store
10789 * Small helper class to make creating Stores from Array data easier.
10790 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10791 * @cfg {Array} fields An array of field definition objects, or field name strings.
10792 * @cfg {Array} data The multi-dimensional array of data
10794 * @param {Object} config
10796 Roo.data.SimpleStore = function(config){
10797 Roo.data.SimpleStore.superclass.constructor.call(this, {
10799 reader: new Roo.data.ArrayReader({
10802 Roo.data.Record.create(config.fields)
10804 proxy : new Roo.data.MemoryProxy(config.data)
10808 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10810 * Ext JS Library 1.1.1
10811 * Copyright(c) 2006-2007, Ext JS, LLC.
10813 * Originally Released Under LGPL - original licence link has changed is not relivant.
10816 * <script type="text/javascript">
10821 * @extends Roo.data.Store
10822 * @class Roo.data.JsonStore
10823 * Small helper class to make creating Stores for JSON data easier. <br/>
10825 var store = new Roo.data.JsonStore({
10826 url: 'get-images.php',
10828 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10831 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10832 * JsonReader and HttpProxy (unless inline data is provided).</b>
10833 * @cfg {Array} fields An array of field definition objects, or field name strings.
10835 * @param {Object} config
10837 Roo.data.JsonStore = function(c){
10838 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10839 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10840 reader: new Roo.data.JsonReader(c, c.fields)
10843 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10845 * Ext JS Library 1.1.1
10846 * Copyright(c) 2006-2007, Ext JS, LLC.
10848 * Originally Released Under LGPL - original licence link has changed is not relivant.
10851 * <script type="text/javascript">
10855 Roo.data.Field = function(config){
10856 if(typeof config == "string"){
10857 config = {name: config};
10859 Roo.apply(this, config);
10862 this.type = "auto";
10865 var st = Roo.data.SortTypes;
10866 // named sortTypes are supported, here we look them up
10867 if(typeof this.sortType == "string"){
10868 this.sortType = st[this.sortType];
10871 // set default sortType for strings and dates
10872 if(!this.sortType){
10875 this.sortType = st.asUCString;
10878 this.sortType = st.asDate;
10881 this.sortType = st.none;
10886 var stripRe = /[\$,%]/g;
10888 // prebuilt conversion function for this field, instead of
10889 // switching every time we're reading a value
10891 var cv, dateFormat = this.dateFormat;
10896 cv = function(v){ return v; };
10899 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10903 return v !== undefined && v !== null && v !== '' ?
10904 parseInt(String(v).replace(stripRe, ""), 10) : '';
10909 return v !== undefined && v !== null && v !== '' ?
10910 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10915 cv = function(v){ return v === true || v === "true" || v == 1; };
10922 if(v instanceof Date){
10926 if(dateFormat == "timestamp"){
10927 return new Date(v*1000);
10929 return Date.parseDate(v, dateFormat);
10931 var parsed = Date.parse(v);
10932 return parsed ? new Date(parsed) : null;
10941 Roo.data.Field.prototype = {
10949 * Ext JS Library 1.1.1
10950 * Copyright(c) 2006-2007, Ext JS, LLC.
10952 * Originally Released Under LGPL - original licence link has changed is not relivant.
10955 * <script type="text/javascript">
10958 // Base class for reading structured data from a data source. This class is intended to be
10959 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10962 * @class Roo.data.DataReader
10963 * Base class for reading structured data from a data source. This class is intended to be
10964 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10967 Roo.data.DataReader = function(meta, recordType){
10971 this.recordType = recordType instanceof Array ?
10972 Roo.data.Record.create(recordType) : recordType;
10975 Roo.data.DataReader.prototype = {
10977 * Create an empty record
10978 * @param {Object} data (optional) - overlay some values
10979 * @return {Roo.data.Record} record created.
10981 newRow : function(d) {
10983 this.recordType.prototype.fields.each(function(c) {
10985 case 'int' : da[c.name] = 0; break;
10986 case 'date' : da[c.name] = new Date(); break;
10987 case 'float' : da[c.name] = 0.0; break;
10988 case 'boolean' : da[c.name] = false; break;
10989 default : da[c.name] = ""; break;
10993 return new this.recordType(Roo.apply(da, d));
10998 * Ext JS Library 1.1.1
10999 * Copyright(c) 2006-2007, Ext JS, LLC.
11001 * Originally Released Under LGPL - original licence link has changed is not relivant.
11004 * <script type="text/javascript">
11008 * @class Roo.data.DataProxy
11009 * @extends Roo.data.Observable
11010 * This class is an abstract base class for implementations which provide retrieval of
11011 * unformatted data objects.<br>
11013 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11014 * (of the appropriate type which knows how to parse the data object) to provide a block of
11015 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11017 * Custom implementations must implement the load method as described in
11018 * {@link Roo.data.HttpProxy#load}.
11020 Roo.data.DataProxy = function(){
11023 * @event beforeload
11024 * Fires before a network request is made to retrieve a data object.
11025 * @param {Object} This DataProxy object.
11026 * @param {Object} params The params parameter to the load function.
11031 * Fires before the load method's callback is called.
11032 * @param {Object} This DataProxy object.
11033 * @param {Object} o The data object.
11034 * @param {Object} arg The callback argument object passed to the load function.
11038 * @event loadexception
11039 * Fires if an Exception occurs during data retrieval.
11040 * @param {Object} This DataProxy object.
11041 * @param {Object} o The data object.
11042 * @param {Object} arg The callback argument object passed to the load function.
11043 * @param {Object} e The Exception.
11045 loadexception : true
11047 Roo.data.DataProxy.superclass.constructor.call(this);
11050 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11053 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11057 * Ext JS Library 1.1.1
11058 * Copyright(c) 2006-2007, Ext JS, LLC.
11060 * Originally Released Under LGPL - original licence link has changed is not relivant.
11063 * <script type="text/javascript">
11066 * @class Roo.data.MemoryProxy
11067 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11068 * to the Reader when its load method is called.
11070 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11072 Roo.data.MemoryProxy = function(data){
11076 Roo.data.MemoryProxy.superclass.constructor.call(this);
11080 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11083 * Load data from the requested source (in this case an in-memory
11084 * data object passed to the constructor), read the data object into
11085 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11086 * process that block using the passed callback.
11087 * @param {Object} params This parameter is not used by the MemoryProxy class.
11088 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11089 * object into a block of Roo.data.Records.
11090 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11091 * The function must be passed <ul>
11092 * <li>The Record block object</li>
11093 * <li>The "arg" argument from the load function</li>
11094 * <li>A boolean success indicator</li>
11096 * @param {Object} scope The scope in which to call the callback
11097 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11099 load : function(params, reader, callback, scope, arg){
11100 params = params || {};
11103 result = reader.readRecords(this.data);
11105 this.fireEvent("loadexception", this, arg, null, e);
11106 callback.call(scope, null, arg, false);
11109 callback.call(scope, result, arg, true);
11113 update : function(params, records){
11118 * Ext JS Library 1.1.1
11119 * Copyright(c) 2006-2007, Ext JS, LLC.
11121 * Originally Released Under LGPL - original licence link has changed is not relivant.
11124 * <script type="text/javascript">
11127 * @class Roo.data.HttpProxy
11128 * @extends Roo.data.DataProxy
11129 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11130 * configured to reference a certain URL.<br><br>
11132 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11133 * from which the running page was served.<br><br>
11135 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11137 * Be aware that to enable the browser to parse an XML document, the server must set
11138 * the Content-Type header in the HTTP response to "text/xml".
11140 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11141 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11142 * will be used to make the request.
11144 Roo.data.HttpProxy = function(conn){
11145 Roo.data.HttpProxy.superclass.constructor.call(this);
11146 // is conn a conn config or a real conn?
11148 this.useAjax = !conn || !conn.events;
11152 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11153 // thse are take from connection...
11156 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11159 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11160 * extra parameters to each request made by this object. (defaults to undefined)
11163 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11164 * to each request made by this object. (defaults to undefined)
11167 * @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)
11170 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11173 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11179 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11183 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11184 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11185 * a finer-grained basis than the DataProxy events.
11187 getConnection : function(){
11188 return this.useAjax ? Roo.Ajax : this.conn;
11192 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11193 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11194 * process that block using the passed callback.
11195 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11196 * for the request to the remote server.
11197 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11198 * object into a block of Roo.data.Records.
11199 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11200 * The function must be passed <ul>
11201 * <li>The Record block object</li>
11202 * <li>The "arg" argument from the load function</li>
11203 * <li>A boolean success indicator</li>
11205 * @param {Object} scope The scope in which to call the callback
11206 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11208 load : function(params, reader, callback, scope, arg){
11209 if(this.fireEvent("beforeload", this, params) !== false){
11211 params : params || {},
11213 callback : callback,
11218 callback : this.loadResponse,
11222 Roo.applyIf(o, this.conn);
11223 if(this.activeRequest){
11224 Roo.Ajax.abort(this.activeRequest);
11226 this.activeRequest = Roo.Ajax.request(o);
11228 this.conn.request(o);
11231 callback.call(scope||this, null, arg, false);
11236 loadResponse : function(o, success, response){
11237 delete this.activeRequest;
11239 this.fireEvent("loadexception", this, o, response);
11240 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11245 result = o.reader.read(response);
11247 this.fireEvent("loadexception", this, o, response, e);
11248 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11252 this.fireEvent("load", this, o, o.request.arg);
11253 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11257 update : function(dataSet){
11262 updateResponse : function(dataSet){
11267 * Ext JS Library 1.1.1
11268 * Copyright(c) 2006-2007, Ext JS, LLC.
11270 * Originally Released Under LGPL - original licence link has changed is not relivant.
11273 * <script type="text/javascript">
11277 * @class Roo.data.ScriptTagProxy
11278 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11279 * other than the originating domain of the running page.<br><br>
11281 * <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
11282 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11284 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11285 * source code that is used as the source inside a <script> tag.<br><br>
11287 * In order for the browser to process the returned data, the server must wrap the data object
11288 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11289 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11290 * depending on whether the callback name was passed:
11293 boolean scriptTag = false;
11294 String cb = request.getParameter("callback");
11297 response.setContentType("text/javascript");
11299 response.setContentType("application/x-json");
11301 Writer out = response.getWriter();
11303 out.write(cb + "(");
11305 out.print(dataBlock.toJsonString());
11312 * @param {Object} config A configuration object.
11314 Roo.data.ScriptTagProxy = function(config){
11315 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11316 Roo.apply(this, config);
11317 this.head = document.getElementsByTagName("head")[0];
11320 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11322 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11324 * @cfg {String} url The URL from which to request the data object.
11327 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11331 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11332 * the server the name of the callback function set up by the load call to process the returned data object.
11333 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11334 * javascript output which calls this named function passing the data object as its only parameter.
11336 callbackParam : "callback",
11338 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11339 * name to the request.
11344 * Load data from the configured URL, read the data object into
11345 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11346 * process that block using the passed callback.
11347 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11348 * for the request to the remote server.
11349 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11350 * object into a block of Roo.data.Records.
11351 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11352 * The function must be passed <ul>
11353 * <li>The Record block object</li>
11354 * <li>The "arg" argument from the load function</li>
11355 * <li>A boolean success indicator</li>
11357 * @param {Object} scope The scope in which to call the callback
11358 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11360 load : function(params, reader, callback, scope, arg){
11361 if(this.fireEvent("beforeload", this, params) !== false){
11363 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11365 var url = this.url;
11366 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11368 url += "&_dc=" + (new Date().getTime());
11370 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11373 cb : "stcCallback"+transId,
11374 scriptId : "stcScript"+transId,
11378 callback : callback,
11384 window[trans.cb] = function(o){
11385 conn.handleResponse(o, trans);
11388 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11390 if(this.autoAbort !== false){
11394 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11396 var script = document.createElement("script");
11397 script.setAttribute("src", url);
11398 script.setAttribute("type", "text/javascript");
11399 script.setAttribute("id", trans.scriptId);
11400 this.head.appendChild(script);
11402 this.trans = trans;
11404 callback.call(scope||this, null, arg, false);
11409 isLoading : function(){
11410 return this.trans ? true : false;
11414 * Abort the current server request.
11416 abort : function(){
11417 if(this.isLoading()){
11418 this.destroyTrans(this.trans);
11423 destroyTrans : function(trans, isLoaded){
11424 this.head.removeChild(document.getElementById(trans.scriptId));
11425 clearTimeout(trans.timeoutId);
11427 window[trans.cb] = undefined;
11429 delete window[trans.cb];
11432 // if hasn't been loaded, wait for load to remove it to prevent script error
11433 window[trans.cb] = function(){
11434 window[trans.cb] = undefined;
11436 delete window[trans.cb];
11443 handleResponse : function(o, trans){
11444 this.trans = false;
11445 this.destroyTrans(trans, true);
11448 result = trans.reader.readRecords(o);
11450 this.fireEvent("loadexception", this, o, trans.arg, e);
11451 trans.callback.call(trans.scope||window, null, trans.arg, false);
11454 this.fireEvent("load", this, o, trans.arg);
11455 trans.callback.call(trans.scope||window, result, trans.arg, true);
11459 handleFailure : function(trans){
11460 this.trans = false;
11461 this.destroyTrans(trans, false);
11462 this.fireEvent("loadexception", this, null, trans.arg);
11463 trans.callback.call(trans.scope||window, null, trans.arg, false);
11467 * Ext JS Library 1.1.1
11468 * Copyright(c) 2006-2007, Ext JS, LLC.
11470 * Originally Released Under LGPL - original licence link has changed is not relivant.
11473 * <script type="text/javascript">
11477 * @class Roo.data.JsonReader
11478 * @extends Roo.data.DataReader
11479 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11480 * based on mappings in a provided Roo.data.Record constructor.
11482 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11483 * in the reply previously.
11488 var RecordDef = Roo.data.Record.create([
11489 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11490 {name: 'occupation'} // This field will use "occupation" as the mapping.
11492 var myReader = new Roo.data.JsonReader({
11493 totalProperty: "results", // The property which contains the total dataset size (optional)
11494 root: "rows", // The property which contains an Array of row objects
11495 id: "id" // The property within each row object that provides an ID for the record (optional)
11499 * This would consume a JSON file like this:
11501 { 'results': 2, 'rows': [
11502 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11503 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11506 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11507 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11508 * paged from the remote server.
11509 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11510 * @cfg {String} root name of the property which contains the Array of row objects.
11511 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11512 * @cfg {Array} fields Array of field definition objects
11514 * Create a new JsonReader
11515 * @param {Object} meta Metadata configuration options
11516 * @param {Object} recordType Either an Array of field definition objects,
11517 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11519 Roo.data.JsonReader = function(meta, recordType){
11522 // set some defaults:
11523 Roo.applyIf(meta, {
11524 totalProperty: 'total',
11525 successProperty : 'success',
11530 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11532 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11535 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11536 * Used by Store query builder to append _requestMeta to params.
11539 metaFromRemote : false,
11541 * This method is only used by a DataProxy which has retrieved data from a remote server.
11542 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11543 * @return {Object} data A data block which is used by an Roo.data.Store object as
11544 * a cache of Roo.data.Records.
11546 read : function(response){
11547 var json = response.responseText;
11549 var o = /* eval:var:o */ eval("("+json+")");
11551 throw {message: "JsonReader.read: Json object not found"};
11557 this.metaFromRemote = true;
11558 this.meta = o.metaData;
11559 this.recordType = Roo.data.Record.create(o.metaData.fields);
11560 this.onMetaChange(this.meta, this.recordType, o);
11562 return this.readRecords(o);
11565 // private function a store will implement
11566 onMetaChange : function(meta, recordType, o){
11573 simpleAccess: function(obj, subsc) {
11580 getJsonAccessor: function(){
11582 return function(expr) {
11584 return(re.test(expr))
11585 ? new Function("obj", "return obj." + expr)
11590 return Roo.emptyFn;
11595 * Create a data block containing Roo.data.Records from an XML document.
11596 * @param {Object} o An object which contains an Array of row objects in the property specified
11597 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11598 * which contains the total size of the dataset.
11599 * @return {Object} data A data block which is used by an Roo.data.Store object as
11600 * a cache of Roo.data.Records.
11602 readRecords : function(o){
11604 * After any data loads, the raw JSON data is available for further custom processing.
11608 var s = this.meta, Record = this.recordType,
11609 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11611 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11613 if(s.totalProperty) {
11614 this.getTotal = this.getJsonAccessor(s.totalProperty);
11616 if(s.successProperty) {
11617 this.getSuccess = this.getJsonAccessor(s.successProperty);
11619 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11621 var g = this.getJsonAccessor(s.id);
11622 this.getId = function(rec) {
11624 return (r === undefined || r === "") ? null : r;
11627 this.getId = function(){return null;};
11630 for(var jj = 0; jj < fl; jj++){
11632 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11633 this.ef[jj] = this.getJsonAccessor(map);
11637 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11638 if(s.totalProperty){
11639 var vt = parseInt(this.getTotal(o), 10);
11644 if(s.successProperty){
11645 var vs = this.getSuccess(o);
11646 if(vs === false || vs === 'false'){
11651 for(var i = 0; i < c; i++){
11654 var id = this.getId(n);
11655 for(var j = 0; j < fl; j++){
11657 var v = this.ef[j](n);
11659 Roo.log('missing convert for ' + f.name);
11663 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11665 var record = new Record(values, id);
11667 records[i] = record;
11673 totalRecords : totalRecords
11678 * Ext JS Library 1.1.1
11679 * Copyright(c) 2006-2007, Ext JS, LLC.
11681 * Originally Released Under LGPL - original licence link has changed is not relivant.
11684 * <script type="text/javascript">
11688 * @class Roo.data.ArrayReader
11689 * @extends Roo.data.DataReader
11690 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11691 * Each element of that Array represents a row of data fields. The
11692 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11693 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11697 var RecordDef = Roo.data.Record.create([
11698 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11699 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11701 var myReader = new Roo.data.ArrayReader({
11702 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11706 * This would consume an Array like this:
11708 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11710 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11712 * Create a new JsonReader
11713 * @param {Object} meta Metadata configuration options.
11714 * @param {Object} recordType Either an Array of field definition objects
11715 * as specified to {@link Roo.data.Record#create},
11716 * or an {@link Roo.data.Record} object
11717 * created using {@link Roo.data.Record#create}.
11719 Roo.data.ArrayReader = function(meta, recordType){
11720 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11723 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11725 * Create a data block containing Roo.data.Records from an XML document.
11726 * @param {Object} o An Array of row objects which represents the dataset.
11727 * @return {Object} data A data block which is used by an Roo.data.Store object as
11728 * a cache of Roo.data.Records.
11730 readRecords : function(o){
11731 var sid = this.meta ? this.meta.id : null;
11732 var recordType = this.recordType, fields = recordType.prototype.fields;
11735 for(var i = 0; i < root.length; i++){
11738 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11739 for(var j = 0, jlen = fields.length; j < jlen; j++){
11740 var f = fields.items[j];
11741 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11742 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11744 values[f.name] = v;
11746 var record = new recordType(values, id);
11748 records[records.length] = record;
11752 totalRecords : records.length
11761 * @class Roo.bootstrap.ComboBox
11762 * @extends Roo.bootstrap.TriggerField
11763 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11764 * @cfg {Boolean} append (true|false) default false
11765 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11766 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11767 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11768 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11769 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11770 * @cfg {Boolean} animate default true
11771 * @cfg {Boolean} emptyResultText only for touch device
11772 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11774 * Create a new ComboBox.
11775 * @param {Object} config Configuration options
11777 Roo.bootstrap.ComboBox = function(config){
11778 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11782 * Fires when the dropdown list is expanded
11783 * @param {Roo.bootstrap.ComboBox} combo This combo box
11788 * Fires when the dropdown list is collapsed
11789 * @param {Roo.bootstrap.ComboBox} combo This combo box
11793 * @event beforeselect
11794 * Fires before a list item is selected. Return false to cancel the selection.
11795 * @param {Roo.bootstrap.ComboBox} combo This combo box
11796 * @param {Roo.data.Record} record The data record returned from the underlying store
11797 * @param {Number} index The index of the selected item in the dropdown list
11799 'beforeselect' : true,
11802 * Fires when a list item is selected
11803 * @param {Roo.bootstrap.ComboBox} combo This combo box
11804 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11805 * @param {Number} index The index of the selected item in the dropdown list
11809 * @event beforequery
11810 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11811 * The event object passed has these properties:
11812 * @param {Roo.bootstrap.ComboBox} combo This combo box
11813 * @param {String} query The query
11814 * @param {Boolean} forceAll true to force "all" query
11815 * @param {Boolean} cancel true to cancel the query
11816 * @param {Object} e The query event object
11818 'beforequery': true,
11821 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11822 * @param {Roo.bootstrap.ComboBox} combo This combo box
11827 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11828 * @param {Roo.bootstrap.ComboBox} combo This combo box
11829 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11834 * Fires when the remove value from the combobox array
11835 * @param {Roo.bootstrap.ComboBox} combo This combo box
11839 * @event afterremove
11840 * Fires when the remove value from the combobox array
11841 * @param {Roo.bootstrap.ComboBox} combo This combo box
11843 'afterremove' : true,
11845 * @event specialfilter
11846 * Fires when specialfilter
11847 * @param {Roo.bootstrap.ComboBox} combo This combo box
11849 'specialfilter' : true,
11852 * Fires when tick the element
11853 * @param {Roo.bootstrap.ComboBox} combo This combo box
11857 * @event touchviewdisplay
11858 * Fires when touch view require special display (default is using displayField)
11859 * @param {Roo.bootstrap.ComboBox} combo This combo box
11860 * @param {Object} cfg set html .
11862 'touchviewdisplay' : true
11867 this.tickItems = [];
11869 this.selectedIndex = -1;
11870 if(this.mode == 'local'){
11871 if(config.queryDelay === undefined){
11872 this.queryDelay = 10;
11874 if(config.minChars === undefined){
11880 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11883 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11884 * rendering into an Roo.Editor, defaults to false)
11887 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11888 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11891 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11894 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11895 * the dropdown list (defaults to undefined, with no header element)
11899 * @cfg {String/Roo.Template} tpl The template to use to render the output
11903 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11905 listWidth: undefined,
11907 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11908 * mode = 'remote' or 'text' if mode = 'local')
11910 displayField: undefined,
11913 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11914 * mode = 'remote' or 'value' if mode = 'local').
11915 * Note: use of a valueField requires the user make a selection
11916 * in order for a value to be mapped.
11918 valueField: undefined,
11922 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11923 * field's data value (defaults to the underlying DOM element's name)
11925 hiddenName: undefined,
11927 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11931 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11933 selectedClass: 'active',
11936 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11940 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11941 * anchor positions (defaults to 'tl-bl')
11943 listAlign: 'tl-bl?',
11945 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11949 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11950 * query specified by the allQuery config option (defaults to 'query')
11952 triggerAction: 'query',
11954 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11955 * (defaults to 4, does not apply if editable = false)
11959 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11960 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11964 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11965 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11969 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11970 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11974 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11975 * when editable = true (defaults to false)
11977 selectOnFocus:false,
11979 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11981 queryParam: 'query',
11983 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11984 * when mode = 'remote' (defaults to 'Loading...')
11986 loadingText: 'Loading...',
11988 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11992 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11996 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11997 * traditional select (defaults to true)
12001 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12005 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12009 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12010 * listWidth has a higher value)
12014 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12015 * allow the user to set arbitrary text into the field (defaults to false)
12017 forceSelection:false,
12019 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12020 * if typeAhead = true (defaults to 250)
12022 typeAheadDelay : 250,
12024 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12025 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12027 valueNotFoundText : undefined,
12029 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12031 blockFocus : false,
12034 * @cfg {Boolean} disableClear Disable showing of clear button.
12036 disableClear : false,
12038 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12040 alwaysQuery : false,
12043 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12048 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12050 invalidClass : "has-warning",
12053 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12055 validClass : "has-success",
12058 * @cfg {Boolean} specialFilter (true|false) special filter default false
12060 specialFilter : false,
12063 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12065 mobileTouchView : true,
12077 btnPosition : 'right',
12078 triggerList : true,
12079 showToggleBtn : true,
12081 emptyResultText: 'Empty',
12082 triggerText : 'Select',
12084 // element that contains real text value.. (when hidden is used..)
12086 getAutoCreate : function()
12094 if(Roo.isTouch && this.mobileTouchView){
12095 cfg = this.getAutoCreateTouchView();
12102 if(!this.tickable){
12103 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12108 * ComboBox with tickable selections
12111 var align = this.labelAlign || this.parentLabelAlign();
12114 cls : 'form-group roo-combobox-tickable' //input-group
12119 cls : 'tickable-buttons',
12124 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12125 html : this.triggerText
12131 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12138 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12145 buttons.cn.unshift({
12147 cls: 'roo-select2-search-field-input'
12153 Roo.each(buttons.cn, function(c){
12155 c.cls += ' btn-' + _this.size;
12158 if (_this.disabled) {
12169 cls: 'form-hidden-field'
12173 cls: 'roo-select2-choices',
12177 cls: 'roo-select2-search-field',
12189 cls: 'roo-select2-container input-group roo-select2-container-multi',
12194 // cls: 'typeahead typeahead-long dropdown-menu',
12195 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12200 if(this.hasFeedback && !this.allowBlank){
12204 cls: 'glyphicon form-control-feedback'
12207 combobox.cn.push(feedback);
12210 if (align ==='left' && this.fieldLabel.length) {
12212 // Roo.log("left and has label");
12218 cls : 'control-label col-sm-' + this.labelWidth,
12219 html : this.fieldLabel
12223 cls : "col-sm-" + (12 - this.labelWidth),
12230 } else if ( this.fieldLabel.length) {
12231 // Roo.log(" label");
12236 //cls : 'input-group-addon',
12237 html : this.fieldLabel
12247 // Roo.log(" no label && no align");
12254 ['xs','sm','md','lg'].map(function(size){
12255 if (settings[size]) {
12256 cfg.cls += ' col-' + size + '-' + settings[size];
12264 _initEventsCalled : false,
12267 initEvents: function()
12270 if (this._initEventsCalled) { // as we call render... prevent looping...
12273 this._initEventsCalled = true;
12276 throw "can not find store for combo";
12279 this.store = Roo.factory(this.store, Roo.data);
12281 // if we are building from html. then this element is so complex, that we can not really
12282 // use the rendered HTML.
12283 // so we have to trash and replace the previous code.
12284 if (Roo.XComponent.build_from_html) {
12286 // remove this element....
12287 var e = this.el.dom, k=0;
12288 while (e ) { e = e.previousSibling; ++k;}
12293 this.rendered = false;
12295 this.render(this.parent().getChildContainer(true), k);
12306 if(Roo.isTouch && this.mobileTouchView){
12307 this.initTouchView();
12312 this.initTickableEvents();
12316 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12318 if(this.hiddenName){
12320 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12322 this.hiddenField.dom.value =
12323 this.hiddenValue !== undefined ? this.hiddenValue :
12324 this.value !== undefined ? this.value : '';
12326 // prevent input submission
12327 this.el.dom.removeAttribute('name');
12328 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12333 // this.el.dom.setAttribute('autocomplete', 'off');
12336 var cls = 'x-combo-list';
12338 //this.list = new Roo.Layer({
12339 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12345 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12346 _this.list.setWidth(lw);
12349 this.list.on('mouseover', this.onViewOver, this);
12350 this.list.on('mousemove', this.onViewMove, this);
12352 this.list.on('scroll', this.onViewScroll, this);
12355 this.list.swallowEvent('mousewheel');
12356 this.assetHeight = 0;
12359 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12360 this.assetHeight += this.header.getHeight();
12363 this.innerList = this.list.createChild({cls:cls+'-inner'});
12364 this.innerList.on('mouseover', this.onViewOver, this);
12365 this.innerList.on('mousemove', this.onViewMove, this);
12366 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12368 if(this.allowBlank && !this.pageSize && !this.disableClear){
12369 this.footer = this.list.createChild({cls:cls+'-ft'});
12370 this.pageTb = new Roo.Toolbar(this.footer);
12374 this.footer = this.list.createChild({cls:cls+'-ft'});
12375 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12376 {pageSize: this.pageSize});
12380 if (this.pageTb && this.allowBlank && !this.disableClear) {
12382 this.pageTb.add(new Roo.Toolbar.Fill(), {
12383 cls: 'x-btn-icon x-btn-clear',
12385 handler: function()
12388 _this.clearValue();
12389 _this.onSelect(false, -1);
12394 this.assetHeight += this.footer.getHeight();
12399 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12402 this.view = new Roo.View(this.list, this.tpl, {
12403 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12405 //this.view.wrapEl.setDisplayed(false);
12406 this.view.on('click', this.onViewClick, this);
12410 this.store.on('beforeload', this.onBeforeLoad, this);
12411 this.store.on('load', this.onLoad, this);
12412 this.store.on('loadexception', this.onLoadException, this);
12414 if(this.resizable){
12415 this.resizer = new Roo.Resizable(this.list, {
12416 pinned:true, handles:'se'
12418 this.resizer.on('resize', function(r, w, h){
12419 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12420 this.listWidth = w;
12421 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12422 this.restrictHeight();
12424 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12427 if(!this.editable){
12428 this.editable = true;
12429 this.setEditable(false);
12434 if (typeof(this.events.add.listeners) != 'undefined') {
12436 this.addicon = this.wrap.createChild(
12437 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12439 this.addicon.on('click', function(e) {
12440 this.fireEvent('add', this);
12443 if (typeof(this.events.edit.listeners) != 'undefined') {
12445 this.editicon = this.wrap.createChild(
12446 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12447 if (this.addicon) {
12448 this.editicon.setStyle('margin-left', '40px');
12450 this.editicon.on('click', function(e) {
12452 // we fire even if inothing is selected..
12453 this.fireEvent('edit', this, this.lastData );
12459 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12460 "up" : function(e){
12461 this.inKeyMode = true;
12465 "down" : function(e){
12466 if(!this.isExpanded()){
12467 this.onTriggerClick();
12469 this.inKeyMode = true;
12474 "enter" : function(e){
12475 // this.onViewClick();
12479 if(this.fireEvent("specialkey", this, e)){
12480 this.onViewClick(false);
12486 "esc" : function(e){
12490 "tab" : function(e){
12493 if(this.fireEvent("specialkey", this, e)){
12494 this.onViewClick(false);
12502 doRelay : function(foo, bar, hname){
12503 if(hname == 'down' || this.scope.isExpanded()){
12504 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12513 this.queryDelay = Math.max(this.queryDelay || 10,
12514 this.mode == 'local' ? 10 : 250);
12517 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12519 if(this.typeAhead){
12520 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12522 if(this.editable !== false){
12523 this.inputEl().on("keyup", this.onKeyUp, this);
12525 if(this.forceSelection){
12526 this.inputEl().on('blur', this.doForce, this);
12530 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12531 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12535 initTickableEvents: function()
12539 if(this.hiddenName){
12541 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12543 this.hiddenField.dom.value =
12544 this.hiddenValue !== undefined ? this.hiddenValue :
12545 this.value !== undefined ? this.value : '';
12547 // prevent input submission
12548 this.el.dom.removeAttribute('name');
12549 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12554 // this.list = this.el.select('ul.dropdown-menu',true).first();
12556 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12557 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12558 if(this.triggerList){
12559 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12562 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12563 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12565 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12566 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12568 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12569 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12571 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12572 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12573 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12576 this.cancelBtn.hide();
12581 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12582 _this.list.setWidth(lw);
12585 this.list.on('mouseover', this.onViewOver, this);
12586 this.list.on('mousemove', this.onViewMove, this);
12588 this.list.on('scroll', this.onViewScroll, this);
12591 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>';
12594 this.view = new Roo.View(this.list, this.tpl, {
12595 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12598 //this.view.wrapEl.setDisplayed(false);
12599 this.view.on('click', this.onViewClick, this);
12603 this.store.on('beforeload', this.onBeforeLoad, this);
12604 this.store.on('load', this.onLoad, this);
12605 this.store.on('loadexception', this.onLoadException, this);
12608 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12609 "up" : function(e){
12610 this.inKeyMode = true;
12614 "down" : function(e){
12615 this.inKeyMode = true;
12619 "enter" : function(e){
12620 if(this.fireEvent("specialkey", this, e)){
12621 this.onViewClick(false);
12627 "esc" : function(e){
12628 this.onTickableFooterButtonClick(e, false, false);
12631 "tab" : function(e){
12632 this.fireEvent("specialkey", this, e);
12634 this.onTickableFooterButtonClick(e, false, false);
12641 doRelay : function(e, fn, key){
12642 if(this.scope.isExpanded()){
12643 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12652 this.queryDelay = Math.max(this.queryDelay || 10,
12653 this.mode == 'local' ? 10 : 250);
12656 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12658 if(this.typeAhead){
12659 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12662 if(this.editable !== false){
12663 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12668 onDestroy : function(){
12670 this.view.setStore(null);
12671 this.view.el.removeAllListeners();
12672 this.view.el.remove();
12673 this.view.purgeListeners();
12676 this.list.dom.innerHTML = '';
12680 this.store.un('beforeload', this.onBeforeLoad, this);
12681 this.store.un('load', this.onLoad, this);
12682 this.store.un('loadexception', this.onLoadException, this);
12684 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12688 fireKey : function(e){
12689 if(e.isNavKeyPress() && !this.list.isVisible()){
12690 this.fireEvent("specialkey", this, e);
12695 onResize: function(w, h){
12696 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12698 // if(typeof w != 'number'){
12699 // // we do not handle it!?!?
12702 // var tw = this.trigger.getWidth();
12703 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12704 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12706 // this.inputEl().setWidth( this.adjustWidth('input', x));
12708 // //this.trigger.setStyle('left', x+'px');
12710 // if(this.list && this.listWidth === undefined){
12711 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12712 // this.list.setWidth(lw);
12713 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12721 * Allow or prevent the user from directly editing the field text. If false is passed,
12722 * the user will only be able to select from the items defined in the dropdown list. This method
12723 * is the runtime equivalent of setting the 'editable' config option at config time.
12724 * @param {Boolean} value True to allow the user to directly edit the field text
12726 setEditable : function(value){
12727 if(value == this.editable){
12730 this.editable = value;
12732 this.inputEl().dom.setAttribute('readOnly', true);
12733 this.inputEl().on('mousedown', this.onTriggerClick, this);
12734 this.inputEl().addClass('x-combo-noedit');
12736 this.inputEl().dom.setAttribute('readOnly', false);
12737 this.inputEl().un('mousedown', this.onTriggerClick, this);
12738 this.inputEl().removeClass('x-combo-noedit');
12744 onBeforeLoad : function(combo,opts){
12745 if(!this.hasFocus){
12749 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12751 this.restrictHeight();
12752 this.selectedIndex = -1;
12756 onLoad : function(){
12758 this.hasQuery = false;
12760 if(!this.hasFocus){
12764 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12765 this.loading.hide();
12768 if(this.store.getCount() > 0){
12770 this.restrictHeight();
12771 if(this.lastQuery == this.allQuery){
12772 if(this.editable && !this.tickable){
12773 this.inputEl().dom.select();
12777 !this.selectByValue(this.value, true) &&
12780 !this.store.lastOptions ||
12781 typeof(this.store.lastOptions.add) == 'undefined' ||
12782 this.store.lastOptions.add != true
12785 this.select(0, true);
12788 if(this.autoFocus){
12791 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12792 this.taTask.delay(this.typeAheadDelay);
12796 this.onEmptyResults();
12802 onLoadException : function()
12804 this.hasQuery = false;
12806 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12807 this.loading.hide();
12810 if(this.tickable && this.editable){
12815 // only causes errors at present
12816 //Roo.log(this.store.reader.jsonData);
12817 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12819 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12825 onTypeAhead : function(){
12826 if(this.store.getCount() > 0){
12827 var r = this.store.getAt(0);
12828 var newValue = r.data[this.displayField];
12829 var len = newValue.length;
12830 var selStart = this.getRawValue().length;
12832 if(selStart != len){
12833 this.setRawValue(newValue);
12834 this.selectText(selStart, newValue.length);
12840 onSelect : function(record, index){
12842 if(this.fireEvent('beforeselect', this, record, index) !== false){
12844 this.setFromData(index > -1 ? record.data : false);
12847 this.fireEvent('select', this, record, index);
12852 * Returns the currently selected field value or empty string if no value is set.
12853 * @return {String} value The selected value
12855 getValue : function(){
12858 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12861 if(this.valueField){
12862 return typeof this.value != 'undefined' ? this.value : '';
12864 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12869 * Clears any text/value currently set in the field
12871 clearValue : function(){
12872 if(this.hiddenField){
12873 this.hiddenField.dom.value = '';
12876 this.setRawValue('');
12877 this.lastSelectionText = '';
12878 this.lastData = false;
12880 var close = this.closeTriggerEl();
12889 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12890 * will be displayed in the field. If the value does not match the data value of an existing item,
12891 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12892 * Otherwise the field will be blank (although the value will still be set).
12893 * @param {String} value The value to match
12895 setValue : function(v){
12902 if(this.valueField){
12903 var r = this.findRecord(this.valueField, v);
12905 text = r.data[this.displayField];
12906 }else if(this.valueNotFoundText !== undefined){
12907 text = this.valueNotFoundText;
12910 this.lastSelectionText = text;
12911 if(this.hiddenField){
12912 this.hiddenField.dom.value = v;
12914 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12917 var close = this.closeTriggerEl();
12920 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12924 * @property {Object} the last set data for the element
12929 * Sets the value of the field based on a object which is related to the record format for the store.
12930 * @param {Object} value the value to set as. or false on reset?
12932 setFromData : function(o){
12939 var dv = ''; // display value
12940 var vv = ''; // value value..
12942 if (this.displayField) {
12943 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12945 // this is an error condition!!!
12946 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12949 if(this.valueField){
12950 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12953 var close = this.closeTriggerEl();
12956 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12959 if(this.hiddenField){
12960 this.hiddenField.dom.value = vv;
12962 this.lastSelectionText = dv;
12963 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12967 // no hidden field.. - we store the value in 'value', but still display
12968 // display field!!!!
12969 this.lastSelectionText = dv;
12970 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12977 reset : function(){
12978 // overridden so that last data is reset..
12985 this.setValue(this.originalValue);
12986 this.clearInvalid();
12987 this.lastData = false;
12989 this.view.clearSelections();
12993 findRecord : function(prop, value){
12995 if(this.store.getCount() > 0){
12996 this.store.each(function(r){
12997 if(r.data[prop] == value){
13007 getName: function()
13009 // returns hidden if it's set..
13010 if (!this.rendered) {return ''};
13011 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13015 onViewMove : function(e, t){
13016 this.inKeyMode = false;
13020 onViewOver : function(e, t){
13021 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13024 var item = this.view.findItemFromChild(t);
13027 var index = this.view.indexOf(item);
13028 this.select(index, false);
13033 onViewClick : function(view, doFocus, el, e)
13035 var index = this.view.getSelectedIndexes()[0];
13037 var r = this.store.getAt(index);
13041 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13048 Roo.each(this.tickItems, function(v,k){
13050 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13052 _this.tickItems.splice(k, 1);
13054 if(typeof(e) == 'undefined' && view == false){
13055 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13067 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13068 this.tickItems.push(r.data);
13071 if(typeof(e) == 'undefined' && view == false){
13072 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13079 this.onSelect(r, index);
13081 if(doFocus !== false && !this.blockFocus){
13082 this.inputEl().focus();
13087 restrictHeight : function(){
13088 //this.innerList.dom.style.height = '';
13089 //var inner = this.innerList.dom;
13090 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13091 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13092 //this.list.beginUpdate();
13093 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13094 this.list.alignTo(this.inputEl(), this.listAlign);
13095 this.list.alignTo(this.inputEl(), this.listAlign);
13096 //this.list.endUpdate();
13100 onEmptyResults : function(){
13102 if(this.tickable && this.editable){
13103 this.restrictHeight();
13111 * Returns true if the dropdown list is expanded, else false.
13113 isExpanded : function(){
13114 return this.list.isVisible();
13118 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13119 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13120 * @param {String} value The data value of the item to select
13121 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13122 * selected item if it is not currently in view (defaults to true)
13123 * @return {Boolean} True if the value matched an item in the list, else false
13125 selectByValue : function(v, scrollIntoView){
13126 if(v !== undefined && v !== null){
13127 var r = this.findRecord(this.valueField || this.displayField, v);
13129 this.select(this.store.indexOf(r), scrollIntoView);
13137 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13138 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13139 * @param {Number} index The zero-based index of the list item to select
13140 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13141 * selected item if it is not currently in view (defaults to true)
13143 select : function(index, scrollIntoView){
13144 this.selectedIndex = index;
13145 this.view.select(index);
13146 if(scrollIntoView !== false){
13147 var el = this.view.getNode(index);
13149 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13152 this.list.scrollChildIntoView(el, false);
13158 selectNext : function(){
13159 var ct = this.store.getCount();
13161 if(this.selectedIndex == -1){
13163 }else if(this.selectedIndex < ct-1){
13164 this.select(this.selectedIndex+1);
13170 selectPrev : function(){
13171 var ct = this.store.getCount();
13173 if(this.selectedIndex == -1){
13175 }else if(this.selectedIndex != 0){
13176 this.select(this.selectedIndex-1);
13182 onKeyUp : function(e){
13183 if(this.editable !== false && !e.isSpecialKey()){
13184 this.lastKey = e.getKey();
13185 this.dqTask.delay(this.queryDelay);
13190 validateBlur : function(){
13191 return !this.list || !this.list.isVisible();
13195 initQuery : function(){
13197 var v = this.getRawValue();
13199 if(this.tickable && this.editable){
13200 v = this.tickableInputEl().getValue();
13207 doForce : function(){
13208 if(this.inputEl().dom.value.length > 0){
13209 this.inputEl().dom.value =
13210 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13216 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13217 * query allowing the query action to be canceled if needed.
13218 * @param {String} query The SQL query to execute
13219 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13220 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13221 * saved in the current store (defaults to false)
13223 doQuery : function(q, forceAll){
13225 if(q === undefined || q === null){
13230 forceAll: forceAll,
13234 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13239 forceAll = qe.forceAll;
13240 if(forceAll === true || (q.length >= this.minChars)){
13242 this.hasQuery = true;
13244 if(this.lastQuery != q || this.alwaysQuery){
13245 this.lastQuery = q;
13246 if(this.mode == 'local'){
13247 this.selectedIndex = -1;
13249 this.store.clearFilter();
13252 if(this.specialFilter){
13253 this.fireEvent('specialfilter', this);
13258 this.store.filter(this.displayField, q);
13261 this.store.fireEvent("datachanged", this.store);
13268 this.store.baseParams[this.queryParam] = q;
13270 var options = {params : this.getParams(q)};
13273 options.add = true;
13274 options.params.start = this.page * this.pageSize;
13277 this.store.load(options);
13280 * this code will make the page width larger, at the beginning, the list not align correctly,
13281 * we should expand the list on onLoad
13282 * so command out it
13287 this.selectedIndex = -1;
13292 this.loadNext = false;
13296 getParams : function(q){
13298 //p[this.queryParam] = q;
13302 p.limit = this.pageSize;
13308 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13310 collapse : function(){
13311 if(!this.isExpanded()){
13318 this.hasFocus = false;
13320 this.cancelBtn.hide();
13321 this.trigger.show();
13324 this.tickableInputEl().dom.value = '';
13325 this.tickableInputEl().blur();
13330 Roo.get(document).un('mousedown', this.collapseIf, this);
13331 Roo.get(document).un('mousewheel', this.collapseIf, this);
13332 if (!this.editable) {
13333 Roo.get(document).un('keydown', this.listKeyPress, this);
13335 this.fireEvent('collapse', this);
13339 collapseIf : function(e){
13340 var in_combo = e.within(this.el);
13341 var in_list = e.within(this.list);
13342 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13344 if (in_combo || in_list || is_list) {
13345 //e.stopPropagation();
13350 this.onTickableFooterButtonClick(e, false, false);
13358 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13360 expand : function(){
13362 if(this.isExpanded() || !this.hasFocus){
13366 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13367 this.list.setWidth(lw);
13374 this.restrictHeight();
13378 this.tickItems = Roo.apply([], this.item);
13381 this.cancelBtn.show();
13382 this.trigger.hide();
13385 this.tickableInputEl().focus();
13390 Roo.get(document).on('mousedown', this.collapseIf, this);
13391 Roo.get(document).on('mousewheel', this.collapseIf, this);
13392 if (!this.editable) {
13393 Roo.get(document).on('keydown', this.listKeyPress, this);
13396 this.fireEvent('expand', this);
13400 // Implements the default empty TriggerField.onTriggerClick function
13401 onTriggerClick : function(e)
13403 Roo.log('trigger click');
13405 if(this.disabled || !this.triggerList){
13410 this.loadNext = false;
13412 if(this.isExpanded()){
13414 if (!this.blockFocus) {
13415 this.inputEl().focus();
13419 this.hasFocus = true;
13420 if(this.triggerAction == 'all') {
13421 this.doQuery(this.allQuery, true);
13423 this.doQuery(this.getRawValue());
13425 if (!this.blockFocus) {
13426 this.inputEl().focus();
13431 onTickableTriggerClick : function(e)
13438 this.loadNext = false;
13439 this.hasFocus = true;
13441 if(this.triggerAction == 'all') {
13442 this.doQuery(this.allQuery, true);
13444 this.doQuery(this.getRawValue());
13448 onSearchFieldClick : function(e)
13450 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13451 this.onTickableFooterButtonClick(e, false, false);
13455 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13460 this.loadNext = false;
13461 this.hasFocus = true;
13463 if(this.triggerAction == 'all') {
13464 this.doQuery(this.allQuery, true);
13466 this.doQuery(this.getRawValue());
13470 listKeyPress : function(e)
13472 //Roo.log('listkeypress');
13473 // scroll to first matching element based on key pres..
13474 if (e.isSpecialKey()) {
13477 var k = String.fromCharCode(e.getKey()).toUpperCase();
13480 var csel = this.view.getSelectedNodes();
13481 var cselitem = false;
13483 var ix = this.view.indexOf(csel[0]);
13484 cselitem = this.store.getAt(ix);
13485 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13491 this.store.each(function(v) {
13493 // start at existing selection.
13494 if (cselitem.id == v.id) {
13500 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13501 match = this.store.indexOf(v);
13507 if (match === false) {
13508 return true; // no more action?
13511 this.view.select(match);
13512 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13513 sn.scrollIntoView(sn.dom.parentNode, false);
13516 onViewScroll : function(e, t){
13518 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){
13522 this.hasQuery = true;
13524 this.loading = this.list.select('.loading', true).first();
13526 if(this.loading === null){
13527 this.list.createChild({
13529 cls: 'loading roo-select2-more-results roo-select2-active',
13530 html: 'Loading more results...'
13533 this.loading = this.list.select('.loading', true).first();
13535 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13537 this.loading.hide();
13540 this.loading.show();
13545 this.loadNext = true;
13547 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13552 addItem : function(o)
13554 var dv = ''; // display value
13556 if (this.displayField) {
13557 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13559 // this is an error condition!!!
13560 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13567 var choice = this.choices.createChild({
13569 cls: 'roo-select2-search-choice',
13578 cls: 'roo-select2-search-choice-close',
13583 }, this.searchField);
13585 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13587 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13595 this.inputEl().dom.value = '';
13600 onRemoveItem : function(e, _self, o)
13602 e.preventDefault();
13604 this.lastItem = Roo.apply([], this.item);
13606 var index = this.item.indexOf(o.data) * 1;
13609 Roo.log('not this item?!');
13613 this.item.splice(index, 1);
13618 this.fireEvent('remove', this, e);
13624 syncValue : function()
13626 if(!this.item.length){
13633 Roo.each(this.item, function(i){
13634 if(_this.valueField){
13635 value.push(i[_this.valueField]);
13642 this.value = value.join(',');
13644 if(this.hiddenField){
13645 this.hiddenField.dom.value = this.value;
13648 this.store.fireEvent("datachanged", this.store);
13651 clearItem : function()
13653 if(!this.multiple){
13659 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13667 if(this.tickable && !Roo.isTouch){
13668 this.view.refresh();
13672 inputEl: function ()
13674 if(Roo.isTouch && this.mobileTouchView){
13675 return this.el.select('input.form-control',true).first();
13679 return this.searchField;
13682 return this.el.select('input.form-control',true).first();
13686 onTickableFooterButtonClick : function(e, btn, el)
13688 e.preventDefault();
13690 this.lastItem = Roo.apply([], this.item);
13692 if(btn && btn.name == 'cancel'){
13693 this.tickItems = Roo.apply([], this.item);
13702 Roo.each(this.tickItems, function(o){
13710 validate : function()
13712 var v = this.getRawValue();
13715 v = this.getValue();
13718 if(this.disabled || this.allowBlank || v.length){
13723 this.markInvalid();
13727 tickableInputEl : function()
13729 if(!this.tickable || !this.editable){
13730 return this.inputEl();
13733 return this.inputEl().select('.roo-select2-search-field-input', true).first();
13737 getAutoCreateTouchView : function()
13742 cls: 'form-group' //input-group
13748 type : this.inputType,
13749 cls : 'form-control x-combo-noedit',
13750 autocomplete: 'new-password',
13751 placeholder : this.placeholder || '',
13756 input.name = this.name;
13760 input.cls += ' input-' + this.size;
13763 if (this.disabled) {
13764 input.disabled = true;
13775 inputblock.cls += ' input-group';
13777 inputblock.cn.unshift({
13779 cls : 'input-group-addon',
13784 if(this.removable && !this.multiple){
13785 inputblock.cls += ' roo-removable';
13787 inputblock.cn.push({
13790 cls : 'roo-combo-removable-btn close'
13794 if(this.hasFeedback && !this.allowBlank){
13796 inputblock.cls += ' has-feedback';
13798 inputblock.cn.push({
13800 cls: 'glyphicon form-control-feedback'
13807 inputblock.cls += (this.before) ? '' : ' input-group';
13809 inputblock.cn.push({
13811 cls : 'input-group-addon',
13822 cls: 'form-hidden-field'
13836 cls: 'form-hidden-field'
13840 cls: 'roo-select2-choices',
13844 cls: 'roo-select2-search-field',
13857 cls: 'roo-select2-container input-group',
13864 combobox.cls += ' roo-select2-container-multi';
13867 var align = this.labelAlign || this.parentLabelAlign();
13871 if(this.fieldLabel.length){
13873 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13874 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13879 cls : 'control-label ' + lw,
13880 html : this.fieldLabel
13892 var settings = this;
13894 ['xs','sm','md','lg'].map(function(size){
13895 if (settings[size]) {
13896 cfg.cls += ' col-' + size + '-' + settings[size];
13903 initTouchView : function()
13905 this.renderTouchView();
13907 this.touchViewEl.on('scroll', function(){
13908 this.el.dom.scrollTop = 0;
13911 this.originalValue = this.getValue();
13913 this.inputEl().on("click", this.showTouchView, this);
13915 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13916 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13918 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13920 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13921 this.store.on('load', this.onTouchViewLoad, this);
13922 this.store.on('loadexception', this.onTouchViewLoadException, this);
13924 if(this.hiddenName){
13926 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13928 this.hiddenField.dom.value =
13929 this.hiddenValue !== undefined ? this.hiddenValue :
13930 this.value !== undefined ? this.value : '';
13932 this.el.dom.removeAttribute('name');
13933 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13937 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13938 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13941 if(this.removable && !this.multiple){
13942 var close = this.closeTriggerEl();
13944 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13945 close.on('click', this.removeBtnClick, this, close);
13949 * fix the bug in Safari iOS8
13951 this.inputEl().on("focus", function(e){
13952 document.activeElement.blur();
13960 renderTouchView : function()
13962 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13963 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13965 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13966 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13968 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13969 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13970 this.touchViewBodyEl.setStyle('overflow', 'auto');
13972 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13973 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13975 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13976 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13980 showTouchView : function()
13986 this.touchViewHeaderEl.hide();
13988 if(this.fieldLabel.length){
13989 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13990 this.touchViewHeaderEl.show();
13993 this.touchViewEl.show();
13995 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13996 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13998 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14000 if(this.fieldLabel.length){
14001 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14004 this.touchViewBodyEl.setHeight(bodyHeight);
14008 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14010 this.touchViewEl.addClass('in');
14013 this.doTouchViewQuery();
14017 hideTouchView : function()
14019 this.touchViewEl.removeClass('in');
14023 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14025 this.touchViewEl.setStyle('display', 'none');
14030 setTouchViewValue : function()
14037 Roo.each(this.tickItems, function(o){
14042 this.hideTouchView();
14045 doTouchViewQuery : function()
14054 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14058 if(!this.alwaysQuery || this.mode == 'local'){
14059 this.onTouchViewLoad();
14066 onTouchViewBeforeLoad : function(combo,opts)
14072 onTouchViewLoad : function()
14074 if(this.store.getCount() < 1){
14075 this.onTouchViewEmptyResults();
14079 this.clearTouchView();
14081 var rawValue = this.getRawValue();
14083 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14085 this.tickItems = [];
14087 this.store.data.each(function(d, rowIndex){
14088 var row = this.touchViewListGroup.createChild(template);
14090 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14091 row.addClass(d.data.cls);
14094 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14097 html : d.data[this.displayField]
14100 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14101 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14105 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
14106 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14109 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
14110 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14111 this.tickItems.push(d.data);
14114 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14118 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14120 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14122 if(this.fieldLabel.length){
14123 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14126 var listHeight = this.touchViewListGroup.getHeight();
14130 if(firstChecked && listHeight > bodyHeight){
14131 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14136 onTouchViewLoadException : function()
14138 this.hideTouchView();
14141 onTouchViewEmptyResults : function()
14143 this.clearTouchView();
14145 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14147 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14151 clearTouchView : function()
14153 this.touchViewListGroup.dom.innerHTML = '';
14156 onTouchViewClick : function(e, el, o)
14158 e.preventDefault();
14161 var rowIndex = o.rowIndex;
14163 var r = this.store.getAt(rowIndex);
14165 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14167 if(!this.multiple){
14168 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14169 c.dom.removeAttribute('checked');
14172 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14174 this.setFromData(r.data);
14176 var close = this.closeTriggerEl();
14182 this.hideTouchView();
14184 this.fireEvent('select', this, r, rowIndex);
14189 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14190 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14191 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14195 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14196 this.addItem(r.data);
14197 this.tickItems.push(r.data);
14203 * @cfg {Boolean} grow
14207 * @cfg {Number} growMin
14211 * @cfg {Number} growMax
14220 Roo.apply(Roo.bootstrap.ComboBox, {
14224 cls: 'modal-header',
14246 cls: 'list-group-item',
14250 cls: 'roo-combobox-list-group-item-value'
14254 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14268 listItemCheckbox : {
14270 cls: 'list-group-item',
14274 cls: 'roo-combobox-list-group-item-value'
14278 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14294 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14299 cls: 'modal-footer',
14307 cls: 'col-xs-6 text-left',
14310 cls: 'btn btn-danger roo-touch-view-cancel',
14316 cls: 'col-xs-6 text-right',
14319 cls: 'btn btn-success roo-touch-view-ok',
14330 Roo.apply(Roo.bootstrap.ComboBox, {
14332 touchViewTemplate : {
14334 cls: 'modal fade roo-combobox-touch-view',
14338 cls: 'modal-dialog',
14339 style : 'position:fixed', // we have to fix position....
14343 cls: 'modal-content',
14345 Roo.bootstrap.ComboBox.header,
14346 Roo.bootstrap.ComboBox.body,
14347 Roo.bootstrap.ComboBox.footer
14356 * Ext JS Library 1.1.1
14357 * Copyright(c) 2006-2007, Ext JS, LLC.
14359 * Originally Released Under LGPL - original licence link has changed is not relivant.
14362 * <script type="text/javascript">
14367 * @extends Roo.util.Observable
14368 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14369 * This class also supports single and multi selection modes. <br>
14370 * Create a data model bound view:
14372 var store = new Roo.data.Store(...);
14374 var view = new Roo.View({
14376 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14378 singleSelect: true,
14379 selectedClass: "ydataview-selected",
14383 // listen for node click?
14384 view.on("click", function(vw, index, node, e){
14385 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14389 dataModel.load("foobar.xml");
14391 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14393 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14394 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14396 * Note: old style constructor is still suported (container, template, config)
14399 * Create a new View
14400 * @param {Object} config The config object
14403 Roo.View = function(config, depreciated_tpl, depreciated_config){
14405 this.parent = false;
14407 if (typeof(depreciated_tpl) == 'undefined') {
14408 // new way.. - universal constructor.
14409 Roo.apply(this, config);
14410 this.el = Roo.get(this.el);
14413 this.el = Roo.get(config);
14414 this.tpl = depreciated_tpl;
14415 Roo.apply(this, depreciated_config);
14417 this.wrapEl = this.el.wrap().wrap();
14418 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14421 if(typeof(this.tpl) == "string"){
14422 this.tpl = new Roo.Template(this.tpl);
14424 // support xtype ctors..
14425 this.tpl = new Roo.factory(this.tpl, Roo);
14429 this.tpl.compile();
14434 * @event beforeclick
14435 * Fires before a click is processed. Returns false to cancel the default action.
14436 * @param {Roo.View} this
14437 * @param {Number} index The index of the target node
14438 * @param {HTMLElement} node The target node
14439 * @param {Roo.EventObject} e The raw event object
14441 "beforeclick" : true,
14444 * Fires when a template node is clicked.
14445 * @param {Roo.View} this
14446 * @param {Number} index The index of the target node
14447 * @param {HTMLElement} node The target node
14448 * @param {Roo.EventObject} e The raw event object
14453 * Fires when a template node is double clicked.
14454 * @param {Roo.View} this
14455 * @param {Number} index The index of the target node
14456 * @param {HTMLElement} node The target node
14457 * @param {Roo.EventObject} e The raw event object
14461 * @event contextmenu
14462 * Fires when a template node is right clicked.
14463 * @param {Roo.View} this
14464 * @param {Number} index The index of the target node
14465 * @param {HTMLElement} node The target node
14466 * @param {Roo.EventObject} e The raw event object
14468 "contextmenu" : true,
14470 * @event selectionchange
14471 * Fires when the selected nodes change.
14472 * @param {Roo.View} this
14473 * @param {Array} selections Array of the selected nodes
14475 "selectionchange" : true,
14478 * @event beforeselect
14479 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14480 * @param {Roo.View} this
14481 * @param {HTMLElement} node The node to be selected
14482 * @param {Array} selections Array of currently selected nodes
14484 "beforeselect" : true,
14486 * @event preparedata
14487 * Fires on every row to render, to allow you to change the data.
14488 * @param {Roo.View} this
14489 * @param {Object} data to be rendered (change this)
14491 "preparedata" : true
14499 "click": this.onClick,
14500 "dblclick": this.onDblClick,
14501 "contextmenu": this.onContextMenu,
14505 this.selections = [];
14507 this.cmp = new Roo.CompositeElementLite([]);
14509 this.store = Roo.factory(this.store, Roo.data);
14510 this.setStore(this.store, true);
14513 if ( this.footer && this.footer.xtype) {
14515 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14517 this.footer.dataSource = this.store;
14518 this.footer.container = fctr;
14519 this.footer = Roo.factory(this.footer, Roo);
14520 fctr.insertFirst(this.el);
14522 // this is a bit insane - as the paging toolbar seems to detach the el..
14523 // dom.parentNode.parentNode.parentNode
14524 // they get detached?
14528 Roo.View.superclass.constructor.call(this);
14533 Roo.extend(Roo.View, Roo.util.Observable, {
14536 * @cfg {Roo.data.Store} store Data store to load data from.
14541 * @cfg {String|Roo.Element} el The container element.
14546 * @cfg {String|Roo.Template} tpl The template used by this View
14550 * @cfg {String} dataName the named area of the template to use as the data area
14551 * Works with domtemplates roo-name="name"
14555 * @cfg {String} selectedClass The css class to add to selected nodes
14557 selectedClass : "x-view-selected",
14559 * @cfg {String} emptyText The empty text to show when nothing is loaded.
14564 * @cfg {String} text to display on mask (default Loading)
14568 * @cfg {Boolean} multiSelect Allow multiple selection
14570 multiSelect : false,
14572 * @cfg {Boolean} singleSelect Allow single selection
14574 singleSelect: false,
14577 * @cfg {Boolean} toggleSelect - selecting
14579 toggleSelect : false,
14582 * @cfg {Boolean} tickable - selecting
14587 * Returns the element this view is bound to.
14588 * @return {Roo.Element}
14590 getEl : function(){
14591 return this.wrapEl;
14597 * Refreshes the view. - called by datachanged on the store. - do not call directly.
14599 refresh : function(){
14600 //Roo.log('refresh');
14603 // if we are using something like 'domtemplate', then
14604 // the what gets used is:
14605 // t.applySubtemplate(NAME, data, wrapping data..)
14606 // the outer template then get' applied with
14607 // the store 'extra data'
14608 // and the body get's added to the
14609 // roo-name="data" node?
14610 // <span class='roo-tpl-{name}'></span> ?????
14614 this.clearSelections();
14615 this.el.update("");
14617 var records = this.store.getRange();
14618 if(records.length < 1) {
14620 // is this valid?? = should it render a template??
14622 this.el.update(this.emptyText);
14626 if (this.dataName) {
14627 this.el.update(t.apply(this.store.meta)); //????
14628 el = this.el.child('.roo-tpl-' + this.dataName);
14631 for(var i = 0, len = records.length; i < len; i++){
14632 var data = this.prepareData(records[i].data, i, records[i]);
14633 this.fireEvent("preparedata", this, data, i, records[i]);
14635 var d = Roo.apply({}, data);
14638 Roo.apply(d, {'roo-id' : Roo.id()});
14642 Roo.each(this.parent.item, function(item){
14643 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
14646 Roo.apply(d, {'roo-data-checked' : 'checked'});
14650 html[html.length] = Roo.util.Format.trim(
14652 t.applySubtemplate(this.dataName, d, this.store.meta) :
14659 el.update(html.join(""));
14660 this.nodes = el.dom.childNodes;
14661 this.updateIndexes(0);
14666 * Function to override to reformat the data that is sent to
14667 * the template for each node.
14668 * DEPRICATED - use the preparedata event handler.
14669 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
14670 * a JSON object for an UpdateManager bound view).
14672 prepareData : function(data, index, record)
14674 this.fireEvent("preparedata", this, data, index, record);
14678 onUpdate : function(ds, record){
14679 // Roo.log('on update');
14680 this.clearSelections();
14681 var index = this.store.indexOf(record);
14682 var n = this.nodes[index];
14683 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
14684 n.parentNode.removeChild(n);
14685 this.updateIndexes(index, index);
14691 onAdd : function(ds, records, index)
14693 //Roo.log(['on Add', ds, records, index] );
14694 this.clearSelections();
14695 if(this.nodes.length == 0){
14699 var n = this.nodes[index];
14700 for(var i = 0, len = records.length; i < len; i++){
14701 var d = this.prepareData(records[i].data, i, records[i]);
14703 this.tpl.insertBefore(n, d);
14706 this.tpl.append(this.el, d);
14709 this.updateIndexes(index);
14712 onRemove : function(ds, record, index){
14713 // Roo.log('onRemove');
14714 this.clearSelections();
14715 var el = this.dataName ?
14716 this.el.child('.roo-tpl-' + this.dataName) :
14719 el.dom.removeChild(this.nodes[index]);
14720 this.updateIndexes(index);
14724 * Refresh an individual node.
14725 * @param {Number} index
14727 refreshNode : function(index){
14728 this.onUpdate(this.store, this.store.getAt(index));
14731 updateIndexes : function(startIndex, endIndex){
14732 var ns = this.nodes;
14733 startIndex = startIndex || 0;
14734 endIndex = endIndex || ns.length - 1;
14735 for(var i = startIndex; i <= endIndex; i++){
14736 ns[i].nodeIndex = i;
14741 * Changes the data store this view uses and refresh the view.
14742 * @param {Store} store
14744 setStore : function(store, initial){
14745 if(!initial && this.store){
14746 this.store.un("datachanged", this.refresh);
14747 this.store.un("add", this.onAdd);
14748 this.store.un("remove", this.onRemove);
14749 this.store.un("update", this.onUpdate);
14750 this.store.un("clear", this.refresh);
14751 this.store.un("beforeload", this.onBeforeLoad);
14752 this.store.un("load", this.onLoad);
14753 this.store.un("loadexception", this.onLoad);
14757 store.on("datachanged", this.refresh, this);
14758 store.on("add", this.onAdd, this);
14759 store.on("remove", this.onRemove, this);
14760 store.on("update", this.onUpdate, this);
14761 store.on("clear", this.refresh, this);
14762 store.on("beforeload", this.onBeforeLoad, this);
14763 store.on("load", this.onLoad, this);
14764 store.on("loadexception", this.onLoad, this);
14772 * onbeforeLoad - masks the loading area.
14775 onBeforeLoad : function(store,opts)
14777 //Roo.log('onBeforeLoad');
14779 this.el.update("");
14781 this.el.mask(this.mask ? this.mask : "Loading" );
14783 onLoad : function ()
14790 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
14791 * @param {HTMLElement} node
14792 * @return {HTMLElement} The template node
14794 findItemFromChild : function(node){
14795 var el = this.dataName ?
14796 this.el.child('.roo-tpl-' + this.dataName,true) :
14799 if(!node || node.parentNode == el){
14802 var p = node.parentNode;
14803 while(p && p != el){
14804 if(p.parentNode == el){
14813 onClick : function(e){
14814 var item = this.findItemFromChild(e.getTarget());
14816 var index = this.indexOf(item);
14817 if(this.onItemClick(item, index, e) !== false){
14818 this.fireEvent("click", this, index, item, e);
14821 this.clearSelections();
14826 onContextMenu : function(e){
14827 var item = this.findItemFromChild(e.getTarget());
14829 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14834 onDblClick : function(e){
14835 var item = this.findItemFromChild(e.getTarget());
14837 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14841 onItemClick : function(item, index, e)
14843 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14846 if (this.toggleSelect) {
14847 var m = this.isSelected(item) ? 'unselect' : 'select';
14850 _t[m](item, true, false);
14853 if(this.multiSelect || this.singleSelect){
14854 if(this.multiSelect && e.shiftKey && this.lastSelection){
14855 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14857 this.select(item, this.multiSelect && e.ctrlKey);
14858 this.lastSelection = item;
14861 if(!this.tickable){
14862 e.preventDefault();
14870 * Get the number of selected nodes.
14873 getSelectionCount : function(){
14874 return this.selections.length;
14878 * Get the currently selected nodes.
14879 * @return {Array} An array of HTMLElements
14881 getSelectedNodes : function(){
14882 return this.selections;
14886 * Get the indexes of the selected nodes.
14889 getSelectedIndexes : function(){
14890 var indexes = [], s = this.selections;
14891 for(var i = 0, len = s.length; i < len; i++){
14892 indexes.push(s[i].nodeIndex);
14898 * Clear all selections
14899 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14901 clearSelections : function(suppressEvent){
14902 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14903 this.cmp.elements = this.selections;
14904 this.cmp.removeClass(this.selectedClass);
14905 this.selections = [];
14906 if(!suppressEvent){
14907 this.fireEvent("selectionchange", this, this.selections);
14913 * Returns true if the passed node is selected
14914 * @param {HTMLElement/Number} node The node or node index
14915 * @return {Boolean}
14917 isSelected : function(node){
14918 var s = this.selections;
14922 node = this.getNode(node);
14923 return s.indexOf(node) !== -1;
14928 * @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
14929 * @param {Boolean} keepExisting (optional) true to keep existing selections
14930 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14932 select : function(nodeInfo, keepExisting, suppressEvent){
14933 if(nodeInfo instanceof Array){
14935 this.clearSelections(true);
14937 for(var i = 0, len = nodeInfo.length; i < len; i++){
14938 this.select(nodeInfo[i], true, true);
14942 var node = this.getNode(nodeInfo);
14943 if(!node || this.isSelected(node)){
14944 return; // already selected.
14947 this.clearSelections(true);
14950 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14951 Roo.fly(node).addClass(this.selectedClass);
14952 this.selections.push(node);
14953 if(!suppressEvent){
14954 this.fireEvent("selectionchange", this, this.selections);
14962 * @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
14963 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14964 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14966 unselect : function(nodeInfo, keepExisting, suppressEvent)
14968 if(nodeInfo instanceof Array){
14969 Roo.each(this.selections, function(s) {
14970 this.unselect(s, nodeInfo);
14974 var node = this.getNode(nodeInfo);
14975 if(!node || !this.isSelected(node)){
14976 //Roo.log("not selected");
14977 return; // not selected.
14981 Roo.each(this.selections, function(s) {
14983 Roo.fly(node).removeClass(this.selectedClass);
14990 this.selections= ns;
14991 this.fireEvent("selectionchange", this, this.selections);
14995 * Gets a template node.
14996 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14997 * @return {HTMLElement} The node or null if it wasn't found
14999 getNode : function(nodeInfo){
15000 if(typeof nodeInfo == "string"){
15001 return document.getElementById(nodeInfo);
15002 }else if(typeof nodeInfo == "number"){
15003 return this.nodes[nodeInfo];
15009 * Gets a range template nodes.
15010 * @param {Number} startIndex
15011 * @param {Number} endIndex
15012 * @return {Array} An array of nodes
15014 getNodes : function(start, end){
15015 var ns = this.nodes;
15016 start = start || 0;
15017 end = typeof end == "undefined" ? ns.length - 1 : end;
15020 for(var i = start; i <= end; i++){
15024 for(var i = start; i >= end; i--){
15032 * Finds the index of the passed node
15033 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15034 * @return {Number} The index of the node or -1
15036 indexOf : function(node){
15037 node = this.getNode(node);
15038 if(typeof node.nodeIndex == "number"){
15039 return node.nodeIndex;
15041 var ns = this.nodes;
15042 for(var i = 0, len = ns.length; i < len; i++){
15053 * based on jquery fullcalendar
15057 Roo.bootstrap = Roo.bootstrap || {};
15059 * @class Roo.bootstrap.Calendar
15060 * @extends Roo.bootstrap.Component
15061 * Bootstrap Calendar class
15062 * @cfg {Boolean} loadMask (true|false) default false
15063 * @cfg {Object} header generate the user specific header of the calendar, default false
15066 * Create a new Container
15067 * @param {Object} config The config object
15072 Roo.bootstrap.Calendar = function(config){
15073 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15077 * Fires when a date is selected
15078 * @param {DatePicker} this
15079 * @param {Date} date The selected date
15083 * @event monthchange
15084 * Fires when the displayed month changes
15085 * @param {DatePicker} this
15086 * @param {Date} date The selected month
15088 'monthchange': true,
15090 * @event evententer
15091 * Fires when mouse over an event
15092 * @param {Calendar} this
15093 * @param {event} Event
15095 'evententer': true,
15097 * @event eventleave
15098 * Fires when the mouse leaves an
15099 * @param {Calendar} this
15102 'eventleave': true,
15104 * @event eventclick
15105 * Fires when the mouse click an
15106 * @param {Calendar} this
15115 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15118 * @cfg {Number} startDay
15119 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15127 getAutoCreate : function(){
15130 var fc_button = function(name, corner, style, content ) {
15131 return Roo.apply({},{
15133 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15135 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15138 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15149 style : 'width:100%',
15156 cls : 'fc-header-left',
15158 fc_button('prev', 'left', 'arrow', '‹' ),
15159 fc_button('next', 'right', 'arrow', '›' ),
15160 { tag: 'span', cls: 'fc-header-space' },
15161 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15169 cls : 'fc-header-center',
15173 cls: 'fc-header-title',
15176 html : 'month / year'
15184 cls : 'fc-header-right',
15186 /* fc_button('month', 'left', '', 'month' ),
15187 fc_button('week', '', '', 'week' ),
15188 fc_button('day', 'right', '', 'day' )
15200 header = this.header;
15203 var cal_heads = function() {
15205 // fixme - handle this.
15207 for (var i =0; i < Date.dayNames.length; i++) {
15208 var d = Date.dayNames[i];
15211 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15212 html : d.substring(0,3)
15216 ret[0].cls += ' fc-first';
15217 ret[6].cls += ' fc-last';
15220 var cal_cell = function(n) {
15223 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15228 cls: 'fc-day-number',
15232 cls: 'fc-day-content',
15236 style: 'position: relative;' // height: 17px;
15248 var cal_rows = function() {
15251 for (var r = 0; r < 6; r++) {
15258 for (var i =0; i < Date.dayNames.length; i++) {
15259 var d = Date.dayNames[i];
15260 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15263 row.cn[0].cls+=' fc-first';
15264 row.cn[0].cn[0].style = 'min-height:90px';
15265 row.cn[6].cls+=' fc-last';
15269 ret[0].cls += ' fc-first';
15270 ret[4].cls += ' fc-prev-last';
15271 ret[5].cls += ' fc-last';
15278 cls: 'fc-border-separate',
15279 style : 'width:100%',
15287 cls : 'fc-first fc-last',
15305 cls : 'fc-content',
15306 style : "position: relative;",
15309 cls : 'fc-view fc-view-month fc-grid',
15310 style : 'position: relative',
15311 unselectable : 'on',
15314 cls : 'fc-event-container',
15315 style : 'position:absolute;z-index:8;top:0;left:0;'
15333 initEvents : function()
15336 throw "can not find store for calendar";
15342 style: "text-align:center",
15346 style: "background-color:white;width:50%;margin:250 auto",
15350 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15361 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15363 var size = this.el.select('.fc-content', true).first().getSize();
15364 this.maskEl.setSize(size.width, size.height);
15365 this.maskEl.enableDisplayMode("block");
15366 if(!this.loadMask){
15367 this.maskEl.hide();
15370 this.store = Roo.factory(this.store, Roo.data);
15371 this.store.on('load', this.onLoad, this);
15372 this.store.on('beforeload', this.onBeforeLoad, this);
15376 this.cells = this.el.select('.fc-day',true);
15377 //Roo.log(this.cells);
15378 this.textNodes = this.el.query('.fc-day-number');
15379 this.cells.addClassOnOver('fc-state-hover');
15381 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15382 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15383 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15384 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15386 this.on('monthchange', this.onMonthChange, this);
15388 this.update(new Date().clearTime());
15391 resize : function() {
15392 var sz = this.el.getSize();
15394 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15395 this.el.select('.fc-day-content div',true).setHeight(34);
15400 showPrevMonth : function(e){
15401 this.update(this.activeDate.add("mo", -1));
15403 showToday : function(e){
15404 this.update(new Date().clearTime());
15407 showNextMonth : function(e){
15408 this.update(this.activeDate.add("mo", 1));
15412 showPrevYear : function(){
15413 this.update(this.activeDate.add("y", -1));
15417 showNextYear : function(){
15418 this.update(this.activeDate.add("y", 1));
15423 update : function(date)
15425 var vd = this.activeDate;
15426 this.activeDate = date;
15427 // if(vd && this.el){
15428 // var t = date.getTime();
15429 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15430 // Roo.log('using add remove');
15432 // this.fireEvent('monthchange', this, date);
15434 // this.cells.removeClass("fc-state-highlight");
15435 // this.cells.each(function(c){
15436 // if(c.dateValue == t){
15437 // c.addClass("fc-state-highlight");
15438 // setTimeout(function(){
15439 // try{c.dom.firstChild.focus();}catch(e){}
15449 var days = date.getDaysInMonth();
15451 var firstOfMonth = date.getFirstDateOfMonth();
15452 var startingPos = firstOfMonth.getDay()-this.startDay;
15454 if(startingPos < this.startDay){
15458 var pm = date.add(Date.MONTH, -1);
15459 var prevStart = pm.getDaysInMonth()-startingPos;
15461 this.cells = this.el.select('.fc-day',true);
15462 this.textNodes = this.el.query('.fc-day-number');
15463 this.cells.addClassOnOver('fc-state-hover');
15465 var cells = this.cells.elements;
15466 var textEls = this.textNodes;
15468 Roo.each(cells, function(cell){
15469 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15472 days += startingPos;
15474 // convert everything to numbers so it's fast
15475 var day = 86400000;
15476 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15479 //Roo.log(prevStart);
15481 var today = new Date().clearTime().getTime();
15482 var sel = date.clearTime().getTime();
15483 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15484 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15485 var ddMatch = this.disabledDatesRE;
15486 var ddText = this.disabledDatesText;
15487 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15488 var ddaysText = this.disabledDaysText;
15489 var format = this.format;
15491 var setCellClass = function(cal, cell){
15495 //Roo.log('set Cell Class');
15497 var t = d.getTime();
15501 cell.dateValue = t;
15503 cell.className += " fc-today";
15504 cell.className += " fc-state-highlight";
15505 cell.title = cal.todayText;
15508 // disable highlight in other month..
15509 //cell.className += " fc-state-highlight";
15514 cell.className = " fc-state-disabled";
15515 cell.title = cal.minText;
15519 cell.className = " fc-state-disabled";
15520 cell.title = cal.maxText;
15524 if(ddays.indexOf(d.getDay()) != -1){
15525 cell.title = ddaysText;
15526 cell.className = " fc-state-disabled";
15529 if(ddMatch && format){
15530 var fvalue = d.dateFormat(format);
15531 if(ddMatch.test(fvalue)){
15532 cell.title = ddText.replace("%0", fvalue);
15533 cell.className = " fc-state-disabled";
15537 if (!cell.initialClassName) {
15538 cell.initialClassName = cell.dom.className;
15541 cell.dom.className = cell.initialClassName + ' ' + cell.className;
15546 for(; i < startingPos; i++) {
15547 textEls[i].innerHTML = (++prevStart);
15548 d.setDate(d.getDate()+1);
15550 cells[i].className = "fc-past fc-other-month";
15551 setCellClass(this, cells[i]);
15556 for(; i < days; i++){
15557 intDay = i - startingPos + 1;
15558 textEls[i].innerHTML = (intDay);
15559 d.setDate(d.getDate()+1);
15561 cells[i].className = ''; // "x-date-active";
15562 setCellClass(this, cells[i]);
15566 for(; i < 42; i++) {
15567 textEls[i].innerHTML = (++extraDays);
15568 d.setDate(d.getDate()+1);
15570 cells[i].className = "fc-future fc-other-month";
15571 setCellClass(this, cells[i]);
15574 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
15576 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
15578 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
15579 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
15581 if(totalRows != 6){
15582 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
15583 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
15586 this.fireEvent('monthchange', this, date);
15590 if(!this.internalRender){
15591 var main = this.el.dom.firstChild;
15592 var w = main.offsetWidth;
15593 this.el.setWidth(w + this.el.getBorderWidth("lr"));
15594 Roo.fly(main).setWidth(w);
15595 this.internalRender = true;
15596 // opera does not respect the auto grow header center column
15597 // then, after it gets a width opera refuses to recalculate
15598 // without a second pass
15599 if(Roo.isOpera && !this.secondPass){
15600 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
15601 this.secondPass = true;
15602 this.update.defer(10, this, [date]);
15609 findCell : function(dt) {
15610 dt = dt.clearTime().getTime();
15612 this.cells.each(function(c){
15613 //Roo.log("check " +c.dateValue + '?=' + dt);
15614 if(c.dateValue == dt){
15624 findCells : function(ev) {
15625 var s = ev.start.clone().clearTime().getTime();
15627 var e= ev.end.clone().clearTime().getTime();
15630 this.cells.each(function(c){
15631 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
15633 if(c.dateValue > e){
15636 if(c.dateValue < s){
15645 // findBestRow: function(cells)
15649 // for (var i =0 ; i < cells.length;i++) {
15650 // ret = Math.max(cells[i].rows || 0,ret);
15657 addItem : function(ev)
15659 // look for vertical location slot in
15660 var cells = this.findCells(ev);
15662 // ev.row = this.findBestRow(cells);
15664 // work out the location.
15668 for(var i =0; i < cells.length; i++) {
15670 cells[i].row = cells[0].row;
15673 cells[i].row = cells[i].row + 1;
15683 if (crow.start.getY() == cells[i].getY()) {
15685 crow.end = cells[i];
15702 cells[0].events.push(ev);
15704 this.calevents.push(ev);
15707 clearEvents: function() {
15709 if(!this.calevents){
15713 Roo.each(this.cells.elements, function(c){
15719 Roo.each(this.calevents, function(e) {
15720 Roo.each(e.els, function(el) {
15721 el.un('mouseenter' ,this.onEventEnter, this);
15722 el.un('mouseleave' ,this.onEventLeave, this);
15727 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
15733 renderEvents: function()
15737 this.cells.each(function(c) {
15746 if(c.row != c.events.length){
15747 r = 4 - (4 - (c.row - c.events.length));
15750 c.events = ev.slice(0, r);
15751 c.more = ev.slice(r);
15753 if(c.more.length && c.more.length == 1){
15754 c.events.push(c.more.pop());
15757 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
15761 this.cells.each(function(c) {
15763 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
15766 for (var e = 0; e < c.events.length; e++){
15767 var ev = c.events[e];
15768 var rows = ev.rows;
15770 for(var i = 0; i < rows.length; i++) {
15772 // how many rows should it span..
15775 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
15776 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
15778 unselectable : "on",
15781 cls: 'fc-event-inner',
15785 // cls: 'fc-event-time',
15786 // html : cells.length > 1 ? '' : ev.time
15790 cls: 'fc-event-title',
15791 html : String.format('{0}', ev.title)
15798 cls: 'ui-resizable-handle ui-resizable-e',
15799 html : '  '
15806 cfg.cls += ' fc-event-start';
15808 if ((i+1) == rows.length) {
15809 cfg.cls += ' fc-event-end';
15812 var ctr = _this.el.select('.fc-event-container',true).first();
15813 var cg = ctr.createChild(cfg);
15815 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
15816 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
15818 var r = (c.more.length) ? 1 : 0;
15819 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
15820 cg.setWidth(ebox.right - sbox.x -2);
15822 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
15823 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
15824 cg.on('click', _this.onEventClick, _this, ev);
15835 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15836 style : 'position: absolute',
15837 unselectable : "on",
15840 cls: 'fc-event-inner',
15844 cls: 'fc-event-title',
15852 cls: 'ui-resizable-handle ui-resizable-e',
15853 html : '  '
15859 var ctr = _this.el.select('.fc-event-container',true).first();
15860 var cg = ctr.createChild(cfg);
15862 var sbox = c.select('.fc-day-content',true).first().getBox();
15863 var ebox = c.select('.fc-day-content',true).first().getBox();
15865 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15866 cg.setWidth(ebox.right - sbox.x -2);
15868 cg.on('click', _this.onMoreEventClick, _this, c.more);
15878 onEventEnter: function (e, el,event,d) {
15879 this.fireEvent('evententer', this, el, event);
15882 onEventLeave: function (e, el,event,d) {
15883 this.fireEvent('eventleave', this, el, event);
15886 onEventClick: function (e, el,event,d) {
15887 this.fireEvent('eventclick', this, el, event);
15890 onMonthChange: function () {
15894 onMoreEventClick: function(e, el, more)
15898 this.calpopover.placement = 'right';
15899 this.calpopover.setTitle('More');
15901 this.calpopover.setContent('');
15903 var ctr = this.calpopover.el.select('.popover-content', true).first();
15905 Roo.each(more, function(m){
15907 cls : 'fc-event-hori fc-event-draggable',
15910 var cg = ctr.createChild(cfg);
15912 cg.on('click', _this.onEventClick, _this, m);
15915 this.calpopover.show(el);
15920 onLoad: function ()
15922 this.calevents = [];
15925 if(this.store.getCount() > 0){
15926 this.store.data.each(function(d){
15929 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15930 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15931 time : d.data.start_time,
15932 title : d.data.title,
15933 description : d.data.description,
15934 venue : d.data.venue
15939 this.renderEvents();
15941 if(this.calevents.length && this.loadMask){
15942 this.maskEl.hide();
15946 onBeforeLoad: function()
15948 this.clearEvents();
15950 this.maskEl.show();
15964 * @class Roo.bootstrap.Popover
15965 * @extends Roo.bootstrap.Component
15966 * Bootstrap Popover class
15967 * @cfg {String} html contents of the popover (or false to use children..)
15968 * @cfg {String} title of popover (or false to hide)
15969 * @cfg {String} placement how it is placed
15970 * @cfg {String} trigger click || hover (or false to trigger manually)
15971 * @cfg {String} over what (parent or false to trigger manually.)
15972 * @cfg {Number} delay - delay before showing
15975 * Create a new Popover
15976 * @param {Object} config The config object
15979 Roo.bootstrap.Popover = function(config){
15980 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15986 * After the popover show
15988 * @param {Roo.bootstrap.Popover} this
15993 * After the popover hide
15995 * @param {Roo.bootstrap.Popover} this
16001 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16003 title: 'Fill in a title',
16006 placement : 'right',
16007 trigger : 'hover', // hover
16013 can_build_overlaid : false,
16015 getChildContainer : function()
16017 return this.el.select('.popover-content',true).first();
16020 getAutoCreate : function(){
16023 cls : 'popover roo-dynamic',
16024 style: 'display:block',
16030 cls : 'popover-inner',
16034 cls: 'popover-title',
16038 cls : 'popover-content',
16049 setTitle: function(str)
16052 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16054 setContent: function(str)
16057 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16059 // as it get's added to the bottom of the page.
16060 onRender : function(ct, position)
16062 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16064 var cfg = Roo.apply({}, this.getAutoCreate());
16068 cfg.cls += ' ' + this.cls;
16071 cfg.style = this.style;
16073 //Roo.log("adding to ");
16074 this.el = Roo.get(document.body).createChild(cfg, position);
16075 // Roo.log(this.el);
16080 initEvents : function()
16082 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16083 this.el.enableDisplayMode('block');
16085 if (this.over === false) {
16088 if (this.triggers === false) {
16091 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16092 var triggers = this.trigger ? this.trigger.split(' ') : [];
16093 Roo.each(triggers, function(trigger) {
16095 if (trigger == 'click') {
16096 on_el.on('click', this.toggle, this);
16097 } else if (trigger != 'manual') {
16098 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16099 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16101 on_el.on(eventIn ,this.enter, this);
16102 on_el.on(eventOut, this.leave, this);
16113 toggle : function () {
16114 this.hoverState == 'in' ? this.leave() : this.enter();
16117 enter : function () {
16119 clearTimeout(this.timeout);
16121 this.hoverState = 'in';
16123 if (!this.delay || !this.delay.show) {
16128 this.timeout = setTimeout(function () {
16129 if (_t.hoverState == 'in') {
16132 }, this.delay.show)
16135 leave : function() {
16136 clearTimeout(this.timeout);
16138 this.hoverState = 'out';
16140 if (!this.delay || !this.delay.hide) {
16145 this.timeout = setTimeout(function () {
16146 if (_t.hoverState == 'out') {
16149 }, this.delay.hide)
16152 show : function (on_el)
16155 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16159 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16160 if (this.html !== false) {
16161 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16163 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16164 if (!this.title.length) {
16165 this.el.select('.popover-title',true).hide();
16168 var placement = typeof this.placement == 'function' ?
16169 this.placement.call(this, this.el, on_el) :
16172 var autoToken = /\s?auto?\s?/i;
16173 var autoPlace = autoToken.test(placement);
16175 placement = placement.replace(autoToken, '') || 'top';
16179 //this.el.setXY([0,0]);
16181 this.el.dom.style.display='block';
16182 this.el.addClass(placement);
16184 //this.el.appendTo(on_el);
16186 var p = this.getPosition();
16187 var box = this.el.getBox();
16192 var align = Roo.bootstrap.Popover.alignment[placement];
16193 this.el.alignTo(on_el, align[0],align[1]);
16194 //var arrow = this.el.select('.arrow',true).first();
16195 //arrow.set(align[2],
16197 this.el.addClass('in');
16200 if (this.el.hasClass('fade')) {
16204 this.hoverState = 'in';
16206 this.fireEvent('show', this);
16211 this.el.setXY([0,0]);
16212 this.el.removeClass('in');
16214 this.hoverState = null;
16216 this.fireEvent('hide', this);
16221 Roo.bootstrap.Popover.alignment = {
16222 'left' : ['r-l', [-10,0], 'right'],
16223 'right' : ['l-r', [10,0], 'left'],
16224 'bottom' : ['t-b', [0,10], 'top'],
16225 'top' : [ 'b-t', [0,-10], 'bottom']
16236 * @class Roo.bootstrap.Progress
16237 * @extends Roo.bootstrap.Component
16238 * Bootstrap Progress class
16239 * @cfg {Boolean} striped striped of the progress bar
16240 * @cfg {Boolean} active animated of the progress bar
16244 * Create a new Progress
16245 * @param {Object} config The config object
16248 Roo.bootstrap.Progress = function(config){
16249 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16252 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16257 getAutoCreate : function(){
16265 cfg.cls += ' progress-striped';
16269 cfg.cls += ' active';
16288 * @class Roo.bootstrap.ProgressBar
16289 * @extends Roo.bootstrap.Component
16290 * Bootstrap ProgressBar class
16291 * @cfg {Number} aria_valuenow aria-value now
16292 * @cfg {Number} aria_valuemin aria-value min
16293 * @cfg {Number} aria_valuemax aria-value max
16294 * @cfg {String} label label for the progress bar
16295 * @cfg {String} panel (success | info | warning | danger )
16296 * @cfg {String} role role of the progress bar
16297 * @cfg {String} sr_only text
16301 * Create a new ProgressBar
16302 * @param {Object} config The config object
16305 Roo.bootstrap.ProgressBar = function(config){
16306 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16309 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16313 aria_valuemax : 100,
16319 getAutoCreate : function()
16324 cls: 'progress-bar',
16325 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16337 cfg.role = this.role;
16340 if(this.aria_valuenow){
16341 cfg['aria-valuenow'] = this.aria_valuenow;
16344 if(this.aria_valuemin){
16345 cfg['aria-valuemin'] = this.aria_valuemin;
16348 if(this.aria_valuemax){
16349 cfg['aria-valuemax'] = this.aria_valuemax;
16352 if(this.label && !this.sr_only){
16353 cfg.html = this.label;
16357 cfg.cls += ' progress-bar-' + this.panel;
16363 update : function(aria_valuenow)
16365 this.aria_valuenow = aria_valuenow;
16367 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16382 * @class Roo.bootstrap.TabGroup
16383 * @extends Roo.bootstrap.Column
16384 * Bootstrap Column class
16385 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16386 * @cfg {Boolean} carousel true to make the group behave like a carousel
16387 * @cfg {Boolean} bullets show bullets for the panels
16388 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16389 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16390 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16393 * Create a new TabGroup
16394 * @param {Object} config The config object
16397 Roo.bootstrap.TabGroup = function(config){
16398 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16400 this.navId = Roo.id();
16403 Roo.bootstrap.TabGroup.register(this);
16407 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16410 transition : false,
16415 slideOnTouch : false,
16417 getAutoCreate : function()
16419 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16421 cfg.cls += ' tab-content';
16423 if (this.carousel) {
16424 cfg.cls += ' carousel slide';
16427 cls : 'carousel-inner'
16430 if(this.bullets && !Roo.isTouch){
16433 cls : 'carousel-bullets',
16437 if(this.bullets_cls){
16438 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16441 for (var i = 0; i < this.bullets; i++){
16443 cls : 'bullet bullet-' + i
16451 cfg.cn[0].cn = bullets;
16458 initEvents: function()
16460 if(Roo.isTouch && this.slideOnTouch){
16461 this.el.on("touchstart", this.onTouchStart, this);
16464 if(this.autoslide){
16467 this.slideFn = window.setInterval(function() {
16468 _this.showPanelNext();
16474 onTouchStart : function(e, el, o)
16476 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16480 this.showPanelNext();
16483 getChildContainer : function()
16485 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
16489 * register a Navigation item
16490 * @param {Roo.bootstrap.NavItem} the navitem to add
16492 register : function(item)
16494 this.tabs.push( item);
16495 item.navId = this.navId; // not really needed..
16500 getActivePanel : function()
16503 Roo.each(this.tabs, function(t) {
16513 getPanelByName : function(n)
16516 Roo.each(this.tabs, function(t) {
16517 if (t.tabId == n) {
16525 indexOfPanel : function(p)
16528 Roo.each(this.tabs, function(t,i) {
16529 if (t.tabId == p.tabId) {
16538 * show a specific panel
16539 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
16540 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
16542 showPanel : function (pan)
16544 if(this.transition || typeof(pan) == 'undefined'){
16545 Roo.log("waiting for the transitionend");
16549 if (typeof(pan) == 'number') {
16550 pan = this.tabs[pan];
16553 if (typeof(pan) == 'string') {
16554 pan = this.getPanelByName(pan);
16557 var cur = this.getActivePanel();
16560 Roo.log('pan or acitve pan is undefined');
16564 if (pan.tabId == this.getActivePanel().tabId) {
16568 if (false === cur.fireEvent('beforedeactivate')) {
16572 if(this.bullets > 0 && !Roo.isTouch){
16573 this.setActiveBullet(this.indexOfPanel(pan));
16576 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
16578 this.transition = true;
16579 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
16580 var lr = dir == 'next' ? 'left' : 'right';
16581 pan.el.addClass(dir); // or prev
16582 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
16583 cur.el.addClass(lr); // or right
16584 pan.el.addClass(lr);
16587 cur.el.on('transitionend', function() {
16588 Roo.log("trans end?");
16590 pan.el.removeClass([lr,dir]);
16591 pan.setActive(true);
16593 cur.el.removeClass([lr]);
16594 cur.setActive(false);
16596 _this.transition = false;
16598 }, this, { single: true } );
16603 cur.setActive(false);
16604 pan.setActive(true);
16609 showPanelNext : function()
16611 var i = this.indexOfPanel(this.getActivePanel());
16613 if (i >= this.tabs.length - 1 && !this.autoslide) {
16617 if (i >= this.tabs.length - 1 && this.autoslide) {
16621 this.showPanel(this.tabs[i+1]);
16624 showPanelPrev : function()
16626 var i = this.indexOfPanel(this.getActivePanel());
16628 if (i < 1 && !this.autoslide) {
16632 if (i < 1 && this.autoslide) {
16633 i = this.tabs.length;
16636 this.showPanel(this.tabs[i-1]);
16640 addBullet: function()
16642 if(!this.bullets || Roo.isTouch){
16645 var ctr = this.el.select('.carousel-bullets',true).first();
16646 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
16647 var bullet = ctr.createChild({
16648 cls : 'bullet bullet-' + i
16649 },ctr.dom.lastChild);
16654 bullet.on('click', (function(e, el, o, ii, t){
16656 e.preventDefault();
16658 this.showPanel(ii);
16660 if(this.autoslide && this.slideFn){
16661 clearInterval(this.slideFn);
16662 this.slideFn = window.setInterval(function() {
16663 _this.showPanelNext();
16667 }).createDelegate(this, [i, bullet], true));
16672 setActiveBullet : function(i)
16678 Roo.each(this.el.select('.bullet', true).elements, function(el){
16679 el.removeClass('selected');
16682 var bullet = this.el.select('.bullet-' + i, true).first();
16688 bullet.addClass('selected');
16699 Roo.apply(Roo.bootstrap.TabGroup, {
16703 * register a Navigation Group
16704 * @param {Roo.bootstrap.NavGroup} the navgroup to add
16706 register : function(navgrp)
16708 this.groups[navgrp.navId] = navgrp;
16712 * fetch a Navigation Group based on the navigation ID
16713 * if one does not exist , it will get created.
16714 * @param {string} the navgroup to add
16715 * @returns {Roo.bootstrap.NavGroup} the navgroup
16717 get: function(navId) {
16718 if (typeof(this.groups[navId]) == 'undefined') {
16719 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
16721 return this.groups[navId] ;
16736 * @class Roo.bootstrap.TabPanel
16737 * @extends Roo.bootstrap.Component
16738 * Bootstrap TabPanel class
16739 * @cfg {Boolean} active panel active
16740 * @cfg {String} html panel content
16741 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
16742 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
16746 * Create a new TabPanel
16747 * @param {Object} config The config object
16750 Roo.bootstrap.TabPanel = function(config){
16751 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
16755 * Fires when the active status changes
16756 * @param {Roo.bootstrap.TabPanel} this
16757 * @param {Boolean} state the new state
16762 * @event beforedeactivate
16763 * Fires before a tab is de-activated - can be used to do validation on a form.
16764 * @param {Roo.bootstrap.TabPanel} this
16765 * @return {Boolean} false if there is an error
16768 'beforedeactivate': true
16771 this.tabId = this.tabId || Roo.id();
16775 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
16782 getAutoCreate : function(){
16785 // item is needed for carousel - not sure if it has any effect otherwise
16786 cls: 'tab-pane item',
16787 html: this.html || ''
16791 cfg.cls += ' active';
16795 cfg.tabId = this.tabId;
16802 initEvents: function()
16804 var p = this.parent();
16805 this.navId = this.navId || p.navId;
16807 if (typeof(this.navId) != 'undefined') {
16808 // not really needed.. but just in case.. parent should be a NavGroup.
16809 var tg = Roo.bootstrap.TabGroup.get(this.navId);
16813 var i = tg.tabs.length - 1;
16815 if(this.active && tg.bullets > 0 && i < tg.bullets){
16816 tg.setActiveBullet(i);
16823 onRender : function(ct, position)
16825 // Roo.log("Call onRender: " + this.xtype);
16827 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
16835 setActive: function(state)
16837 Roo.log("panel - set active " + this.tabId + "=" + state);
16839 this.active = state;
16841 this.el.removeClass('active');
16843 } else if (!this.el.hasClass('active')) {
16844 this.el.addClass('active');
16847 this.fireEvent('changed', this, state);
16864 * @class Roo.bootstrap.DateField
16865 * @extends Roo.bootstrap.Input
16866 * Bootstrap DateField class
16867 * @cfg {Number} weekStart default 0
16868 * @cfg {String} viewMode default empty, (months|years)
16869 * @cfg {String} minViewMode default empty, (months|years)
16870 * @cfg {Number} startDate default -Infinity
16871 * @cfg {Number} endDate default Infinity
16872 * @cfg {Boolean} todayHighlight default false
16873 * @cfg {Boolean} todayBtn default false
16874 * @cfg {Boolean} calendarWeeks default false
16875 * @cfg {Object} daysOfWeekDisabled default empty
16876 * @cfg {Boolean} singleMode default false (true | false)
16878 * @cfg {Boolean} keyboardNavigation default true
16879 * @cfg {String} language default en
16882 * Create a new DateField
16883 * @param {Object} config The config object
16886 Roo.bootstrap.DateField = function(config){
16887 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16891 * Fires when this field show.
16892 * @param {Roo.bootstrap.DateField} this
16893 * @param {Mixed} date The date value
16898 * Fires when this field hide.
16899 * @param {Roo.bootstrap.DateField} this
16900 * @param {Mixed} date The date value
16905 * Fires when select a date.
16906 * @param {Roo.bootstrap.DateField} this
16907 * @param {Mixed} date The date value
16911 * @event beforeselect
16912 * Fires when before select a date.
16913 * @param {Roo.bootstrap.DateField} this
16914 * @param {Mixed} date The date value
16916 beforeselect : true
16920 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16923 * @cfg {String} format
16924 * The default date format string which can be overriden for localization support. The format must be
16925 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16929 * @cfg {String} altFormats
16930 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16931 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16933 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16941 todayHighlight : false,
16947 keyboardNavigation: true,
16949 calendarWeeks: false,
16951 startDate: -Infinity,
16955 daysOfWeekDisabled: [],
16959 singleMode : false,
16961 UTCDate: function()
16963 return new Date(Date.UTC.apply(Date, arguments));
16966 UTCToday: function()
16968 var today = new Date();
16969 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16972 getDate: function() {
16973 var d = this.getUTCDate();
16974 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16977 getUTCDate: function() {
16981 setDate: function(d) {
16982 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16985 setUTCDate: function(d) {
16987 this.setValue(this.formatDate(this.date));
16990 onRender: function(ct, position)
16993 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16995 this.language = this.language || 'en';
16996 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16997 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16999 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17000 this.format = this.format || 'm/d/y';
17001 this.isInline = false;
17002 this.isInput = true;
17003 this.component = this.el.select('.add-on', true).first() || false;
17004 this.component = (this.component && this.component.length === 0) ? false : this.component;
17005 this.hasInput = this.component && this.inputEL().length;
17007 if (typeof(this.minViewMode === 'string')) {
17008 switch (this.minViewMode) {
17010 this.minViewMode = 1;
17013 this.minViewMode = 2;
17016 this.minViewMode = 0;
17021 if (typeof(this.viewMode === 'string')) {
17022 switch (this.viewMode) {
17035 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17037 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17039 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17041 this.picker().on('mousedown', this.onMousedown, this);
17042 this.picker().on('click', this.onClick, this);
17044 this.picker().addClass('datepicker-dropdown');
17046 this.startViewMode = this.viewMode;
17048 if(this.singleMode){
17049 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17050 v.setVisibilityMode(Roo.Element.DISPLAY);
17054 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17055 v.setStyle('width', '189px');
17059 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17060 if(!this.calendarWeeks){
17065 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17066 v.attr('colspan', function(i, val){
17067 return parseInt(val) + 1;
17072 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17074 this.setStartDate(this.startDate);
17075 this.setEndDate(this.endDate);
17077 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17084 if(this.isInline) {
17089 picker : function()
17091 return this.pickerEl;
17092 // return this.el.select('.datepicker', true).first();
17095 fillDow: function()
17097 var dowCnt = this.weekStart;
17106 if(this.calendarWeeks){
17114 while (dowCnt < this.weekStart + 7) {
17118 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17122 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17125 fillMonths: function()
17128 var months = this.picker().select('>.datepicker-months td', true).first();
17130 months.dom.innerHTML = '';
17136 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17139 months.createChild(month);
17146 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;
17148 if (this.date < this.startDate) {
17149 this.viewDate = new Date(this.startDate);
17150 } else if (this.date > this.endDate) {
17151 this.viewDate = new Date(this.endDate);
17153 this.viewDate = new Date(this.date);
17161 var d = new Date(this.viewDate),
17162 year = d.getUTCFullYear(),
17163 month = d.getUTCMonth(),
17164 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17165 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17166 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17167 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17168 currentDate = this.date && this.date.valueOf(),
17169 today = this.UTCToday();
17171 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17173 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17175 // this.picker.select('>tfoot th.today').
17176 // .text(dates[this.language].today)
17177 // .toggle(this.todayBtn !== false);
17179 this.updateNavArrows();
17182 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17184 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17186 prevMonth.setUTCDate(day);
17188 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17190 var nextMonth = new Date(prevMonth);
17192 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17194 nextMonth = nextMonth.valueOf();
17196 var fillMonths = false;
17198 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17200 while(prevMonth.valueOf() < nextMonth) {
17203 if (prevMonth.getUTCDay() === this.weekStart) {
17205 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17213 if(this.calendarWeeks){
17214 // ISO 8601: First week contains first thursday.
17215 // ISO also states week starts on Monday, but we can be more abstract here.
17217 // Start of current week: based on weekstart/current date
17218 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17219 // Thursday of this week
17220 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17221 // First Thursday of year, year from thursday
17222 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17223 // Calendar week: ms between thursdays, div ms per day, div 7 days
17224 calWeek = (th - yth) / 864e5 / 7 + 1;
17226 fillMonths.cn.push({
17234 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17236 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17239 if (this.todayHighlight &&
17240 prevMonth.getUTCFullYear() == today.getFullYear() &&
17241 prevMonth.getUTCMonth() == today.getMonth() &&
17242 prevMonth.getUTCDate() == today.getDate()) {
17243 clsName += ' today';
17246 if (currentDate && prevMonth.valueOf() === currentDate) {
17247 clsName += ' active';
17250 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17251 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17252 clsName += ' disabled';
17255 fillMonths.cn.push({
17257 cls: 'day ' + clsName,
17258 html: prevMonth.getDate()
17261 prevMonth.setDate(prevMonth.getDate()+1);
17264 var currentYear = this.date && this.date.getUTCFullYear();
17265 var currentMonth = this.date && this.date.getUTCMonth();
17267 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17269 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17270 v.removeClass('active');
17272 if(currentYear === year && k === currentMonth){
17273 v.addClass('active');
17276 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17277 v.addClass('disabled');
17283 year = parseInt(year/10, 10) * 10;
17285 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17287 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17290 for (var i = -1; i < 11; i++) {
17291 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17293 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17301 showMode: function(dir)
17304 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17307 Roo.each(this.picker().select('>div',true).elements, function(v){
17308 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17311 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17316 if(this.isInline) {
17320 this.picker().removeClass(['bottom', 'top']);
17322 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17324 * place to the top of element!
17328 this.picker().addClass('top');
17329 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17334 this.picker().addClass('bottom');
17336 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17339 parseDate : function(value)
17341 if(!value || value instanceof Date){
17344 var v = Date.parseDate(value, this.format);
17345 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17346 v = Date.parseDate(value, 'Y-m-d');
17348 if(!v && this.altFormats){
17349 if(!this.altFormatsArray){
17350 this.altFormatsArray = this.altFormats.split("|");
17352 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17353 v = Date.parseDate(value, this.altFormatsArray[i]);
17359 formatDate : function(date, fmt)
17361 return (!date || !(date instanceof Date)) ?
17362 date : date.dateFormat(fmt || this.format);
17365 onFocus : function()
17367 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17371 onBlur : function()
17373 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17375 var d = this.inputEl().getValue();
17384 this.picker().show();
17388 this.fireEvent('show', this, this.date);
17393 if(this.isInline) {
17396 this.picker().hide();
17397 this.viewMode = this.startViewMode;
17400 this.fireEvent('hide', this, this.date);
17404 onMousedown: function(e)
17406 e.stopPropagation();
17407 e.preventDefault();
17412 Roo.bootstrap.DateField.superclass.keyup.call(this);
17416 setValue: function(v)
17418 if(this.fireEvent('beforeselect', this, v) !== false){
17419 var d = new Date(this.parseDate(v) ).clearTime();
17421 if(isNaN(d.getTime())){
17422 this.date = this.viewDate = '';
17423 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17427 v = this.formatDate(d);
17429 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17431 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17435 this.fireEvent('select', this, this.date);
17439 getValue: function()
17441 return this.formatDate(this.date);
17444 fireKey: function(e)
17446 if (!this.picker().isVisible()){
17447 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17453 var dateChanged = false,
17455 newDate, newViewDate;
17460 e.preventDefault();
17464 if (!this.keyboardNavigation) {
17467 dir = e.keyCode == 37 ? -1 : 1;
17470 newDate = this.moveYear(this.date, dir);
17471 newViewDate = this.moveYear(this.viewDate, dir);
17472 } else if (e.shiftKey){
17473 newDate = this.moveMonth(this.date, dir);
17474 newViewDate = this.moveMonth(this.viewDate, dir);
17476 newDate = new Date(this.date);
17477 newDate.setUTCDate(this.date.getUTCDate() + dir);
17478 newViewDate = new Date(this.viewDate);
17479 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
17481 if (this.dateWithinRange(newDate)){
17482 this.date = newDate;
17483 this.viewDate = newViewDate;
17484 this.setValue(this.formatDate(this.date));
17486 e.preventDefault();
17487 dateChanged = true;
17492 if (!this.keyboardNavigation) {
17495 dir = e.keyCode == 38 ? -1 : 1;
17497 newDate = this.moveYear(this.date, dir);
17498 newViewDate = this.moveYear(this.viewDate, dir);
17499 } else if (e.shiftKey){
17500 newDate = this.moveMonth(this.date, dir);
17501 newViewDate = this.moveMonth(this.viewDate, dir);
17503 newDate = new Date(this.date);
17504 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
17505 newViewDate = new Date(this.viewDate);
17506 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
17508 if (this.dateWithinRange(newDate)){
17509 this.date = newDate;
17510 this.viewDate = newViewDate;
17511 this.setValue(this.formatDate(this.date));
17513 e.preventDefault();
17514 dateChanged = true;
17518 this.setValue(this.formatDate(this.date));
17520 e.preventDefault();
17523 this.setValue(this.formatDate(this.date));
17537 onClick: function(e)
17539 e.stopPropagation();
17540 e.preventDefault();
17542 var target = e.getTarget();
17544 if(target.nodeName.toLowerCase() === 'i'){
17545 target = Roo.get(target).dom.parentNode;
17548 var nodeName = target.nodeName;
17549 var className = target.className;
17550 var html = target.innerHTML;
17551 //Roo.log(nodeName);
17553 switch(nodeName.toLowerCase()) {
17555 switch(className) {
17561 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
17562 switch(this.viewMode){
17564 this.viewDate = this.moveMonth(this.viewDate, dir);
17568 this.viewDate = this.moveYear(this.viewDate, dir);
17574 var date = new Date();
17575 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
17577 this.setValue(this.formatDate(this.date));
17584 if (className.indexOf('disabled') < 0) {
17585 this.viewDate.setUTCDate(1);
17586 if (className.indexOf('month') > -1) {
17587 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
17589 var year = parseInt(html, 10) || 0;
17590 this.viewDate.setUTCFullYear(year);
17594 if(this.singleMode){
17595 this.setValue(this.formatDate(this.viewDate));
17606 //Roo.log(className);
17607 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
17608 var day = parseInt(html, 10) || 1;
17609 var year = this.viewDate.getUTCFullYear(),
17610 month = this.viewDate.getUTCMonth();
17612 if (className.indexOf('old') > -1) {
17619 } else if (className.indexOf('new') > -1) {
17627 //Roo.log([year,month,day]);
17628 this.date = this.UTCDate(year, month, day,0,0,0,0);
17629 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
17631 //Roo.log(this.formatDate(this.date));
17632 this.setValue(this.formatDate(this.date));
17639 setStartDate: function(startDate)
17641 this.startDate = startDate || -Infinity;
17642 if (this.startDate !== -Infinity) {
17643 this.startDate = this.parseDate(this.startDate);
17646 this.updateNavArrows();
17649 setEndDate: function(endDate)
17651 this.endDate = endDate || Infinity;
17652 if (this.endDate !== Infinity) {
17653 this.endDate = this.parseDate(this.endDate);
17656 this.updateNavArrows();
17659 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
17661 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
17662 if (typeof(this.daysOfWeekDisabled) !== 'object') {
17663 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
17665 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
17666 return parseInt(d, 10);
17669 this.updateNavArrows();
17672 updateNavArrows: function()
17674 if(this.singleMode){
17678 var d = new Date(this.viewDate),
17679 year = d.getUTCFullYear(),
17680 month = d.getUTCMonth();
17682 Roo.each(this.picker().select('.prev', true).elements, function(v){
17684 switch (this.viewMode) {
17687 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
17693 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
17700 Roo.each(this.picker().select('.next', true).elements, function(v){
17702 switch (this.viewMode) {
17705 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
17711 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
17719 moveMonth: function(date, dir)
17724 var new_date = new Date(date.valueOf()),
17725 day = new_date.getUTCDate(),
17726 month = new_date.getUTCMonth(),
17727 mag = Math.abs(dir),
17729 dir = dir > 0 ? 1 : -1;
17732 // If going back one month, make sure month is not current month
17733 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
17735 return new_date.getUTCMonth() == month;
17737 // If going forward one month, make sure month is as expected
17738 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
17740 return new_date.getUTCMonth() != new_month;
17742 new_month = month + dir;
17743 new_date.setUTCMonth(new_month);
17744 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
17745 if (new_month < 0 || new_month > 11) {
17746 new_month = (new_month + 12) % 12;
17749 // For magnitudes >1, move one month at a time...
17750 for (var i=0; i<mag; i++) {
17751 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
17752 new_date = this.moveMonth(new_date, dir);
17754 // ...then reset the day, keeping it in the new month
17755 new_month = new_date.getUTCMonth();
17756 new_date.setUTCDate(day);
17758 return new_month != new_date.getUTCMonth();
17761 // Common date-resetting loop -- if date is beyond end of month, make it
17764 new_date.setUTCDate(--day);
17765 new_date.setUTCMonth(new_month);
17770 moveYear: function(date, dir)
17772 return this.moveMonth(date, dir*12);
17775 dateWithinRange: function(date)
17777 return date >= this.startDate && date <= this.endDate;
17783 this.picker().remove();
17788 Roo.apply(Roo.bootstrap.DateField, {
17799 html: '<i class="fa fa-arrow-left"/>'
17809 html: '<i class="fa fa-arrow-right"/>'
17851 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
17852 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17853 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
17854 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17855 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17868 navFnc: 'FullYear',
17873 navFnc: 'FullYear',
17878 Roo.apply(Roo.bootstrap.DateField, {
17882 cls: 'datepicker dropdown-menu roo-dynamic',
17886 cls: 'datepicker-days',
17890 cls: 'table-condensed',
17892 Roo.bootstrap.DateField.head,
17896 Roo.bootstrap.DateField.footer
17903 cls: 'datepicker-months',
17907 cls: 'table-condensed',
17909 Roo.bootstrap.DateField.head,
17910 Roo.bootstrap.DateField.content,
17911 Roo.bootstrap.DateField.footer
17918 cls: 'datepicker-years',
17922 cls: 'table-condensed',
17924 Roo.bootstrap.DateField.head,
17925 Roo.bootstrap.DateField.content,
17926 Roo.bootstrap.DateField.footer
17945 * @class Roo.bootstrap.TimeField
17946 * @extends Roo.bootstrap.Input
17947 * Bootstrap DateField class
17951 * Create a new TimeField
17952 * @param {Object} config The config object
17955 Roo.bootstrap.TimeField = function(config){
17956 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17960 * Fires when this field show.
17961 * @param {Roo.bootstrap.DateField} thisthis
17962 * @param {Mixed} date The date value
17967 * Fires when this field hide.
17968 * @param {Roo.bootstrap.DateField} this
17969 * @param {Mixed} date The date value
17974 * Fires when select a date.
17975 * @param {Roo.bootstrap.DateField} this
17976 * @param {Mixed} date The date value
17982 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17985 * @cfg {String} format
17986 * The default time format string which can be overriden for localization support. The format must be
17987 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17991 onRender: function(ct, position)
17994 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17996 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17998 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18000 this.pop = this.picker().select('>.datepicker-time',true).first();
18001 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18003 this.picker().on('mousedown', this.onMousedown, this);
18004 this.picker().on('click', this.onClick, this);
18006 this.picker().addClass('datepicker-dropdown');
18011 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18012 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18013 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18014 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18015 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18016 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18020 fireKey: function(e){
18021 if (!this.picker().isVisible()){
18022 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18028 e.preventDefault();
18036 this.onTogglePeriod();
18039 this.onIncrementMinutes();
18042 this.onDecrementMinutes();
18051 onClick: function(e) {
18052 e.stopPropagation();
18053 e.preventDefault();
18056 picker : function()
18058 return this.el.select('.datepicker', true).first();
18061 fillTime: function()
18063 var time = this.pop.select('tbody', true).first();
18065 time.dom.innerHTML = '';
18080 cls: 'hours-up glyphicon glyphicon-chevron-up'
18100 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18121 cls: 'timepicker-hour',
18136 cls: 'timepicker-minute',
18151 cls: 'btn btn-primary period',
18173 cls: 'hours-down glyphicon glyphicon-chevron-down'
18193 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18211 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18218 var hours = this.time.getHours();
18219 var minutes = this.time.getMinutes();
18232 hours = hours - 12;
18236 hours = '0' + hours;
18240 minutes = '0' + minutes;
18243 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18244 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18245 this.pop.select('button', true).first().dom.innerHTML = period;
18251 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18253 var cls = ['bottom'];
18255 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18262 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18267 this.picker().addClass(cls.join('-'));
18271 Roo.each(cls, function(c){
18273 _this.picker().setTop(_this.inputEl().getHeight());
18277 _this.picker().setTop(0 - _this.picker().getHeight());
18282 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18286 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18293 onFocus : function()
18295 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18299 onBlur : function()
18301 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18307 this.picker().show();
18312 this.fireEvent('show', this, this.date);
18317 this.picker().hide();
18320 this.fireEvent('hide', this, this.date);
18323 setTime : function()
18326 this.setValue(this.time.format(this.format));
18328 this.fireEvent('select', this, this.date);
18333 onMousedown: function(e){
18334 e.stopPropagation();
18335 e.preventDefault();
18338 onIncrementHours: function()
18340 Roo.log('onIncrementHours');
18341 this.time = this.time.add(Date.HOUR, 1);
18346 onDecrementHours: function()
18348 Roo.log('onDecrementHours');
18349 this.time = this.time.add(Date.HOUR, -1);
18353 onIncrementMinutes: function()
18355 Roo.log('onIncrementMinutes');
18356 this.time = this.time.add(Date.MINUTE, 1);
18360 onDecrementMinutes: function()
18362 Roo.log('onDecrementMinutes');
18363 this.time = this.time.add(Date.MINUTE, -1);
18367 onTogglePeriod: function()
18369 Roo.log('onTogglePeriod');
18370 this.time = this.time.add(Date.HOUR, 12);
18377 Roo.apply(Roo.bootstrap.TimeField, {
18407 cls: 'btn btn-info ok',
18419 Roo.apply(Roo.bootstrap.TimeField, {
18423 cls: 'datepicker dropdown-menu',
18427 cls: 'datepicker-time',
18431 cls: 'table-condensed',
18433 Roo.bootstrap.TimeField.content,
18434 Roo.bootstrap.TimeField.footer
18453 * @class Roo.bootstrap.MonthField
18454 * @extends Roo.bootstrap.Input
18455 * Bootstrap MonthField class
18457 * @cfg {String} language default en
18460 * Create a new MonthField
18461 * @param {Object} config The config object
18464 Roo.bootstrap.MonthField = function(config){
18465 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
18470 * Fires when this field show.
18471 * @param {Roo.bootstrap.MonthField} this
18472 * @param {Mixed} date The date value
18477 * Fires when this field hide.
18478 * @param {Roo.bootstrap.MonthField} this
18479 * @param {Mixed} date The date value
18484 * Fires when select a date.
18485 * @param {Roo.bootstrap.MonthField} this
18486 * @param {String} oldvalue The old value
18487 * @param {String} newvalue The new value
18493 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
18495 onRender: function(ct, position)
18498 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
18500 this.language = this.language || 'en';
18501 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
18502 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
18504 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
18505 this.isInline = false;
18506 this.isInput = true;
18507 this.component = this.el.select('.add-on', true).first() || false;
18508 this.component = (this.component && this.component.length === 0) ? false : this.component;
18509 this.hasInput = this.component && this.inputEL().length;
18511 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
18513 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18515 this.picker().on('mousedown', this.onMousedown, this);
18516 this.picker().on('click', this.onClick, this);
18518 this.picker().addClass('datepicker-dropdown');
18520 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18521 v.setStyle('width', '189px');
18528 if(this.isInline) {
18534 setValue: function(v, suppressEvent)
18536 var o = this.getValue();
18538 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
18542 if(suppressEvent !== true){
18543 this.fireEvent('select', this, o, v);
18548 getValue: function()
18553 onClick: function(e)
18555 e.stopPropagation();
18556 e.preventDefault();
18558 var target = e.getTarget();
18560 if(target.nodeName.toLowerCase() === 'i'){
18561 target = Roo.get(target).dom.parentNode;
18564 var nodeName = target.nodeName;
18565 var className = target.className;
18566 var html = target.innerHTML;
18568 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
18572 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
18574 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18580 picker : function()
18582 return this.pickerEl;
18585 fillMonths: function()
18588 var months = this.picker().select('>.datepicker-months td', true).first();
18590 months.dom.innerHTML = '';
18596 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
18599 months.createChild(month);
18608 if(typeof(this.vIndex) == 'undefined' && this.value.length){
18609 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
18612 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
18613 e.removeClass('active');
18615 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
18616 e.addClass('active');
18623 if(this.isInline) {
18627 this.picker().removeClass(['bottom', 'top']);
18629 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18631 * place to the top of element!
18635 this.picker().addClass('top');
18636 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18641 this.picker().addClass('bottom');
18643 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18646 onFocus : function()
18648 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
18652 onBlur : function()
18654 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
18656 var d = this.inputEl().getValue();
18665 this.picker().show();
18666 this.picker().select('>.datepicker-months', true).first().show();
18670 this.fireEvent('show', this, this.date);
18675 if(this.isInline) {
18678 this.picker().hide();
18679 this.fireEvent('hide', this, this.date);
18683 onMousedown: function(e)
18685 e.stopPropagation();
18686 e.preventDefault();
18691 Roo.bootstrap.MonthField.superclass.keyup.call(this);
18695 fireKey: function(e)
18697 if (!this.picker().isVisible()){
18698 if (e.keyCode == 27) {// allow escape to hide and re-show picker
18709 e.preventDefault();
18713 dir = e.keyCode == 37 ? -1 : 1;
18715 this.vIndex = this.vIndex + dir;
18717 if(this.vIndex < 0){
18721 if(this.vIndex > 11){
18725 if(isNaN(this.vIndex)){
18729 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18735 dir = e.keyCode == 38 ? -1 : 1;
18737 this.vIndex = this.vIndex + dir * 4;
18739 if(this.vIndex < 0){
18743 if(this.vIndex > 11){
18747 if(isNaN(this.vIndex)){
18751 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18756 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18757 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18761 e.preventDefault();
18764 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18765 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18781 this.picker().remove();
18786 Roo.apply(Roo.bootstrap.MonthField, {
18805 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18806 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
18811 Roo.apply(Roo.bootstrap.MonthField, {
18815 cls: 'datepicker dropdown-menu roo-dynamic',
18819 cls: 'datepicker-months',
18823 cls: 'table-condensed',
18825 Roo.bootstrap.DateField.content
18845 * @class Roo.bootstrap.CheckBox
18846 * @extends Roo.bootstrap.Input
18847 * Bootstrap CheckBox class
18849 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
18850 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
18851 * @cfg {String} boxLabel The text that appears beside the checkbox
18852 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
18853 * @cfg {Boolean} checked initnal the element
18854 * @cfg {Boolean} inline inline the element (default false)
18855 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
18858 * Create a new CheckBox
18859 * @param {Object} config The config object
18862 Roo.bootstrap.CheckBox = function(config){
18863 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18868 * Fires when the element is checked or unchecked.
18869 * @param {Roo.bootstrap.CheckBox} this This input
18870 * @param {Boolean} checked The new checked value
18877 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18879 inputType: 'checkbox',
18887 getAutoCreate : function()
18889 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18895 cfg.cls = 'form-group ' + this.inputType; //input-group
18898 cfg.cls += ' ' + this.inputType + '-inline';
18904 type : this.inputType,
18905 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18906 cls : 'roo-' + this.inputType, //'form-box',
18907 placeholder : this.placeholder || ''
18911 if (this.weight) { // Validity check?
18912 cfg.cls += " " + this.inputType + "-" + this.weight;
18915 if (this.disabled) {
18916 input.disabled=true;
18920 input.checked = this.checked;
18924 input.name = this.name;
18928 input.cls += ' input-' + this.size;
18933 ['xs','sm','md','lg'].map(function(size){
18934 if (settings[size]) {
18935 cfg.cls += ' col-' + size + '-' + settings[size];
18939 var inputblock = input;
18941 if (this.before || this.after) {
18944 cls : 'input-group',
18949 inputblock.cn.push({
18951 cls : 'input-group-addon',
18956 inputblock.cn.push(input);
18959 inputblock.cn.push({
18961 cls : 'input-group-addon',
18968 if (align ==='left' && this.fieldLabel.length) {
18969 // Roo.log("left and has label");
18975 cls : 'control-label col-md-' + this.labelWidth,
18976 html : this.fieldLabel
18980 cls : "col-md-" + (12 - this.labelWidth),
18987 } else if ( this.fieldLabel.length) {
18988 // Roo.log(" label");
18992 tag: this.boxLabel ? 'span' : 'label',
18994 cls: 'control-label box-input-label',
18995 //cls : 'input-group-addon',
18996 html : this.fieldLabel
19006 // Roo.log(" no label && no align");
19007 cfg.cn = [ inputblock ] ;
19013 var boxLabelCfg = {
19015 //'for': id, // box label is handled by onclick - so no for...
19017 html: this.boxLabel
19021 boxLabelCfg.tooltip = this.tooltip;
19024 cfg.cn.push(boxLabelCfg);
19034 * return the real input element.
19036 inputEl: function ()
19038 return this.el.select('input.roo-' + this.inputType,true).first();
19041 labelEl: function()
19043 return this.el.select('label.control-label',true).first();
19045 /* depricated... */
19049 return this.labelEl();
19052 boxLabelEl: function()
19054 return this.el.select('label.box-label',true).first();
19057 initEvents : function()
19059 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19061 this.inputEl().on('click', this.onClick, this);
19063 if (this.boxLabel) {
19064 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19067 this.startValue = this.getValue();
19070 Roo.bootstrap.CheckBox.register(this);
19074 onClick : function()
19076 this.setChecked(!this.checked);
19079 setChecked : function(state,suppressEvent)
19081 this.startValue = this.getValue();
19083 if(this.inputType == 'radio'){
19085 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19086 e.dom.checked = false;
19089 this.inputEl().dom.checked = true;
19091 this.inputEl().dom.value = this.inputValue;
19093 if(suppressEvent !== true){
19094 this.fireEvent('check', this, true);
19102 this.checked = state;
19104 this.inputEl().dom.checked = state;
19106 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19108 if(suppressEvent !== true){
19109 this.fireEvent('check', this, state);
19115 getValue : function()
19117 if(this.inputType == 'radio'){
19118 return this.getGroupValue();
19121 return this.inputEl().getValue();
19125 getGroupValue : function()
19127 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19131 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19134 setValue : function(v,suppressEvent)
19136 if(this.inputType == 'radio'){
19137 this.setGroupValue(v, suppressEvent);
19141 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19146 setGroupValue : function(v, suppressEvent)
19148 this.startValue = this.getValue();
19150 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19151 e.dom.checked = false;
19153 if(e.dom.value == v){
19154 e.dom.checked = true;
19158 if(suppressEvent !== true){
19159 this.fireEvent('check', this, true);
19167 validate : function()
19171 (this.inputType == 'radio' && this.validateRadio()) ||
19172 (this.inputType == 'checkbox' && this.validateCheckbox())
19178 this.markInvalid();
19182 validateRadio : function()
19186 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19187 if(!e.dom.checked){
19199 validateCheckbox : function()
19202 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19205 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19213 for(var i in group){
19218 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19225 * Mark this field as valid
19227 markValid : function()
19229 if(this.allowBlank){
19235 this.fireEvent('valid', this);
19237 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19240 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19247 if(this.inputType == 'radio'){
19248 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19249 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19250 e.findParent('.form-group', false, true).addClass(_this.validClass);
19257 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19258 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19262 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19268 for(var i in group){
19269 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19270 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19275 * Mark this field as invalid
19276 * @param {String} msg The validation message
19278 markInvalid : function(msg)
19280 if(this.allowBlank){
19286 this.fireEvent('invalid', this, msg);
19288 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19291 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19295 label.markInvalid();
19298 if(this.inputType == 'radio'){
19299 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19300 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19301 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19308 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19309 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19313 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19319 for(var i in group){
19320 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19321 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19328 Roo.apply(Roo.bootstrap.CheckBox, {
19333 * register a CheckBox Group
19334 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19336 register : function(checkbox)
19338 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19339 this.groups[checkbox.groupId] = {};
19342 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19346 this.groups[checkbox.groupId][checkbox.name] = checkbox;
19350 * fetch a CheckBox Group based on the group ID
19351 * @param {string} the group ID
19352 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
19354 get: function(groupId) {
19355 if (typeof(this.groups[groupId]) == 'undefined') {
19359 return this.groups[groupId] ;
19371 *<div class="radio">
19373 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
19374 Option one is this and that—be sure to include why it's great
19381 *<label class="radio-inline">fieldLabel</label>
19382 *<label class="radio-inline">
19383 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
19391 * @class Roo.bootstrap.Radio
19392 * @extends Roo.bootstrap.CheckBox
19393 * Bootstrap Radio class
19396 * Create a new Radio
19397 * @param {Object} config The config object
19400 Roo.bootstrap.Radio = function(config){
19401 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
19405 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
19407 inputType: 'radio',
19411 getAutoCreate : function()
19413 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19414 align = align || 'left'; // default...
19421 tag : this.inline ? 'span' : 'div',
19426 var inline = this.inline ? ' radio-inline' : '';
19430 // does not need for, as we wrap the input with it..
19432 cls : 'control-label box-label' + inline,
19435 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
19439 //cls : 'control-label' + inline,
19440 html : this.fieldLabel,
19441 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
19450 type : this.inputType,
19451 //value : (!this.checked) ? this.valueOff : this.inputValue,
19452 value : this.inputValue,
19454 placeholder : this.placeholder || '' // ?? needed????
19457 if (this.weight) { // Validity check?
19458 input.cls += " radio-" + this.weight;
19460 if (this.disabled) {
19461 input.disabled=true;
19465 input.checked = this.checked;
19469 input.name = this.name;
19473 input.cls += ' input-' + this.size;
19476 //?? can span's inline have a width??
19479 ['xs','sm','md','lg'].map(function(size){
19480 if (settings[size]) {
19481 cfg.cls += ' col-' + size + '-' + settings[size];
19485 var inputblock = input;
19487 if (this.before || this.after) {
19490 cls : 'input-group',
19495 inputblock.cn.push({
19497 cls : 'input-group-addon',
19501 inputblock.cn.push(input);
19503 inputblock.cn.push({
19505 cls : 'input-group-addon',
19513 if (this.fieldLabel && this.fieldLabel.length) {
19514 cfg.cn.push(fieldLabel);
19517 // normal bootstrap puts the input inside the label.
19518 // however with our styled version - it has to go after the input.
19520 //lbl.cn.push(inputblock);
19524 cls: 'radio' + inline,
19531 cfg.cn.push( lblwrap);
19536 html: this.boxLabel
19545 initEvents : function()
19547 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19549 this.inputEl().on('click', this.onClick, this);
19550 if (this.boxLabel) {
19551 //Roo.log('find label');
19552 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
19557 inputEl: function ()
19559 return this.el.select('input.roo-radio',true).first();
19561 onClick : function()
19564 this.setChecked(true);
19567 setChecked : function(state,suppressEvent)
19570 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19571 v.dom.checked = false;
19574 Roo.log(this.inputEl().dom);
19575 this.checked = state;
19576 this.inputEl().dom.checked = state;
19578 if(suppressEvent !== true){
19579 this.fireEvent('check', this, state);
19582 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19586 getGroupValue : function()
19589 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19590 if(v.dom.checked == true){
19591 value = v.dom.value;
19599 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19600 * @return {Mixed} value The field value
19602 getValue : function(){
19603 return this.getGroupValue();
19609 //<script type="text/javascript">
19612 * Based Ext JS Library 1.1.1
19613 * Copyright(c) 2006-2007, Ext JS, LLC.
19619 * @class Roo.HtmlEditorCore
19620 * @extends Roo.Component
19621 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
19623 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
19626 Roo.HtmlEditorCore = function(config){
19629 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
19634 * @event initialize
19635 * Fires when the editor is fully initialized (including the iframe)
19636 * @param {Roo.HtmlEditorCore} this
19641 * Fires when the editor is first receives the focus. Any insertion must wait
19642 * until after this event.
19643 * @param {Roo.HtmlEditorCore} this
19647 * @event beforesync
19648 * Fires before the textarea is updated with content from the editor iframe. Return false
19649 * to cancel the sync.
19650 * @param {Roo.HtmlEditorCore} this
19651 * @param {String} html
19655 * @event beforepush
19656 * Fires before the iframe editor is updated with content from the textarea. Return false
19657 * to cancel the push.
19658 * @param {Roo.HtmlEditorCore} this
19659 * @param {String} html
19664 * Fires when the textarea is updated with content from the editor iframe.
19665 * @param {Roo.HtmlEditorCore} this
19666 * @param {String} html
19671 * Fires when the iframe editor is updated with content from the textarea.
19672 * @param {Roo.HtmlEditorCore} this
19673 * @param {String} html
19678 * @event editorevent
19679 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19680 * @param {Roo.HtmlEditorCore} this
19686 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
19688 // defaults : white / black...
19689 this.applyBlacklists();
19696 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
19700 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
19706 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19711 * @cfg {Number} height (in pixels)
19715 * @cfg {Number} width (in pixels)
19720 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19723 stylesheets: false,
19728 // private properties
19729 validationEvent : false,
19731 initialized : false,
19733 sourceEditMode : false,
19734 onFocus : Roo.emptyFn,
19736 hideMode:'offsets',
19740 // blacklist + whitelisted elements..
19747 * Protected method that will not generally be called directly. It
19748 * is called when the editor initializes the iframe with HTML contents. Override this method if you
19749 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
19751 getDocMarkup : function(){
19755 // inherit styels from page...??
19756 if (this.stylesheets === false) {
19758 Roo.get(document.head).select('style').each(function(node) {
19759 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19762 Roo.get(document.head).select('link').each(function(node) {
19763 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19766 } else if (!this.stylesheets.length) {
19768 st = '<style type="text/css">' +
19769 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19775 st += '<style type="text/css">' +
19776 'IMG { cursor: pointer } ' +
19780 return '<html><head>' + st +
19781 //<style type="text/css">' +
19782 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19784 ' </head><body class="roo-htmleditor-body"></body></html>';
19788 onRender : function(ct, position)
19791 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
19792 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
19795 this.el.dom.style.border = '0 none';
19796 this.el.dom.setAttribute('tabIndex', -1);
19797 this.el.addClass('x-hidden hide');
19801 if(Roo.isIE){ // fix IE 1px bogus margin
19802 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
19806 this.frameId = Roo.id();
19810 var iframe = this.owner.wrap.createChild({
19812 cls: 'form-control', // bootstrap..
19814 name: this.frameId,
19815 frameBorder : 'no',
19816 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
19821 this.iframe = iframe.dom;
19823 this.assignDocWin();
19825 this.doc.designMode = 'on';
19828 this.doc.write(this.getDocMarkup());
19832 var task = { // must defer to wait for browser to be ready
19834 //console.log("run task?" + this.doc.readyState);
19835 this.assignDocWin();
19836 if(this.doc.body || this.doc.readyState == 'complete'){
19838 this.doc.designMode="on";
19842 Roo.TaskMgr.stop(task);
19843 this.initEditor.defer(10, this);
19850 Roo.TaskMgr.start(task);
19855 onResize : function(w, h)
19857 Roo.log('resize: ' +w + ',' + h );
19858 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
19862 if(typeof w == 'number'){
19864 this.iframe.style.width = w + 'px';
19866 if(typeof h == 'number'){
19868 this.iframe.style.height = h + 'px';
19870 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
19877 * Toggles the editor between standard and source edit mode.
19878 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19880 toggleSourceEdit : function(sourceEditMode){
19882 this.sourceEditMode = sourceEditMode === true;
19884 if(this.sourceEditMode){
19886 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19889 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19890 //this.iframe.className = '';
19893 //this.setSize(this.owner.wrap.getSize());
19894 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19901 * Protected method that will not generally be called directly. If you need/want
19902 * custom HTML cleanup, this is the method you should override.
19903 * @param {String} html The HTML to be cleaned
19904 * return {String} The cleaned HTML
19906 cleanHtml : function(html){
19907 html = String(html);
19908 if(html.length > 5){
19909 if(Roo.isSafari){ // strip safari nonsense
19910 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19913 if(html == ' '){
19920 * HTML Editor -> Textarea
19921 * Protected method that will not generally be called directly. Syncs the contents
19922 * of the editor iframe with the textarea.
19924 syncValue : function(){
19925 if(this.initialized){
19926 var bd = (this.doc.body || this.doc.documentElement);
19927 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19928 var html = bd.innerHTML;
19930 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19931 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19933 html = '<div style="'+m[0]+'">' + html + '</div>';
19936 html = this.cleanHtml(html);
19937 // fix up the special chars.. normaly like back quotes in word...
19938 // however we do not want to do this with chinese..
19939 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19940 var cc = b.charCodeAt();
19942 (cc >= 0x4E00 && cc < 0xA000 ) ||
19943 (cc >= 0x3400 && cc < 0x4E00 ) ||
19944 (cc >= 0xf900 && cc < 0xfb00 )
19950 if(this.owner.fireEvent('beforesync', this, html) !== false){
19951 this.el.dom.value = html;
19952 this.owner.fireEvent('sync', this, html);
19958 * Protected method that will not generally be called directly. Pushes the value of the textarea
19959 * into the iframe editor.
19961 pushValue : function(){
19962 if(this.initialized){
19963 var v = this.el.dom.value.trim();
19965 // if(v.length < 1){
19969 if(this.owner.fireEvent('beforepush', this, v) !== false){
19970 var d = (this.doc.body || this.doc.documentElement);
19972 this.cleanUpPaste();
19973 this.el.dom.value = d.innerHTML;
19974 this.owner.fireEvent('push', this, v);
19980 deferFocus : function(){
19981 this.focus.defer(10, this);
19985 focus : function(){
19986 if(this.win && !this.sourceEditMode){
19993 assignDocWin: function()
19995 var iframe = this.iframe;
19998 this.doc = iframe.contentWindow.document;
19999 this.win = iframe.contentWindow;
20001 // if (!Roo.get(this.frameId)) {
20004 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20005 // this.win = Roo.get(this.frameId).dom.contentWindow;
20007 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20011 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20012 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20017 initEditor : function(){
20018 //console.log("INIT EDITOR");
20019 this.assignDocWin();
20023 this.doc.designMode="on";
20025 this.doc.write(this.getDocMarkup());
20028 var dbody = (this.doc.body || this.doc.documentElement);
20029 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20030 // this copies styles from the containing element into thsi one..
20031 // not sure why we need all of this..
20032 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20034 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20035 //ss['background-attachment'] = 'fixed'; // w3c
20036 dbody.bgProperties = 'fixed'; // ie
20037 //Roo.DomHelper.applyStyles(dbody, ss);
20038 Roo.EventManager.on(this.doc, {
20039 //'mousedown': this.onEditorEvent,
20040 'mouseup': this.onEditorEvent,
20041 'dblclick': this.onEditorEvent,
20042 'click': this.onEditorEvent,
20043 'keyup': this.onEditorEvent,
20048 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20050 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20051 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20053 this.initialized = true;
20055 this.owner.fireEvent('initialize', this);
20060 onDestroy : function(){
20066 //for (var i =0; i < this.toolbars.length;i++) {
20067 // // fixme - ask toolbars for heights?
20068 // this.toolbars[i].onDestroy();
20071 //this.wrap.dom.innerHTML = '';
20072 //this.wrap.remove();
20077 onFirstFocus : function(){
20079 this.assignDocWin();
20082 this.activated = true;
20085 if(Roo.isGecko){ // prevent silly gecko errors
20087 var s = this.win.getSelection();
20088 if(!s.focusNode || s.focusNode.nodeType != 3){
20089 var r = s.getRangeAt(0);
20090 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20095 this.execCmd('useCSS', true);
20096 this.execCmd('styleWithCSS', false);
20099 this.owner.fireEvent('activate', this);
20103 adjustFont: function(btn){
20104 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20105 //if(Roo.isSafari){ // safari
20108 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20109 if(Roo.isSafari){ // safari
20110 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20111 v = (v < 10) ? 10 : v;
20112 v = (v > 48) ? 48 : v;
20113 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20118 v = Math.max(1, v+adjust);
20120 this.execCmd('FontSize', v );
20123 onEditorEvent : function(e)
20125 this.owner.fireEvent('editorevent', this, e);
20126 // this.updateToolbar();
20127 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20130 insertTag : function(tg)
20132 // could be a bit smarter... -> wrap the current selected tRoo..
20133 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20135 range = this.createRange(this.getSelection());
20136 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20137 wrappingNode.appendChild(range.extractContents());
20138 range.insertNode(wrappingNode);
20145 this.execCmd("formatblock", tg);
20149 insertText : function(txt)
20153 var range = this.createRange();
20154 range.deleteContents();
20155 //alert(Sender.getAttribute('label'));
20157 range.insertNode(this.doc.createTextNode(txt));
20163 * Executes a Midas editor command on the editor document and performs necessary focus and
20164 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20165 * @param {String} cmd The Midas command
20166 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20168 relayCmd : function(cmd, value){
20170 this.execCmd(cmd, value);
20171 this.owner.fireEvent('editorevent', this);
20172 //this.updateToolbar();
20173 this.owner.deferFocus();
20177 * Executes a Midas editor command directly on the editor document.
20178 * For visual commands, you should use {@link #relayCmd} instead.
20179 * <b>This should only be called after the editor is initialized.</b>
20180 * @param {String} cmd The Midas command
20181 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20183 execCmd : function(cmd, value){
20184 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20191 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20193 * @param {String} text | dom node..
20195 insertAtCursor : function(text)
20200 if(!this.activated){
20206 var r = this.doc.selection.createRange();
20217 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20221 // from jquery ui (MIT licenced)
20223 var win = this.win;
20225 if (win.getSelection && win.getSelection().getRangeAt) {
20226 range = win.getSelection().getRangeAt(0);
20227 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20228 range.insertNode(node);
20229 } else if (win.document.selection && win.document.selection.createRange) {
20230 // no firefox support
20231 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20232 win.document.selection.createRange().pasteHTML(txt);
20234 // no firefox support
20235 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20236 this.execCmd('InsertHTML', txt);
20245 mozKeyPress : function(e){
20247 var c = e.getCharCode(), cmd;
20250 c = String.fromCharCode(c).toLowerCase();
20264 this.cleanUpPaste.defer(100, this);
20272 e.preventDefault();
20280 fixKeys : function(){ // load time branching for fastest keydown performance
20282 return function(e){
20283 var k = e.getKey(), r;
20286 r = this.doc.selection.createRange();
20289 r.pasteHTML('    ');
20296 r = this.doc.selection.createRange();
20298 var target = r.parentElement();
20299 if(!target || target.tagName.toLowerCase() != 'li'){
20301 r.pasteHTML('<br />');
20307 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20308 this.cleanUpPaste.defer(100, this);
20314 }else if(Roo.isOpera){
20315 return function(e){
20316 var k = e.getKey();
20320 this.execCmd('InsertHTML','    ');
20323 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20324 this.cleanUpPaste.defer(100, this);
20329 }else if(Roo.isSafari){
20330 return function(e){
20331 var k = e.getKey();
20335 this.execCmd('InsertText','\t');
20339 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20340 this.cleanUpPaste.defer(100, this);
20348 getAllAncestors: function()
20350 var p = this.getSelectedNode();
20353 a.push(p); // push blank onto stack..
20354 p = this.getParentElement();
20358 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
20362 a.push(this.doc.body);
20366 lastSelNode : false,
20369 getSelection : function()
20371 this.assignDocWin();
20372 return Roo.isIE ? this.doc.selection : this.win.getSelection();
20375 getSelectedNode: function()
20377 // this may only work on Gecko!!!
20379 // should we cache this!!!!
20384 var range = this.createRange(this.getSelection()).cloneRange();
20387 var parent = range.parentElement();
20389 var testRange = range.duplicate();
20390 testRange.moveToElementText(parent);
20391 if (testRange.inRange(range)) {
20394 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
20397 parent = parent.parentElement;
20402 // is ancestor a text element.
20403 var ac = range.commonAncestorContainer;
20404 if (ac.nodeType == 3) {
20405 ac = ac.parentNode;
20408 var ar = ac.childNodes;
20411 var other_nodes = [];
20412 var has_other_nodes = false;
20413 for (var i=0;i<ar.length;i++) {
20414 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
20417 // fullly contained node.
20419 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
20424 // probably selected..
20425 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
20426 other_nodes.push(ar[i]);
20430 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
20435 has_other_nodes = true;
20437 if (!nodes.length && other_nodes.length) {
20438 nodes= other_nodes;
20440 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
20446 createRange: function(sel)
20448 // this has strange effects when using with
20449 // top toolbar - not sure if it's a great idea.
20450 //this.editor.contentWindow.focus();
20451 if (typeof sel != "undefined") {
20453 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
20455 return this.doc.createRange();
20458 return this.doc.createRange();
20461 getParentElement: function()
20464 this.assignDocWin();
20465 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
20467 var range = this.createRange(sel);
20470 var p = range.commonAncestorContainer;
20471 while (p.nodeType == 3) { // text node
20482 * Range intersection.. the hard stuff...
20486 * [ -- selected range --- ]
20490 * if end is before start or hits it. fail.
20491 * if start is after end or hits it fail.
20493 * if either hits (but other is outside. - then it's not
20499 // @see http://www.thismuchiknow.co.uk/?p=64.
20500 rangeIntersectsNode : function(range, node)
20502 var nodeRange = node.ownerDocument.createRange();
20504 nodeRange.selectNode(node);
20506 nodeRange.selectNodeContents(node);
20509 var rangeStartRange = range.cloneRange();
20510 rangeStartRange.collapse(true);
20512 var rangeEndRange = range.cloneRange();
20513 rangeEndRange.collapse(false);
20515 var nodeStartRange = nodeRange.cloneRange();
20516 nodeStartRange.collapse(true);
20518 var nodeEndRange = nodeRange.cloneRange();
20519 nodeEndRange.collapse(false);
20521 return rangeStartRange.compareBoundaryPoints(
20522 Range.START_TO_START, nodeEndRange) == -1 &&
20523 rangeEndRange.compareBoundaryPoints(
20524 Range.START_TO_START, nodeStartRange) == 1;
20528 rangeCompareNode : function(range, node)
20530 var nodeRange = node.ownerDocument.createRange();
20532 nodeRange.selectNode(node);
20534 nodeRange.selectNodeContents(node);
20538 range.collapse(true);
20540 nodeRange.collapse(true);
20542 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
20543 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
20545 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
20547 var nodeIsBefore = ss == 1;
20548 var nodeIsAfter = ee == -1;
20550 if (nodeIsBefore && nodeIsAfter) {
20553 if (!nodeIsBefore && nodeIsAfter) {
20554 return 1; //right trailed.
20557 if (nodeIsBefore && !nodeIsAfter) {
20558 return 2; // left trailed.
20564 // private? - in a new class?
20565 cleanUpPaste : function()
20567 // cleans up the whole document..
20568 Roo.log('cleanuppaste');
20570 this.cleanUpChildren(this.doc.body);
20571 var clean = this.cleanWordChars(this.doc.body.innerHTML);
20572 if (clean != this.doc.body.innerHTML) {
20573 this.doc.body.innerHTML = clean;
20578 cleanWordChars : function(input) {// change the chars to hex code
20579 var he = Roo.HtmlEditorCore;
20581 var output = input;
20582 Roo.each(he.swapCodes, function(sw) {
20583 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
20585 output = output.replace(swapper, sw[1]);
20592 cleanUpChildren : function (n)
20594 if (!n.childNodes.length) {
20597 for (var i = n.childNodes.length-1; i > -1 ; i--) {
20598 this.cleanUpChild(n.childNodes[i]);
20605 cleanUpChild : function (node)
20608 //console.log(node);
20609 if (node.nodeName == "#text") {
20610 // clean up silly Windows -- stuff?
20613 if (node.nodeName == "#comment") {
20614 node.parentNode.removeChild(node);
20615 // clean up silly Windows -- stuff?
20618 var lcname = node.tagName.toLowerCase();
20619 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
20620 // whitelist of tags..
20622 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
20624 node.parentNode.removeChild(node);
20629 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
20631 // remove <a name=....> as rendering on yahoo mailer is borked with this.
20632 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
20634 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
20635 // remove_keep_children = true;
20638 if (remove_keep_children) {
20639 this.cleanUpChildren(node);
20640 // inserts everything just before this node...
20641 while (node.childNodes.length) {
20642 var cn = node.childNodes[0];
20643 node.removeChild(cn);
20644 node.parentNode.insertBefore(cn, node);
20646 node.parentNode.removeChild(node);
20650 if (!node.attributes || !node.attributes.length) {
20651 this.cleanUpChildren(node);
20655 function cleanAttr(n,v)
20658 if (v.match(/^\./) || v.match(/^\//)) {
20661 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
20664 if (v.match(/^#/)) {
20667 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
20668 node.removeAttribute(n);
20672 var cwhite = this.cwhite;
20673 var cblack = this.cblack;
20675 function cleanStyle(n,v)
20677 if (v.match(/expression/)) { //XSS?? should we even bother..
20678 node.removeAttribute(n);
20682 var parts = v.split(/;/);
20685 Roo.each(parts, function(p) {
20686 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
20690 var l = p.split(':').shift().replace(/\s+/g,'');
20691 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
20693 if ( cwhite.length && cblack.indexOf(l) > -1) {
20694 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20695 //node.removeAttribute(n);
20699 // only allow 'c whitelisted system attributes'
20700 if ( cwhite.length && cwhite.indexOf(l) < 0) {
20701 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20702 //node.removeAttribute(n);
20712 if (clean.length) {
20713 node.setAttribute(n, clean.join(';'));
20715 node.removeAttribute(n);
20721 for (var i = node.attributes.length-1; i > -1 ; i--) {
20722 var a = node.attributes[i];
20725 if (a.name.toLowerCase().substr(0,2)=='on') {
20726 node.removeAttribute(a.name);
20729 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
20730 node.removeAttribute(a.name);
20733 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
20734 cleanAttr(a.name,a.value); // fixme..
20737 if (a.name == 'style') {
20738 cleanStyle(a.name,a.value);
20741 /// clean up MS crap..
20742 // tecnically this should be a list of valid class'es..
20745 if (a.name == 'class') {
20746 if (a.value.match(/^Mso/)) {
20747 node.className = '';
20750 if (a.value.match(/body/)) {
20751 node.className = '';
20762 this.cleanUpChildren(node);
20768 * Clean up MS wordisms...
20770 cleanWord : function(node)
20775 this.cleanWord(this.doc.body);
20778 if (node.nodeName == "#text") {
20779 // clean up silly Windows -- stuff?
20782 if (node.nodeName == "#comment") {
20783 node.parentNode.removeChild(node);
20784 // clean up silly Windows -- stuff?
20788 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
20789 node.parentNode.removeChild(node);
20793 // remove - but keep children..
20794 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
20795 while (node.childNodes.length) {
20796 var cn = node.childNodes[0];
20797 node.removeChild(cn);
20798 node.parentNode.insertBefore(cn, node);
20800 node.parentNode.removeChild(node);
20801 this.iterateChildren(node, this.cleanWord);
20805 if (node.className.length) {
20807 var cn = node.className.split(/\W+/);
20809 Roo.each(cn, function(cls) {
20810 if (cls.match(/Mso[a-zA-Z]+/)) {
20815 node.className = cna.length ? cna.join(' ') : '';
20817 node.removeAttribute("class");
20821 if (node.hasAttribute("lang")) {
20822 node.removeAttribute("lang");
20825 if (node.hasAttribute("style")) {
20827 var styles = node.getAttribute("style").split(";");
20829 Roo.each(styles, function(s) {
20830 if (!s.match(/:/)) {
20833 var kv = s.split(":");
20834 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
20837 // what ever is left... we allow.
20840 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20841 if (!nstyle.length) {
20842 node.removeAttribute('style');
20845 this.iterateChildren(node, this.cleanWord);
20851 * iterateChildren of a Node, calling fn each time, using this as the scole..
20852 * @param {DomNode} node node to iterate children of.
20853 * @param {Function} fn method of this class to call on each item.
20855 iterateChildren : function(node, fn)
20857 if (!node.childNodes.length) {
20860 for (var i = node.childNodes.length-1; i > -1 ; i--) {
20861 fn.call(this, node.childNodes[i])
20867 * cleanTableWidths.
20869 * Quite often pasting from word etc.. results in tables with column and widths.
20870 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
20873 cleanTableWidths : function(node)
20878 this.cleanTableWidths(this.doc.body);
20883 if (node.nodeName == "#text" || node.nodeName == "#comment") {
20886 Roo.log(node.tagName);
20887 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
20888 this.iterateChildren(node, this.cleanTableWidths);
20891 if (node.hasAttribute('width')) {
20892 node.removeAttribute('width');
20896 if (node.hasAttribute("style")) {
20899 var styles = node.getAttribute("style").split(";");
20901 Roo.each(styles, function(s) {
20902 if (!s.match(/:/)) {
20905 var kv = s.split(":");
20906 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20909 // what ever is left... we allow.
20912 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20913 if (!nstyle.length) {
20914 node.removeAttribute('style');
20918 this.iterateChildren(node, this.cleanTableWidths);
20926 domToHTML : function(currentElement, depth, nopadtext) {
20928 depth = depth || 0;
20929 nopadtext = nopadtext || false;
20931 if (!currentElement) {
20932 return this.domToHTML(this.doc.body);
20935 //Roo.log(currentElement);
20937 var allText = false;
20938 var nodeName = currentElement.nodeName;
20939 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20941 if (nodeName == '#text') {
20943 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20948 if (nodeName != 'BODY') {
20951 // Prints the node tagName, such as <A>, <IMG>, etc
20954 for(i = 0; i < currentElement.attributes.length;i++) {
20956 var aname = currentElement.attributes.item(i).name;
20957 if (!currentElement.attributes.item(i).value.length) {
20960 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20963 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20972 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20975 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20980 // Traverse the tree
20982 var currentElementChild = currentElement.childNodes.item(i);
20983 var allText = true;
20984 var innerHTML = '';
20986 while (currentElementChild) {
20987 // Formatting code (indent the tree so it looks nice on the screen)
20988 var nopad = nopadtext;
20989 if (lastnode == 'SPAN') {
20993 if (currentElementChild.nodeName == '#text') {
20994 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20995 toadd = nopadtext ? toadd : toadd.trim();
20996 if (!nopad && toadd.length > 80) {
20997 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20999 innerHTML += toadd;
21002 currentElementChild = currentElement.childNodes.item(i);
21008 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21010 // Recursively traverse the tree structure of the child node
21011 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21012 lastnode = currentElementChild.nodeName;
21014 currentElementChild=currentElement.childNodes.item(i);
21020 // The remaining code is mostly for formatting the tree
21021 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21026 ret+= "</"+tagName+">";
21032 applyBlacklists : function()
21034 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21035 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21039 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21040 if (b.indexOf(tag) > -1) {
21043 this.white.push(tag);
21047 Roo.each(w, function(tag) {
21048 if (b.indexOf(tag) > -1) {
21051 if (this.white.indexOf(tag) > -1) {
21054 this.white.push(tag);
21059 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21060 if (w.indexOf(tag) > -1) {
21063 this.black.push(tag);
21067 Roo.each(b, function(tag) {
21068 if (w.indexOf(tag) > -1) {
21071 if (this.black.indexOf(tag) > -1) {
21074 this.black.push(tag);
21079 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21080 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21084 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21085 if (b.indexOf(tag) > -1) {
21088 this.cwhite.push(tag);
21092 Roo.each(w, function(tag) {
21093 if (b.indexOf(tag) > -1) {
21096 if (this.cwhite.indexOf(tag) > -1) {
21099 this.cwhite.push(tag);
21104 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21105 if (w.indexOf(tag) > -1) {
21108 this.cblack.push(tag);
21112 Roo.each(b, function(tag) {
21113 if (w.indexOf(tag) > -1) {
21116 if (this.cblack.indexOf(tag) > -1) {
21119 this.cblack.push(tag);
21124 setStylesheets : function(stylesheets)
21126 if(typeof(stylesheets) == 'string'){
21127 Roo.get(this.iframe.contentDocument.head).createChild({
21129 rel : 'stylesheet',
21138 Roo.each(stylesheets, function(s) {
21143 Roo.get(_this.iframe.contentDocument.head).createChild({
21145 rel : 'stylesheet',
21154 removeStylesheets : function()
21158 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21163 // hide stuff that is not compatible
21177 * @event specialkey
21181 * @cfg {String} fieldClass @hide
21184 * @cfg {String} focusClass @hide
21187 * @cfg {String} autoCreate @hide
21190 * @cfg {String} inputType @hide
21193 * @cfg {String} invalidClass @hide
21196 * @cfg {String} invalidText @hide
21199 * @cfg {String} msgFx @hide
21202 * @cfg {String} validateOnBlur @hide
21206 Roo.HtmlEditorCore.white = [
21207 'area', 'br', 'img', 'input', 'hr', 'wbr',
21209 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21210 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21211 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21212 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21213 'table', 'ul', 'xmp',
21215 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21218 'dir', 'menu', 'ol', 'ul', 'dl',
21224 Roo.HtmlEditorCore.black = [
21225 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21227 'base', 'basefont', 'bgsound', 'blink', 'body',
21228 'frame', 'frameset', 'head', 'html', 'ilayer',
21229 'iframe', 'layer', 'link', 'meta', 'object',
21230 'script', 'style' ,'title', 'xml' // clean later..
21232 Roo.HtmlEditorCore.clean = [
21233 'script', 'style', 'title', 'xml'
21235 Roo.HtmlEditorCore.remove = [
21240 Roo.HtmlEditorCore.ablack = [
21244 Roo.HtmlEditorCore.aclean = [
21245 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21249 Roo.HtmlEditorCore.pwhite= [
21250 'http', 'https', 'mailto'
21253 // white listed style attributes.
21254 Roo.HtmlEditorCore.cwhite= [
21255 // 'text-align', /// default is to allow most things..
21261 // black listed style attributes.
21262 Roo.HtmlEditorCore.cblack= [
21263 // 'font-size' -- this can be set by the project
21267 Roo.HtmlEditorCore.swapCodes =[
21286 * @class Roo.bootstrap.HtmlEditor
21287 * @extends Roo.bootstrap.TextArea
21288 * Bootstrap HtmlEditor class
21291 * Create a new HtmlEditor
21292 * @param {Object} config The config object
21295 Roo.bootstrap.HtmlEditor = function(config){
21296 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21297 if (!this.toolbars) {
21298 this.toolbars = [];
21300 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21303 * @event initialize
21304 * Fires when the editor is fully initialized (including the iframe)
21305 * @param {HtmlEditor} this
21310 * Fires when the editor is first receives the focus. Any insertion must wait
21311 * until after this event.
21312 * @param {HtmlEditor} this
21316 * @event beforesync
21317 * Fires before the textarea is updated with content from the editor iframe. Return false
21318 * to cancel the sync.
21319 * @param {HtmlEditor} this
21320 * @param {String} html
21324 * @event beforepush
21325 * Fires before the iframe editor is updated with content from the textarea. Return false
21326 * to cancel the push.
21327 * @param {HtmlEditor} this
21328 * @param {String} html
21333 * Fires when the textarea is updated with content from the editor iframe.
21334 * @param {HtmlEditor} this
21335 * @param {String} html
21340 * Fires when the iframe editor is updated with content from the textarea.
21341 * @param {HtmlEditor} this
21342 * @param {String} html
21346 * @event editmodechange
21347 * Fires when the editor switches edit modes
21348 * @param {HtmlEditor} this
21349 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21351 editmodechange: true,
21353 * @event editorevent
21354 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21355 * @param {HtmlEditor} this
21359 * @event firstfocus
21360 * Fires when on first focus - needed by toolbars..
21361 * @param {HtmlEditor} this
21366 * Auto save the htmlEditor value as a file into Events
21367 * @param {HtmlEditor} this
21371 * @event savedpreview
21372 * preview the saved version of htmlEditor
21373 * @param {HtmlEditor} this
21380 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
21384 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
21389 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21394 * @cfg {Number} height (in pixels)
21398 * @cfg {Number} width (in pixels)
21403 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21406 stylesheets: false,
21411 // private properties
21412 validationEvent : false,
21414 initialized : false,
21417 onFocus : Roo.emptyFn,
21419 hideMode:'offsets',
21422 tbContainer : false,
21424 toolbarContainer :function() {
21425 return this.wrap.select('.x-html-editor-tb',true).first();
21429 * Protected method that will not generally be called directly. It
21430 * is called when the editor creates its toolbar. Override this method if you need to
21431 * add custom toolbar buttons.
21432 * @param {HtmlEditor} editor
21434 createToolbar : function(){
21436 Roo.log("create toolbars");
21438 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
21439 this.toolbars[0].render(this.toolbarContainer());
21443 // if (!editor.toolbars || !editor.toolbars.length) {
21444 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
21447 // for (var i =0 ; i < editor.toolbars.length;i++) {
21448 // editor.toolbars[i] = Roo.factory(
21449 // typeof(editor.toolbars[i]) == 'string' ?
21450 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
21451 // Roo.bootstrap.HtmlEditor);
21452 // editor.toolbars[i].init(editor);
21458 onRender : function(ct, position)
21460 // Roo.log("Call onRender: " + this.xtype);
21462 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
21464 this.wrap = this.inputEl().wrap({
21465 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
21468 this.editorcore.onRender(ct, position);
21470 if (this.resizable) {
21471 this.resizeEl = new Roo.Resizable(this.wrap, {
21475 minHeight : this.height,
21476 height: this.height,
21477 handles : this.resizable,
21480 resize : function(r, w, h) {
21481 _t.onResize(w,h); // -something
21487 this.createToolbar(this);
21490 if(!this.width && this.resizable){
21491 this.setSize(this.wrap.getSize());
21493 if (this.resizeEl) {
21494 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
21495 // should trigger onReize..
21501 onResize : function(w, h)
21503 Roo.log('resize: ' +w + ',' + h );
21504 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
21508 if(this.inputEl() ){
21509 if(typeof w == 'number'){
21510 var aw = w - this.wrap.getFrameWidth('lr');
21511 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
21514 if(typeof h == 'number'){
21515 var tbh = -11; // fixme it needs to tool bar size!
21516 for (var i =0; i < this.toolbars.length;i++) {
21517 // fixme - ask toolbars for heights?
21518 tbh += this.toolbars[i].el.getHeight();
21519 //if (this.toolbars[i].footer) {
21520 // tbh += this.toolbars[i].footer.el.getHeight();
21528 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
21529 ah -= 5; // knock a few pixes off for look..
21530 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
21534 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
21535 this.editorcore.onResize(ew,eh);
21540 * Toggles the editor between standard and source edit mode.
21541 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21543 toggleSourceEdit : function(sourceEditMode)
21545 this.editorcore.toggleSourceEdit(sourceEditMode);
21547 if(this.editorcore.sourceEditMode){
21548 Roo.log('editor - showing textarea');
21551 // Roo.log(this.syncValue());
21553 this.inputEl().removeClass(['hide', 'x-hidden']);
21554 this.inputEl().dom.removeAttribute('tabIndex');
21555 this.inputEl().focus();
21557 Roo.log('editor - hiding textarea');
21559 // Roo.log(this.pushValue());
21562 this.inputEl().addClass(['hide', 'x-hidden']);
21563 this.inputEl().dom.setAttribute('tabIndex', -1);
21564 //this.deferFocus();
21567 if(this.resizable){
21568 this.setSize(this.wrap.getSize());
21571 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
21574 // private (for BoxComponent)
21575 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21577 // private (for BoxComponent)
21578 getResizeEl : function(){
21582 // private (for BoxComponent)
21583 getPositionEl : function(){
21588 initEvents : function(){
21589 this.originalValue = this.getValue();
21593 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21596 // markInvalid : Roo.emptyFn,
21598 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21601 // clearInvalid : Roo.emptyFn,
21603 setValue : function(v){
21604 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
21605 this.editorcore.pushValue();
21610 deferFocus : function(){
21611 this.focus.defer(10, this);
21615 focus : function(){
21616 this.editorcore.focus();
21622 onDestroy : function(){
21628 for (var i =0; i < this.toolbars.length;i++) {
21629 // fixme - ask toolbars for heights?
21630 this.toolbars[i].onDestroy();
21633 this.wrap.dom.innerHTML = '';
21634 this.wrap.remove();
21639 onFirstFocus : function(){
21640 //Roo.log("onFirstFocus");
21641 this.editorcore.onFirstFocus();
21642 for (var i =0; i < this.toolbars.length;i++) {
21643 this.toolbars[i].onFirstFocus();
21649 syncValue : function()
21651 this.editorcore.syncValue();
21654 pushValue : function()
21656 this.editorcore.pushValue();
21660 // hide stuff that is not compatible
21674 * @event specialkey
21678 * @cfg {String} fieldClass @hide
21681 * @cfg {String} focusClass @hide
21684 * @cfg {String} autoCreate @hide
21687 * @cfg {String} inputType @hide
21690 * @cfg {String} invalidClass @hide
21693 * @cfg {String} invalidText @hide
21696 * @cfg {String} msgFx @hide
21699 * @cfg {String} validateOnBlur @hide
21708 Roo.namespace('Roo.bootstrap.htmleditor');
21710 * @class Roo.bootstrap.HtmlEditorToolbar1
21715 new Roo.bootstrap.HtmlEditor({
21718 new Roo.bootstrap.HtmlEditorToolbar1({
21719 disable : { fonts: 1 , format: 1, ..., ... , ...],
21725 * @cfg {Object} disable List of elements to disable..
21726 * @cfg {Array} btns List of additional buttons.
21730 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
21733 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
21736 Roo.apply(this, config);
21738 // default disabled, based on 'good practice'..
21739 this.disable = this.disable || {};
21740 Roo.applyIf(this.disable, {
21743 specialElements : true
21745 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
21747 this.editor = config.editor;
21748 this.editorcore = config.editor.editorcore;
21750 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
21752 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
21753 // dont call parent... till later.
21755 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
21760 editorcore : false,
21765 "h1","h2","h3","h4","h5","h6",
21767 "abbr", "acronym", "address", "cite", "samp", "var",
21771 onRender : function(ct, position)
21773 // Roo.log("Call onRender: " + this.xtype);
21775 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
21777 this.el.dom.style.marginBottom = '0';
21779 var editorcore = this.editorcore;
21780 var editor= this.editor;
21783 var btn = function(id,cmd , toggle, handler){
21785 var event = toggle ? 'toggle' : 'click';
21790 xns: Roo.bootstrap,
21793 enableToggle:toggle !== false,
21795 pressed : toggle ? false : null,
21798 a.listeners[toggle ? 'toggle' : 'click'] = function() {
21799 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
21808 xns: Roo.bootstrap,
21809 glyphicon : 'font',
21813 xns: Roo.bootstrap,
21817 Roo.each(this.formats, function(f) {
21818 style.menu.items.push({
21820 xns: Roo.bootstrap,
21821 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
21826 editorcore.insertTag(this.tagname);
21833 children.push(style);
21836 btn('bold',false,true);
21837 btn('italic',false,true);
21838 btn('align-left', 'justifyleft',true);
21839 btn('align-center', 'justifycenter',true);
21840 btn('align-right' , 'justifyright',true);
21841 btn('link', false, false, function(btn) {
21842 //Roo.log("create link?");
21843 var url = prompt(this.createLinkText, this.defaultLinkValue);
21844 if(url && url != 'http:/'+'/'){
21845 this.editorcore.relayCmd('createlink', url);
21848 btn('list','insertunorderedlist',true);
21849 btn('pencil', false,true, function(btn){
21852 this.toggleSourceEdit(btn.pressed);
21858 xns: Roo.bootstrap,
21863 xns: Roo.bootstrap,
21868 cog.menu.items.push({
21870 xns: Roo.bootstrap,
21871 html : Clean styles,
21876 editorcore.insertTag(this.tagname);
21885 this.xtype = 'NavSimplebar';
21887 for(var i=0;i< children.length;i++) {
21889 this.buttons.add(this.addxtypeChild(children[i]));
21893 editor.on('editorevent', this.updateToolbar, this);
21895 onBtnClick : function(id)
21897 this.editorcore.relayCmd(id);
21898 this.editorcore.focus();
21902 * Protected method that will not generally be called directly. It triggers
21903 * a toolbar update by reading the markup state of the current selection in the editor.
21905 updateToolbar: function(){
21907 if(!this.editorcore.activated){
21908 this.editor.onFirstFocus(); // is this neeed?
21912 var btns = this.buttons;
21913 var doc = this.editorcore.doc;
21914 btns.get('bold').setActive(doc.queryCommandState('bold'));
21915 btns.get('italic').setActive(doc.queryCommandState('italic'));
21916 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21918 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21919 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21920 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21922 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21923 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21926 var ans = this.editorcore.getAllAncestors();
21927 if (this.formatCombo) {
21930 var store = this.formatCombo.store;
21931 this.formatCombo.setValue("");
21932 for (var i =0; i < ans.length;i++) {
21933 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21935 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21943 // hides menus... - so this cant be on a menu...
21944 Roo.bootstrap.MenuMgr.hideAll();
21946 Roo.bootstrap.MenuMgr.hideAll();
21947 //this.editorsyncValue();
21949 onFirstFocus: function() {
21950 this.buttons.each(function(item){
21954 toggleSourceEdit : function(sourceEditMode){
21957 if(sourceEditMode){
21958 Roo.log("disabling buttons");
21959 this.buttons.each( function(item){
21960 if(item.cmd != 'pencil'){
21966 Roo.log("enabling buttons");
21967 if(this.editorcore.initialized){
21968 this.buttons.each( function(item){
21974 Roo.log("calling toggole on editor");
21975 // tell the editor that it's been pressed..
21976 this.editor.toggleSourceEdit(sourceEditMode);
21986 * @class Roo.bootstrap.Table.AbstractSelectionModel
21987 * @extends Roo.util.Observable
21988 * Abstract base class for grid SelectionModels. It provides the interface that should be
21989 * implemented by descendant classes. This class should not be directly instantiated.
21992 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21993 this.locked = false;
21994 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21998 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21999 /** @ignore Called by the grid automatically. Do not call directly. */
22000 init : function(grid){
22006 * Locks the selections.
22009 this.locked = true;
22013 * Unlocks the selections.
22015 unlock : function(){
22016 this.locked = false;
22020 * Returns true if the selections are locked.
22021 * @return {Boolean}
22023 isLocked : function(){
22024 return this.locked;
22028 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22029 * @class Roo.bootstrap.Table.RowSelectionModel
22030 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22031 * It supports multiple selections and keyboard selection/navigation.
22033 * @param {Object} config
22036 Roo.bootstrap.Table.RowSelectionModel = function(config){
22037 Roo.apply(this, config);
22038 this.selections = new Roo.util.MixedCollection(false, function(o){
22043 this.lastActive = false;
22047 * @event selectionchange
22048 * Fires when the selection changes
22049 * @param {SelectionModel} this
22051 "selectionchange" : true,
22053 * @event afterselectionchange
22054 * Fires after the selection changes (eg. by key press or clicking)
22055 * @param {SelectionModel} this
22057 "afterselectionchange" : true,
22059 * @event beforerowselect
22060 * Fires when a row is selected being selected, return false to cancel.
22061 * @param {SelectionModel} this
22062 * @param {Number} rowIndex The selected index
22063 * @param {Boolean} keepExisting False if other selections will be cleared
22065 "beforerowselect" : true,
22068 * Fires when a row is selected.
22069 * @param {SelectionModel} this
22070 * @param {Number} rowIndex The selected index
22071 * @param {Roo.data.Record} r The record
22073 "rowselect" : true,
22075 * @event rowdeselect
22076 * Fires when a row is deselected.
22077 * @param {SelectionModel} this
22078 * @param {Number} rowIndex The selected index
22080 "rowdeselect" : true
22082 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22083 this.locked = false;
22086 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22088 * @cfg {Boolean} singleSelect
22089 * True to allow selection of only one row at a time (defaults to false)
22091 singleSelect : false,
22094 initEvents : function(){
22096 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22097 this.grid.on("mousedown", this.handleMouseDown, this);
22098 }else{ // allow click to work like normal
22099 this.grid.on("rowclick", this.handleDragableRowClick, this);
22102 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22103 "up" : function(e){
22105 this.selectPrevious(e.shiftKey);
22106 }else if(this.last !== false && this.lastActive !== false){
22107 var last = this.last;
22108 this.selectRange(this.last, this.lastActive-1);
22109 this.grid.getView().focusRow(this.lastActive);
22110 if(last !== false){
22114 this.selectFirstRow();
22116 this.fireEvent("afterselectionchange", this);
22118 "down" : function(e){
22120 this.selectNext(e.shiftKey);
22121 }else if(this.last !== false && this.lastActive !== false){
22122 var last = this.last;
22123 this.selectRange(this.last, this.lastActive+1);
22124 this.grid.getView().focusRow(this.lastActive);
22125 if(last !== false){
22129 this.selectFirstRow();
22131 this.fireEvent("afterselectionchange", this);
22136 var view = this.grid.view;
22137 view.on("refresh", this.onRefresh, this);
22138 view.on("rowupdated", this.onRowUpdated, this);
22139 view.on("rowremoved", this.onRemove, this);
22143 onRefresh : function(){
22144 var ds = this.grid.dataSource, i, v = this.grid.view;
22145 var s = this.selections;
22146 s.each(function(r){
22147 if((i = ds.indexOfId(r.id)) != -1){
22156 onRemove : function(v, index, r){
22157 this.selections.remove(r);
22161 onRowUpdated : function(v, index, r){
22162 if(this.isSelected(r)){
22163 v.onRowSelect(index);
22169 * @param {Array} records The records to select
22170 * @param {Boolean} keepExisting (optional) True to keep existing selections
22172 selectRecords : function(records, keepExisting){
22174 this.clearSelections();
22176 var ds = this.grid.dataSource;
22177 for(var i = 0, len = records.length; i < len; i++){
22178 this.selectRow(ds.indexOf(records[i]), true);
22183 * Gets the number of selected rows.
22186 getCount : function(){
22187 return this.selections.length;
22191 * Selects the first row in the grid.
22193 selectFirstRow : function(){
22198 * Select the last row.
22199 * @param {Boolean} keepExisting (optional) True to keep existing selections
22201 selectLastRow : function(keepExisting){
22202 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22206 * Selects the row immediately following the last selected row.
22207 * @param {Boolean} keepExisting (optional) True to keep existing selections
22209 selectNext : function(keepExisting){
22210 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
22211 this.selectRow(this.last+1, keepExisting);
22212 this.grid.getView().focusRow(this.last);
22217 * Selects the row that precedes the last selected row.
22218 * @param {Boolean} keepExisting (optional) True to keep existing selections
22220 selectPrevious : function(keepExisting){
22222 this.selectRow(this.last-1, keepExisting);
22223 this.grid.getView().focusRow(this.last);
22228 * Returns the selected records
22229 * @return {Array} Array of selected records
22231 getSelections : function(){
22232 return [].concat(this.selections.items);
22236 * Returns the first selected record.
22239 getSelected : function(){
22240 return this.selections.itemAt(0);
22245 * Clears all selections.
22247 clearSelections : function(fast){
22252 var ds = this.grid.dataSource;
22253 var s = this.selections;
22254 s.each(function(r){
22255 this.deselectRow(ds.indexOfId(r.id));
22259 this.selections.clear();
22266 * Selects all rows.
22268 selectAll : function(){
22272 this.selections.clear();
22273 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
22274 this.selectRow(i, true);
22279 * Returns True if there is a selection.
22280 * @return {Boolean}
22282 hasSelection : function(){
22283 return this.selections.length > 0;
22287 * Returns True if the specified row is selected.
22288 * @param {Number/Record} record The record or index of the record to check
22289 * @return {Boolean}
22291 isSelected : function(index){
22292 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
22293 return (r && this.selections.key(r.id) ? true : false);
22297 * Returns True if the specified record id is selected.
22298 * @param {String} id The id of record to check
22299 * @return {Boolean}
22301 isIdSelected : function(id){
22302 return (this.selections.key(id) ? true : false);
22306 handleMouseDown : function(e, t){
22307 var view = this.grid.getView(), rowIndex;
22308 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
22311 if(e.shiftKey && this.last !== false){
22312 var last = this.last;
22313 this.selectRange(last, rowIndex, e.ctrlKey);
22314 this.last = last; // reset the last
22315 view.focusRow(rowIndex);
22317 var isSelected = this.isSelected(rowIndex);
22318 if(e.button !== 0 && isSelected){
22319 view.focusRow(rowIndex);
22320 }else if(e.ctrlKey && isSelected){
22321 this.deselectRow(rowIndex);
22322 }else if(!isSelected){
22323 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22324 view.focusRow(rowIndex);
22327 this.fireEvent("afterselectionchange", this);
22330 handleDragableRowClick : function(grid, rowIndex, e)
22332 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
22333 this.selectRow(rowIndex, false);
22334 grid.view.focusRow(rowIndex);
22335 this.fireEvent("afterselectionchange", this);
22340 * Selects multiple rows.
22341 * @param {Array} rows Array of the indexes of the row to select
22342 * @param {Boolean} keepExisting (optional) True to keep existing selections
22344 selectRows : function(rows, keepExisting){
22346 this.clearSelections();
22348 for(var i = 0, len = rows.length; i < len; i++){
22349 this.selectRow(rows[i], true);
22354 * Selects a range of rows. All rows in between startRow and endRow are also selected.
22355 * @param {Number} startRow The index of the first row in the range
22356 * @param {Number} endRow The index of the last row in the range
22357 * @param {Boolean} keepExisting (optional) True to retain existing selections
22359 selectRange : function(startRow, endRow, keepExisting){
22364 this.clearSelections();
22366 if(startRow <= endRow){
22367 for(var i = startRow; i <= endRow; i++){
22368 this.selectRow(i, true);
22371 for(var i = startRow; i >= endRow; i--){
22372 this.selectRow(i, true);
22378 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
22379 * @param {Number} startRow The index of the first row in the range
22380 * @param {Number} endRow The index of the last row in the range
22382 deselectRange : function(startRow, endRow, preventViewNotify){
22386 for(var i = startRow; i <= endRow; i++){
22387 this.deselectRow(i, preventViewNotify);
22393 * @param {Number} row The index of the row to select
22394 * @param {Boolean} keepExisting (optional) True to keep existing selections
22396 selectRow : function(index, keepExisting, preventViewNotify){
22397 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
22400 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
22401 if(!keepExisting || this.singleSelect){
22402 this.clearSelections();
22404 var r = this.grid.dataSource.getAt(index);
22405 this.selections.add(r);
22406 this.last = this.lastActive = index;
22407 if(!preventViewNotify){
22408 this.grid.getView().onRowSelect(index);
22410 this.fireEvent("rowselect", this, index, r);
22411 this.fireEvent("selectionchange", this);
22417 * @param {Number} row The index of the row to deselect
22419 deselectRow : function(index, preventViewNotify){
22423 if(this.last == index){
22426 if(this.lastActive == index){
22427 this.lastActive = false;
22429 var r = this.grid.dataSource.getAt(index);
22430 this.selections.remove(r);
22431 if(!preventViewNotify){
22432 this.grid.getView().onRowDeselect(index);
22434 this.fireEvent("rowdeselect", this, index);
22435 this.fireEvent("selectionchange", this);
22439 restoreLast : function(){
22441 this.last = this._last;
22446 acceptsNav : function(row, col, cm){
22447 return !cm.isHidden(col) && cm.isCellEditable(col, row);
22451 onEditorKey : function(field, e){
22452 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
22457 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
22459 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
22461 }else if(k == e.ENTER && !e.ctrlKey){
22465 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
22467 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
22469 }else if(k == e.ESC){
22473 g.startEditing(newCell[0], newCell[1]);
22478 * Ext JS Library 1.1.1
22479 * Copyright(c) 2006-2007, Ext JS, LLC.
22481 * Originally Released Under LGPL - original licence link has changed is not relivant.
22484 * <script type="text/javascript">
22488 * @class Roo.bootstrap.PagingToolbar
22489 * @extends Roo.bootstrap.NavSimplebar
22490 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
22492 * Create a new PagingToolbar
22493 * @param {Object} config The config object
22494 * @param {Roo.data.Store} store
22496 Roo.bootstrap.PagingToolbar = function(config)
22498 // old args format still supported... - xtype is prefered..
22499 // created from xtype...
22501 this.ds = config.dataSource;
22503 if (config.store && !this.ds) {
22504 this.store= Roo.factory(config.store, Roo.data);
22505 this.ds = this.store;
22506 this.ds.xmodule = this.xmodule || false;
22509 this.toolbarItems = [];
22510 if (config.items) {
22511 this.toolbarItems = config.items;
22514 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
22519 this.bind(this.ds);
22522 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
22526 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
22528 * @cfg {Roo.data.Store} dataSource
22529 * The underlying data store providing the paged data
22532 * @cfg {String/HTMLElement/Element} container
22533 * container The id or element that will contain the toolbar
22536 * @cfg {Boolean} displayInfo
22537 * True to display the displayMsg (defaults to false)
22540 * @cfg {Number} pageSize
22541 * The number of records to display per page (defaults to 20)
22545 * @cfg {String} displayMsg
22546 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
22548 displayMsg : 'Displaying {0} - {1} of {2}',
22550 * @cfg {String} emptyMsg
22551 * The message to display when no records are found (defaults to "No data to display")
22553 emptyMsg : 'No data to display',
22555 * Customizable piece of the default paging text (defaults to "Page")
22558 beforePageText : "Page",
22560 * Customizable piece of the default paging text (defaults to "of %0")
22563 afterPageText : "of {0}",
22565 * Customizable piece of the default paging text (defaults to "First Page")
22568 firstText : "First Page",
22570 * Customizable piece of the default paging text (defaults to "Previous Page")
22573 prevText : "Previous Page",
22575 * Customizable piece of the default paging text (defaults to "Next Page")
22578 nextText : "Next Page",
22580 * Customizable piece of the default paging text (defaults to "Last Page")
22583 lastText : "Last Page",
22585 * Customizable piece of the default paging text (defaults to "Refresh")
22588 refreshText : "Refresh",
22592 onRender : function(ct, position)
22594 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
22595 this.navgroup.parentId = this.id;
22596 this.navgroup.onRender(this.el, null);
22597 // add the buttons to the navgroup
22599 if(this.displayInfo){
22600 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
22601 this.displayEl = this.el.select('.x-paging-info', true).first();
22602 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
22603 // this.displayEl = navel.el.select('span',true).first();
22609 Roo.each(_this.buttons, function(e){ // this might need to use render????
22610 Roo.factory(e).onRender(_this.el, null);
22614 Roo.each(_this.toolbarItems, function(e) {
22615 _this.navgroup.addItem(e);
22619 this.first = this.navgroup.addItem({
22620 tooltip: this.firstText,
22622 icon : 'fa fa-backward',
22624 preventDefault: true,
22625 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
22628 this.prev = this.navgroup.addItem({
22629 tooltip: this.prevText,
22631 icon : 'fa fa-step-backward',
22633 preventDefault: true,
22634 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
22636 //this.addSeparator();
22639 var field = this.navgroup.addItem( {
22641 cls : 'x-paging-position',
22643 html : this.beforePageText +
22644 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
22645 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
22648 this.field = field.el.select('input', true).first();
22649 this.field.on("keydown", this.onPagingKeydown, this);
22650 this.field.on("focus", function(){this.dom.select();});
22653 this.afterTextEl = field.el.select('.x-paging-after',true).first();
22654 //this.field.setHeight(18);
22655 //this.addSeparator();
22656 this.next = this.navgroup.addItem({
22657 tooltip: this.nextText,
22659 html : ' <i class="fa fa-step-forward">',
22661 preventDefault: true,
22662 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
22664 this.last = this.navgroup.addItem({
22665 tooltip: this.lastText,
22666 icon : 'fa fa-forward',
22669 preventDefault: true,
22670 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
22672 //this.addSeparator();
22673 this.loading = this.navgroup.addItem({
22674 tooltip: this.refreshText,
22675 icon: 'fa fa-refresh',
22676 preventDefault: true,
22677 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
22683 updateInfo : function(){
22684 if(this.displayEl){
22685 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
22686 var msg = count == 0 ?
22690 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
22692 this.displayEl.update(msg);
22697 onLoad : function(ds, r, o){
22698 this.cursor = o.params ? o.params.start : 0;
22699 var d = this.getPageData(),
22703 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
22704 this.field.dom.value = ap;
22705 this.first.setDisabled(ap == 1);
22706 this.prev.setDisabled(ap == 1);
22707 this.next.setDisabled(ap == ps);
22708 this.last.setDisabled(ap == ps);
22709 this.loading.enable();
22714 getPageData : function(){
22715 var total = this.ds.getTotalCount();
22718 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
22719 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
22724 onLoadError : function(){
22725 this.loading.enable();
22729 onPagingKeydown : function(e){
22730 var k = e.getKey();
22731 var d = this.getPageData();
22733 var v = this.field.dom.value, pageNum;
22734 if(!v || isNaN(pageNum = parseInt(v, 10))){
22735 this.field.dom.value = d.activePage;
22738 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
22739 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22742 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))
22744 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
22745 this.field.dom.value = pageNum;
22746 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
22749 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
22751 var v = this.field.dom.value, pageNum;
22752 var increment = (e.shiftKey) ? 10 : 1;
22753 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
22756 if(!v || isNaN(pageNum = parseInt(v, 10))) {
22757 this.field.dom.value = d.activePage;
22760 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
22762 this.field.dom.value = parseInt(v, 10) + increment;
22763 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
22764 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22771 beforeLoad : function(){
22773 this.loading.disable();
22778 onClick : function(which){
22787 ds.load({params:{start: 0, limit: this.pageSize}});
22790 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
22793 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
22796 var total = ds.getTotalCount();
22797 var extra = total % this.pageSize;
22798 var lastStart = extra ? (total - extra) : total-this.pageSize;
22799 ds.load({params:{start: lastStart, limit: this.pageSize}});
22802 ds.load({params:{start: this.cursor, limit: this.pageSize}});
22808 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
22809 * @param {Roo.data.Store} store The data store to unbind
22811 unbind : function(ds){
22812 ds.un("beforeload", this.beforeLoad, this);
22813 ds.un("load", this.onLoad, this);
22814 ds.un("loadexception", this.onLoadError, this);
22815 ds.un("remove", this.updateInfo, this);
22816 ds.un("add", this.updateInfo, this);
22817 this.ds = undefined;
22821 * Binds the paging toolbar to the specified {@link Roo.data.Store}
22822 * @param {Roo.data.Store} store The data store to bind
22824 bind : function(ds){
22825 ds.on("beforeload", this.beforeLoad, this);
22826 ds.on("load", this.onLoad, this);
22827 ds.on("loadexception", this.onLoadError, this);
22828 ds.on("remove", this.updateInfo, this);
22829 ds.on("add", this.updateInfo, this);
22840 * @class Roo.bootstrap.MessageBar
22841 * @extends Roo.bootstrap.Component
22842 * Bootstrap MessageBar class
22843 * @cfg {String} html contents of the MessageBar
22844 * @cfg {String} weight (info | success | warning | danger) default info
22845 * @cfg {String} beforeClass insert the bar before the given class
22846 * @cfg {Boolean} closable (true | false) default false
22847 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
22850 * Create a new Element
22851 * @param {Object} config The config object
22854 Roo.bootstrap.MessageBar = function(config){
22855 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
22858 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
22864 beforeClass: 'bootstrap-sticky-wrap',
22866 getAutoCreate : function(){
22870 cls: 'alert alert-dismissable alert-' + this.weight,
22875 html: this.html || ''
22881 cfg.cls += ' alert-messages-fixed';
22895 onRender : function(ct, position)
22897 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
22900 var cfg = Roo.apply({}, this.getAutoCreate());
22904 cfg.cls += ' ' + this.cls;
22907 cfg.style = this.style;
22909 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22911 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22914 this.el.select('>button.close').on('click', this.hide, this);
22920 if (!this.rendered) {
22926 this.fireEvent('show', this);
22932 if (!this.rendered) {
22938 this.fireEvent('hide', this);
22941 update : function()
22943 // var e = this.el.dom.firstChild;
22945 // if(this.closable){
22946 // e = e.nextSibling;
22949 // e.data = this.html || '';
22951 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22967 * @class Roo.bootstrap.Graph
22968 * @extends Roo.bootstrap.Component
22969 * Bootstrap Graph class
22973 @cfg {String} graphtype bar | vbar | pie
22974 @cfg {number} g_x coodinator | centre x (pie)
22975 @cfg {number} g_y coodinator | centre y (pie)
22976 @cfg {number} g_r radius (pie)
22977 @cfg {number} g_height height of the chart (respected by all elements in the set)
22978 @cfg {number} g_width width of the chart (respected by all elements in the set)
22979 @cfg {Object} title The title of the chart
22982 -opts (object) options for the chart
22984 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22985 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22987 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.
22988 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22990 o stretch (boolean)
22992 -opts (object) options for the pie
22995 o startAngle (number)
22996 o endAngle (number)
23000 * Create a new Input
23001 * @param {Object} config The config object
23004 Roo.bootstrap.Graph = function(config){
23005 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23011 * The img click event for the img.
23012 * @param {Roo.EventObject} e
23018 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23029 //g_colors: this.colors,
23036 getAutoCreate : function(){
23047 onRender : function(ct,position){
23050 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23052 if (typeof(Raphael) == 'undefined') {
23053 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23057 this.raphael = Raphael(this.el.dom);
23059 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23060 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23061 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23062 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23064 r.text(160, 10, "Single Series Chart").attr(txtattr);
23065 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23066 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23067 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23069 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23070 r.barchart(330, 10, 300, 220, data1);
23071 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23072 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23075 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23076 // r.barchart(30, 30, 560, 250, xdata, {
23077 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23078 // axis : "0 0 1 1",
23079 // axisxlabels : xdata
23080 // //yvalues : cols,
23083 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23085 // this.load(null,xdata,{
23086 // axis : "0 0 1 1",
23087 // axisxlabels : xdata
23092 load : function(graphtype,xdata,opts)
23094 this.raphael.clear();
23096 graphtype = this.graphtype;
23101 var r = this.raphael,
23102 fin = function () {
23103 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23105 fout = function () {
23106 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23108 pfin = function() {
23109 this.sector.stop();
23110 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23113 this.label[0].stop();
23114 this.label[0].attr({ r: 7.5 });
23115 this.label[1].attr({ "font-weight": 800 });
23118 pfout = function() {
23119 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23122 this.label[0].animate({ r: 5 }, 500, "bounce");
23123 this.label[1].attr({ "font-weight": 400 });
23129 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23132 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23135 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23136 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23138 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23145 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23150 setTitle: function(o)
23155 initEvents: function() {
23158 this.el.on('click', this.onClick, this);
23162 onClick : function(e)
23164 Roo.log('img onclick');
23165 this.fireEvent('click', this, e);
23177 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23180 * @class Roo.bootstrap.dash.NumberBox
23181 * @extends Roo.bootstrap.Component
23182 * Bootstrap NumberBox class
23183 * @cfg {String} headline Box headline
23184 * @cfg {String} content Box content
23185 * @cfg {String} icon Box icon
23186 * @cfg {String} footer Footer text
23187 * @cfg {String} fhref Footer href
23190 * Create a new NumberBox
23191 * @param {Object} config The config object
23195 Roo.bootstrap.dash.NumberBox = function(config){
23196 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23200 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23209 getAutoCreate : function(){
23213 cls : 'small-box ',
23221 cls : 'roo-headline',
23222 html : this.headline
23226 cls : 'roo-content',
23227 html : this.content
23241 cls : 'ion ' + this.icon
23250 cls : 'small-box-footer',
23251 href : this.fhref || '#',
23255 cfg.cn.push(footer);
23262 onRender : function(ct,position){
23263 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23270 setHeadline: function (value)
23272 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23275 setFooter: function (value, href)
23277 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23280 this.el.select('a.small-box-footer',true).first().attr('href', href);
23285 setContent: function (value)
23287 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23290 initEvents: function()
23304 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23307 * @class Roo.bootstrap.dash.TabBox
23308 * @extends Roo.bootstrap.Component
23309 * Bootstrap TabBox class
23310 * @cfg {String} title Title of the TabBox
23311 * @cfg {String} icon Icon of the TabBox
23312 * @cfg {Boolean} showtabs (true|false) show the tabs default true
23313 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
23316 * Create a new TabBox
23317 * @param {Object} config The config object
23321 Roo.bootstrap.dash.TabBox = function(config){
23322 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
23327 * When a pane is added
23328 * @param {Roo.bootstrap.dash.TabPane} pane
23332 * @event activatepane
23333 * When a pane is activated
23334 * @param {Roo.bootstrap.dash.TabPane} pane
23336 "activatepane" : true
23344 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
23349 tabScrollable : false,
23351 getChildContainer : function()
23353 return this.el.select('.tab-content', true).first();
23356 getAutoCreate : function(){
23360 cls: 'pull-left header',
23368 cls: 'fa ' + this.icon
23374 cls: 'nav nav-tabs pull-right',
23380 if(this.tabScrollable){
23387 cls: 'nav nav-tabs pull-right',
23398 cls: 'nav-tabs-custom',
23403 cls: 'tab-content no-padding',
23411 initEvents : function()
23413 //Roo.log('add add pane handler');
23414 this.on('addpane', this.onAddPane, this);
23417 * Updates the box title
23418 * @param {String} html to set the title to.
23420 setTitle : function(value)
23422 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
23424 onAddPane : function(pane)
23426 this.panes.push(pane);
23427 //Roo.log('addpane');
23429 // tabs are rendere left to right..
23430 if(!this.showtabs){
23434 var ctr = this.el.select('.nav-tabs', true).first();
23437 var existing = ctr.select('.nav-tab',true);
23438 var qty = existing.getCount();;
23441 var tab = ctr.createChild({
23443 cls : 'nav-tab' + (qty ? '' : ' active'),
23451 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
23454 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
23456 pane.el.addClass('active');
23461 onTabClick : function(ev,un,ob,pane)
23463 //Roo.log('tab - prev default');
23464 ev.preventDefault();
23467 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
23468 pane.tab.addClass('active');
23469 //Roo.log(pane.title);
23470 this.getChildContainer().select('.tab-pane',true).removeClass('active');
23471 // technically we should have a deactivate event.. but maybe add later.
23472 // and it should not de-activate the selected tab...
23473 this.fireEvent('activatepane', pane);
23474 pane.el.addClass('active');
23475 pane.fireEvent('activate');
23480 getActivePane : function()
23483 Roo.each(this.panes, function(p) {
23484 if(p.el.hasClass('active')){
23505 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23507 * @class Roo.bootstrap.TabPane
23508 * @extends Roo.bootstrap.Component
23509 * Bootstrap TabPane class
23510 * @cfg {Boolean} active (false | true) Default false
23511 * @cfg {String} title title of panel
23515 * Create a new TabPane
23516 * @param {Object} config The config object
23519 Roo.bootstrap.dash.TabPane = function(config){
23520 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
23526 * When a pane is activated
23527 * @param {Roo.bootstrap.dash.TabPane} pane
23534 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
23539 // the tabBox that this is attached to.
23542 getAutoCreate : function()
23550 cfg.cls += ' active';
23555 initEvents : function()
23557 //Roo.log('trigger add pane handler');
23558 this.parent().fireEvent('addpane', this)
23562 * Updates the tab title
23563 * @param {String} html to set the title to.
23565 setTitle: function(str)
23571 this.tab.select('a', true).first().dom.innerHTML = str;
23588 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23591 * @class Roo.bootstrap.menu.Menu
23592 * @extends Roo.bootstrap.Component
23593 * Bootstrap Menu class - container for Menu
23594 * @cfg {String} html Text of the menu
23595 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
23596 * @cfg {String} icon Font awesome icon
23597 * @cfg {String} pos Menu align to (top | bottom) default bottom
23601 * Create a new Menu
23602 * @param {Object} config The config object
23606 Roo.bootstrap.menu.Menu = function(config){
23607 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
23611 * @event beforeshow
23612 * Fires before this menu is displayed
23613 * @param {Roo.bootstrap.menu.Menu} this
23617 * @event beforehide
23618 * Fires before this menu is hidden
23619 * @param {Roo.bootstrap.menu.Menu} this
23624 * Fires after this menu is displayed
23625 * @param {Roo.bootstrap.menu.Menu} this
23630 * Fires after this menu is hidden
23631 * @param {Roo.bootstrap.menu.Menu} this
23636 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
23637 * @param {Roo.bootstrap.menu.Menu} this
23638 * @param {Roo.EventObject} e
23645 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
23649 weight : 'default',
23654 getChildContainer : function() {
23655 if(this.isSubMenu){
23659 return this.el.select('ul.dropdown-menu', true).first();
23662 getAutoCreate : function()
23667 cls : 'roo-menu-text',
23675 cls : 'fa ' + this.icon
23686 cls : 'dropdown-button btn btn-' + this.weight,
23691 cls : 'dropdown-toggle btn btn-' + this.weight,
23701 cls : 'dropdown-menu'
23707 if(this.pos == 'top'){
23708 cfg.cls += ' dropup';
23711 if(this.isSubMenu){
23714 cls : 'dropdown-menu'
23721 onRender : function(ct, position)
23723 this.isSubMenu = ct.hasClass('dropdown-submenu');
23725 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
23728 initEvents : function()
23730 if(this.isSubMenu){
23734 this.hidden = true;
23736 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
23737 this.triggerEl.on('click', this.onTriggerPress, this);
23739 this.buttonEl = this.el.select('button.dropdown-button', true).first();
23740 this.buttonEl.on('click', this.onClick, this);
23746 if(this.isSubMenu){
23750 return this.el.select('ul.dropdown-menu', true).first();
23753 onClick : function(e)
23755 this.fireEvent("click", this, e);
23758 onTriggerPress : function(e)
23760 if (this.isVisible()) {
23767 isVisible : function(){
23768 return !this.hidden;
23773 this.fireEvent("beforeshow", this);
23775 this.hidden = false;
23776 this.el.addClass('open');
23778 Roo.get(document).on("mouseup", this.onMouseUp, this);
23780 this.fireEvent("show", this);
23787 this.fireEvent("beforehide", this);
23789 this.hidden = true;
23790 this.el.removeClass('open');
23792 Roo.get(document).un("mouseup", this.onMouseUp);
23794 this.fireEvent("hide", this);
23797 onMouseUp : function()
23811 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23814 * @class Roo.bootstrap.menu.Item
23815 * @extends Roo.bootstrap.Component
23816 * Bootstrap MenuItem class
23817 * @cfg {Boolean} submenu (true | false) default false
23818 * @cfg {String} html text of the item
23819 * @cfg {String} href the link
23820 * @cfg {Boolean} disable (true | false) default false
23821 * @cfg {Boolean} preventDefault (true | false) default true
23822 * @cfg {String} icon Font awesome icon
23823 * @cfg {String} pos Submenu align to (left | right) default right
23827 * Create a new Item
23828 * @param {Object} config The config object
23832 Roo.bootstrap.menu.Item = function(config){
23833 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
23837 * Fires when the mouse is hovering over this menu
23838 * @param {Roo.bootstrap.menu.Item} this
23839 * @param {Roo.EventObject} e
23844 * Fires when the mouse exits this menu
23845 * @param {Roo.bootstrap.menu.Item} this
23846 * @param {Roo.EventObject} e
23852 * The raw click event for the entire grid.
23853 * @param {Roo.EventObject} e
23859 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
23864 preventDefault: true,
23869 getAutoCreate : function()
23874 cls : 'roo-menu-item-text',
23882 cls : 'fa ' + this.icon
23891 href : this.href || '#',
23898 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
23902 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
23904 if(this.pos == 'left'){
23905 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
23912 initEvents : function()
23914 this.el.on('mouseover', this.onMouseOver, this);
23915 this.el.on('mouseout', this.onMouseOut, this);
23917 this.el.select('a', true).first().on('click', this.onClick, this);
23921 onClick : function(e)
23923 if(this.preventDefault){
23924 e.preventDefault();
23927 this.fireEvent("click", this, e);
23930 onMouseOver : function(e)
23932 if(this.submenu && this.pos == 'left'){
23933 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23936 this.fireEvent("mouseover", this, e);
23939 onMouseOut : function(e)
23941 this.fireEvent("mouseout", this, e);
23953 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23956 * @class Roo.bootstrap.menu.Separator
23957 * @extends Roo.bootstrap.Component
23958 * Bootstrap Separator class
23961 * Create a new Separator
23962 * @param {Object} config The config object
23966 Roo.bootstrap.menu.Separator = function(config){
23967 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23970 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23972 getAutoCreate : function(){
23993 * @class Roo.bootstrap.Tooltip
23994 * Bootstrap Tooltip class
23995 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23996 * to determine which dom element triggers the tooltip.
23998 * It needs to add support for additional attributes like tooltip-position
24001 * Create a new Toolti
24002 * @param {Object} config The config object
24005 Roo.bootstrap.Tooltip = function(config){
24006 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24009 Roo.apply(Roo.bootstrap.Tooltip, {
24011 * @function init initialize tooltip monitoring.
24015 currentTip : false,
24016 currentRegion : false,
24022 Roo.get(document).on('mouseover', this.enter ,this);
24023 Roo.get(document).on('mouseout', this.leave, this);
24026 this.currentTip = new Roo.bootstrap.Tooltip();
24029 enter : function(ev)
24031 var dom = ev.getTarget();
24033 //Roo.log(['enter',dom]);
24034 var el = Roo.fly(dom);
24035 if (this.currentEl) {
24037 //Roo.log(this.currentEl);
24038 //Roo.log(this.currentEl.contains(dom));
24039 if (this.currentEl == el) {
24042 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24048 if (this.currentTip.el) {
24049 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24054 // you can not look for children, as if el is the body.. then everythign is the child..
24055 if (!el.attr('tooltip')) { //
24056 if (!el.select("[tooltip]").elements.length) {
24059 // is the mouse over this child...?
24060 bindEl = el.select("[tooltip]").first();
24061 var xy = ev.getXY();
24062 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24063 //Roo.log("not in region.");
24066 //Roo.log("child element over..");
24069 this.currentEl = bindEl;
24070 this.currentTip.bind(bindEl);
24071 this.currentRegion = Roo.lib.Region.getRegion(dom);
24072 this.currentTip.enter();
24075 leave : function(ev)
24077 var dom = ev.getTarget();
24078 //Roo.log(['leave',dom]);
24079 if (!this.currentEl) {
24084 if (dom != this.currentEl.dom) {
24087 var xy = ev.getXY();
24088 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24091 // only activate leave if mouse cursor is outside... bounding box..
24096 if (this.currentTip) {
24097 this.currentTip.leave();
24099 //Roo.log('clear currentEl');
24100 this.currentEl = false;
24105 'left' : ['r-l', [-2,0], 'right'],
24106 'right' : ['l-r', [2,0], 'left'],
24107 'bottom' : ['t-b', [0,2], 'top'],
24108 'top' : [ 'b-t', [0,-2], 'bottom']
24114 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24119 delay : null, // can be { show : 300 , hide: 500}
24123 hoverState : null, //???
24125 placement : 'bottom',
24127 getAutoCreate : function(){
24134 cls : 'tooltip-arrow'
24137 cls : 'tooltip-inner'
24144 bind : function(el)
24150 enter : function () {
24152 if (this.timeout != null) {
24153 clearTimeout(this.timeout);
24156 this.hoverState = 'in';
24157 //Roo.log("enter - show");
24158 if (!this.delay || !this.delay.show) {
24163 this.timeout = setTimeout(function () {
24164 if (_t.hoverState == 'in') {
24167 }, this.delay.show);
24171 clearTimeout(this.timeout);
24173 this.hoverState = 'out';
24174 if (!this.delay || !this.delay.hide) {
24180 this.timeout = setTimeout(function () {
24181 //Roo.log("leave - timeout");
24183 if (_t.hoverState == 'out') {
24185 Roo.bootstrap.Tooltip.currentEl = false;
24193 this.render(document.body);
24196 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24198 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24200 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24202 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24204 var placement = typeof this.placement == 'function' ?
24205 this.placement.call(this, this.el, on_el) :
24208 var autoToken = /\s?auto?\s?/i;
24209 var autoPlace = autoToken.test(placement);
24211 placement = placement.replace(autoToken, '') || 'top';
24215 //this.el.setXY([0,0]);
24217 //this.el.dom.style.display='block';
24219 //this.el.appendTo(on_el);
24221 var p = this.getPosition();
24222 var box = this.el.getBox();
24228 var align = Roo.bootstrap.Tooltip.alignment[placement];
24230 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24232 if(placement == 'top' || placement == 'bottom'){
24234 placement = 'right';
24237 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24238 placement = 'left';
24242 align = Roo.bootstrap.Tooltip.alignment[placement];
24244 this.el.alignTo(this.bindEl, align[0],align[1]);
24245 //var arrow = this.el.select('.arrow',true).first();
24246 //arrow.set(align[2],
24248 this.el.addClass(placement);
24250 this.el.addClass('in fade');
24252 this.hoverState = null;
24254 if (this.el.hasClass('fade')) {
24265 //this.el.setXY([0,0]);
24266 this.el.removeClass('in');
24282 * @class Roo.bootstrap.LocationPicker
24283 * @extends Roo.bootstrap.Component
24284 * Bootstrap LocationPicker class
24285 * @cfg {Number} latitude Position when init default 0
24286 * @cfg {Number} longitude Position when init default 0
24287 * @cfg {Number} zoom default 15
24288 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24289 * @cfg {Boolean} mapTypeControl default false
24290 * @cfg {Boolean} disableDoubleClickZoom default false
24291 * @cfg {Boolean} scrollwheel default true
24292 * @cfg {Boolean} streetViewControl default false
24293 * @cfg {Number} radius default 0
24294 * @cfg {String} locationName
24295 * @cfg {Boolean} draggable default true
24296 * @cfg {Boolean} enableAutocomplete default false
24297 * @cfg {Boolean} enableReverseGeocode default true
24298 * @cfg {String} markerTitle
24301 * Create a new LocationPicker
24302 * @param {Object} config The config object
24306 Roo.bootstrap.LocationPicker = function(config){
24308 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
24313 * Fires when the picker initialized.
24314 * @param {Roo.bootstrap.LocationPicker} this
24315 * @param {Google Location} location
24319 * @event positionchanged
24320 * Fires when the picker position changed.
24321 * @param {Roo.bootstrap.LocationPicker} this
24322 * @param {Google Location} location
24324 positionchanged : true,
24327 * Fires when the map resize.
24328 * @param {Roo.bootstrap.LocationPicker} this
24333 * Fires when the map show.
24334 * @param {Roo.bootstrap.LocationPicker} this
24339 * Fires when the map hide.
24340 * @param {Roo.bootstrap.LocationPicker} this
24345 * Fires when click the map.
24346 * @param {Roo.bootstrap.LocationPicker} this
24347 * @param {Map event} e
24351 * @event mapRightClick
24352 * Fires when right click the map.
24353 * @param {Roo.bootstrap.LocationPicker} this
24354 * @param {Map event} e
24356 mapRightClick : true,
24358 * @event markerClick
24359 * Fires when click the marker.
24360 * @param {Roo.bootstrap.LocationPicker} this
24361 * @param {Map event} e
24363 markerClick : true,
24365 * @event markerRightClick
24366 * Fires when right click the marker.
24367 * @param {Roo.bootstrap.LocationPicker} this
24368 * @param {Map event} e
24370 markerRightClick : true,
24372 * @event OverlayViewDraw
24373 * Fires when OverlayView Draw
24374 * @param {Roo.bootstrap.LocationPicker} this
24376 OverlayViewDraw : true,
24378 * @event OverlayViewOnAdd
24379 * Fires when OverlayView Draw
24380 * @param {Roo.bootstrap.LocationPicker} this
24382 OverlayViewOnAdd : true,
24384 * @event OverlayViewOnRemove
24385 * Fires when OverlayView Draw
24386 * @param {Roo.bootstrap.LocationPicker} this
24388 OverlayViewOnRemove : true,
24390 * @event OverlayViewShow
24391 * Fires when OverlayView Draw
24392 * @param {Roo.bootstrap.LocationPicker} this
24393 * @param {Pixel} cpx
24395 OverlayViewShow : true,
24397 * @event OverlayViewHide
24398 * Fires when OverlayView Draw
24399 * @param {Roo.bootstrap.LocationPicker} this
24401 OverlayViewHide : true,
24403 * @event loadexception
24404 * Fires when load google lib failed.
24405 * @param {Roo.bootstrap.LocationPicker} this
24407 loadexception : true
24412 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
24414 gMapContext: false,
24420 mapTypeControl: false,
24421 disableDoubleClickZoom: false,
24423 streetViewControl: false,
24427 enableAutocomplete: false,
24428 enableReverseGeocode: true,
24431 getAutoCreate: function()
24436 cls: 'roo-location-picker'
24442 initEvents: function(ct, position)
24444 if(!this.el.getWidth() || this.isApplied()){
24448 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24453 initial: function()
24455 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
24456 this.fireEvent('loadexception', this);
24460 if(!this.mapTypeId){
24461 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
24464 this.gMapContext = this.GMapContext();
24466 this.initOverlayView();
24468 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
24472 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
24473 _this.setPosition(_this.gMapContext.marker.position);
24476 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
24477 _this.fireEvent('mapClick', this, event);
24481 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
24482 _this.fireEvent('mapRightClick', this, event);
24486 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
24487 _this.fireEvent('markerClick', this, event);
24491 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
24492 _this.fireEvent('markerRightClick', this, event);
24496 this.setPosition(this.gMapContext.location);
24498 this.fireEvent('initial', this, this.gMapContext.location);
24501 initOverlayView: function()
24505 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
24509 _this.fireEvent('OverlayViewDraw', _this);
24514 _this.fireEvent('OverlayViewOnAdd', _this);
24517 onRemove: function()
24519 _this.fireEvent('OverlayViewOnRemove', _this);
24522 show: function(cpx)
24524 _this.fireEvent('OverlayViewShow', _this, cpx);
24529 _this.fireEvent('OverlayViewHide', _this);
24535 fromLatLngToContainerPixel: function(event)
24537 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
24540 isApplied: function()
24542 return this.getGmapContext() == false ? false : true;
24545 getGmapContext: function()
24547 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
24550 GMapContext: function()
24552 var position = new google.maps.LatLng(this.latitude, this.longitude);
24554 var _map = new google.maps.Map(this.el.dom, {
24557 mapTypeId: this.mapTypeId,
24558 mapTypeControl: this.mapTypeControl,
24559 disableDoubleClickZoom: this.disableDoubleClickZoom,
24560 scrollwheel: this.scrollwheel,
24561 streetViewControl: this.streetViewControl,
24562 locationName: this.locationName,
24563 draggable: this.draggable,
24564 enableAutocomplete: this.enableAutocomplete,
24565 enableReverseGeocode: this.enableReverseGeocode
24568 var _marker = new google.maps.Marker({
24569 position: position,
24571 title: this.markerTitle,
24572 draggable: this.draggable
24579 location: position,
24580 radius: this.radius,
24581 locationName: this.locationName,
24582 addressComponents: {
24583 formatted_address: null,
24584 addressLine1: null,
24585 addressLine2: null,
24587 streetNumber: null,
24591 stateOrProvince: null
24594 domContainer: this.el.dom,
24595 geodecoder: new google.maps.Geocoder()
24599 drawCircle: function(center, radius, options)
24601 if (this.gMapContext.circle != null) {
24602 this.gMapContext.circle.setMap(null);
24606 options = Roo.apply({}, options, {
24607 strokeColor: "#0000FF",
24608 strokeOpacity: .35,
24610 fillColor: "#0000FF",
24614 options.map = this.gMapContext.map;
24615 options.radius = radius;
24616 options.center = center;
24617 this.gMapContext.circle = new google.maps.Circle(options);
24618 return this.gMapContext.circle;
24624 setPosition: function(location)
24626 this.gMapContext.location = location;
24627 this.gMapContext.marker.setPosition(location);
24628 this.gMapContext.map.panTo(location);
24629 this.drawCircle(location, this.gMapContext.radius, {});
24633 if (this.gMapContext.settings.enableReverseGeocode) {
24634 this.gMapContext.geodecoder.geocode({
24635 latLng: this.gMapContext.location
24636 }, function(results, status) {
24638 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
24639 _this.gMapContext.locationName = results[0].formatted_address;
24640 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
24642 _this.fireEvent('positionchanged', this, location);
24649 this.fireEvent('positionchanged', this, location);
24654 google.maps.event.trigger(this.gMapContext.map, "resize");
24656 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
24658 this.fireEvent('resize', this);
24661 setPositionByLatLng: function(latitude, longitude)
24663 this.setPosition(new google.maps.LatLng(latitude, longitude));
24666 getCurrentPosition: function()
24669 latitude: this.gMapContext.location.lat(),
24670 longitude: this.gMapContext.location.lng()
24674 getAddressName: function()
24676 return this.gMapContext.locationName;
24679 getAddressComponents: function()
24681 return this.gMapContext.addressComponents;
24684 address_component_from_google_geocode: function(address_components)
24688 for (var i = 0; i < address_components.length; i++) {
24689 var component = address_components[i];
24690 if (component.types.indexOf("postal_code") >= 0) {
24691 result.postalCode = component.short_name;
24692 } else if (component.types.indexOf("street_number") >= 0) {
24693 result.streetNumber = component.short_name;
24694 } else if (component.types.indexOf("route") >= 0) {
24695 result.streetName = component.short_name;
24696 } else if (component.types.indexOf("neighborhood") >= 0) {
24697 result.city = component.short_name;
24698 } else if (component.types.indexOf("locality") >= 0) {
24699 result.city = component.short_name;
24700 } else if (component.types.indexOf("sublocality") >= 0) {
24701 result.district = component.short_name;
24702 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
24703 result.stateOrProvince = component.short_name;
24704 } else if (component.types.indexOf("country") >= 0) {
24705 result.country = component.short_name;
24709 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
24710 result.addressLine2 = "";
24714 setZoomLevel: function(zoom)
24716 this.gMapContext.map.setZoom(zoom);
24729 this.fireEvent('show', this);
24740 this.fireEvent('hide', this);
24745 Roo.apply(Roo.bootstrap.LocationPicker, {
24747 OverlayView : function(map, options)
24749 options = options || {};
24763 * @class Roo.bootstrap.Alert
24764 * @extends Roo.bootstrap.Component
24765 * Bootstrap Alert class
24766 * @cfg {String} title The title of alert
24767 * @cfg {String} html The content of alert
24768 * @cfg {String} weight ( success | info | warning | danger )
24769 * @cfg {String} faicon font-awesomeicon
24772 * Create a new alert
24773 * @param {Object} config The config object
24777 Roo.bootstrap.Alert = function(config){
24778 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
24782 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
24789 getAutoCreate : function()
24798 cls : 'roo-alert-icon'
24803 cls : 'roo-alert-title',
24808 cls : 'roo-alert-text',
24815 cfg.cn[0].cls += ' fa ' + this.faicon;
24819 cfg.cls += ' alert-' + this.weight;
24825 initEvents: function()
24827 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24830 setTitle : function(str)
24832 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
24835 setText : function(str)
24837 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
24840 setWeight : function(weight)
24843 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
24846 this.weight = weight;
24848 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
24851 setIcon : function(icon)
24854 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
24857 this.faicon = icon;
24859 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
24880 * @class Roo.bootstrap.UploadCropbox
24881 * @extends Roo.bootstrap.Component
24882 * Bootstrap UploadCropbox class
24883 * @cfg {String} emptyText show when image has been loaded
24884 * @cfg {String} rotateNotify show when image too small to rotate
24885 * @cfg {Number} errorTimeout default 3000
24886 * @cfg {Number} minWidth default 300
24887 * @cfg {Number} minHeight default 300
24888 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
24889 * @cfg {Boolean} isDocument (true|false) default false
24890 * @cfg {String} url action url
24891 * @cfg {String} paramName default 'imageUpload'
24892 * @cfg {String} method default POST
24893 * @cfg {Boolean} loadMask (true|false) default true
24894 * @cfg {Boolean} loadingText default 'Loading...'
24897 * Create a new UploadCropbox
24898 * @param {Object} config The config object
24901 Roo.bootstrap.UploadCropbox = function(config){
24902 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
24906 * @event beforeselectfile
24907 * Fire before select file
24908 * @param {Roo.bootstrap.UploadCropbox} this
24910 "beforeselectfile" : true,
24913 * Fire after initEvent
24914 * @param {Roo.bootstrap.UploadCropbox} this
24919 * Fire after initEvent
24920 * @param {Roo.bootstrap.UploadCropbox} this
24921 * @param {String} data
24926 * Fire when preparing the file data
24927 * @param {Roo.bootstrap.UploadCropbox} this
24928 * @param {Object} file
24933 * Fire when get exception
24934 * @param {Roo.bootstrap.UploadCropbox} this
24935 * @param {XMLHttpRequest} xhr
24937 "exception" : true,
24939 * @event beforeloadcanvas
24940 * Fire before load the canvas
24941 * @param {Roo.bootstrap.UploadCropbox} this
24942 * @param {String} src
24944 "beforeloadcanvas" : true,
24947 * Fire when trash image
24948 * @param {Roo.bootstrap.UploadCropbox} this
24953 * Fire when download the image
24954 * @param {Roo.bootstrap.UploadCropbox} this
24958 * @event footerbuttonclick
24959 * Fire when footerbuttonclick
24960 * @param {Roo.bootstrap.UploadCropbox} this
24961 * @param {String} type
24963 "footerbuttonclick" : true,
24967 * @param {Roo.bootstrap.UploadCropbox} this
24972 * Fire when rotate the image
24973 * @param {Roo.bootstrap.UploadCropbox} this
24974 * @param {String} pos
24979 * Fire when inspect the file
24980 * @param {Roo.bootstrap.UploadCropbox} this
24981 * @param {Object} file
24986 * Fire when xhr upload the file
24987 * @param {Roo.bootstrap.UploadCropbox} this
24988 * @param {Object} data
24993 * Fire when arrange the file data
24994 * @param {Roo.bootstrap.UploadCropbox} this
24995 * @param {Object} formData
25000 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25003 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25005 emptyText : 'Click to upload image',
25006 rotateNotify : 'Image is too small to rotate',
25007 errorTimeout : 3000,
25021 cropType : 'image/jpeg',
25023 canvasLoaded : false,
25024 isDocument : false,
25026 paramName : 'imageUpload',
25028 loadingText : 'Loading...',
25031 getAutoCreate : function()
25035 cls : 'roo-upload-cropbox',
25039 cls : 'roo-upload-cropbox-selector',
25044 cls : 'roo-upload-cropbox-body',
25045 style : 'cursor:pointer',
25049 cls : 'roo-upload-cropbox-preview'
25053 cls : 'roo-upload-cropbox-thumb'
25057 cls : 'roo-upload-cropbox-empty-notify',
25058 html : this.emptyText
25062 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25063 html : this.rotateNotify
25069 cls : 'roo-upload-cropbox-footer',
25072 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25082 onRender : function(ct, position)
25084 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25086 if (this.buttons.length) {
25088 Roo.each(this.buttons, function(bb) {
25090 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25092 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25098 this.maskEl = this.el;
25102 initEvents : function()
25104 this.urlAPI = (window.createObjectURL && window) ||
25105 (window.URL && URL.revokeObjectURL && URL) ||
25106 (window.webkitURL && webkitURL);
25108 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25109 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25111 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25112 this.selectorEl.hide();
25114 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25115 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25117 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25118 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25119 this.thumbEl.hide();
25121 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25122 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25124 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25125 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25126 this.errorEl.hide();
25128 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25129 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25130 this.footerEl.hide();
25132 this.setThumbBoxSize();
25138 this.fireEvent('initial', this);
25145 window.addEventListener("resize", function() { _this.resize(); } );
25147 this.bodyEl.on('click', this.beforeSelectFile, this);
25150 this.bodyEl.on('touchstart', this.onTouchStart, this);
25151 this.bodyEl.on('touchmove', this.onTouchMove, this);
25152 this.bodyEl.on('touchend', this.onTouchEnd, this);
25156 this.bodyEl.on('mousedown', this.onMouseDown, this);
25157 this.bodyEl.on('mousemove', this.onMouseMove, this);
25158 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25159 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25160 Roo.get(document).on('mouseup', this.onMouseUp, this);
25163 this.selectorEl.on('change', this.onFileSelected, this);
25169 this.baseScale = 1;
25171 this.baseRotate = 1;
25172 this.dragable = false;
25173 this.pinching = false;
25176 this.cropData = false;
25177 this.notifyEl.dom.innerHTML = this.emptyText;
25179 this.selectorEl.dom.value = '';
25183 resize : function()
25185 if(this.fireEvent('resize', this) != false){
25186 this.setThumbBoxPosition();
25187 this.setCanvasPosition();
25191 onFooterButtonClick : function(e, el, o, type)
25194 case 'rotate-left' :
25195 this.onRotateLeft(e);
25197 case 'rotate-right' :
25198 this.onRotateRight(e);
25201 this.beforeSelectFile(e);
25216 this.fireEvent('footerbuttonclick', this, type);
25219 beforeSelectFile : function(e)
25221 e.preventDefault();
25223 if(this.fireEvent('beforeselectfile', this) != false){
25224 this.selectorEl.dom.click();
25228 onFileSelected : function(e)
25230 e.preventDefault();
25232 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25236 var file = this.selectorEl.dom.files[0];
25238 if(this.fireEvent('inspect', this, file) != false){
25239 this.prepare(file);
25244 trash : function(e)
25246 this.fireEvent('trash', this);
25249 download : function(e)
25251 this.fireEvent('download', this);
25254 loadCanvas : function(src)
25256 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25260 this.imageEl = document.createElement('img');
25264 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25266 this.imageEl.src = src;
25270 onLoadCanvas : function()
25272 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25273 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25275 this.bodyEl.un('click', this.beforeSelectFile, this);
25277 this.notifyEl.hide();
25278 this.thumbEl.show();
25279 this.footerEl.show();
25281 this.baseRotateLevel();
25283 if(this.isDocument){
25284 this.setThumbBoxSize();
25287 this.setThumbBoxPosition();
25289 this.baseScaleLevel();
25295 this.canvasLoaded = true;
25298 this.maskEl.unmask();
25303 setCanvasPosition : function()
25305 if(!this.canvasEl){
25309 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
25310 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
25312 this.previewEl.setLeft(pw);
25313 this.previewEl.setTop(ph);
25317 onMouseDown : function(e)
25321 this.dragable = true;
25322 this.pinching = false;
25324 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
25325 this.dragable = false;
25329 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25330 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25334 onMouseMove : function(e)
25338 if(!this.canvasLoaded){
25342 if (!this.dragable){
25346 var minX = Math.ceil(this.thumbEl.getLeft(true));
25347 var minY = Math.ceil(this.thumbEl.getTop(true));
25349 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
25350 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
25352 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25353 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25355 x = x - this.mouseX;
25356 y = y - this.mouseY;
25358 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
25359 var bgY = Math.ceil(y + this.previewEl.getTop(true));
25361 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
25362 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
25364 this.previewEl.setLeft(bgX);
25365 this.previewEl.setTop(bgY);
25367 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25368 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25371 onMouseUp : function(e)
25375 this.dragable = false;
25378 onMouseWheel : function(e)
25382 this.startScale = this.scale;
25384 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
25386 if(!this.zoomable()){
25387 this.scale = this.startScale;
25396 zoomable : function()
25398 var minScale = this.thumbEl.getWidth() / this.minWidth;
25400 if(this.minWidth < this.minHeight){
25401 minScale = this.thumbEl.getHeight() / this.minHeight;
25404 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
25405 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
25409 (this.rotate == 0 || this.rotate == 180) &&
25411 width > this.imageEl.OriginWidth ||
25412 height > this.imageEl.OriginHeight ||
25413 (width < this.minWidth && height < this.minHeight)
25421 (this.rotate == 90 || this.rotate == 270) &&
25423 width > this.imageEl.OriginWidth ||
25424 height > this.imageEl.OriginHeight ||
25425 (width < this.minHeight && height < this.minWidth)
25432 !this.isDocument &&
25433 (this.rotate == 0 || this.rotate == 180) &&
25435 width < this.minWidth ||
25436 width > this.imageEl.OriginWidth ||
25437 height < this.minHeight ||
25438 height > this.imageEl.OriginHeight
25445 !this.isDocument &&
25446 (this.rotate == 90 || this.rotate == 270) &&
25448 width < this.minHeight ||
25449 width > this.imageEl.OriginWidth ||
25450 height < this.minWidth ||
25451 height > this.imageEl.OriginHeight
25461 onRotateLeft : function(e)
25463 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25465 var minScale = this.thumbEl.getWidth() / this.minWidth;
25467 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25468 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25470 this.startScale = this.scale;
25472 while (this.getScaleLevel() < minScale){
25474 this.scale = this.scale + 1;
25476 if(!this.zoomable()){
25481 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25482 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25487 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25494 this.scale = this.startScale;
25496 this.onRotateFail();
25501 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25503 if(this.isDocument){
25504 this.setThumbBoxSize();
25505 this.setThumbBoxPosition();
25506 this.setCanvasPosition();
25511 this.fireEvent('rotate', this, 'left');
25515 onRotateRight : function(e)
25517 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25519 var minScale = this.thumbEl.getWidth() / this.minWidth;
25521 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25522 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25524 this.startScale = this.scale;
25526 while (this.getScaleLevel() < minScale){
25528 this.scale = this.scale + 1;
25530 if(!this.zoomable()){
25535 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25536 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25541 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25548 this.scale = this.startScale;
25550 this.onRotateFail();
25555 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25557 if(this.isDocument){
25558 this.setThumbBoxSize();
25559 this.setThumbBoxPosition();
25560 this.setCanvasPosition();
25565 this.fireEvent('rotate', this, 'right');
25568 onRotateFail : function()
25570 this.errorEl.show(true);
25574 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
25579 this.previewEl.dom.innerHTML = '';
25581 var canvasEl = document.createElement("canvas");
25583 var contextEl = canvasEl.getContext("2d");
25585 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25586 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25587 var center = this.imageEl.OriginWidth / 2;
25589 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
25590 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25591 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25592 center = this.imageEl.OriginHeight / 2;
25595 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
25597 contextEl.translate(center, center);
25598 contextEl.rotate(this.rotate * Math.PI / 180);
25600 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25602 this.canvasEl = document.createElement("canvas");
25604 this.contextEl = this.canvasEl.getContext("2d");
25606 switch (this.rotate) {
25609 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25610 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25612 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25617 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25618 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25620 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25621 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);
25625 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25630 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25631 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25633 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25634 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);
25638 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);
25643 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25644 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25646 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25647 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25651 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);
25658 this.previewEl.appendChild(this.canvasEl);
25660 this.setCanvasPosition();
25665 if(!this.canvasLoaded){
25669 var imageCanvas = document.createElement("canvas");
25671 var imageContext = imageCanvas.getContext("2d");
25673 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25674 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25676 var center = imageCanvas.width / 2;
25678 imageContext.translate(center, center);
25680 imageContext.rotate(this.rotate * Math.PI / 180);
25682 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25684 var canvas = document.createElement("canvas");
25686 var context = canvas.getContext("2d");
25688 canvas.width = this.minWidth;
25689 canvas.height = this.minHeight;
25691 switch (this.rotate) {
25694 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25695 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25697 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25698 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25700 var targetWidth = this.minWidth - 2 * x;
25701 var targetHeight = this.minHeight - 2 * y;
25705 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25706 scale = targetWidth / width;
25709 if(x > 0 && y == 0){
25710 scale = targetHeight / height;
25713 if(x > 0 && y > 0){
25714 scale = targetWidth / width;
25716 if(width < height){
25717 scale = targetHeight / height;
25721 context.scale(scale, scale);
25723 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25724 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25726 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25727 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25729 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25734 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25735 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25737 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25738 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25740 var targetWidth = this.minWidth - 2 * x;
25741 var targetHeight = this.minHeight - 2 * y;
25745 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25746 scale = targetWidth / width;
25749 if(x > 0 && y == 0){
25750 scale = targetHeight / height;
25753 if(x > 0 && y > 0){
25754 scale = targetWidth / width;
25756 if(width < height){
25757 scale = targetHeight / height;
25761 context.scale(scale, scale);
25763 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25764 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25766 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25767 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25769 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25771 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25776 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25777 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25779 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25780 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25782 var targetWidth = this.minWidth - 2 * x;
25783 var targetHeight = this.minHeight - 2 * y;
25787 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25788 scale = targetWidth / width;
25791 if(x > 0 && y == 0){
25792 scale = targetHeight / height;
25795 if(x > 0 && y > 0){
25796 scale = targetWidth / width;
25798 if(width < height){
25799 scale = targetHeight / height;
25803 context.scale(scale, scale);
25805 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25806 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25808 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25809 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25811 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25812 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25814 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25819 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25820 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25822 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25823 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25825 var targetWidth = this.minWidth - 2 * x;
25826 var targetHeight = this.minHeight - 2 * y;
25830 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25831 scale = targetWidth / width;
25834 if(x > 0 && y == 0){
25835 scale = targetHeight / height;
25838 if(x > 0 && y > 0){
25839 scale = targetWidth / width;
25841 if(width < height){
25842 scale = targetHeight / height;
25846 context.scale(scale, scale);
25848 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25849 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25851 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25852 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25854 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25856 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25863 this.cropData = canvas.toDataURL(this.cropType);
25865 if(this.fireEvent('crop', this, this.cropData) !== false){
25866 this.process(this.file, this.cropData);
25873 setThumbBoxSize : function()
25877 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
25878 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
25879 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
25881 this.minWidth = width;
25882 this.minHeight = height;
25884 if(this.rotate == 90 || this.rotate == 270){
25885 this.minWidth = height;
25886 this.minHeight = width;
25891 width = Math.ceil(this.minWidth * height / this.minHeight);
25893 if(this.minWidth > this.minHeight){
25895 height = Math.ceil(this.minHeight * width / this.minWidth);
25898 this.thumbEl.setStyle({
25899 width : width + 'px',
25900 height : height + 'px'
25907 setThumbBoxPosition : function()
25909 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
25910 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
25912 this.thumbEl.setLeft(x);
25913 this.thumbEl.setTop(y);
25917 baseRotateLevel : function()
25919 this.baseRotate = 1;
25922 typeof(this.exif) != 'undefined' &&
25923 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
25924 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
25926 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
25929 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
25933 baseScaleLevel : function()
25937 if(this.isDocument){
25939 if(this.baseRotate == 6 || this.baseRotate == 8){
25941 height = this.thumbEl.getHeight();
25942 this.baseScale = height / this.imageEl.OriginWidth;
25944 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
25945 width = this.thumbEl.getWidth();
25946 this.baseScale = width / this.imageEl.OriginHeight;
25952 height = this.thumbEl.getHeight();
25953 this.baseScale = height / this.imageEl.OriginHeight;
25955 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
25956 width = this.thumbEl.getWidth();
25957 this.baseScale = width / this.imageEl.OriginWidth;
25963 if(this.baseRotate == 6 || this.baseRotate == 8){
25965 width = this.thumbEl.getHeight();
25966 this.baseScale = width / this.imageEl.OriginHeight;
25968 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
25969 height = this.thumbEl.getWidth();
25970 this.baseScale = height / this.imageEl.OriginHeight;
25973 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25974 height = this.thumbEl.getWidth();
25975 this.baseScale = height / this.imageEl.OriginHeight;
25977 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
25978 width = this.thumbEl.getHeight();
25979 this.baseScale = width / this.imageEl.OriginWidth;
25986 width = this.thumbEl.getWidth();
25987 this.baseScale = width / this.imageEl.OriginWidth;
25989 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
25990 height = this.thumbEl.getHeight();
25991 this.baseScale = height / this.imageEl.OriginHeight;
25994 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25996 height = this.thumbEl.getHeight();
25997 this.baseScale = height / this.imageEl.OriginHeight;
25999 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26000 width = this.thumbEl.getWidth();
26001 this.baseScale = width / this.imageEl.OriginWidth;
26009 getScaleLevel : function()
26011 return this.baseScale * Math.pow(1.1, this.scale);
26014 onTouchStart : function(e)
26016 if(!this.canvasLoaded){
26017 this.beforeSelectFile(e);
26021 var touches = e.browserEvent.touches;
26027 if(touches.length == 1){
26028 this.onMouseDown(e);
26032 if(touches.length != 2){
26038 for(var i = 0, finger; finger = touches[i]; i++){
26039 coords.push(finger.pageX, finger.pageY);
26042 var x = Math.pow(coords[0] - coords[2], 2);
26043 var y = Math.pow(coords[1] - coords[3], 2);
26045 this.startDistance = Math.sqrt(x + y);
26047 this.startScale = this.scale;
26049 this.pinching = true;
26050 this.dragable = false;
26054 onTouchMove : function(e)
26056 if(!this.pinching && !this.dragable){
26060 var touches = e.browserEvent.touches;
26067 this.onMouseMove(e);
26073 for(var i = 0, finger; finger = touches[i]; i++){
26074 coords.push(finger.pageX, finger.pageY);
26077 var x = Math.pow(coords[0] - coords[2], 2);
26078 var y = Math.pow(coords[1] - coords[3], 2);
26080 this.endDistance = Math.sqrt(x + y);
26082 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26084 if(!this.zoomable()){
26085 this.scale = this.startScale;
26093 onTouchEnd : function(e)
26095 this.pinching = false;
26096 this.dragable = false;
26100 process : function(file, crop)
26103 this.maskEl.mask(this.loadingText);
26106 this.xhr = new XMLHttpRequest();
26108 file.xhr = this.xhr;
26110 this.xhr.open(this.method, this.url, true);
26113 "Accept": "application/json",
26114 "Cache-Control": "no-cache",
26115 "X-Requested-With": "XMLHttpRequest"
26118 for (var headerName in headers) {
26119 var headerValue = headers[headerName];
26121 this.xhr.setRequestHeader(headerName, headerValue);
26127 this.xhr.onload = function()
26129 _this.xhrOnLoad(_this.xhr);
26132 this.xhr.onerror = function()
26134 _this.xhrOnError(_this.xhr);
26137 var formData = new FormData();
26139 formData.append('returnHTML', 'NO');
26142 formData.append('crop', crop);
26145 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26146 formData.append(this.paramName, file, file.name);
26149 if(typeof(file.filename) != 'undefined'){
26150 formData.append('filename', file.filename);
26153 if(typeof(file.mimetype) != 'undefined'){
26154 formData.append('mimetype', file.mimetype);
26157 if(this.fireEvent('arrange', this, formData) != false){
26158 this.xhr.send(formData);
26162 xhrOnLoad : function(xhr)
26165 this.maskEl.unmask();
26168 if (xhr.readyState !== 4) {
26169 this.fireEvent('exception', this, xhr);
26173 var response = Roo.decode(xhr.responseText);
26175 if(!response.success){
26176 this.fireEvent('exception', this, xhr);
26180 var response = Roo.decode(xhr.responseText);
26182 this.fireEvent('upload', this, response);
26186 xhrOnError : function()
26189 this.maskEl.unmask();
26192 Roo.log('xhr on error');
26194 var response = Roo.decode(xhr.responseText);
26200 prepare : function(file)
26203 this.maskEl.mask(this.loadingText);
26209 if(typeof(file) === 'string'){
26210 this.loadCanvas(file);
26214 if(!file || !this.urlAPI){
26219 this.cropType = file.type;
26223 if(this.fireEvent('prepare', this, this.file) != false){
26225 var reader = new FileReader();
26227 reader.onload = function (e) {
26228 if (e.target.error) {
26229 Roo.log(e.target.error);
26233 var buffer = e.target.result,
26234 dataView = new DataView(buffer),
26236 maxOffset = dataView.byteLength - 4,
26240 if (dataView.getUint16(0) === 0xffd8) {
26241 while (offset < maxOffset) {
26242 markerBytes = dataView.getUint16(offset);
26244 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26245 markerLength = dataView.getUint16(offset + 2) + 2;
26246 if (offset + markerLength > dataView.byteLength) {
26247 Roo.log('Invalid meta data: Invalid segment size.');
26251 if(markerBytes == 0xffe1){
26252 _this.parseExifData(
26259 offset += markerLength;
26269 var url = _this.urlAPI.createObjectURL(_this.file);
26271 _this.loadCanvas(url);
26276 reader.readAsArrayBuffer(this.file);
26282 parseExifData : function(dataView, offset, length)
26284 var tiffOffset = offset + 10,
26288 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26289 // No Exif data, might be XMP data instead
26293 // Check for the ASCII code for "Exif" (0x45786966):
26294 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26295 // No Exif data, might be XMP data instead
26298 if (tiffOffset + 8 > dataView.byteLength) {
26299 Roo.log('Invalid Exif data: Invalid segment size.');
26302 // Check for the two null bytes:
26303 if (dataView.getUint16(offset + 8) !== 0x0000) {
26304 Roo.log('Invalid Exif data: Missing byte alignment offset.');
26307 // Check the byte alignment:
26308 switch (dataView.getUint16(tiffOffset)) {
26310 littleEndian = true;
26313 littleEndian = false;
26316 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
26319 // Check for the TIFF tag marker (0x002A):
26320 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
26321 Roo.log('Invalid Exif data: Missing TIFF marker.');
26324 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
26325 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
26327 this.parseExifTags(
26330 tiffOffset + dirOffset,
26335 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
26340 if (dirOffset + 6 > dataView.byteLength) {
26341 Roo.log('Invalid Exif data: Invalid directory offset.');
26344 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
26345 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
26346 if (dirEndOffset + 4 > dataView.byteLength) {
26347 Roo.log('Invalid Exif data: Invalid directory size.');
26350 for (i = 0; i < tagsNumber; i += 1) {
26354 dirOffset + 2 + 12 * i, // tag offset
26358 // Return the offset to the next directory:
26359 return dataView.getUint32(dirEndOffset, littleEndian);
26362 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
26364 var tag = dataView.getUint16(offset, littleEndian);
26366 this.exif[tag] = this.getExifValue(
26370 dataView.getUint16(offset + 2, littleEndian), // tag type
26371 dataView.getUint32(offset + 4, littleEndian), // tag length
26376 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
26378 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
26387 Roo.log('Invalid Exif data: Invalid tag type.');
26391 tagSize = tagType.size * length;
26392 // Determine if the value is contained in the dataOffset bytes,
26393 // or if the value at the dataOffset is a pointer to the actual data:
26394 dataOffset = tagSize > 4 ?
26395 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
26396 if (dataOffset + tagSize > dataView.byteLength) {
26397 Roo.log('Invalid Exif data: Invalid data offset.');
26400 if (length === 1) {
26401 return tagType.getValue(dataView, dataOffset, littleEndian);
26404 for (i = 0; i < length; i += 1) {
26405 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
26408 if (tagType.ascii) {
26410 // Concatenate the chars:
26411 for (i = 0; i < values.length; i += 1) {
26413 // Ignore the terminating NULL byte(s):
26414 if (c === '\u0000') {
26426 Roo.apply(Roo.bootstrap.UploadCropbox, {
26428 'Orientation': 0x0112
26432 1: 0, //'top-left',
26434 3: 180, //'bottom-right',
26435 // 4: 'bottom-left',
26437 6: 90, //'right-top',
26438 // 7: 'right-bottom',
26439 8: 270 //'left-bottom'
26443 // byte, 8-bit unsigned int:
26445 getValue: function (dataView, dataOffset) {
26446 return dataView.getUint8(dataOffset);
26450 // ascii, 8-bit byte:
26452 getValue: function (dataView, dataOffset) {
26453 return String.fromCharCode(dataView.getUint8(dataOffset));
26458 // short, 16 bit int:
26460 getValue: function (dataView, dataOffset, littleEndian) {
26461 return dataView.getUint16(dataOffset, littleEndian);
26465 // long, 32 bit int:
26467 getValue: function (dataView, dataOffset, littleEndian) {
26468 return dataView.getUint32(dataOffset, littleEndian);
26472 // rational = two long values, first is numerator, second is denominator:
26474 getValue: function (dataView, dataOffset, littleEndian) {
26475 return dataView.getUint32(dataOffset, littleEndian) /
26476 dataView.getUint32(dataOffset + 4, littleEndian);
26480 // slong, 32 bit signed int:
26482 getValue: function (dataView, dataOffset, littleEndian) {
26483 return dataView.getInt32(dataOffset, littleEndian);
26487 // srational, two slongs, first is numerator, second is denominator:
26489 getValue: function (dataView, dataOffset, littleEndian) {
26490 return dataView.getInt32(dataOffset, littleEndian) /
26491 dataView.getInt32(dataOffset + 4, littleEndian);
26501 cls : 'btn-group roo-upload-cropbox-rotate-left',
26502 action : 'rotate-left',
26506 cls : 'btn btn-default',
26507 html : '<i class="fa fa-undo"></i>'
26513 cls : 'btn-group roo-upload-cropbox-picture',
26514 action : 'picture',
26518 cls : 'btn btn-default',
26519 html : '<i class="fa fa-picture-o"></i>'
26525 cls : 'btn-group roo-upload-cropbox-rotate-right',
26526 action : 'rotate-right',
26530 cls : 'btn btn-default',
26531 html : '<i class="fa fa-repeat"></i>'
26539 cls : 'btn-group roo-upload-cropbox-rotate-left',
26540 action : 'rotate-left',
26544 cls : 'btn btn-default',
26545 html : '<i class="fa fa-undo"></i>'
26551 cls : 'btn-group roo-upload-cropbox-download',
26552 action : 'download',
26556 cls : 'btn btn-default',
26557 html : '<i class="fa fa-download"></i>'
26563 cls : 'btn-group roo-upload-cropbox-crop',
26568 cls : 'btn btn-default',
26569 html : '<i class="fa fa-crop"></i>'
26575 cls : 'btn-group roo-upload-cropbox-trash',
26580 cls : 'btn btn-default',
26581 html : '<i class="fa fa-trash"></i>'
26587 cls : 'btn-group roo-upload-cropbox-rotate-right',
26588 action : 'rotate-right',
26592 cls : 'btn btn-default',
26593 html : '<i class="fa fa-repeat"></i>'
26601 cls : 'btn-group roo-upload-cropbox-rotate-left',
26602 action : 'rotate-left',
26606 cls : 'btn btn-default',
26607 html : '<i class="fa fa-undo"></i>'
26613 cls : 'btn-group roo-upload-cropbox-rotate-right',
26614 action : 'rotate-right',
26618 cls : 'btn btn-default',
26619 html : '<i class="fa fa-repeat"></i>'
26632 * @class Roo.bootstrap.DocumentManager
26633 * @extends Roo.bootstrap.Component
26634 * Bootstrap DocumentManager class
26635 * @cfg {String} paramName default 'imageUpload'
26636 * @cfg {String} method default POST
26637 * @cfg {String} url action url
26638 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
26639 * @cfg {Boolean} multiple multiple upload default true
26640 * @cfg {Number} thumbSize default 300
26641 * @cfg {String} fieldLabel
26642 * @cfg {Number} labelWidth default 4
26643 * @cfg {String} labelAlign (left|top) default left
26644 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
26647 * Create a new DocumentManager
26648 * @param {Object} config The config object
26651 Roo.bootstrap.DocumentManager = function(config){
26652 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
26657 * Fire when initial the DocumentManager
26658 * @param {Roo.bootstrap.DocumentManager} this
26663 * inspect selected file
26664 * @param {Roo.bootstrap.DocumentManager} this
26665 * @param {File} file
26670 * Fire when xhr load exception
26671 * @param {Roo.bootstrap.DocumentManager} this
26672 * @param {XMLHttpRequest} xhr
26674 "exception" : true,
26677 * prepare the form data
26678 * @param {Roo.bootstrap.DocumentManager} this
26679 * @param {Object} formData
26684 * Fire when remove the file
26685 * @param {Roo.bootstrap.DocumentManager} this
26686 * @param {Object} file
26691 * Fire after refresh the file
26692 * @param {Roo.bootstrap.DocumentManager} this
26697 * Fire after click the image
26698 * @param {Roo.bootstrap.DocumentManager} this
26699 * @param {Object} file
26704 * Fire when upload a image and editable set to true
26705 * @param {Roo.bootstrap.DocumentManager} this
26706 * @param {Object} file
26710 * @event beforeselectfile
26711 * Fire before select file
26712 * @param {Roo.bootstrap.DocumentManager} this
26714 "beforeselectfile" : true,
26717 * Fire before process file
26718 * @param {Roo.bootstrap.DocumentManager} this
26719 * @param {Object} file
26726 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
26735 paramName : 'imageUpload',
26738 labelAlign : 'left',
26745 getAutoCreate : function()
26747 var managerWidget = {
26749 cls : 'roo-document-manager',
26753 cls : 'roo-document-manager-selector',
26758 cls : 'roo-document-manager-uploader',
26762 cls : 'roo-document-manager-upload-btn',
26763 html : '<i class="fa fa-plus"></i>'
26774 cls : 'column col-md-12',
26779 if(this.fieldLabel.length){
26784 cls : 'column col-md-12',
26785 html : this.fieldLabel
26789 cls : 'column col-md-12',
26794 if(this.labelAlign == 'left'){
26798 cls : 'column col-md-' + this.labelWidth,
26799 html : this.fieldLabel
26803 cls : 'column col-md-' + (12 - this.labelWidth),
26813 cls : 'row clearfix',
26821 initEvents : function()
26823 this.managerEl = this.el.select('.roo-document-manager', true).first();
26824 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26826 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
26827 this.selectorEl.hide();
26830 this.selectorEl.attr('multiple', 'multiple');
26833 this.selectorEl.on('change', this.onFileSelected, this);
26835 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
26836 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26838 this.uploader.on('click', this.onUploaderClick, this);
26840 this.renderProgressDialog();
26844 window.addEventListener("resize", function() { _this.refresh(); } );
26846 this.fireEvent('initial', this);
26849 renderProgressDialog : function()
26853 this.progressDialog = new Roo.bootstrap.Modal({
26854 cls : 'roo-document-manager-progress-dialog',
26855 allow_close : false,
26865 btnclick : function() {
26866 _this.uploadCancel();
26872 this.progressDialog.render(Roo.get(document.body));
26874 this.progress = new Roo.bootstrap.Progress({
26875 cls : 'roo-document-manager-progress',
26880 this.progress.render(this.progressDialog.getChildContainer());
26882 this.progressBar = new Roo.bootstrap.ProgressBar({
26883 cls : 'roo-document-manager-progress-bar',
26886 aria_valuemax : 12,
26890 this.progressBar.render(this.progress.getChildContainer());
26893 onUploaderClick : function(e)
26895 e.preventDefault();
26897 if(this.fireEvent('beforeselectfile', this) != false){
26898 this.selectorEl.dom.click();
26903 onFileSelected : function(e)
26905 e.preventDefault();
26907 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26911 Roo.each(this.selectorEl.dom.files, function(file){
26912 if(this.fireEvent('inspect', this, file) != false){
26913 this.files.push(file);
26923 this.selectorEl.dom.value = '';
26925 if(!this.files.length){
26929 if(this.boxes > 0 && this.files.length > this.boxes){
26930 this.files = this.files.slice(0, this.boxes);
26933 this.uploader.show();
26935 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26936 this.uploader.hide();
26945 Roo.each(this.files, function(file){
26947 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
26948 var f = this.renderPreview(file);
26953 if(file.type.indexOf('image') != -1){
26954 this.delegates.push(
26956 _this.process(file);
26957 }).createDelegate(this)
26965 _this.process(file);
26966 }).createDelegate(this)
26971 this.files = files;
26973 this.delegates = this.delegates.concat(docs);
26975 if(!this.delegates.length){
26980 this.progressBar.aria_valuemax = this.delegates.length;
26987 arrange : function()
26989 if(!this.delegates.length){
26990 this.progressDialog.hide();
26995 var delegate = this.delegates.shift();
26997 this.progressDialog.show();
26999 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27001 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27006 refresh : function()
27008 this.uploader.show();
27010 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27011 this.uploader.hide();
27014 Roo.isTouch ? this.closable(false) : this.closable(true);
27016 this.fireEvent('refresh', this);
27019 onRemove : function(e, el, o)
27021 e.preventDefault();
27023 this.fireEvent('remove', this, o);
27027 remove : function(o)
27031 Roo.each(this.files, function(file){
27032 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27041 this.files = files;
27048 Roo.each(this.files, function(file){
27053 file.target.remove();
27062 onClick : function(e, el, o)
27064 e.preventDefault();
27066 this.fireEvent('click', this, o);
27070 closable : function(closable)
27072 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27074 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27086 xhrOnLoad : function(xhr)
27088 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27092 if (xhr.readyState !== 4) {
27094 this.fireEvent('exception', this, xhr);
27098 var response = Roo.decode(xhr.responseText);
27100 if(!response.success){
27102 this.fireEvent('exception', this, xhr);
27106 var file = this.renderPreview(response.data);
27108 this.files.push(file);
27114 xhrOnError : function(xhr)
27116 Roo.log('xhr on error');
27118 var response = Roo.decode(xhr.responseText);
27125 process : function(file)
27127 if(this.fireEvent('process', this, file) !== false){
27128 if(this.editable && file.type.indexOf('image') != -1){
27129 this.fireEvent('edit', this, file);
27133 this.uploadStart(file, false);
27140 uploadStart : function(file, crop)
27142 this.xhr = new XMLHttpRequest();
27144 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27149 file.xhr = this.xhr;
27151 this.managerEl.createChild({
27153 cls : 'roo-document-manager-loading',
27157 tooltip : file.name,
27158 cls : 'roo-document-manager-thumb',
27159 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27165 this.xhr.open(this.method, this.url, true);
27168 "Accept": "application/json",
27169 "Cache-Control": "no-cache",
27170 "X-Requested-With": "XMLHttpRequest"
27173 for (var headerName in headers) {
27174 var headerValue = headers[headerName];
27176 this.xhr.setRequestHeader(headerName, headerValue);
27182 this.xhr.onload = function()
27184 _this.xhrOnLoad(_this.xhr);
27187 this.xhr.onerror = function()
27189 _this.xhrOnError(_this.xhr);
27192 var formData = new FormData();
27194 formData.append('returnHTML', 'NO');
27197 formData.append('crop', crop);
27200 formData.append(this.paramName, file, file.name);
27202 if(this.fireEvent('prepare', this, formData) != false){
27203 this.xhr.send(formData);
27207 uploadCancel : function()
27214 this.delegates = [];
27216 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27223 renderPreview : function(file)
27225 if(typeof(file.target) != 'undefined' && file.target){
27229 var previewEl = this.managerEl.createChild({
27231 cls : 'roo-document-manager-preview',
27235 tooltip : file.filename,
27236 cls : 'roo-document-manager-thumb',
27237 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27242 html : '<i class="fa fa-times-circle"></i>'
27247 var close = previewEl.select('button.close', true).first();
27249 close.on('click', this.onRemove, this, file);
27251 file.target = previewEl;
27253 var image = previewEl.select('img', true).first();
27257 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27259 image.on('click', this.onClick, this, file);
27265 onPreviewLoad : function(file, image)
27267 if(typeof(file.target) == 'undefined' || !file.target){
27271 var width = image.dom.naturalWidth || image.dom.width;
27272 var height = image.dom.naturalHeight || image.dom.height;
27274 if(width > height){
27275 file.target.addClass('wide');
27279 file.target.addClass('tall');
27284 uploadFromSource : function(file, crop)
27286 this.xhr = new XMLHttpRequest();
27288 this.managerEl.createChild({
27290 cls : 'roo-document-manager-loading',
27294 tooltip : file.name,
27295 cls : 'roo-document-manager-thumb',
27296 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27302 this.xhr.open(this.method, this.url, true);
27305 "Accept": "application/json",
27306 "Cache-Control": "no-cache",
27307 "X-Requested-With": "XMLHttpRequest"
27310 for (var headerName in headers) {
27311 var headerValue = headers[headerName];
27313 this.xhr.setRequestHeader(headerName, headerValue);
27319 this.xhr.onload = function()
27321 _this.xhrOnLoad(_this.xhr);
27324 this.xhr.onerror = function()
27326 _this.xhrOnError(_this.xhr);
27329 var formData = new FormData();
27331 formData.append('returnHTML', 'NO');
27333 formData.append('crop', crop);
27335 if(typeof(file.filename) != 'undefined'){
27336 formData.append('filename', file.filename);
27339 if(typeof(file.mimetype) != 'undefined'){
27340 formData.append('mimetype', file.mimetype);
27343 if(this.fireEvent('prepare', this, formData) != false){
27344 this.xhr.send(formData);
27354 * @class Roo.bootstrap.DocumentViewer
27355 * @extends Roo.bootstrap.Component
27356 * Bootstrap DocumentViewer class
27359 * Create a new DocumentViewer
27360 * @param {Object} config The config object
27363 Roo.bootstrap.DocumentViewer = function(config){
27364 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
27369 * Fire after initEvent
27370 * @param {Roo.bootstrap.DocumentViewer} this
27376 * @param {Roo.bootstrap.DocumentViewer} this
27381 * Fire after trash button
27382 * @param {Roo.bootstrap.DocumentViewer} this
27389 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
27391 getAutoCreate : function()
27395 cls : 'roo-document-viewer',
27399 cls : 'roo-document-viewer-body',
27403 cls : 'roo-document-viewer-thumb',
27407 cls : 'roo-document-viewer-image'
27415 cls : 'roo-document-viewer-footer',
27418 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
27426 cls : 'btn btn-default roo-document-viewer-trash',
27427 html : '<i class="fa fa-trash"></i>'
27440 initEvents : function()
27443 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
27444 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27446 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
27447 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27449 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
27450 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27452 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
27453 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27455 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
27456 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27458 this.bodyEl.on('click', this.onClick, this);
27460 this.trashBtn.on('click', this.onTrash, this);
27464 initial : function()
27466 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
27469 this.fireEvent('initial', this);
27473 onClick : function(e)
27475 e.preventDefault();
27477 this.fireEvent('click', this);
27480 onTrash : function(e)
27482 e.preventDefault();
27484 this.fireEvent('trash', this);
27496 * @class Roo.bootstrap.NavProgressBar
27497 * @extends Roo.bootstrap.Component
27498 * Bootstrap NavProgressBar class
27501 * Create a new nav progress bar
27502 * @param {Object} config The config object
27505 Roo.bootstrap.NavProgressBar = function(config){
27506 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
27508 this.bullets = this.bullets || [];
27510 // Roo.bootstrap.NavProgressBar.register(this);
27514 * Fires when the active item changes
27515 * @param {Roo.bootstrap.NavProgressBar} this
27516 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
27517 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
27524 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
27529 getAutoCreate : function()
27531 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
27535 cls : 'roo-navigation-bar-group',
27539 cls : 'roo-navigation-top-bar'
27543 cls : 'roo-navigation-bullets-bar',
27547 cls : 'roo-navigation-bar'
27554 cls : 'roo-navigation-bottom-bar'
27564 initEvents: function()
27569 onRender : function(ct, position)
27571 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
27573 if(this.bullets.length){
27574 Roo.each(this.bullets, function(b){
27583 addItem : function(cfg)
27585 var item = new Roo.bootstrap.NavProgressItem(cfg);
27587 item.parentId = this.id;
27588 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
27591 var top = new Roo.bootstrap.Element({
27593 cls : 'roo-navigation-bar-text'
27596 var bottom = new Roo.bootstrap.Element({
27598 cls : 'roo-navigation-bar-text'
27601 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
27602 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
27604 var topText = new Roo.bootstrap.Element({
27606 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
27609 var bottomText = new Roo.bootstrap.Element({
27611 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
27614 topText.onRender(top.el, null);
27615 bottomText.onRender(bottom.el, null);
27618 item.bottomEl = bottom;
27621 this.barItems.push(item);
27626 getActive : function()
27628 var active = false;
27630 Roo.each(this.barItems, function(v){
27632 if (!v.isActive()) {
27644 setActiveItem : function(item)
27648 Roo.each(this.barItems, function(v){
27649 if (v.rid == item.rid) {
27653 if (v.isActive()) {
27654 v.setActive(false);
27659 item.setActive(true);
27661 this.fireEvent('changed', this, item, prev);
27664 getBarItem: function(rid)
27668 Roo.each(this.barItems, function(e) {
27669 if (e.rid != rid) {
27680 indexOfItem : function(item)
27684 Roo.each(this.barItems, function(v, i){
27686 if (v.rid != item.rid) {
27697 setActiveNext : function()
27699 var i = this.indexOfItem(this.getActive());
27701 if (i > this.barItems.length) {
27705 this.setActiveItem(this.barItems[i+1]);
27708 setActivePrev : function()
27710 var i = this.indexOfItem(this.getActive());
27716 this.setActiveItem(this.barItems[i-1]);
27719 format : function()
27721 if(!this.barItems.length){
27725 var width = 100 / this.barItems.length;
27727 Roo.each(this.barItems, function(i){
27728 i.el.setStyle('width', width + '%');
27729 i.topEl.el.setStyle('width', width + '%');
27730 i.bottomEl.el.setStyle('width', width + '%');
27739 * Nav Progress Item
27744 * @class Roo.bootstrap.NavProgressItem
27745 * @extends Roo.bootstrap.Component
27746 * Bootstrap NavProgressItem class
27747 * @cfg {String} rid the reference id
27748 * @cfg {Boolean} active (true|false) Is item active default false
27749 * @cfg {Boolean} disabled (true|false) Is item active default false
27750 * @cfg {String} html
27751 * @cfg {String} position (top|bottom) text position default bottom
27752 * @cfg {String} icon show icon instead of number
27755 * Create a new NavProgressItem
27756 * @param {Object} config The config object
27758 Roo.bootstrap.NavProgressItem = function(config){
27759 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
27764 * The raw click event for the entire grid.
27765 * @param {Roo.bootstrap.NavProgressItem} this
27766 * @param {Roo.EventObject} e
27773 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
27779 position : 'bottom',
27782 getAutoCreate : function()
27784 var iconCls = 'roo-navigation-bar-item-icon';
27786 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
27790 cls: 'roo-navigation-bar-item',
27800 cfg.cls += ' active';
27803 cfg.cls += ' disabled';
27809 disable : function()
27811 this.setDisabled(true);
27814 enable : function()
27816 this.setDisabled(false);
27819 initEvents: function()
27821 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
27823 this.iconEl.on('click', this.onClick, this);
27826 onClick : function(e)
27828 e.preventDefault();
27834 if(this.fireEvent('click', this, e) === false){
27838 this.parent().setActiveItem(this);
27841 isActive: function ()
27843 return this.active;
27846 setActive : function(state)
27848 if(this.active == state){
27852 this.active = state;
27855 this.el.addClass('active');
27859 this.el.removeClass('active');
27864 setDisabled : function(state)
27866 if(this.disabled == state){
27870 this.disabled = state;
27873 this.el.addClass('disabled');
27877 this.el.removeClass('disabled');
27880 tooltipEl : function()
27882 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
27895 * @class Roo.bootstrap.FieldLabel
27896 * @extends Roo.bootstrap.Component
27897 * Bootstrap FieldLabel class
27898 * @cfg {String} html contents of the element
27899 * @cfg {String} tag tag of the element default label
27900 * @cfg {String} cls class of the element
27901 * @cfg {String} target label target
27902 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
27903 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
27904 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
27905 * @cfg {String} iconTooltip default "This field is required"
27908 * Create a new FieldLabel
27909 * @param {Object} config The config object
27912 Roo.bootstrap.FieldLabel = function(config){
27913 Roo.bootstrap.Element.superclass.constructor.call(this, config);
27918 * Fires after the field has been marked as invalid.
27919 * @param {Roo.form.FieldLabel} this
27920 * @param {String} msg The validation message
27925 * Fires after the field has been validated with no errors.
27926 * @param {Roo.form.FieldLabel} this
27932 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
27939 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
27940 validClass : 'text-success fa fa-lg fa-check',
27941 iconTooltip : 'This field is required',
27943 getAutoCreate : function(){
27947 cls : 'roo-bootstrap-field-label ' + this.cls,
27953 tooltip : this.iconTooltip
27965 initEvents: function()
27967 Roo.bootstrap.Element.superclass.initEvents.call(this);
27969 this.iconEl = this.el.select('i', true).first();
27971 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
27973 Roo.bootstrap.FieldLabel.register(this);
27977 * Mark this field as valid
27979 markValid : function()
27981 this.iconEl.show();
27983 this.iconEl.removeClass(this.invalidClass);
27985 this.iconEl.addClass(this.validClass);
27987 this.fireEvent('valid', this);
27991 * Mark this field as invalid
27992 * @param {String} msg The validation message
27994 markInvalid : function(msg)
27996 this.iconEl.show();
27998 this.iconEl.removeClass(this.validClass);
28000 this.iconEl.addClass(this.invalidClass);
28002 this.fireEvent('invalid', this, msg);
28008 Roo.apply(Roo.bootstrap.FieldLabel, {
28013 * register a FieldLabel Group
28014 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28016 register : function(label)
28018 if(this.groups.hasOwnProperty(label.target)){
28022 this.groups[label.target] = label;
28026 * fetch a FieldLabel Group based on the target
28027 * @param {string} target
28028 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28030 get: function(target) {
28031 if (typeof(this.groups[target]) == 'undefined') {
28035 return this.groups[target] ;
28044 * page DateSplitField.
28050 * @class Roo.bootstrap.DateSplitField
28051 * @extends Roo.bootstrap.Component
28052 * Bootstrap DateSplitField class
28053 * @cfg {string} fieldLabel - the label associated
28054 * @cfg {Number} labelWidth set the width of label (0-12)
28055 * @cfg {String} labelAlign (top|left)
28056 * @cfg {Boolean} dayAllowBlank (true|false) default false
28057 * @cfg {Boolean} monthAllowBlank (true|false) default false
28058 * @cfg {Boolean} yearAllowBlank (true|false) default false
28059 * @cfg {string} dayPlaceholder
28060 * @cfg {string} monthPlaceholder
28061 * @cfg {string} yearPlaceholder
28062 * @cfg {string} dayFormat default 'd'
28063 * @cfg {string} monthFormat default 'm'
28064 * @cfg {string} yearFormat default 'Y'
28068 * Create a new DateSplitField
28069 * @param {Object} config The config object
28072 Roo.bootstrap.DateSplitField = function(config){
28073 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28079 * getting the data of years
28080 * @param {Roo.bootstrap.DateSplitField} this
28081 * @param {Object} years
28086 * getting the data of days
28087 * @param {Roo.bootstrap.DateSplitField} this
28088 * @param {Object} days
28093 * Fires after the field has been marked as invalid.
28094 * @param {Roo.form.Field} this
28095 * @param {String} msg The validation message
28100 * Fires after the field has been validated with no errors.
28101 * @param {Roo.form.Field} this
28107 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28110 labelAlign : 'top',
28112 dayAllowBlank : false,
28113 monthAllowBlank : false,
28114 yearAllowBlank : false,
28115 dayPlaceholder : '',
28116 monthPlaceholder : '',
28117 yearPlaceholder : '',
28121 isFormField : true,
28123 getAutoCreate : function()
28127 cls : 'row roo-date-split-field-group',
28132 cls : 'form-hidden-field roo-date-split-field-group-value',
28138 if(this.fieldLabel){
28141 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28145 html : this.fieldLabel
28151 Roo.each(['day', 'month', 'year'], function(t){
28154 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28161 inputEl: function ()
28163 return this.el.select('.roo-date-split-field-group-value', true).first();
28166 onRender : function(ct, position)
28170 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28172 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28174 this.dayField = new Roo.bootstrap.ComboBox({
28175 allowBlank : this.dayAllowBlank,
28176 alwaysQuery : true,
28177 displayField : 'value',
28180 forceSelection : true,
28182 placeholder : this.dayPlaceholder,
28183 selectOnFocus : true,
28184 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28185 triggerAction : 'all',
28187 valueField : 'value',
28188 store : new Roo.data.SimpleStore({
28189 data : (function() {
28191 _this.fireEvent('days', _this, days);
28194 fields : [ 'value' ]
28197 select : function (_self, record, index)
28199 _this.setValue(_this.getValue());
28204 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28206 this.monthField = new Roo.bootstrap.MonthField({
28207 after : '<i class=\"fa fa-calendar\"></i>',
28208 allowBlank : this.monthAllowBlank,
28209 placeholder : this.monthPlaceholder,
28212 render : function (_self)
28214 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28215 e.preventDefault();
28219 select : function (_self, oldvalue, newvalue)
28221 _this.setValue(_this.getValue());
28226 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28228 this.yearField = new Roo.bootstrap.ComboBox({
28229 allowBlank : this.yearAllowBlank,
28230 alwaysQuery : true,
28231 displayField : 'value',
28234 forceSelection : true,
28236 placeholder : this.yearPlaceholder,
28237 selectOnFocus : true,
28238 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28239 triggerAction : 'all',
28241 valueField : 'value',
28242 store : new Roo.data.SimpleStore({
28243 data : (function() {
28245 _this.fireEvent('years', _this, years);
28248 fields : [ 'value' ]
28251 select : function (_self, record, index)
28253 _this.setValue(_this.getValue());
28258 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28261 setValue : function(v, format)
28263 this.inputEl.dom.value = v;
28265 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28267 var d = Date.parseDate(v, f);
28274 this.setDay(d.format(this.dayFormat));
28275 this.setMonth(d.format(this.monthFormat));
28276 this.setYear(d.format(this.yearFormat));
28283 setDay : function(v)
28285 this.dayField.setValue(v);
28286 this.inputEl.dom.value = this.getValue();
28291 setMonth : function(v)
28293 this.monthField.setValue(v, true);
28294 this.inputEl.dom.value = this.getValue();
28299 setYear : function(v)
28301 this.yearField.setValue(v);
28302 this.inputEl.dom.value = this.getValue();
28307 getDay : function()
28309 return this.dayField.getValue();
28312 getMonth : function()
28314 return this.monthField.getValue();
28317 getYear : function()
28319 return this.yearField.getValue();
28322 getValue : function()
28324 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
28326 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
28336 this.inputEl.dom.value = '';
28341 validate : function()
28343 var d = this.dayField.validate();
28344 var m = this.monthField.validate();
28345 var y = this.yearField.validate();
28350 (!this.dayAllowBlank && !d) ||
28351 (!this.monthAllowBlank && !m) ||
28352 (!this.yearAllowBlank && !y)
28357 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
28366 this.markInvalid();
28371 markValid : function()
28374 var label = this.el.select('label', true).first();
28375 var icon = this.el.select('i.fa-star', true).first();
28381 this.fireEvent('valid', this);
28385 * Mark this field as invalid
28386 * @param {String} msg The validation message
28388 markInvalid : function(msg)
28391 var label = this.el.select('label', true).first();
28392 var icon = this.el.select('i.fa-star', true).first();
28394 if(label && !icon){
28395 this.el.select('.roo-date-split-field-label', true).createChild({
28397 cls : 'text-danger fa fa-lg fa-star',
28398 tooltip : 'This field is required',
28399 style : 'margin-right:5px;'
28403 this.fireEvent('invalid', this, msg);
28406 clearInvalid : function()
28408 var label = this.el.select('label', true).first();
28409 var icon = this.el.select('i.fa-star', true).first();
28415 this.fireEvent('valid', this);
28418 getName: function()
28428 * http://masonry.desandro.com
28430 * The idea is to render all the bricks based on vertical width...
28432 * The original code extends 'outlayer' - we might need to use that....
28438 * @class Roo.bootstrap.LayoutMasonry
28439 * @extends Roo.bootstrap.Component
28440 * Bootstrap Layout Masonry class
28443 * Create a new Element
28444 * @param {Object} config The config object
28447 Roo.bootstrap.LayoutMasonry = function(config){
28448 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
28454 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
28457 * @cfg {Boolean} isLayoutInstant = no animation?
28459 isLayoutInstant : false, // needed?
28462 * @cfg {Number} boxWidth width of the columns
28467 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
28472 * @cfg {Number} padWidth padding below box..
28477 * @cfg {Number} gutter gutter width..
28482 * @cfg {Number} maxCols maximum number of columns
28488 * @cfg {Boolean} isAutoInitial defalut true
28490 isAutoInitial : true,
28495 * @cfg {Boolean} isHorizontal defalut false
28497 isHorizontal : false,
28499 currentSize : null,
28505 bricks: null, //CompositeElement
28509 _isLayoutInited : false,
28511 // isAlternative : false, // only use for vertical layout...
28514 * @cfg {Number} alternativePadWidth padding below box..
28516 alternativePadWidth : 50,
28518 getAutoCreate : function(){
28522 cls: 'blog-masonary-wrapper ' + this.cls,
28524 cls : 'mas-boxes masonary'
28531 getChildContainer: function( )
28533 if (this.boxesEl) {
28534 return this.boxesEl;
28537 this.boxesEl = this.el.select('.mas-boxes').first();
28539 return this.boxesEl;
28543 initEvents : function()
28547 if(this.isAutoInitial){
28548 Roo.log('hook children rendered');
28549 this.on('childrenrendered', function() {
28550 Roo.log('children rendered');
28556 initial : function()
28558 this.currentSize = this.el.getBox(true);
28560 Roo.EventManager.onWindowResize(this.resize, this);
28562 if(!this.isAutoInitial){
28570 //this.layout.defer(500,this);
28574 resize : function()
28578 var cs = this.el.getBox(true);
28580 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
28581 Roo.log("no change in with or X");
28585 this.currentSize = cs;
28591 layout : function()
28593 this._resetLayout();
28595 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
28597 this.layoutItems( isInstant );
28599 this._isLayoutInited = true;
28603 _resetLayout : function()
28605 if(this.isHorizontal){
28606 this.horizontalMeasureColumns();
28610 this.verticalMeasureColumns();
28614 verticalMeasureColumns : function()
28616 this.getContainerWidth();
28618 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28619 // this.colWidth = Math.floor(this.containerWidth * 0.8);
28623 var boxWidth = this.boxWidth + this.padWidth;
28625 if(this.containerWidth < this.boxWidth){
28626 boxWidth = this.containerWidth
28629 var containerWidth = this.containerWidth;
28631 var cols = Math.floor(containerWidth / boxWidth);
28633 this.cols = Math.max( cols, 1 );
28635 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
28637 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
28639 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
28641 this.colWidth = boxWidth + avail - this.padWidth;
28643 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
28644 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
28647 horizontalMeasureColumns : function()
28649 this.getContainerWidth();
28651 var boxWidth = this.boxWidth;
28653 if(this.containerWidth < boxWidth){
28654 boxWidth = this.containerWidth;
28657 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
28659 this.el.setHeight(boxWidth);
28663 getContainerWidth : function()
28665 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
28668 layoutItems : function( isInstant )
28670 var items = Roo.apply([], this.bricks);
28672 if(this.isHorizontal){
28673 this._horizontalLayoutItems( items , isInstant );
28677 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28678 // this._verticalAlternativeLayoutItems( items , isInstant );
28682 this._verticalLayoutItems( items , isInstant );
28686 _verticalLayoutItems : function ( items , isInstant)
28688 if ( !items || !items.length ) {
28693 ['xs', 'xs', 'xs', 'tall'],
28694 ['xs', 'xs', 'tall'],
28695 ['xs', 'xs', 'sm'],
28696 ['xs', 'xs', 'xs'],
28702 ['sm', 'xs', 'xs'],
28706 ['tall', 'xs', 'xs', 'xs'],
28707 ['tall', 'xs', 'xs'],
28719 Roo.each(items, function(item, k){
28721 switch (item.size) {
28722 // these layouts take up a full box,
28733 boxes.push([item]);
28756 var filterPattern = function(box, length)
28764 var pattern = box.slice(0, length);
28768 Roo.each(pattern, function(i){
28769 format.push(i.size);
28772 Roo.each(standard, function(s){
28774 if(String(s) != String(format)){
28783 if(!match && length == 1){
28788 filterPattern(box, length - 1);
28792 queue.push(pattern);
28794 box = box.slice(length, box.length);
28796 filterPattern(box, 4);
28802 Roo.each(boxes, function(box, k){
28808 if(box.length == 1){
28813 filterPattern(box, 4);
28817 this._processVerticalLayoutQueue( queue, isInstant );
28821 // _verticalAlternativeLayoutItems : function( items , isInstant )
28823 // if ( !items || !items.length ) {
28827 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
28831 _horizontalLayoutItems : function ( items , isInstant)
28833 if ( !items || !items.length || items.length < 3) {
28839 var eItems = items.slice(0, 3);
28841 items = items.slice(3, items.length);
28844 ['xs', 'xs', 'xs', 'wide'],
28845 ['xs', 'xs', 'wide'],
28846 ['xs', 'xs', 'sm'],
28847 ['xs', 'xs', 'xs'],
28853 ['sm', 'xs', 'xs'],
28857 ['wide', 'xs', 'xs', 'xs'],
28858 ['wide', 'xs', 'xs'],
28871 Roo.each(items, function(item, k){
28873 switch (item.size) {
28884 boxes.push([item]);
28908 var filterPattern = function(box, length)
28916 var pattern = box.slice(0, length);
28920 Roo.each(pattern, function(i){
28921 format.push(i.size);
28924 Roo.each(standard, function(s){
28926 if(String(s) != String(format)){
28935 if(!match && length == 1){
28940 filterPattern(box, length - 1);
28944 queue.push(pattern);
28946 box = box.slice(length, box.length);
28948 filterPattern(box, 4);
28954 Roo.each(boxes, function(box, k){
28960 if(box.length == 1){
28965 filterPattern(box, 4);
28972 var pos = this.el.getBox(true);
28976 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
28978 var hit_end = false;
28980 Roo.each(queue, function(box){
28984 Roo.each(box, function(b){
28986 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28996 Roo.each(box, function(b){
28998 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29001 mx = Math.max(mx, b.x);
29005 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29009 Roo.each(box, function(b){
29011 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29025 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29028 /** Sets position of item in DOM
29029 * @param {Element} item
29030 * @param {Number} x - horizontal position
29031 * @param {Number} y - vertical position
29032 * @param {Boolean} isInstant - disables transitions
29034 _processVerticalLayoutQueue : function( queue, isInstant )
29036 var pos = this.el.getBox(true);
29041 for (var i = 0; i < this.cols; i++){
29045 Roo.each(queue, function(box, k){
29047 var col = k % this.cols;
29049 Roo.each(box, function(b,kk){
29051 b.el.position('absolute');
29053 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29054 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29056 if(b.size == 'md-left' || b.size == 'md-right'){
29057 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29058 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29061 b.el.setWidth(width);
29062 b.el.setHeight(height);
29066 for (var i = 0; i < this.cols; i++){
29068 if(maxY[i] < maxY[col]){
29073 col = Math.min(col, i);
29077 x = pos.x + col * (this.colWidth + this.padWidth);
29081 var positions = [];
29083 switch (box.length){
29085 positions = this.getVerticalOneBoxColPositions(x, y, box);
29088 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29091 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29094 positions = this.getVerticalFourBoxColPositions(x, y, box);
29100 Roo.each(box, function(b,kk){
29102 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29104 var sz = b.el.getSize();
29106 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29114 for (var i = 0; i < this.cols; i++){
29115 mY = Math.max(mY, maxY[i]);
29118 this.el.setHeight(mY - pos.y);
29122 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29124 // var pos = this.el.getBox(true);
29127 // var maxX = pos.right;
29129 // var maxHeight = 0;
29131 // Roo.each(items, function(item, k){
29135 // item.el.position('absolute');
29137 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29139 // item.el.setWidth(width);
29141 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29143 // item.el.setHeight(height);
29146 // item.el.setXY([x, y], isInstant ? false : true);
29148 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29151 // y = y + height + this.alternativePadWidth;
29153 // maxHeight = maxHeight + height + this.alternativePadWidth;
29157 // this.el.setHeight(maxHeight);
29161 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29163 var pos = this.el.getBox(true);
29168 var maxX = pos.right;
29170 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29172 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29174 Roo.each(queue, function(box, k){
29176 Roo.each(box, function(b, kk){
29178 b.el.position('absolute');
29180 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29181 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29183 if(b.size == 'md-left' || b.size == 'md-right'){
29184 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29185 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29188 b.el.setWidth(width);
29189 b.el.setHeight(height);
29197 var positions = [];
29199 switch (box.length){
29201 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29204 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29207 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29210 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29216 Roo.each(box, function(b,kk){
29218 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29220 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29228 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29230 Roo.each(eItems, function(b,k){
29232 b.size = (k == 0) ? 'sm' : 'xs';
29233 b.x = (k == 0) ? 2 : 1;
29234 b.y = (k == 0) ? 2 : 1;
29236 b.el.position('absolute');
29238 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29240 b.el.setWidth(width);
29242 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29244 b.el.setHeight(height);
29248 var positions = [];
29251 x : maxX - this.unitWidth * 2 - this.gutter,
29256 x : maxX - this.unitWidth,
29257 y : minY + (this.unitWidth + this.gutter) * 2
29261 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29265 Roo.each(eItems, function(b,k){
29267 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29273 getVerticalOneBoxColPositions : function(x, y, box)
29277 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29279 if(box[0].size == 'md-left'){
29283 if(box[0].size == 'md-right'){
29288 x : x + (this.unitWidth + this.gutter) * rand,
29295 getVerticalTwoBoxColPositions : function(x, y, box)
29299 if(box[0].size == 'xs'){
29303 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
29307 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
29321 x : x + (this.unitWidth + this.gutter) * 2,
29322 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
29329 getVerticalThreeBoxColPositions : function(x, y, box)
29333 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29341 x : x + (this.unitWidth + this.gutter) * 1,
29346 x : x + (this.unitWidth + this.gutter) * 2,
29354 if(box[0].size == 'xs' && box[1].size == 'xs'){
29363 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
29367 x : x + (this.unitWidth + this.gutter) * 1,
29381 x : x + (this.unitWidth + this.gutter) * 2,
29386 x : x + (this.unitWidth + this.gutter) * 2,
29387 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
29394 getVerticalFourBoxColPositions : function(x, y, box)
29398 if(box[0].size == 'xs'){
29407 y : y + (this.unitHeight + this.gutter) * 1
29412 y : y + (this.unitHeight + this.gutter) * 2
29416 x : x + (this.unitWidth + this.gutter) * 1,
29430 x : x + (this.unitWidth + this.gutter) * 2,
29435 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
29436 y : y + (this.unitHeight + this.gutter) * 1
29440 x : x + (this.unitWidth + this.gutter) * 2,
29441 y : y + (this.unitWidth + this.gutter) * 2
29448 getHorizontalOneBoxColPositions : function(maxX, minY, box)
29452 if(box[0].size == 'md-left'){
29454 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29461 if(box[0].size == 'md-right'){
29463 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29464 y : minY + (this.unitWidth + this.gutter) * 1
29470 var rand = Math.floor(Math.random() * (4 - box[0].y));
29473 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29474 y : minY + (this.unitWidth + this.gutter) * rand
29481 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
29485 if(box[0].size == 'xs'){
29488 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29493 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29494 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
29502 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29507 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29508 y : minY + (this.unitWidth + this.gutter) * 2
29515 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
29519 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29522 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29527 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29528 y : minY + (this.unitWidth + this.gutter) * 1
29532 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29533 y : minY + (this.unitWidth + this.gutter) * 2
29540 if(box[0].size == 'xs' && box[1].size == 'xs'){
29543 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29548 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29553 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29554 y : minY + (this.unitWidth + this.gutter) * 1
29562 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29567 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29568 y : minY + (this.unitWidth + this.gutter) * 2
29572 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29573 y : minY + (this.unitWidth + this.gutter) * 2
29580 getHorizontalFourBoxColPositions : function(maxX, minY, box)
29584 if(box[0].size == 'xs'){
29587 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29592 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29597 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),
29602 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
29603 y : minY + (this.unitWidth + this.gutter) * 1
29611 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29616 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29617 y : minY + (this.unitWidth + this.gutter) * 2
29621 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29622 y : minY + (this.unitWidth + this.gutter) * 2
29626 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),
29627 y : minY + (this.unitWidth + this.gutter) * 2
29641 * http://masonry.desandro.com
29643 * The idea is to render all the bricks based on vertical width...
29645 * The original code extends 'outlayer' - we might need to use that....
29651 * @class Roo.bootstrap.LayoutMasonryAuto
29652 * @extends Roo.bootstrap.Component
29653 * Bootstrap Layout Masonry class
29656 * Create a new Element
29657 * @param {Object} config The config object
29660 Roo.bootstrap.LayoutMasonryAuto = function(config){
29661 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
29664 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
29667 * @cfg {Boolean} isFitWidth - resize the width..
29669 isFitWidth : false, // options..
29671 * @cfg {Boolean} isOriginLeft = left align?
29673 isOriginLeft : true,
29675 * @cfg {Boolean} isOriginTop = top align?
29677 isOriginTop : false,
29679 * @cfg {Boolean} isLayoutInstant = no animation?
29681 isLayoutInstant : false, // needed?
29683 * @cfg {Boolean} isResizingContainer = not sure if this is used..
29685 isResizingContainer : true,
29687 * @cfg {Number} columnWidth width of the columns
29693 * @cfg {Number} maxCols maximum number of columns
29698 * @cfg {Number} padHeight padding below box..
29704 * @cfg {Boolean} isAutoInitial defalut true
29707 isAutoInitial : true,
29713 initialColumnWidth : 0,
29714 currentSize : null,
29716 colYs : null, // array.
29723 bricks: null, //CompositeElement
29724 cols : 0, // array?
29725 // element : null, // wrapped now this.el
29726 _isLayoutInited : null,
29729 getAutoCreate : function(){
29733 cls: 'blog-masonary-wrapper ' + this.cls,
29735 cls : 'mas-boxes masonary'
29742 getChildContainer: function( )
29744 if (this.boxesEl) {
29745 return this.boxesEl;
29748 this.boxesEl = this.el.select('.mas-boxes').first();
29750 return this.boxesEl;
29754 initEvents : function()
29758 if(this.isAutoInitial){
29759 Roo.log('hook children rendered');
29760 this.on('childrenrendered', function() {
29761 Roo.log('children rendered');
29768 initial : function()
29770 this.reloadItems();
29772 this.currentSize = this.el.getBox(true);
29774 /// was window resize... - let's see if this works..
29775 Roo.EventManager.onWindowResize(this.resize, this);
29777 if(!this.isAutoInitial){
29782 this.layout.defer(500,this);
29785 reloadItems: function()
29787 this.bricks = this.el.select('.masonry-brick', true);
29789 this.bricks.each(function(b) {
29790 //Roo.log(b.getSize());
29791 if (!b.attr('originalwidth')) {
29792 b.attr('originalwidth', b.getSize().width);
29797 Roo.log(this.bricks.elements.length);
29800 resize : function()
29803 var cs = this.el.getBox(true);
29805 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29806 Roo.log("no change in with or X");
29809 this.currentSize = cs;
29813 layout : function()
29816 this._resetLayout();
29817 //this._manageStamps();
29819 // don't animate first layout
29820 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29821 this.layoutItems( isInstant );
29823 // flag for initalized
29824 this._isLayoutInited = true;
29827 layoutItems : function( isInstant )
29829 //var items = this._getItemsForLayout( this.items );
29830 // original code supports filtering layout items.. we just ignore it..
29832 this._layoutItems( this.bricks , isInstant );
29834 this._postLayout();
29836 _layoutItems : function ( items , isInstant)
29838 //this.fireEvent( 'layout', this, items );
29841 if ( !items || !items.elements.length ) {
29842 // no items, emit event with empty array
29847 items.each(function(item) {
29848 Roo.log("layout item");
29850 // get x/y object from method
29851 var position = this._getItemLayoutPosition( item );
29853 position.item = item;
29854 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
29855 queue.push( position );
29858 this._processLayoutQueue( queue );
29860 /** Sets position of item in DOM
29861 * @param {Element} item
29862 * @param {Number} x - horizontal position
29863 * @param {Number} y - vertical position
29864 * @param {Boolean} isInstant - disables transitions
29866 _processLayoutQueue : function( queue )
29868 for ( var i=0, len = queue.length; i < len; i++ ) {
29869 var obj = queue[i];
29870 obj.item.position('absolute');
29871 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
29877 * Any logic you want to do after each layout,
29878 * i.e. size the container
29880 _postLayout : function()
29882 this.resizeContainer();
29885 resizeContainer : function()
29887 if ( !this.isResizingContainer ) {
29890 var size = this._getContainerSize();
29892 this.el.setSize(size.width,size.height);
29893 this.boxesEl.setSize(size.width,size.height);
29899 _resetLayout : function()
29901 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
29902 this.colWidth = this.el.getWidth();
29903 //this.gutter = this.el.getWidth();
29905 this.measureColumns();
29911 this.colYs.push( 0 );
29917 measureColumns : function()
29919 this.getContainerWidth();
29920 // if columnWidth is 0, default to outerWidth of first item
29921 if ( !this.columnWidth ) {
29922 var firstItem = this.bricks.first();
29923 Roo.log(firstItem);
29924 this.columnWidth = this.containerWidth;
29925 if (firstItem && firstItem.attr('originalwidth') ) {
29926 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
29928 // columnWidth fall back to item of first element
29929 Roo.log("set column width?");
29930 this.initialColumnWidth = this.columnWidth ;
29932 // if first elem has no width, default to size of container
29937 if (this.initialColumnWidth) {
29938 this.columnWidth = this.initialColumnWidth;
29943 // column width is fixed at the top - however if container width get's smaller we should
29946 // this bit calcs how man columns..
29948 var columnWidth = this.columnWidth += this.gutter;
29950 // calculate columns
29951 var containerWidth = this.containerWidth + this.gutter;
29953 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
29954 // fix rounding errors, typically with gutters
29955 var excess = columnWidth - containerWidth % columnWidth;
29958 // if overshoot is less than a pixel, round up, otherwise floor it
29959 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
29960 cols = Math[ mathMethod ]( cols );
29961 this.cols = Math.max( cols, 1 );
29962 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29964 // padding positioning..
29965 var totalColWidth = this.cols * this.columnWidth;
29966 var padavail = this.containerWidth - totalColWidth;
29967 // so for 2 columns - we need 3 'pads'
29969 var padNeeded = (1+this.cols) * this.padWidth;
29971 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
29973 this.columnWidth += padExtra
29974 //this.padWidth = Math.floor(padavail / ( this.cols));
29976 // adjust colum width so that padding is fixed??
29978 // we have 3 columns ... total = width * 3
29979 // we have X left over... that should be used by
29981 //if (this.expandC) {
29989 getContainerWidth : function()
29991 /* // container is parent if fit width
29992 var container = this.isFitWidth ? this.element.parentNode : this.element;
29993 // check that this.size and size are there
29994 // IE8 triggers resize on body size change, so they might not be
29996 var size = getSize( container ); //FIXME
29997 this.containerWidth = size && size.innerWidth; //FIXME
30000 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30004 _getItemLayoutPosition : function( item ) // what is item?
30006 // we resize the item to our columnWidth..
30008 item.setWidth(this.columnWidth);
30009 item.autoBoxAdjust = false;
30011 var sz = item.getSize();
30013 // how many columns does this brick span
30014 var remainder = this.containerWidth % this.columnWidth;
30016 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30017 // round if off by 1 pixel, otherwise use ceil
30018 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30019 colSpan = Math.min( colSpan, this.cols );
30021 // normally this should be '1' as we dont' currently allow multi width columns..
30023 var colGroup = this._getColGroup( colSpan );
30024 // get the minimum Y value from the columns
30025 var minimumY = Math.min.apply( Math, colGroup );
30026 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30028 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30030 // position the brick
30032 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30033 y: this.currentSize.y + minimumY + this.padHeight
30037 // apply setHeight to necessary columns
30038 var setHeight = minimumY + sz.height + this.padHeight;
30039 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30041 var setSpan = this.cols + 1 - colGroup.length;
30042 for ( var i = 0; i < setSpan; i++ ) {
30043 this.colYs[ shortColIndex + i ] = setHeight ;
30050 * @param {Number} colSpan - number of columns the element spans
30051 * @returns {Array} colGroup
30053 _getColGroup : function( colSpan )
30055 if ( colSpan < 2 ) {
30056 // if brick spans only one column, use all the column Ys
30061 // how many different places could this brick fit horizontally
30062 var groupCount = this.cols + 1 - colSpan;
30063 // for each group potential horizontal position
30064 for ( var i = 0; i < groupCount; i++ ) {
30065 // make an array of colY values for that one group
30066 var groupColYs = this.colYs.slice( i, i + colSpan );
30067 // and get the max value of the array
30068 colGroup[i] = Math.max.apply( Math, groupColYs );
30073 _manageStamp : function( stamp )
30075 var stampSize = stamp.getSize();
30076 var offset = stamp.getBox();
30077 // get the columns that this stamp affects
30078 var firstX = this.isOriginLeft ? offset.x : offset.right;
30079 var lastX = firstX + stampSize.width;
30080 var firstCol = Math.floor( firstX / this.columnWidth );
30081 firstCol = Math.max( 0, firstCol );
30083 var lastCol = Math.floor( lastX / this.columnWidth );
30084 // lastCol should not go over if multiple of columnWidth #425
30085 lastCol -= lastX % this.columnWidth ? 0 : 1;
30086 lastCol = Math.min( this.cols - 1, lastCol );
30088 // set colYs to bottom of the stamp
30089 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30092 for ( var i = firstCol; i <= lastCol; i++ ) {
30093 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30098 _getContainerSize : function()
30100 this.maxY = Math.max.apply( Math, this.colYs );
30105 if ( this.isFitWidth ) {
30106 size.width = this._getContainerFitWidth();
30112 _getContainerFitWidth : function()
30114 var unusedCols = 0;
30115 // count unused columns
30118 if ( this.colYs[i] !== 0 ) {
30123 // fit container to columns that have been used
30124 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30127 needsResizeLayout : function()
30129 var previousWidth = this.containerWidth;
30130 this.getContainerWidth();
30131 return previousWidth !== this.containerWidth;
30146 * @class Roo.bootstrap.MasonryBrick
30147 * @extends Roo.bootstrap.Component
30148 * Bootstrap MasonryBrick class
30151 * Create a new MasonryBrick
30152 * @param {Object} config The config object
30155 Roo.bootstrap.MasonryBrick = function(config){
30156 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30162 * When a MasonryBrick is clcik
30163 * @param {Roo.bootstrap.MasonryBrick} this
30164 * @param {Roo.EventObject} e
30170 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30173 * @cfg {String} title
30177 * @cfg {String} html
30181 * @cfg {String} bgimage
30185 * @cfg {String} cls
30189 * @cfg {String} href
30193 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30198 * @cfg {String} (center|bottom) placetitle
30202 getAutoCreate : function()
30204 var cls = 'masonry-brick';
30206 if(this.href.length){
30207 cls += ' masonry-brick-link';
30210 if(this.bgimage.length){
30211 cls += ' masonry-brick-image';
30215 cls += ' masonry-' + this.size + '-brick';
30218 if(this.placetitle.length){
30220 switch (this.placetitle) {
30222 cls += ' masonry-center-title';
30225 cls += ' masonry-bottom-title';
30232 if(!this.html.length && !this.bgimage.length){
30233 cls += ' masonry-center-title';
30236 if(!this.html.length && this.bgimage.length){
30237 cls += ' masonry-bottom-title';
30242 cls += ' ' + this.cls;
30246 tag: (this.href.length) ? 'a' : 'div',
30251 cls: 'masonry-brick-paragraph',
30257 if(this.href.length){
30258 cfg.href = this.href;
30261 var cn = cfg.cn[0].cn;
30263 if(this.title.length){
30266 cls: 'masonry-brick-title',
30271 if(this.html.length){
30274 cls: 'masonry-brick-text',
30279 if(this.bgimage.length){
30282 cls: 'masonry-brick-image-view',
30291 initEvents: function()
30293 switch (this.size) {
30295 // this.intSize = 1;
30300 // this.intSize = 2;
30307 // this.intSize = 3;
30312 // this.intSize = 3;
30317 // this.intSize = 3;
30322 // this.intSize = 3;
30334 this.el.on('touchstart', this.onTouchStart, this);
30335 this.el.on('touchmove', this.onTouchMove, this);
30336 this.el.on('touchend', this.onTouchEnd, this);
30337 this.el.on('contextmenu', this.onContextMenu, this);
30339 this.el.on('mouseenter' ,this.enter, this);
30340 this.el.on('mouseleave', this.leave, this);
30343 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
30344 this.parent().bricks.push(this);
30349 onClick: function(e, el)
30357 var time = this.endTimer - this.startTimer;
30365 e.preventDefault();
30368 enter: function(e, el)
30370 e.preventDefault();
30372 if(this.bgimage.length && this.html.length){
30373 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30377 leave: function(e, el)
30379 e.preventDefault();
30381 if(this.bgimage.length && this.html.length){
30382 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30386 onTouchStart: function(e, el)
30388 // e.preventDefault();
30390 if(!this.bgimage.length || !this.html.length){
30394 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30396 this.timer = new Date().getTime();
30398 this.touchmoved = false;
30401 onTouchMove: function(e, el)
30403 this.touchmoved = true;
30405 onContextMenu : function(e,el)
30407 e.preventDefault();
30408 e.stopPropagation();
30413 onTouchEnd: function(e, el)
30415 // e.preventDefault();
30417 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
30424 if(!this.bgimage.length || !this.html.length){
30426 if(this.href.length){
30427 window.location.href = this.href;
30433 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30435 window.location.href = this.href;
30450 * @class Roo.bootstrap.Brick
30451 * @extends Roo.bootstrap.Component
30452 * Bootstrap Brick class
30455 * Create a new Brick
30456 * @param {Object} config The config object
30459 Roo.bootstrap.Brick = function(config){
30460 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
30466 * When a Brick is click
30467 * @param {Roo.bootstrap.Brick} this
30468 * @param {Roo.EventObject} e
30474 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
30477 * @cfg {String} title
30481 * @cfg {String} html
30485 * @cfg {String} bgimage
30489 * @cfg {String} cls
30493 * @cfg {String} href
30497 * @cfg {String} video
30501 * @cfg {Boolean} square
30505 getAutoCreate : function()
30507 var cls = 'roo-brick';
30509 if(this.href.length){
30510 cls += ' roo-brick-link';
30513 if(this.bgimage.length){
30514 cls += ' roo-brick-image';
30517 if(!this.html.length && !this.bgimage.length){
30518 cls += ' roo-brick-center-title';
30521 if(!this.html.length && this.bgimage.length){
30522 cls += ' roo-brick-bottom-title';
30526 cls += ' ' + this.cls;
30530 tag: (this.href.length) ? 'a' : 'div',
30535 cls: 'roo-brick-paragraph',
30541 if(this.href.length){
30542 cfg.href = this.href;
30545 var cn = cfg.cn[0].cn;
30547 if(this.title.length){
30550 cls: 'roo-brick-title',
30555 if(this.html.length){
30558 cls: 'roo-brick-text',
30563 if(this.bgimage.length){
30566 cls: 'roo-brick-image-view',
30574 initEvents: function()
30576 if(this.title.length || this.html.length){
30577 this.el.on('mouseenter' ,this.enter, this);
30578 this.el.on('mouseleave', this.leave, this);
30582 Roo.EventManager.onWindowResize(this.resize, this);
30587 resize : function()
30589 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
30591 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
30592 // paragraph.setHeight(paragraph.getWidth());
30594 if(this.bgimage.length){
30595 var image = this.el.select('.roo-brick-image-view', true).first();
30596 image.setWidth(paragraph.getWidth());
30597 image.setHeight(paragraph.getWidth());
30602 enter: function(e, el)
30604 e.preventDefault();
30606 if(this.bgimage.length){
30607 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
30608 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
30612 leave: function(e, el)
30614 e.preventDefault();
30616 if(this.bgimage.length){
30617 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
30618 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
30628 * Ext JS Library 1.1.1
30629 * Copyright(c) 2006-2007, Ext JS, LLC.
30631 * Originally Released Under LGPL - original licence link has changed is not relivant.
30634 * <script type="text/javascript">
30639 * @class Roo.bootstrap.SplitBar
30640 * @extends Roo.util.Observable
30641 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
30645 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
30646 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
30647 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
30648 split.minSize = 100;
30649 split.maxSize = 600;
30650 split.animate = true;
30651 split.on('moved', splitterMoved);
30654 * Create a new SplitBar
30655 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
30656 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
30657 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30658 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
30659 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
30660 position of the SplitBar).
30662 Roo.bootstrap.SplitBar = function(cfg){
30667 // dragElement : elm
30668 // resizingElement: el,
30670 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
30671 // placement : Roo.bootstrap.SplitBar.LEFT ,
30672 // existingProxy ???
30675 this.el = Roo.get(cfg.dragElement, true);
30676 this.el.dom.unselectable = "on";
30678 this.resizingEl = Roo.get(cfg.resizingElement, true);
30682 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30683 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
30686 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
30689 * The minimum size of the resizing element. (Defaults to 0)
30695 * The maximum size of the resizing element. (Defaults to 2000)
30698 this.maxSize = 2000;
30701 * Whether to animate the transition to the new size
30704 this.animate = false;
30707 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
30710 this.useShim = false;
30715 if(!cfg.existingProxy){
30717 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
30719 this.proxy = Roo.get(cfg.existingProxy).dom;
30722 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
30725 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
30728 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
30731 this.dragSpecs = {};
30734 * @private The adapter to use to positon and resize elements
30736 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30737 this.adapter.init(this);
30739 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30741 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
30742 this.el.addClass("roo-splitbar-h");
30745 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
30746 this.el.addClass("roo-splitbar-v");
30752 * Fires when the splitter is moved (alias for {@link #event-moved})
30753 * @param {Roo.bootstrap.SplitBar} this
30754 * @param {Number} newSize the new width or height
30759 * Fires when the splitter is moved
30760 * @param {Roo.bootstrap.SplitBar} this
30761 * @param {Number} newSize the new width or height
30765 * @event beforeresize
30766 * Fires before the splitter is dragged
30767 * @param {Roo.bootstrap.SplitBar} this
30769 "beforeresize" : true,
30771 "beforeapply" : true
30774 Roo.util.Observable.call(this);
30777 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
30778 onStartProxyDrag : function(x, y){
30779 this.fireEvent("beforeresize", this);
30781 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
30783 o.enableDisplayMode("block");
30784 // all splitbars share the same overlay
30785 Roo.bootstrap.SplitBar.prototype.overlay = o;
30787 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30788 this.overlay.show();
30789 Roo.get(this.proxy).setDisplayed("block");
30790 var size = this.adapter.getElementSize(this);
30791 this.activeMinSize = this.getMinimumSize();;
30792 this.activeMaxSize = this.getMaximumSize();;
30793 var c1 = size - this.activeMinSize;
30794 var c2 = Math.max(this.activeMaxSize - size, 0);
30795 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30796 this.dd.resetConstraints();
30797 this.dd.setXConstraint(
30798 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
30799 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
30801 this.dd.setYConstraint(0, 0);
30803 this.dd.resetConstraints();
30804 this.dd.setXConstraint(0, 0);
30805 this.dd.setYConstraint(
30806 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
30807 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
30810 this.dragSpecs.startSize = size;
30811 this.dragSpecs.startPoint = [x, y];
30812 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
30816 * @private Called after the drag operation by the DDProxy
30818 onEndProxyDrag : function(e){
30819 Roo.get(this.proxy).setDisplayed(false);
30820 var endPoint = Roo.lib.Event.getXY(e);
30822 this.overlay.hide();
30825 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30826 newSize = this.dragSpecs.startSize +
30827 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
30828 endPoint[0] - this.dragSpecs.startPoint[0] :
30829 this.dragSpecs.startPoint[0] - endPoint[0]
30832 newSize = this.dragSpecs.startSize +
30833 (this.placement == Roo.bootstrap.SplitBar.TOP ?
30834 endPoint[1] - this.dragSpecs.startPoint[1] :
30835 this.dragSpecs.startPoint[1] - endPoint[1]
30838 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
30839 if(newSize != this.dragSpecs.startSize){
30840 if(this.fireEvent('beforeapply', this, newSize) !== false){
30841 this.adapter.setElementSize(this, newSize);
30842 this.fireEvent("moved", this, newSize);
30843 this.fireEvent("resize", this, newSize);
30849 * Get the adapter this SplitBar uses
30850 * @return The adapter object
30852 getAdapter : function(){
30853 return this.adapter;
30857 * Set the adapter this SplitBar uses
30858 * @param {Object} adapter A SplitBar adapter object
30860 setAdapter : function(adapter){
30861 this.adapter = adapter;
30862 this.adapter.init(this);
30866 * Gets the minimum size for the resizing element
30867 * @return {Number} The minimum size
30869 getMinimumSize : function(){
30870 return this.minSize;
30874 * Sets the minimum size for the resizing element
30875 * @param {Number} minSize The minimum size
30877 setMinimumSize : function(minSize){
30878 this.minSize = minSize;
30882 * Gets the maximum size for the resizing element
30883 * @return {Number} The maximum size
30885 getMaximumSize : function(){
30886 return this.maxSize;
30890 * Sets the maximum size for the resizing element
30891 * @param {Number} maxSize The maximum size
30893 setMaximumSize : function(maxSize){
30894 this.maxSize = maxSize;
30898 * Sets the initialize size for the resizing element
30899 * @param {Number} size The initial size
30901 setCurrentSize : function(size){
30902 var oldAnimate = this.animate;
30903 this.animate = false;
30904 this.adapter.setElementSize(this, size);
30905 this.animate = oldAnimate;
30909 * Destroy this splitbar.
30910 * @param {Boolean} removeEl True to remove the element
30912 destroy : function(removeEl){
30914 this.shim.remove();
30917 this.proxy.parentNode.removeChild(this.proxy);
30925 * @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.
30927 Roo.bootstrap.SplitBar.createProxy = function(dir){
30928 var proxy = new Roo.Element(document.createElement("div"));
30929 proxy.unselectable();
30930 var cls = 'roo-splitbar-proxy';
30931 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
30932 document.body.appendChild(proxy.dom);
30937 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
30938 * Default Adapter. It assumes the splitter and resizing element are not positioned
30939 * elements and only gets/sets the width of the element. Generally used for table based layouts.
30941 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
30944 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
30945 // do nothing for now
30946 init : function(s){
30950 * Called before drag operations to get the current size of the resizing element.
30951 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30953 getElementSize : function(s){
30954 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30955 return s.resizingEl.getWidth();
30957 return s.resizingEl.getHeight();
30962 * Called after drag operations to set the size of the resizing element.
30963 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30964 * @param {Number} newSize The new size to set
30965 * @param {Function} onComplete A function to be invoked when resizing is complete
30967 setElementSize : function(s, newSize, onComplete){
30968 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30970 s.resizingEl.setWidth(newSize);
30972 onComplete(s, newSize);
30975 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
30980 s.resizingEl.setHeight(newSize);
30982 onComplete(s, newSize);
30985 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
30992 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
30993 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
30994 * Adapter that moves the splitter element to align with the resized sizing element.
30995 * Used with an absolute positioned SplitBar.
30996 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
30997 * document.body, make sure you assign an id to the body element.
30999 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
31000 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31001 this.container = Roo.get(container);
31004 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
31005 init : function(s){
31006 this.basic.init(s);
31009 getElementSize : function(s){
31010 return this.basic.getElementSize(s);
31013 setElementSize : function(s, newSize, onComplete){
31014 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
31017 moveSplitter : function(s){
31018 var yes = Roo.bootstrap.SplitBar;
31019 switch(s.placement){
31021 s.el.setX(s.resizingEl.getRight());
31024 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
31027 s.el.setY(s.resizingEl.getBottom());
31030 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
31037 * Orientation constant - Create a vertical SplitBar
31041 Roo.bootstrap.SplitBar.VERTICAL = 1;
31044 * Orientation constant - Create a horizontal SplitBar
31048 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
31051 * Placement constant - The resizing element is to the left of the splitter element
31055 Roo.bootstrap.SplitBar.LEFT = 1;
31058 * Placement constant - The resizing element is to the right of the splitter element
31062 Roo.bootstrap.SplitBar.RIGHT = 2;
31065 * Placement constant - The resizing element is positioned above the splitter element
31069 Roo.bootstrap.SplitBar.TOP = 3;
31072 * Placement constant - The resizing element is positioned under splitter element
31076 Roo.bootstrap.SplitBar.BOTTOM = 4;
31077 Roo.namespace("Roo.bootstrap.layout");/*
31079 * Ext JS Library 1.1.1
31080 * Copyright(c) 2006-2007, Ext JS, LLC.
31082 * Originally Released Under LGPL - original licence link has changed is not relivant.
31085 * <script type="text/javascript">
31089 * @class Roo.bootstrap.layout.Manager
31090 * @extends Roo.bootstrap.Component
31091 * Base class for layout managers.
31093 Roo.bootstrap.layout.Manager = function(config)
31095 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
31096 this.el = Roo.get(config.el);
31097 // ie scrollbar fix
31098 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31099 document.body.scroll = "no";
31100 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31101 this.el.position('relative');
31104 this.id = this.el.id;
31105 this.el.addClass("roo-layout-container");
31106 /** false to disable window resize monitoring @type Boolean */
31107 this.monitorWindowResize = true;
31112 * Fires when a layout is performed.
31113 * @param {Roo.LayoutManager} this
31117 * @event regionresized
31118 * Fires when the user resizes a region.
31119 * @param {Roo.LayoutRegion} region The resized region
31120 * @param {Number} newSize The new size (width for east/west, height for north/south)
31122 "regionresized" : true,
31124 * @event regioncollapsed
31125 * Fires when a region is collapsed.
31126 * @param {Roo.LayoutRegion} region The collapsed region
31128 "regioncollapsed" : true,
31130 * @event regionexpanded
31131 * Fires when a region is expanded.
31132 * @param {Roo.LayoutRegion} region The expanded region
31134 "regionexpanded" : true
31136 this.updating = false;
31137 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31140 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31145 monitorWindowResize : true,
31151 * Returns true if this layout is currently being updated
31152 * @return {Boolean}
31154 isUpdating : function(){
31155 return this.updating;
31159 * Suspend the LayoutManager from doing auto-layouts while
31160 * making multiple add or remove calls
31162 beginUpdate : function(){
31163 this.updating = true;
31167 * Restore auto-layouts and optionally disable the manager from performing a layout
31168 * @param {Boolean} noLayout true to disable a layout update
31170 endUpdate : function(noLayout){
31171 this.updating = false;
31177 layout: function(){
31181 onRegionResized : function(region, newSize){
31182 this.fireEvent("regionresized", region, newSize);
31186 onRegionCollapsed : function(region){
31187 this.fireEvent("regioncollapsed", region);
31190 onRegionExpanded : function(region){
31191 this.fireEvent("regionexpanded", region);
31195 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31196 * performs box-model adjustments.
31197 * @return {Object} The size as an object {width: (the width), height: (the height)}
31199 getViewSize : function()
31202 if(this.el.dom != document.body){
31203 size = this.el.getSize();
31205 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31207 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31208 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31213 * Returns the Element this layout is bound to.
31214 * @return {Roo.Element}
31216 getEl : function(){
31221 * Returns the specified region.
31222 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31223 * @return {Roo.LayoutRegion}
31225 getRegion : function(target){
31226 return this.regions[target.toLowerCase()];
31229 onWindowResize : function(){
31230 if(this.monitorWindowResize){
31236 * Ext JS Library 1.1.1
31237 * Copyright(c) 2006-2007, Ext JS, LLC.
31239 * Originally Released Under LGPL - original licence link has changed is not relivant.
31242 * <script type="text/javascript">
31245 * @class Roo.bootstrap.layout.Border
31246 * @extends Roo.bootstrap.layout.Manager
31247 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
31248 * please see: examples/bootstrap/nested.html<br><br>
31250 <b>The container the layout is rendered into can be either the body element or any other element.
31251 If it is not the body element, the container needs to either be an absolute positioned element,
31252 or you will need to add "position:relative" to the css of the container. You will also need to specify
31253 the container size if it is not the body element.</b>
31256 * Create a new Border
31257 * @param {Object} config Configuration options
31259 Roo.bootstrap.layout.Border = function(config){
31260 config = config || {};
31261 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
31265 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
31266 if(config[region]){
31267 config[region].region = region;
31268 this.addRegion(config[region]);
31274 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
31276 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
31278 * Creates and adds a new region if it doesn't already exist.
31279 * @param {String} target The target region key (north, south, east, west or center).
31280 * @param {Object} config The regions config object
31281 * @return {BorderLayoutRegion} The new region
31283 addRegion : function(config)
31285 if(!this.regions[config.region]){
31286 var r = this.factory(config);
31287 this.bindRegion(r);
31289 return this.regions[config.region];
31293 bindRegion : function(r){
31294 this.regions[r.config.region] = r;
31296 r.on("visibilitychange", this.layout, this);
31297 r.on("paneladded", this.layout, this);
31298 r.on("panelremoved", this.layout, this);
31299 r.on("invalidated", this.layout, this);
31300 r.on("resized", this.onRegionResized, this);
31301 r.on("collapsed", this.onRegionCollapsed, this);
31302 r.on("expanded", this.onRegionExpanded, this);
31306 * Performs a layout update.
31308 layout : function()
31310 if(this.updating) {
31313 var size = this.getViewSize();
31314 var w = size.width;
31315 var h = size.height;
31320 //var x = 0, y = 0;
31322 var rs = this.regions;
31323 var north = rs["north"];
31324 var south = rs["south"];
31325 var west = rs["west"];
31326 var east = rs["east"];
31327 var center = rs["center"];
31328 //if(this.hideOnLayout){ // not supported anymore
31329 //c.el.setStyle("display", "none");
31331 if(north && north.isVisible()){
31332 var b = north.getBox();
31333 var m = north.getMargins();
31334 b.width = w - (m.left+m.right);
31337 centerY = b.height + b.y + m.bottom;
31338 centerH -= centerY;
31339 north.updateBox(this.safeBox(b));
31341 if(south && south.isVisible()){
31342 var b = south.getBox();
31343 var m = south.getMargins();
31344 b.width = w - (m.left+m.right);
31346 var totalHeight = (b.height + m.top + m.bottom);
31347 b.y = h - totalHeight + m.top;
31348 centerH -= totalHeight;
31349 south.updateBox(this.safeBox(b));
31351 if(west && west.isVisible()){
31352 var b = west.getBox();
31353 var m = west.getMargins();
31354 b.height = centerH - (m.top+m.bottom);
31356 b.y = centerY + m.top;
31357 var totalWidth = (b.width + m.left + m.right);
31358 centerX += totalWidth;
31359 centerW -= totalWidth;
31360 west.updateBox(this.safeBox(b));
31362 if(east && east.isVisible()){
31363 var b = east.getBox();
31364 var m = east.getMargins();
31365 b.height = centerH - (m.top+m.bottom);
31366 var totalWidth = (b.width + m.left + m.right);
31367 b.x = w - totalWidth + m.left;
31368 b.y = centerY + m.top;
31369 centerW -= totalWidth;
31370 east.updateBox(this.safeBox(b));
31373 var m = center.getMargins();
31375 x: centerX + m.left,
31376 y: centerY + m.top,
31377 width: centerW - (m.left+m.right),
31378 height: centerH - (m.top+m.bottom)
31380 //if(this.hideOnLayout){
31381 //center.el.setStyle("display", "block");
31383 center.updateBox(this.safeBox(centerBox));
31386 this.fireEvent("layout", this);
31390 safeBox : function(box){
31391 box.width = Math.max(0, box.width);
31392 box.height = Math.max(0, box.height);
31397 * Adds a ContentPanel (or subclass) to this layout.
31398 * @param {String} target The target region key (north, south, east, west or center).
31399 * @param {Roo.ContentPanel} panel The panel to add
31400 * @return {Roo.ContentPanel} The added panel
31402 add : function(target, panel){
31404 target = target.toLowerCase();
31405 return this.regions[target].add(panel);
31409 * Remove a ContentPanel (or subclass) to this layout.
31410 * @param {String} target The target region key (north, south, east, west or center).
31411 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
31412 * @return {Roo.ContentPanel} The removed panel
31414 remove : function(target, panel){
31415 target = target.toLowerCase();
31416 return this.regions[target].remove(panel);
31420 * Searches all regions for a panel with the specified id
31421 * @param {String} panelId
31422 * @return {Roo.ContentPanel} The panel or null if it wasn't found
31424 findPanel : function(panelId){
31425 var rs = this.regions;
31426 for(var target in rs){
31427 if(typeof rs[target] != "function"){
31428 var p = rs[target].getPanel(panelId);
31438 * Searches all regions for a panel with the specified id and activates (shows) it.
31439 * @param {String/ContentPanel} panelId The panels id or the panel itself
31440 * @return {Roo.ContentPanel} The shown panel or null
31442 showPanel : function(panelId) {
31443 var rs = this.regions;
31444 for(var target in rs){
31445 var r = rs[target];
31446 if(typeof r != "function"){
31447 if(r.hasPanel(panelId)){
31448 return r.showPanel(panelId);
31456 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
31457 * @param {Roo.state.Provider} provider (optional) An alternate state provider
31460 restoreState : function(provider){
31462 provider = Roo.state.Manager;
31464 var sm = new Roo.LayoutStateManager();
31465 sm.init(this, provider);
31471 * Adds a xtype elements to the layout.
31475 xtype : 'ContentPanel',
31482 xtype : 'NestedLayoutPanel',
31488 items : [ ... list of content panels or nested layout panels.. ]
31492 * @param {Object} cfg Xtype definition of item to add.
31494 addxtype : function(cfg)
31496 // basically accepts a pannel...
31497 // can accept a layout region..!?!?
31498 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
31501 // theory? children can only be panels??
31503 //if (!cfg.xtype.match(/Panel$/)) {
31508 if (typeof(cfg.region) == 'undefined') {
31509 Roo.log("Failed to add Panel, region was not set");
31513 var region = cfg.region;
31519 xitems = cfg.items;
31526 case 'Content': // ContentPanel (el, cfg)
31527 case 'Scroll': // ContentPanel (el, cfg)
31529 cfg.autoCreate = true;
31530 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31532 // var el = this.el.createChild();
31533 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
31536 this.add(region, ret);
31540 case 'TreePanel': // our new panel!
31541 cfg.el = this.el.createChild();
31542 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31543 this.add(region, ret);
31548 // create a new Layout (which is a Border Layout...
31550 var clayout = cfg.layout;
31551 clayout.el = this.el.createChild();
31552 clayout.items = clayout.items || [];
31556 // replace this exitems with the clayout ones..
31557 xitems = clayout.items;
31559 // force background off if it's in center...
31560 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
31561 cfg.background = false;
31563 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
31566 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31567 //console.log('adding nested layout panel ' + cfg.toSource());
31568 this.add(region, ret);
31569 nb = {}; /// find first...
31574 // needs grid and region
31576 //var el = this.getRegion(region).el.createChild();
31577 var el = this.el.createChild();
31578 // create the grid first...
31579 cfg.grid.container = el;
31580 cfg.grid.scrollBody = true;
31581 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
31584 if (region == 'center' && this.active ) {
31585 cfg.background = false;
31588 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31590 this.add(region, ret);
31592 if (cfg.background) {
31593 // render grid on panel activation (if panel background)
31594 ret.on('activate', function(gp) {
31595 if (!gp.grid.rendered) {
31596 gp.grid.render(gp.grid.getGridEl());
31600 cfg.grid.render(cfg.grid.getGridEl());
31605 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
31606 // it was the old xcomponent building that caused this before.
31607 // espeically if border is the top element in the tree.
31617 if (typeof(Roo[cfg.xtype]) != 'undefined') {
31619 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31620 this.add(region, ret);
31624 throw "Can not add '" + cfg.xtype + "' to Border";
31630 this.beginUpdate();
31634 Roo.each(xitems, function(i) {
31635 region = nb && i.region ? i.region : false;
31637 var add = ret.addxtype(i);
31640 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
31641 if (!i.background) {
31642 abn[region] = nb[region] ;
31649 // make the last non-background panel active..
31650 //if (nb) { Roo.log(abn); }
31653 for(var r in abn) {
31654 region = this.getRegion(r);
31656 // tried using nb[r], but it does not work..
31658 region.showPanel(abn[r]);
31669 factory : function(cfg)
31672 var validRegions = Roo.bootstrap.layout.Border.regions;
31674 var target = cfg.region;
31677 var r = Roo.bootstrap.layout;
31681 return new r.North(cfg);
31683 return new r.South(cfg);
31685 return new r.East(cfg);
31687 return new r.West(cfg);
31689 return new r.Center(cfg);
31691 throw 'Layout region "'+target+'" not supported.';
31698 * Ext JS Library 1.1.1
31699 * Copyright(c) 2006-2007, Ext JS, LLC.
31701 * Originally Released Under LGPL - original licence link has changed is not relivant.
31704 * <script type="text/javascript">
31708 * @class Roo.bootstrap.layout.Basic
31709 * @extends Roo.util.Observable
31710 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
31711 * and does not have a titlebar, tabs or any other features. All it does is size and position
31712 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
31713 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31714 * @cfg {string} region the region that it inhabits..
31715 * @cfg {bool} skipConfig skip config?
31719 Roo.bootstrap.layout.Basic = function(config){
31721 this.mgr = config.mgr;
31723 this.position = config.region;
31725 var skipConfig = config.skipConfig;
31729 * @scope Roo.BasicLayoutRegion
31733 * @event beforeremove
31734 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
31735 * @param {Roo.LayoutRegion} this
31736 * @param {Roo.ContentPanel} panel The panel
31737 * @param {Object} e The cancel event object
31739 "beforeremove" : true,
31741 * @event invalidated
31742 * Fires when the layout for this region is changed.
31743 * @param {Roo.LayoutRegion} this
31745 "invalidated" : true,
31747 * @event visibilitychange
31748 * Fires when this region is shown or hidden
31749 * @param {Roo.LayoutRegion} this
31750 * @param {Boolean} visibility true or false
31752 "visibilitychange" : true,
31754 * @event paneladded
31755 * Fires when a panel is added.
31756 * @param {Roo.LayoutRegion} this
31757 * @param {Roo.ContentPanel} panel The panel
31759 "paneladded" : true,
31761 * @event panelremoved
31762 * Fires when a panel is removed.
31763 * @param {Roo.LayoutRegion} this
31764 * @param {Roo.ContentPanel} panel The panel
31766 "panelremoved" : true,
31768 * @event beforecollapse
31769 * Fires when this region before collapse.
31770 * @param {Roo.LayoutRegion} this
31772 "beforecollapse" : true,
31775 * Fires when this region is collapsed.
31776 * @param {Roo.LayoutRegion} this
31778 "collapsed" : true,
31781 * Fires when this region is expanded.
31782 * @param {Roo.LayoutRegion} this
31787 * Fires when this region is slid into view.
31788 * @param {Roo.LayoutRegion} this
31790 "slideshow" : true,
31793 * Fires when this region slides out of view.
31794 * @param {Roo.LayoutRegion} this
31796 "slidehide" : true,
31798 * @event panelactivated
31799 * Fires when a panel is activated.
31800 * @param {Roo.LayoutRegion} this
31801 * @param {Roo.ContentPanel} panel The activated panel
31803 "panelactivated" : true,
31806 * Fires when the user resizes this region.
31807 * @param {Roo.LayoutRegion} this
31808 * @param {Number} newSize The new size (width for east/west, height for north/south)
31812 /** A collection of panels in this region. @type Roo.util.MixedCollection */
31813 this.panels = new Roo.util.MixedCollection();
31814 this.panels.getKey = this.getPanelId.createDelegate(this);
31816 this.activePanel = null;
31817 // ensure listeners are added...
31819 if (config.listeners || config.events) {
31820 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
31821 listeners : config.listeners || {},
31822 events : config.events || {}
31826 if(skipConfig !== true){
31827 this.applyConfig(config);
31831 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
31833 getPanelId : function(p){
31837 applyConfig : function(config){
31838 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
31839 this.config = config;
31844 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
31845 * the width, for horizontal (north, south) the height.
31846 * @param {Number} newSize The new width or height
31848 resizeTo : function(newSize){
31849 var el = this.el ? this.el :
31850 (this.activePanel ? this.activePanel.getEl() : null);
31852 switch(this.position){
31855 el.setWidth(newSize);
31856 this.fireEvent("resized", this, newSize);
31860 el.setHeight(newSize);
31861 this.fireEvent("resized", this, newSize);
31867 getBox : function(){
31868 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
31871 getMargins : function(){
31872 return this.margins;
31875 updateBox : function(box){
31877 var el = this.activePanel.getEl();
31878 el.dom.style.left = box.x + "px";
31879 el.dom.style.top = box.y + "px";
31880 this.activePanel.setSize(box.width, box.height);
31884 * Returns the container element for this region.
31885 * @return {Roo.Element}
31887 getEl : function(){
31888 return this.activePanel;
31892 * Returns true if this region is currently visible.
31893 * @return {Boolean}
31895 isVisible : function(){
31896 return this.activePanel ? true : false;
31899 setActivePanel : function(panel){
31900 panel = this.getPanel(panel);
31901 if(this.activePanel && this.activePanel != panel){
31902 this.activePanel.setActiveState(false);
31903 this.activePanel.getEl().setLeftTop(-10000,-10000);
31905 this.activePanel = panel;
31906 panel.setActiveState(true);
31908 panel.setSize(this.box.width, this.box.height);
31910 this.fireEvent("panelactivated", this, panel);
31911 this.fireEvent("invalidated");
31915 * Show the specified panel.
31916 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
31917 * @return {Roo.ContentPanel} The shown panel or null
31919 showPanel : function(panel){
31920 panel = this.getPanel(panel);
31922 this.setActivePanel(panel);
31928 * Get the active panel for this region.
31929 * @return {Roo.ContentPanel} The active panel or null
31931 getActivePanel : function(){
31932 return this.activePanel;
31936 * Add the passed ContentPanel(s)
31937 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
31938 * @return {Roo.ContentPanel} The panel added (if only one was added)
31940 add : function(panel){
31941 if(arguments.length > 1){
31942 for(var i = 0, len = arguments.length; i < len; i++) {
31943 this.add(arguments[i]);
31947 if(this.hasPanel(panel)){
31948 this.showPanel(panel);
31951 var el = panel.getEl();
31952 if(el.dom.parentNode != this.mgr.el.dom){
31953 this.mgr.el.dom.appendChild(el.dom);
31955 if(panel.setRegion){
31956 panel.setRegion(this);
31958 this.panels.add(panel);
31959 el.setStyle("position", "absolute");
31960 if(!panel.background){
31961 this.setActivePanel(panel);
31962 if(this.config.initialSize && this.panels.getCount()==1){
31963 this.resizeTo(this.config.initialSize);
31966 this.fireEvent("paneladded", this, panel);
31971 * Returns true if the panel is in this region.
31972 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31973 * @return {Boolean}
31975 hasPanel : function(panel){
31976 if(typeof panel == "object"){ // must be panel obj
31977 panel = panel.getId();
31979 return this.getPanel(panel) ? true : false;
31983 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
31984 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31985 * @param {Boolean} preservePanel Overrides the config preservePanel option
31986 * @return {Roo.ContentPanel} The panel that was removed
31988 remove : function(panel, preservePanel){
31989 panel = this.getPanel(panel);
31994 this.fireEvent("beforeremove", this, panel, e);
31995 if(e.cancel === true){
31998 var panelId = panel.getId();
31999 this.panels.removeKey(panelId);
32004 * Returns the panel specified or null if it's not in this region.
32005 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32006 * @return {Roo.ContentPanel}
32008 getPanel : function(id){
32009 if(typeof id == "object"){ // must be panel obj
32012 return this.panels.get(id);
32016 * Returns this regions position (north/south/east/west/center).
32019 getPosition: function(){
32020 return this.position;
32024 * Ext JS Library 1.1.1
32025 * Copyright(c) 2006-2007, Ext JS, LLC.
32027 * Originally Released Under LGPL - original licence link has changed is not relivant.
32030 * <script type="text/javascript">
32034 * @class Roo.bootstrap.layout.Region
32035 * @extends Roo.bootstrap.layout.Basic
32036 * This class represents a region in a layout manager.
32038 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
32039 * @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})
32040 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
32041 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
32042 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
32043 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
32044 * @cfg {String} title The title for the region (overrides panel titles)
32045 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
32046 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
32047 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
32048 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
32049 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
32050 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
32051 * the space available, similar to FireFox 1.5 tabs (defaults to false)
32052 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
32053 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
32054 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
32056 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
32057 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
32058 * @cfg {Boolean} disableTabTips True to disable tab tooltips
32059 * @cfg {Number} width For East/West panels
32060 * @cfg {Number} height For North/South panels
32061 * @cfg {Boolean} split To show the splitter
32062 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
32064 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32065 * @cfg {string} region the region that it inhabits..
32068 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
32069 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
32071 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
32072 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
32073 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
32075 Roo.bootstrap.layout.Region = function(config)
32078 var mgr = config.mgr;
32079 var pos = config.region;
32080 config.skipConfig = true;
32081 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
32082 var dh = Roo.DomHelper;
32083 /** This region's container element
32084 * @type Roo.Element */
32085 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "roo-layout-region roo-layout-panel roo-layout-panel-" + this.position}, true);
32086 /** This region's title element
32087 * @type Roo.Element */
32089 this.titleEl = dh.append(this.el.dom,
32092 unselectable: "on",
32093 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32095 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32096 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32099 this.titleEl.enableDisplayMode();
32100 /** This region's title text element
32101 * @type HTMLElement */
32102 this.titleTextEl = this.titleEl.dom.firstChild;
32103 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32105 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32106 this.closeBtn.enableDisplayMode();
32107 this.closeBtn.on("click", this.closeClicked, this);
32108 this.closeBtn.hide();
32110 this.createBody(config);
32111 this.visible = true;
32112 this.collapsed = false;
32114 if(config.hideWhenEmpty){
32116 this.on("paneladded", this.validateVisibility, this);
32117 this.on("panelremoved", this.validateVisibility, this);
32119 this.applyConfig(config);
32122 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32126 createBody : function(){
32127 /** This region's body element
32128 * @type Roo.Element */
32129 this.bodyEl = this.el.createChild({
32131 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32135 applyConfig : function(c)
32138 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32139 var dh = Roo.DomHelper;
32140 if(c.titlebar !== false){
32141 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32142 this.collapseBtn.on("click", this.collapse, this);
32143 this.collapseBtn.enableDisplayMode();
32145 if(c.showPin === true || this.showPin){
32146 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32147 this.stickBtn.enableDisplayMode();
32148 this.stickBtn.on("click", this.expand, this);
32149 this.stickBtn.hide();
32154 /** This region's collapsed element
32155 * @type Roo.Element */
32158 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32159 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32162 if(c.floatable !== false){
32163 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32164 this.collapsedEl.on("click", this.collapseClick, this);
32167 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32168 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32169 id: "message", unselectable: "on", style:{"float":"left"}});
32170 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32172 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32173 this.expandBtn.on("click", this.expand, this);
32177 if(this.collapseBtn){
32178 this.collapseBtn.setVisible(c.collapsible == true);
32181 this.cmargins = c.cmargins || this.cmargins ||
32182 (this.position == "west" || this.position == "east" ?
32183 {top: 0, left: 2, right:2, bottom: 0} :
32184 {top: 2, left: 0, right:0, bottom: 2});
32186 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32189 this.bottomTabs = c.tabPosition != "top";
32191 this.autoScroll = c.autoScroll || false;
32194 if(this.autoScroll){
32195 this.bodyEl.setStyle("overflow", "auto");
32197 this.bodyEl.setStyle("overflow", c.overflow || 'hidden');
32199 //if(c.titlebar !== false){
32200 if((!c.titlebar && !c.title) || c.titlebar === false){
32201 this.titleEl.hide();
32203 this.titleEl.show();
32205 this.titleTextEl.innerHTML = c.title;
32209 this.duration = c.duration || .30;
32210 this.slideDuration = c.slideDuration || .45;
32213 this.collapse(true);
32220 * Returns true if this region is currently visible.
32221 * @return {Boolean}
32223 isVisible : function(){
32224 return this.visible;
32228 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
32229 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
32231 //setCollapsedTitle : function(title){
32232 // title = title || " ";
32233 // if(this.collapsedTitleTextEl){
32234 // this.collapsedTitleTextEl.innerHTML = title;
32238 getBox : function(){
32240 // if(!this.collapsed){
32241 b = this.el.getBox(false, true);
32243 // b = this.collapsedEl.getBox(false, true);
32248 getMargins : function(){
32249 return this.margins;
32250 //return this.collapsed ? this.cmargins : this.margins;
32253 highlight : function(){
32254 this.el.addClass("x-layout-panel-dragover");
32257 unhighlight : function(){
32258 this.el.removeClass("x-layout-panel-dragover");
32261 updateBox : function(box)
32264 if(!this.collapsed){
32265 this.el.dom.style.left = box.x + "px";
32266 this.el.dom.style.top = box.y + "px";
32267 this.updateBody(box.width, box.height);
32269 this.collapsedEl.dom.style.left = box.x + "px";
32270 this.collapsedEl.dom.style.top = box.y + "px";
32271 this.collapsedEl.setSize(box.width, box.height);
32274 this.tabs.autoSizeTabs();
32278 updateBody : function(w, h)
32281 this.el.setWidth(w);
32282 w -= this.el.getBorderWidth("rl");
32283 if(this.config.adjustments){
32284 w += this.config.adjustments[0];
32288 this.el.setHeight(h);
32289 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
32290 h -= this.el.getBorderWidth("tb");
32291 if(this.config.adjustments){
32292 h += this.config.adjustments[1];
32294 this.bodyEl.setHeight(h);
32296 h = this.tabs.syncHeight(h);
32299 if(this.panelSize){
32300 w = w !== null ? w : this.panelSize.width;
32301 h = h !== null ? h : this.panelSize.height;
32303 if(this.activePanel){
32304 var el = this.activePanel.getEl();
32305 w = w !== null ? w : el.getWidth();
32306 h = h !== null ? h : el.getHeight();
32307 this.panelSize = {width: w, height: h};
32308 this.activePanel.setSize(w, h);
32310 if(Roo.isIE && this.tabs){
32311 this.tabs.el.repaint();
32316 * Returns the container element for this region.
32317 * @return {Roo.Element}
32319 getEl : function(){
32324 * Hides this region.
32327 //if(!this.collapsed){
32328 this.el.dom.style.left = "-2000px";
32331 // this.collapsedEl.dom.style.left = "-2000px";
32332 // this.collapsedEl.hide();
32334 this.visible = false;
32335 this.fireEvent("visibilitychange", this, false);
32339 * Shows this region if it was previously hidden.
32342 //if(!this.collapsed){
32345 // this.collapsedEl.show();
32347 this.visible = true;
32348 this.fireEvent("visibilitychange", this, true);
32351 closeClicked : function(){
32352 if(this.activePanel){
32353 this.remove(this.activePanel);
32357 collapseClick : function(e){
32359 e.stopPropagation();
32362 e.stopPropagation();
32368 * Collapses this region.
32369 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
32372 collapse : function(skipAnim, skipCheck = false){
32373 if(this.collapsed) {
32377 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
32379 this.collapsed = true;
32381 this.split.el.hide();
32383 if(this.config.animate && skipAnim !== true){
32384 this.fireEvent("invalidated", this);
32385 this.animateCollapse();
32387 this.el.setLocation(-20000,-20000);
32389 this.collapsedEl.show();
32390 this.fireEvent("collapsed", this);
32391 this.fireEvent("invalidated", this);
32397 animateCollapse : function(){
32402 * Expands this region if it was previously collapsed.
32403 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
32404 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
32407 expand : function(e, skipAnim){
32409 e.stopPropagation();
32411 if(!this.collapsed || this.el.hasActiveFx()) {
32415 this.afterSlideIn();
32418 this.collapsed = false;
32419 if(this.config.animate && skipAnim !== true){
32420 this.animateExpand();
32424 this.split.el.show();
32426 this.collapsedEl.setLocation(-2000,-2000);
32427 this.collapsedEl.hide();
32428 this.fireEvent("invalidated", this);
32429 this.fireEvent("expanded", this);
32433 animateExpand : function(){
32437 initTabs : function()
32439 this.bodyEl.setStyle("overflow", "hidden");
32440 var ts = new Roo.bootstrap.panel.Tabs({
32441 el: this.bodyEl.dom,
32442 tabPosition: this.bottomTabs ? 'bottom' : 'top',
32443 disableTooltips: this.config.disableTabTips,
32444 toolbar : this.config.toolbar
32447 if(this.config.hideTabs){
32448 ts.stripWrap.setDisplayed(false);
32451 ts.resizeTabs = this.config.resizeTabs === true;
32452 ts.minTabWidth = this.config.minTabWidth || 40;
32453 ts.maxTabWidth = this.config.maxTabWidth || 250;
32454 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
32455 ts.monitorResize = false;
32456 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32457 ts.bodyEl.addClass('roo-layout-tabs-body');
32458 this.panels.each(this.initPanelAsTab, this);
32461 initPanelAsTab : function(panel){
32462 var ti = this.tabs.addTab(
32464 panel.getTitle(), null,
32465 this.config.closeOnTab && panel.isClosable()
32467 if(panel.tabTip !== undefined){
32468 ti.setTooltip(panel.tabTip);
32470 ti.on("activate", function(){
32471 this.setActivePanel(panel);
32474 if(this.config.closeOnTab){
32475 ti.on("beforeclose", function(t, e){
32477 this.remove(panel);
32483 updatePanelTitle : function(panel, title)
32485 if(this.activePanel == panel){
32486 this.updateTitle(title);
32489 var ti = this.tabs.getTab(panel.getEl().id);
32491 if(panel.tabTip !== undefined){
32492 ti.setTooltip(panel.tabTip);
32497 updateTitle : function(title){
32498 if(this.titleTextEl && !this.config.title){
32499 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
32503 setActivePanel : function(panel)
32505 panel = this.getPanel(panel);
32506 if(this.activePanel && this.activePanel != panel){
32507 this.activePanel.setActiveState(false);
32509 this.activePanel = panel;
32510 panel.setActiveState(true);
32511 if(this.panelSize){
32512 panel.setSize(this.panelSize.width, this.panelSize.height);
32515 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
32517 this.updateTitle(panel.getTitle());
32519 this.fireEvent("invalidated", this);
32521 this.fireEvent("panelactivated", this, panel);
32525 * Shows the specified panel.
32526 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
32527 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
32529 showPanel : function(panel)
32531 panel = this.getPanel(panel);
32534 var tab = this.tabs.getTab(panel.getEl().id);
32535 if(tab.isHidden()){
32536 this.tabs.unhideTab(tab.id);
32540 this.setActivePanel(panel);
32547 * Get the active panel for this region.
32548 * @return {Roo.ContentPanel} The active panel or null
32550 getActivePanel : function(){
32551 return this.activePanel;
32554 validateVisibility : function(){
32555 if(this.panels.getCount() < 1){
32556 this.updateTitle(" ");
32557 this.closeBtn.hide();
32560 if(!this.isVisible()){
32567 * Adds the passed ContentPanel(s) to this region.
32568 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32569 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
32571 add : function(panel){
32572 if(arguments.length > 1){
32573 for(var i = 0, len = arguments.length; i < len; i++) {
32574 this.add(arguments[i]);
32578 if(this.hasPanel(panel)){
32579 this.showPanel(panel);
32582 panel.setRegion(this);
32583 this.panels.add(panel);
32584 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
32585 this.bodyEl.dom.appendChild(panel.getEl().dom);
32586 if(panel.background !== true){
32587 this.setActivePanel(panel);
32589 this.fireEvent("paneladded", this, panel);
32595 this.initPanelAsTab(panel);
32599 if(panel.background !== true){
32600 this.tabs.activate(panel.getEl().id);
32602 this.fireEvent("paneladded", this, panel);
32607 * Hides the tab for the specified panel.
32608 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32610 hidePanel : function(panel){
32611 if(this.tabs && (panel = this.getPanel(panel))){
32612 this.tabs.hideTab(panel.getEl().id);
32617 * Unhides the tab for a previously hidden panel.
32618 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32620 unhidePanel : function(panel){
32621 if(this.tabs && (panel = this.getPanel(panel))){
32622 this.tabs.unhideTab(panel.getEl().id);
32626 clearPanels : function(){
32627 while(this.panels.getCount() > 0){
32628 this.remove(this.panels.first());
32633 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32634 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32635 * @param {Boolean} preservePanel Overrides the config preservePanel option
32636 * @return {Roo.ContentPanel} The panel that was removed
32638 remove : function(panel, preservePanel)
32640 panel = this.getPanel(panel);
32645 this.fireEvent("beforeremove", this, panel, e);
32646 if(e.cancel === true){
32649 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
32650 var panelId = panel.getId();
32651 this.panels.removeKey(panelId);
32653 document.body.appendChild(panel.getEl().dom);
32656 this.tabs.removeTab(panel.getEl().id);
32657 }else if (!preservePanel){
32658 this.bodyEl.dom.removeChild(panel.getEl().dom);
32660 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
32661 var p = this.panels.first();
32662 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
32663 tempEl.appendChild(p.getEl().dom);
32664 this.bodyEl.update("");
32665 this.bodyEl.dom.appendChild(p.getEl().dom);
32667 this.updateTitle(p.getTitle());
32669 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32670 this.setActivePanel(p);
32672 panel.setRegion(null);
32673 if(this.activePanel == panel){
32674 this.activePanel = null;
32676 if(this.config.autoDestroy !== false && preservePanel !== true){
32677 try{panel.destroy();}catch(e){}
32679 this.fireEvent("panelremoved", this, panel);
32684 * Returns the TabPanel component used by this region
32685 * @return {Roo.TabPanel}
32687 getTabs : function(){
32691 createTool : function(parentEl, className){
32692 var btn = Roo.DomHelper.append(parentEl, {
32694 cls: "x-layout-tools-button",
32697 cls: "roo-layout-tools-button-inner " + className,
32701 btn.addClassOnOver("roo-layout-tools-button-over");
32706 * Ext JS Library 1.1.1
32707 * Copyright(c) 2006-2007, Ext JS, LLC.
32709 * Originally Released Under LGPL - original licence link has changed is not relivant.
32712 * <script type="text/javascript">
32718 * @class Roo.SplitLayoutRegion
32719 * @extends Roo.LayoutRegion
32720 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
32722 Roo.bootstrap.layout.Split = function(config){
32723 this.cursor = config.cursor;
32724 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
32727 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
32729 splitTip : "Drag to resize.",
32730 collapsibleSplitTip : "Drag to resize. Double click to hide.",
32731 useSplitTips : false,
32733 applyConfig : function(config){
32734 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
32740 var splitEl = Roo.DomHelper.append(this.mgr.el.dom, {
32742 id: this.el.id + "-split",
32743 cls: "roo-layout-split roo-layout-split-"+this.position,
32746 /** The SplitBar for this region
32747 * @type Roo.SplitBar */
32748 // does not exist yet...
32749 Roo.log([this.position, this.orientation]);
32751 this.split = new Roo.bootstrap.SplitBar({
32752 dragElement : splitEl,
32753 resizingElement: this.el,
32754 orientation : this.orientation
32757 this.split.on("moved", this.onSplitMove, this);
32758 this.split.useShim = config.useShim === true;
32759 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
32760 if(this.useSplitTips){
32761 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
32763 //if(config.collapsible){
32764 // this.split.el.on("dblclick", this.collapse, this);
32767 if(typeof config.minSize != "undefined"){
32768 this.split.minSize = config.minSize;
32770 if(typeof config.maxSize != "undefined"){
32771 this.split.maxSize = config.maxSize;
32773 if(config.hideWhenEmpty || config.hidden || config.collapsed){
32774 this.hideSplitter();
32779 getHMaxSize : function(){
32780 var cmax = this.config.maxSize || 10000;
32781 var center = this.mgr.getRegion("center");
32782 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
32785 getVMaxSize : function(){
32786 var cmax = this.config.maxSize || 10000;
32787 var center = this.mgr.getRegion("center");
32788 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
32791 onSplitMove : function(split, newSize){
32792 this.fireEvent("resized", this, newSize);
32796 * Returns the {@link Roo.SplitBar} for this region.
32797 * @return {Roo.SplitBar}
32799 getSplitBar : function(){
32804 this.hideSplitter();
32805 Roo.bootstrap.layout.Split.superclass.hide.call(this);
32808 hideSplitter : function(){
32810 this.split.el.setLocation(-2000,-2000);
32811 this.split.el.hide();
32817 this.split.el.show();
32819 Roo.bootstrap.layout.Split.superclass.show.call(this);
32822 beforeSlide: function(){
32823 if(Roo.isGecko){// firefox overflow auto bug workaround
32824 this.bodyEl.clip();
32826 this.tabs.bodyEl.clip();
32828 if(this.activePanel){
32829 this.activePanel.getEl().clip();
32831 if(this.activePanel.beforeSlide){
32832 this.activePanel.beforeSlide();
32838 afterSlide : function(){
32839 if(Roo.isGecko){// firefox overflow auto bug workaround
32840 this.bodyEl.unclip();
32842 this.tabs.bodyEl.unclip();
32844 if(this.activePanel){
32845 this.activePanel.getEl().unclip();
32846 if(this.activePanel.afterSlide){
32847 this.activePanel.afterSlide();
32853 initAutoHide : function(){
32854 if(this.autoHide !== false){
32855 if(!this.autoHideHd){
32856 var st = new Roo.util.DelayedTask(this.slideIn, this);
32857 this.autoHideHd = {
32858 "mouseout": function(e){
32859 if(!e.within(this.el, true)){
32863 "mouseover" : function(e){
32869 this.el.on(this.autoHideHd);
32873 clearAutoHide : function(){
32874 if(this.autoHide !== false){
32875 this.el.un("mouseout", this.autoHideHd.mouseout);
32876 this.el.un("mouseover", this.autoHideHd.mouseover);
32880 clearMonitor : function(){
32881 Roo.get(document).un("click", this.slideInIf, this);
32884 // these names are backwards but not changed for compat
32885 slideOut : function(){
32886 if(this.isSlid || this.el.hasActiveFx()){
32889 this.isSlid = true;
32890 if(this.collapseBtn){
32891 this.collapseBtn.hide();
32893 this.closeBtnState = this.closeBtn.getStyle('display');
32894 this.closeBtn.hide();
32896 this.stickBtn.show();
32899 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
32900 this.beforeSlide();
32901 this.el.setStyle("z-index", 10001);
32902 this.el.slideIn(this.getSlideAnchor(), {
32903 callback: function(){
32905 this.initAutoHide();
32906 Roo.get(document).on("click", this.slideInIf, this);
32907 this.fireEvent("slideshow", this);
32914 afterSlideIn : function(){
32915 this.clearAutoHide();
32916 this.isSlid = false;
32917 this.clearMonitor();
32918 this.el.setStyle("z-index", "");
32919 if(this.collapseBtn){
32920 this.collapseBtn.show();
32922 this.closeBtn.setStyle('display', this.closeBtnState);
32924 this.stickBtn.hide();
32926 this.fireEvent("slidehide", this);
32929 slideIn : function(cb){
32930 if(!this.isSlid || this.el.hasActiveFx()){
32934 this.isSlid = false;
32935 this.beforeSlide();
32936 this.el.slideOut(this.getSlideAnchor(), {
32937 callback: function(){
32938 this.el.setLeftTop(-10000, -10000);
32940 this.afterSlideIn();
32948 slideInIf : function(e){
32949 if(!e.within(this.el)){
32954 animateCollapse : function(){
32955 this.beforeSlide();
32956 this.el.setStyle("z-index", 20000);
32957 var anchor = this.getSlideAnchor();
32958 this.el.slideOut(anchor, {
32959 callback : function(){
32960 this.el.setStyle("z-index", "");
32961 this.collapsedEl.slideIn(anchor, {duration:.3});
32963 this.el.setLocation(-10000,-10000);
32965 this.fireEvent("collapsed", this);
32972 animateExpand : function(){
32973 this.beforeSlide();
32974 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
32975 this.el.setStyle("z-index", 20000);
32976 this.collapsedEl.hide({
32979 this.el.slideIn(this.getSlideAnchor(), {
32980 callback : function(){
32981 this.el.setStyle("z-index", "");
32984 this.split.el.show();
32986 this.fireEvent("invalidated", this);
32987 this.fireEvent("expanded", this);
33015 getAnchor : function(){
33016 return this.anchors[this.position];
33019 getCollapseAnchor : function(){
33020 return this.canchors[this.position];
33023 getSlideAnchor : function(){
33024 return this.sanchors[this.position];
33027 getAlignAdj : function(){
33028 var cm = this.cmargins;
33029 switch(this.position){
33045 getExpandAdj : function(){
33046 var c = this.collapsedEl, cm = this.cmargins;
33047 switch(this.position){
33049 return [-(cm.right+c.getWidth()+cm.left), 0];
33052 return [cm.right+c.getWidth()+cm.left, 0];
33055 return [0, -(cm.top+cm.bottom+c.getHeight())];
33058 return [0, cm.top+cm.bottom+c.getHeight()];
33064 * Ext JS Library 1.1.1
33065 * Copyright(c) 2006-2007, Ext JS, LLC.
33067 * Originally Released Under LGPL - original licence link has changed is not relivant.
33070 * <script type="text/javascript">
33073 * These classes are private internal classes
33075 Roo.bootstrap.layout.Center = function(config){
33076 config.region = "center";
33077 Roo.bootstrap.layout.Region.call(this, config);
33078 this.visible = true;
33079 this.minWidth = config.minWidth || 20;
33080 this.minHeight = config.minHeight || 20;
33083 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
33085 // center panel can't be hidden
33089 // center panel can't be hidden
33092 getMinWidth: function(){
33093 return this.minWidth;
33096 getMinHeight: function(){
33097 return this.minHeight;
33110 Roo.bootstrap.layout.North = function(config)
33112 config.region = 'north';
33113 config.cursor = 'n-resize';
33115 Roo.bootstrap.layout.Split.call(this, config);
33117 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33118 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33119 this.split.el.addClass("roo-layout-split-v");
33121 var size = config.initialSize || config.height;
33122 if(typeof size != "undefined"){
33123 this.el.setHeight(size);
33126 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
33128 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33129 getBox : function(){
33130 if(this.collapsed){
33131 return this.collapsedEl.getBox();
33133 var box = this.el.getBox();
33135 box.height += this.split.el.getHeight();
33140 updateBox : function(box){
33141 if(this.split && !this.collapsed){
33142 box.height -= this.split.el.getHeight();
33143 this.split.el.setLeft(box.x);
33144 this.split.el.setTop(box.y+box.height);
33145 this.split.el.setWidth(box.width);
33147 if(this.collapsed){
33148 this.updateBody(box.width, null);
33150 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33158 Roo.bootstrap.layout.South = function(config){
33159 config.region = 'south';
33160 config.cursor = 's-resize';
33161 Roo.bootstrap.layout.Split.call(this, config);
33163 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33164 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33165 this.split.el.addClass("roo-layout-split-v");
33167 var size = config.initialSize || config.height;
33168 if(typeof size != "undefined"){
33169 this.el.setHeight(size);
33173 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33174 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33175 getBox : function(){
33176 if(this.collapsed){
33177 return this.collapsedEl.getBox();
33179 var box = this.el.getBox();
33181 var sh = this.split.el.getHeight();
33188 updateBox : function(box){
33189 if(this.split && !this.collapsed){
33190 var sh = this.split.el.getHeight();
33193 this.split.el.setLeft(box.x);
33194 this.split.el.setTop(box.y-sh);
33195 this.split.el.setWidth(box.width);
33197 if(this.collapsed){
33198 this.updateBody(box.width, null);
33200 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33204 Roo.bootstrap.layout.East = function(config){
33205 config.region = "east";
33206 config.cursor = "e-resize";
33207 Roo.bootstrap.layout.Split.call(this, config);
33209 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
33210 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33211 this.split.el.addClass("roo-layout-split-h");
33213 var size = config.initialSize || config.width;
33214 if(typeof size != "undefined"){
33215 this.el.setWidth(size);
33218 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
33219 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33220 getBox : function(){
33221 if(this.collapsed){
33222 return this.collapsedEl.getBox();
33224 var box = this.el.getBox();
33226 var sw = this.split.el.getWidth();
33233 updateBox : function(box){
33234 if(this.split && !this.collapsed){
33235 var sw = this.split.el.getWidth();
33237 this.split.el.setLeft(box.x);
33238 this.split.el.setTop(box.y);
33239 this.split.el.setHeight(box.height);
33242 if(this.collapsed){
33243 this.updateBody(null, box.height);
33245 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33249 Roo.bootstrap.layout.West = function(config){
33250 config.region = "west";
33251 config.cursor = "w-resize";
33253 Roo.bootstrap.layout.Split.call(this, config);
33255 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
33256 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33257 this.split.el.addClass("roo-layout-split-h");
33259 var size = config.initialSize || config.width;
33260 if(typeof size != "undefined"){
33261 this.el.setWidth(size);
33264 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
33265 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33266 getBox : function(){
33267 if(this.collapsed){
33268 return this.collapsedEl.getBox();
33270 var box = this.el.getBox();
33272 box.width += this.split.el.getWidth();
33277 updateBox : function(box){
33278 if(this.split && !this.collapsed){
33279 var sw = this.split.el.getWidth();
33281 this.split.el.setLeft(box.x+box.width);
33282 this.split.el.setTop(box.y);
33283 this.split.el.setHeight(box.height);
33285 if(this.collapsed){
33286 this.updateBody(null, box.height);
33288 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33291 Roo.namespace("Roo.bootstrap.panel");/*
33293 * Ext JS Library 1.1.1
33294 * Copyright(c) 2006-2007, Ext JS, LLC.
33296 * Originally Released Under LGPL - original licence link has changed is not relivant.
33299 * <script type="text/javascript">
33302 * @class Roo.ContentPanel
33303 * @extends Roo.util.Observable
33304 * A basic ContentPanel element.
33305 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
33306 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
33307 * @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
33308 * @cfg {Boolean} closable True if the panel can be closed/removed
33309 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
33310 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
33311 * @cfg {Toolbar} toolbar A toolbar for this panel
33312 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
33313 * @cfg {String} title The title for this panel
33314 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
33315 * @cfg {String} url Calls {@link #setUrl} with this value
33316 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
33317 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
33318 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
33319 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
33322 * Create a new ContentPanel.
33323 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
33324 * @param {String/Object} config A string to set only the title or a config object
33325 * @param {String} content (optional) Set the HTML content for this panel
33326 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
33328 Roo.bootstrap.panel.Content = function( config){
33330 var el = config.el;
33331 var content = config.content;
33333 if(config.autoCreate){ // xtype is available if this is called from factory
33336 this.el = Roo.get(el);
33337 if(!this.el && config && config.autoCreate){
33338 if(typeof config.autoCreate == "object"){
33339 if(!config.autoCreate.id){
33340 config.autoCreate.id = config.id||el;
33342 this.el = Roo.DomHelper.append(document.body,
33343 config.autoCreate, true);
33345 var elcfg = { tag: "div",
33346 cls: "roo-layout-inactive-content",
33350 elcfg.html = config.html;
33354 this.el = Roo.DomHelper.append(document.body, elcfg , true);
33357 this.closable = false;
33358 this.loaded = false;
33359 this.active = false;
33360 if(typeof config == "string"){
33361 this.title = config;
33363 Roo.apply(this, config);
33366 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
33367 this.wrapEl = this.el.wrap();
33368 this.toolbar.container = this.el.insertSibling(false, 'before');
33369 this.toolbar = new Roo.Toolbar(this.toolbar);
33372 // xtype created footer. - not sure if will work as we normally have to render first..
33373 if (this.footer && !this.footer.el && this.footer.xtype) {
33374 if (!this.wrapEl) {
33375 this.wrapEl = this.el.wrap();
33378 this.footer.container = this.wrapEl.createChild();
33380 this.footer = Roo.factory(this.footer, Roo);
33385 this.resizeEl = Roo.get(this.resizeEl, true);
33387 this.resizeEl = this.el;
33389 // handle view.xtype
33397 * Fires when this panel is activated.
33398 * @param {Roo.ContentPanel} this
33402 * @event deactivate
33403 * Fires when this panel is activated.
33404 * @param {Roo.ContentPanel} this
33406 "deactivate" : true,
33410 * Fires when this panel is resized if fitToFrame is true.
33411 * @param {Roo.ContentPanel} this
33412 * @param {Number} width The width after any component adjustments
33413 * @param {Number} height The height after any component adjustments
33419 * Fires when this tab is created
33420 * @param {Roo.ContentPanel} this
33431 if(this.autoScroll){
33432 this.resizeEl.setStyle("overflow", "auto");
33434 // fix randome scrolling
33435 this.el.on('scroll', function() {
33436 Roo.log('fix random scolling');
33437 this.scrollTo('top',0);
33440 content = content || this.content;
33442 this.setContent(content);
33444 if(config && config.url){
33445 this.setUrl(this.url, this.params, this.loadOnce);
33450 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
33452 if (this.view && typeof(this.view.xtype) != 'undefined') {
33453 this.view.el = this.el.appendChild(document.createElement("div"));
33454 this.view = Roo.factory(this.view);
33455 this.view.render && this.view.render(false, '');
33459 this.fireEvent('render', this);
33462 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
33464 setRegion : function(region){
33465 this.region = region;
33467 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
33469 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
33474 * Returns the toolbar for this Panel if one was configured.
33475 * @return {Roo.Toolbar}
33477 getToolbar : function(){
33478 return this.toolbar;
33481 setActiveState : function(active){
33482 this.active = active;
33484 this.fireEvent("deactivate", this);
33486 this.fireEvent("activate", this);
33490 * Updates this panel's element
33491 * @param {String} content The new content
33492 * @param {Boolean} loadScripts (optional) true to look for and process scripts
33494 setContent : function(content, loadScripts){
33495 this.el.update(content, loadScripts);
33498 ignoreResize : function(w, h){
33499 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
33502 this.lastSize = {width: w, height: h};
33507 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
33508 * @return {Roo.UpdateManager} The UpdateManager
33510 getUpdateManager : function(){
33511 return this.el.getUpdateManager();
33514 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
33515 * @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:
33518 url: "your-url.php",
33519 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
33520 callback: yourFunction,
33521 scope: yourObject, //(optional scope)
33524 text: "Loading...",
33529 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
33530 * 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.
33531 * @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}
33532 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
33533 * @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.
33534 * @return {Roo.ContentPanel} this
33537 var um = this.el.getUpdateManager();
33538 um.update.apply(um, arguments);
33544 * 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.
33545 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
33546 * @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)
33547 * @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)
33548 * @return {Roo.UpdateManager} The UpdateManager
33550 setUrl : function(url, params, loadOnce){
33551 if(this.refreshDelegate){
33552 this.removeListener("activate", this.refreshDelegate);
33554 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
33555 this.on("activate", this.refreshDelegate);
33556 return this.el.getUpdateManager();
33559 _handleRefresh : function(url, params, loadOnce){
33560 if(!loadOnce || !this.loaded){
33561 var updater = this.el.getUpdateManager();
33562 updater.update(url, params, this._setLoaded.createDelegate(this));
33566 _setLoaded : function(){
33567 this.loaded = true;
33571 * Returns this panel's id
33574 getId : function(){
33579 * Returns this panel's element - used by regiosn to add.
33580 * @return {Roo.Element}
33582 getEl : function(){
33583 return this.wrapEl || this.el;
33588 adjustForComponents : function(width, height)
33590 //Roo.log('adjustForComponents ');
33591 if(this.resizeEl != this.el){
33592 width -= this.el.getFrameWidth('lr');
33593 height -= this.el.getFrameWidth('tb');
33596 var te = this.toolbar.getEl();
33597 height -= te.getHeight();
33598 te.setWidth(width);
33601 var te = this.footer.getEl();
33602 Roo.log("footer:" + te.getHeight());
33604 height -= te.getHeight();
33605 te.setWidth(width);
33609 if(this.adjustments){
33610 width += this.adjustments[0];
33611 height += this.adjustments[1];
33613 return {"width": width, "height": height};
33616 setSize : function(width, height){
33617 if(this.fitToFrame && !this.ignoreResize(width, height)){
33618 if(this.fitContainer && this.resizeEl != this.el){
33619 this.el.setSize(width, height);
33621 var size = this.adjustForComponents(width, height);
33622 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
33623 this.fireEvent('resize', this, size.width, size.height);
33628 * Returns this panel's title
33631 getTitle : function(){
33636 * Set this panel's title
33637 * @param {String} title
33639 setTitle : function(title){
33640 this.title = title;
33642 this.region.updatePanelTitle(this, title);
33647 * Returns true is this panel was configured to be closable
33648 * @return {Boolean}
33650 isClosable : function(){
33651 return this.closable;
33654 beforeSlide : function(){
33656 this.resizeEl.clip();
33659 afterSlide : function(){
33661 this.resizeEl.unclip();
33665 * Force a content refresh from the URL specified in the {@link #setUrl} method.
33666 * Will fail silently if the {@link #setUrl} method has not been called.
33667 * This does not activate the panel, just updates its content.
33669 refresh : function(){
33670 if(this.refreshDelegate){
33671 this.loaded = false;
33672 this.refreshDelegate();
33677 * Destroys this panel
33679 destroy : function(){
33680 this.el.removeAllListeners();
33681 var tempEl = document.createElement("span");
33682 tempEl.appendChild(this.el.dom);
33683 tempEl.innerHTML = "";
33689 * form - if the content panel contains a form - this is a reference to it.
33690 * @type {Roo.form.Form}
33694 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
33695 * This contains a reference to it.
33701 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
33711 * @param {Object} cfg Xtype definition of item to add.
33715 getChildContainer: function () {
33716 return this.getEl();
33721 var ret = new Roo.factory(cfg);
33726 if (cfg.xtype.match(/^Form$/)) {
33729 //if (this.footer) {
33730 // el = this.footer.container.insertSibling(false, 'before');
33732 el = this.el.createChild();
33735 this.form = new Roo.form.Form(cfg);
33738 if ( this.form.allItems.length) {
33739 this.form.render(el.dom);
33743 // should only have one of theses..
33744 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
33745 // views.. should not be just added - used named prop 'view''
33747 cfg.el = this.el.appendChild(document.createElement("div"));
33750 var ret = new Roo.factory(cfg);
33752 ret.render && ret.render(false, ''); // render blank..
33762 * @class Roo.bootstrap.panel.Grid
33763 * @extends Roo.bootstrap.panel.Content
33765 * Create a new GridPanel.
33766 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
33767 * @param {String/Object} config A string to set only the panel's title, or a config object
33769 new Roo.bootstrap.panel.Grid({
33778 Roo.bootstrap.panel.Grid = function(config){
33781 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
33782 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
33785 if(config.toolbar){
33786 var tool_el = this.wrapper.createChild();
33787 this.toolbar = Roo.factory(config.toolbar);
33789 if (config.toolbar.items) {
33790 ti = config.toolbar.items ;
33791 delete config.toolbar.items ;
33795 this.toolbar.render(tool_el);
33796 for(var i =0;i < ti.length;i++) {
33797 // Roo.log(['add child', items[i]]);
33798 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
33800 this.toolbar.items = nitems;
33802 delete config.toolbar;
33805 this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
33806 config.el = this.wrapper;
33808 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
33811 // xtype created footer. - not sure if will work as we normally have to render first..
33812 if (this.footer && !this.footer.el && this.footer.xtype) {
33814 var ctr = this.grid.getView().getFooterPanel(true);
33815 this.footer.dataSource = this.grid.dataSource;
33816 this.footer = Roo.factory(this.footer, Roo);
33817 this.footer.render(ctr);
33822 config.grid.monitorWindowResize = false; // turn off autosizing
33823 config.grid.autoHeight = false;
33824 config.grid.autoWidth = false;
33825 this.grid = config.grid;
33826 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
33831 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
33832 getId : function(){
33833 return this.grid.id;
33837 * Returns the grid for this panel
33838 * @return {Roo.bootstrap.Table}
33840 getGrid : function(){
33844 setSize : function(width, height){
33845 if(!this.ignoreResize(width, height)){
33846 var grid = this.grid;
33847 var size = this.adjustForComponents(width, height);
33848 grid.getGridEl().setSize(size.width, size.height);
33850 var thd = grid.getGridEl().select('thead',true).first();
33851 var tbd = grid.getGridEl().select('tbody', true).first();
33853 tbd.setSize(width, height - thd.getHeight());
33862 beforeSlide : function(){
33863 this.grid.getView().scroller.clip();
33866 afterSlide : function(){
33867 this.grid.getView().scroller.unclip();
33870 destroy : function(){
33871 this.grid.destroy();
33873 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
33878 * @class Roo.bootstrap.panel.Nest
33879 * @extends Roo.bootstrap.panel.Content
33881 * Create a new Panel, that can contain a layout.Border.
33884 * @param {Roo.BorderLayout} layout The layout for this panel
33885 * @param {String/Object} config A string to set only the title or a config object
33887 Roo.bootstrap.panel.Nest = function(config)
33889 // construct with only one argument..
33890 /* FIXME - implement nicer consturctors
33891 if (layout.layout) {
33893 layout = config.layout;
33894 delete config.layout;
33896 if (layout.xtype && !layout.getEl) {
33897 // then layout needs constructing..
33898 layout = Roo.factory(layout, Roo);
33902 config.el = config.layout.getEl();
33904 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
33906 config.layout.monitorWindowResize = false; // turn off autosizing
33907 this.layout = config.layout;
33908 this.layout.getEl().addClass("roo-layout-nested-layout");
33915 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
33917 setSize : function(width, height){
33918 if(!this.ignoreResize(width, height)){
33919 var size = this.adjustForComponents(width, height);
33920 var el = this.layout.getEl();
33921 el.setSize(size.width, size.height);
33922 var touch = el.dom.offsetWidth;
33923 this.layout.layout();
33924 // ie requires a double layout on the first pass
33925 if(Roo.isIE && !this.initialized){
33926 this.initialized = true;
33927 this.layout.layout();
33932 // activate all subpanels if not currently active..
33934 setActiveState : function(active){
33935 this.active = active;
33937 this.fireEvent("deactivate", this);
33941 this.fireEvent("activate", this);
33942 // not sure if this should happen before or after..
33943 if (!this.layout) {
33944 return; // should not happen..
33947 for (var r in this.layout.regions) {
33948 reg = this.layout.getRegion(r);
33949 if (reg.getActivePanel()) {
33950 //reg.showPanel(reg.getActivePanel()); // force it to activate..
33951 reg.setActivePanel(reg.getActivePanel());
33954 if (!reg.panels.length) {
33957 reg.showPanel(reg.getPanel(0));
33966 * Returns the nested BorderLayout for this panel
33967 * @return {Roo.BorderLayout}
33969 getLayout : function(){
33970 return this.layout;
33974 * Adds a xtype elements to the layout of the nested panel
33978 xtype : 'ContentPanel',
33985 xtype : 'NestedLayoutPanel',
33991 items : [ ... list of content panels or nested layout panels.. ]
33995 * @param {Object} cfg Xtype definition of item to add.
33997 addxtype : function(cfg) {
33998 return this.layout.addxtype(cfg);
34003 * Ext JS Library 1.1.1
34004 * Copyright(c) 2006-2007, Ext JS, LLC.
34006 * Originally Released Under LGPL - original licence link has changed is not relivant.
34009 * <script type="text/javascript">
34012 * @class Roo.TabPanel
34013 * @extends Roo.util.Observable
34014 * A lightweight tab container.
34018 // basic tabs 1, built from existing content
34019 var tabs = new Roo.TabPanel("tabs1");
34020 tabs.addTab("script", "View Script");
34021 tabs.addTab("markup", "View Markup");
34022 tabs.activate("script");
34024 // more advanced tabs, built from javascript
34025 var jtabs = new Roo.TabPanel("jtabs");
34026 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
34028 // set up the UpdateManager
34029 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
34030 var updater = tab2.getUpdateManager();
34031 updater.setDefaultUrl("ajax1.htm");
34032 tab2.on('activate', updater.refresh, updater, true);
34034 // Use setUrl for Ajax loading
34035 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
34036 tab3.setUrl("ajax2.htm", null, true);
34039 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
34042 jtabs.activate("jtabs-1");
34045 * Create a new TabPanel.
34046 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
34047 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
34049 Roo.bootstrap.panel.Tabs = function(config){
34051 * The container element for this TabPanel.
34052 * @type Roo.Element
34054 this.el = Roo.get(config.el);
34057 if(typeof config == "boolean"){
34058 this.tabPosition = config ? "bottom" : "top";
34060 Roo.apply(this, config);
34064 if(this.tabPosition == "bottom"){
34065 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34066 this.el.addClass("roo-tabs-bottom");
34068 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
34069 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
34070 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
34072 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
34074 if(this.tabPosition != "bottom"){
34075 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
34076 * @type Roo.Element
34078 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34079 this.el.addClass("roo-tabs-top");
34083 this.bodyEl.setStyle("position", "relative");
34085 this.active = null;
34086 this.activateDelegate = this.activate.createDelegate(this);
34091 * Fires when the active tab changes
34092 * @param {Roo.TabPanel} this
34093 * @param {Roo.TabPanelItem} activePanel The new active tab
34097 * @event beforetabchange
34098 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
34099 * @param {Roo.TabPanel} this
34100 * @param {Object} e Set cancel to true on this object to cancel the tab change
34101 * @param {Roo.TabPanelItem} tab The tab being changed to
34103 "beforetabchange" : true
34106 Roo.EventManager.onWindowResize(this.onResize, this);
34107 this.cpad = this.el.getPadding("lr");
34108 this.hiddenCount = 0;
34111 // toolbar on the tabbar support...
34112 if (this.toolbar) {
34113 alert("no toolbar support yet");
34114 this.toolbar = false;
34116 var tcfg = this.toolbar;
34117 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
34118 this.toolbar = new Roo.Toolbar(tcfg);
34119 if (Roo.isSafari) {
34120 var tbl = tcfg.container.child('table', true);
34121 tbl.setAttribute('width', '100%');
34129 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
34132 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
34134 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
34136 tabPosition : "top",
34138 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
34140 currentTabWidth : 0,
34142 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
34146 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
34150 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
34152 preferredTabWidth : 175,
34154 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
34156 resizeTabs : false,
34158 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
34160 monitorResize : true,
34162 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
34167 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
34168 * @param {String} id The id of the div to use <b>or create</b>
34169 * @param {String} text The text for the tab
34170 * @param {String} content (optional) Content to put in the TabPanelItem body
34171 * @param {Boolean} closable (optional) True to create a close icon on the tab
34172 * @return {Roo.TabPanelItem} The created TabPanelItem
34174 addTab : function(id, text, content, closable)
34176 var item = new Roo.bootstrap.panel.TabItem({
34180 closable : closable
34182 this.addTabItem(item);
34184 item.setContent(content);
34190 * Returns the {@link Roo.TabPanelItem} with the specified id/index
34191 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
34192 * @return {Roo.TabPanelItem}
34194 getTab : function(id){
34195 return this.items[id];
34199 * Hides the {@link Roo.TabPanelItem} with the specified id/index
34200 * @param {String/Number} id The id or index of the TabPanelItem to hide.
34202 hideTab : function(id){
34203 var t = this.items[id];
34206 this.hiddenCount++;
34207 this.autoSizeTabs();
34212 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
34213 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
34215 unhideTab : function(id){
34216 var t = this.items[id];
34218 t.setHidden(false);
34219 this.hiddenCount--;
34220 this.autoSizeTabs();
34225 * Adds an existing {@link Roo.TabPanelItem}.
34226 * @param {Roo.TabPanelItem} item The TabPanelItem to add
34228 addTabItem : function(item){
34229 this.items[item.id] = item;
34230 this.items.push(item);
34231 // if(this.resizeTabs){
34232 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
34233 // this.autoSizeTabs();
34235 // item.autoSize();
34240 * Removes a {@link Roo.TabPanelItem}.
34241 * @param {String/Number} id The id or index of the TabPanelItem to remove.
34243 removeTab : function(id){
34244 var items = this.items;
34245 var tab = items[id];
34246 if(!tab) { return; }
34247 var index = items.indexOf(tab);
34248 if(this.active == tab && items.length > 1){
34249 var newTab = this.getNextAvailable(index);
34254 this.stripEl.dom.removeChild(tab.pnode.dom);
34255 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
34256 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
34258 items.splice(index, 1);
34259 delete this.items[tab.id];
34260 tab.fireEvent("close", tab);
34261 tab.purgeListeners();
34262 this.autoSizeTabs();
34265 getNextAvailable : function(start){
34266 var items = this.items;
34268 // look for a next tab that will slide over to
34269 // replace the one being removed
34270 while(index < items.length){
34271 var item = items[++index];
34272 if(item && !item.isHidden()){
34276 // if one isn't found select the previous tab (on the left)
34279 var item = items[--index];
34280 if(item && !item.isHidden()){
34288 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
34289 * @param {String/Number} id The id or index of the TabPanelItem to disable.
34291 disableTab : function(id){
34292 var tab = this.items[id];
34293 if(tab && this.active != tab){
34299 * Enables a {@link Roo.TabPanelItem} that is disabled.
34300 * @param {String/Number} id The id or index of the TabPanelItem to enable.
34302 enableTab : function(id){
34303 var tab = this.items[id];
34308 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
34309 * @param {String/Number} id The id or index of the TabPanelItem to activate.
34310 * @return {Roo.TabPanelItem} The TabPanelItem.
34312 activate : function(id){
34313 var tab = this.items[id];
34317 if(tab == this.active || tab.disabled){
34321 this.fireEvent("beforetabchange", this, e, tab);
34322 if(e.cancel !== true && !tab.disabled){
34324 this.active.hide();
34326 this.active = this.items[id];
34327 this.active.show();
34328 this.fireEvent("tabchange", this, this.active);
34334 * Gets the active {@link Roo.TabPanelItem}.
34335 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
34337 getActiveTab : function(){
34338 return this.active;
34342 * Updates the tab body element to fit the height of the container element
34343 * for overflow scrolling
34344 * @param {Number} targetHeight (optional) Override the starting height from the elements height
34346 syncHeight : function(targetHeight){
34347 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34348 var bm = this.bodyEl.getMargins();
34349 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
34350 this.bodyEl.setHeight(newHeight);
34354 onResize : function(){
34355 if(this.monitorResize){
34356 this.autoSizeTabs();
34361 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
34363 beginUpdate : function(){
34364 this.updating = true;
34368 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
34370 endUpdate : function(){
34371 this.updating = false;
34372 this.autoSizeTabs();
34376 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
34378 autoSizeTabs : function(){
34379 var count = this.items.length;
34380 var vcount = count - this.hiddenCount;
34381 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
34384 var w = Math.max(this.el.getWidth() - this.cpad, 10);
34385 var availWidth = Math.floor(w / vcount);
34386 var b = this.stripBody;
34387 if(b.getWidth() > w){
34388 var tabs = this.items;
34389 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
34390 if(availWidth < this.minTabWidth){
34391 /*if(!this.sleft){ // incomplete scrolling code
34392 this.createScrollButtons();
34395 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
34398 if(this.currentTabWidth < this.preferredTabWidth){
34399 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
34405 * Returns the number of tabs in this TabPanel.
34408 getCount : function(){
34409 return this.items.length;
34413 * Resizes all the tabs to the passed width
34414 * @param {Number} The new width
34416 setTabWidth : function(width){
34417 this.currentTabWidth = width;
34418 for(var i = 0, len = this.items.length; i < len; i++) {
34419 if(!this.items[i].isHidden()) {
34420 this.items[i].setWidth(width);
34426 * Destroys this TabPanel
34427 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
34429 destroy : function(removeEl){
34430 Roo.EventManager.removeResizeListener(this.onResize, this);
34431 for(var i = 0, len = this.items.length; i < len; i++){
34432 this.items[i].purgeListeners();
34434 if(removeEl === true){
34435 this.el.update("");
34440 createStrip : function(container)
34442 var strip = document.createElement("nav");
34443 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
34444 container.appendChild(strip);
34448 createStripList : function(strip)
34450 // div wrapper for retard IE
34451 // returns the "tr" element.
34452 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
34453 //'<div class="x-tabs-strip-wrap">'+
34454 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
34455 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
34456 return strip.firstChild; //.firstChild.firstChild.firstChild;
34458 createBody : function(container)
34460 var body = document.createElement("div");
34461 Roo.id(body, "tab-body");
34462 //Roo.fly(body).addClass("x-tabs-body");
34463 Roo.fly(body).addClass("tab-content");
34464 container.appendChild(body);
34467 createItemBody :function(bodyEl, id){
34468 var body = Roo.getDom(id);
34470 body = document.createElement("div");
34473 //Roo.fly(body).addClass("x-tabs-item-body");
34474 Roo.fly(body).addClass("tab-pane");
34475 bodyEl.insertBefore(body, bodyEl.firstChild);
34479 createStripElements : function(stripEl, text, closable)
34481 var td = document.createElement("li"); // was td..
34482 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
34483 //stripEl.appendChild(td);
34485 td.className = "x-tabs-closable";
34486 if(!this.closeTpl){
34487 this.closeTpl = new Roo.Template(
34488 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34489 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
34490 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
34493 var el = this.closeTpl.overwrite(td, {"text": text});
34494 var close = el.getElementsByTagName("div")[0];
34495 var inner = el.getElementsByTagName("em")[0];
34496 return {"el": el, "close": close, "inner": inner};
34499 // not sure what this is..
34501 //this.tabTpl = new Roo.Template(
34502 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34503 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
34505 this.tabTpl = new Roo.Template(
34507 '<span unselectable="on"' +
34508 (this.disableTooltips ? '' : ' title="{text}"') +
34509 ' >{text}</span></span></a>'
34513 var el = this.tabTpl.overwrite(td, {"text": text});
34514 var inner = el.getElementsByTagName("span")[0];
34515 return {"el": el, "inner": inner};
34523 * @class Roo.TabPanelItem
34524 * @extends Roo.util.Observable
34525 * Represents an individual item (tab plus body) in a TabPanel.
34526 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
34527 * @param {String} id The id of this TabPanelItem
34528 * @param {String} text The text for the tab of this TabPanelItem
34529 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
34531 Roo.bootstrap.panel.TabItem = function(config){
34533 * The {@link Roo.TabPanel} this TabPanelItem belongs to
34534 * @type Roo.TabPanel
34536 this.tabPanel = config.panel;
34538 * The id for this TabPanelItem
34541 this.id = config.id;
34543 this.disabled = false;
34545 this.text = config.text;
34547 this.loaded = false;
34548 this.closable = config.closable;
34551 * The body element for this TabPanelItem.
34552 * @type Roo.Element
34554 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
34555 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
34556 this.bodyEl.setStyle("display", "block");
34557 this.bodyEl.setStyle("zoom", "1");
34558 //this.hideAction();
34560 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
34562 this.el = Roo.get(els.el);
34563 this.inner = Roo.get(els.inner, true);
34564 this.textEl = Roo.get(this.el.dom.firstChild, true);
34565 this.pnode = Roo.get(els.el.parentNode, true);
34566 this.el.on("mousedown", this.onTabMouseDown, this);
34567 this.el.on("click", this.onTabClick, this);
34569 if(config.closable){
34570 var c = Roo.get(els.close, true);
34571 c.dom.title = this.closeText;
34572 c.addClassOnOver("close-over");
34573 c.on("click", this.closeClick, this);
34579 * Fires when this tab becomes the active tab.
34580 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34581 * @param {Roo.TabPanelItem} this
34585 * @event beforeclose
34586 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
34587 * @param {Roo.TabPanelItem} this
34588 * @param {Object} e Set cancel to true on this object to cancel the close.
34590 "beforeclose": true,
34593 * Fires when this tab is closed.
34594 * @param {Roo.TabPanelItem} this
34598 * @event deactivate
34599 * Fires when this tab is no longer the active tab.
34600 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34601 * @param {Roo.TabPanelItem} this
34603 "deactivate" : true
34605 this.hidden = false;
34607 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
34610 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
34612 purgeListeners : function(){
34613 Roo.util.Observable.prototype.purgeListeners.call(this);
34614 this.el.removeAllListeners();
34617 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
34620 this.pnode.addClass("active");
34623 this.tabPanel.stripWrap.repaint();
34625 this.fireEvent("activate", this.tabPanel, this);
34629 * Returns true if this tab is the active tab.
34630 * @return {Boolean}
34632 isActive : function(){
34633 return this.tabPanel.getActiveTab() == this;
34637 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
34640 this.pnode.removeClass("active");
34642 this.fireEvent("deactivate", this.tabPanel, this);
34645 hideAction : function(){
34646 this.bodyEl.hide();
34647 this.bodyEl.setStyle("position", "absolute");
34648 this.bodyEl.setLeft("-20000px");
34649 this.bodyEl.setTop("-20000px");
34652 showAction : function(){
34653 this.bodyEl.setStyle("position", "relative");
34654 this.bodyEl.setTop("");
34655 this.bodyEl.setLeft("");
34656 this.bodyEl.show();
34660 * Set the tooltip for the tab.
34661 * @param {String} tooltip The tab's tooltip
34663 setTooltip : function(text){
34664 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
34665 this.textEl.dom.qtip = text;
34666 this.textEl.dom.removeAttribute('title');
34668 this.textEl.dom.title = text;
34672 onTabClick : function(e){
34673 e.preventDefault();
34674 this.tabPanel.activate(this.id);
34677 onTabMouseDown : function(e){
34678 e.preventDefault();
34679 this.tabPanel.activate(this.id);
34682 getWidth : function(){
34683 return this.inner.getWidth();
34686 setWidth : function(width){
34687 var iwidth = width - this.pnode.getPadding("lr");
34688 this.inner.setWidth(iwidth);
34689 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
34690 this.pnode.setWidth(width);
34694 * Show or hide the tab
34695 * @param {Boolean} hidden True to hide or false to show.
34697 setHidden : function(hidden){
34698 this.hidden = hidden;
34699 this.pnode.setStyle("display", hidden ? "none" : "");
34703 * Returns true if this tab is "hidden"
34704 * @return {Boolean}
34706 isHidden : function(){
34707 return this.hidden;
34711 * Returns the text for this tab
34714 getText : function(){
34718 autoSize : function(){
34719 //this.el.beginMeasure();
34720 this.textEl.setWidth(1);
34722 * #2804 [new] Tabs in Roojs
34723 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
34725 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
34726 //this.el.endMeasure();
34730 * Sets the text for the tab (Note: this also sets the tooltip text)
34731 * @param {String} text The tab's text and tooltip
34733 setText : function(text){
34735 this.textEl.update(text);
34736 this.setTooltip(text);
34737 //if(!this.tabPanel.resizeTabs){
34738 // this.autoSize();
34742 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
34744 activate : function(){
34745 this.tabPanel.activate(this.id);
34749 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
34751 disable : function(){
34752 if(this.tabPanel.active != this){
34753 this.disabled = true;
34754 this.pnode.addClass("disabled");
34759 * Enables this TabPanelItem if it was previously disabled.
34761 enable : function(){
34762 this.disabled = false;
34763 this.pnode.removeClass("disabled");
34767 * Sets the content for this TabPanelItem.
34768 * @param {String} content The content
34769 * @param {Boolean} loadScripts true to look for and load scripts
34771 setContent : function(content, loadScripts){
34772 this.bodyEl.update(content, loadScripts);
34776 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
34777 * @return {Roo.UpdateManager} The UpdateManager
34779 getUpdateManager : function(){
34780 return this.bodyEl.getUpdateManager();
34784 * Set a URL to be used to load the content for this TabPanelItem.
34785 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
34786 * @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)
34787 * @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)
34788 * @return {Roo.UpdateManager} The UpdateManager
34790 setUrl : function(url, params, loadOnce){
34791 if(this.refreshDelegate){
34792 this.un('activate', this.refreshDelegate);
34794 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34795 this.on("activate", this.refreshDelegate);
34796 return this.bodyEl.getUpdateManager();
34800 _handleRefresh : function(url, params, loadOnce){
34801 if(!loadOnce || !this.loaded){
34802 var updater = this.bodyEl.getUpdateManager();
34803 updater.update(url, params, this._setLoaded.createDelegate(this));
34808 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
34809 * Will fail silently if the setUrl method has not been called.
34810 * This does not activate the panel, just updates its content.
34812 refresh : function(){
34813 if(this.refreshDelegate){
34814 this.loaded = false;
34815 this.refreshDelegate();
34820 _setLoaded : function(){
34821 this.loaded = true;
34825 closeClick : function(e){
34828 this.fireEvent("beforeclose", this, o);
34829 if(o.cancel !== true){
34830 this.tabPanel.removeTab(this.id);
34834 * The text displayed in the tooltip for the close icon.
34837 closeText : "Close this tab"