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
2459 * @cfg {Boolean} fitwindow default true
2463 * Create a new Modal Dialog
2464 * @param {Object} config The config object
2467 Roo.bootstrap.Modal = function(config){
2468 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2473 * The raw btnclick event for the button
2474 * @param {Roo.EventObject} e
2478 this.buttons = this.buttons || [];
2481 this.tmpl = Roo.factory(this.tmpl);
2486 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2488 title : 'test dialog',
2498 specificTitle: false,
2500 buttonPosition: 'right',
2517 onRender : function(ct, position)
2519 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2522 var cfg = Roo.apply({}, this.getAutoCreate());
2525 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2527 //if (!cfg.name.length) {
2531 cfg.cls += ' ' + this.cls;
2534 cfg.style = this.style;
2536 this.el = Roo.get(document.body).createChild(cfg, position);
2538 //var type = this.el.dom.type;
2541 if(this.tabIndex !== undefined){
2542 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2545 this.dialogEl = this.el.select('.modal-dialog',true).first();
2546 this.bodyEl = this.el.select('.modal-body',true).first();
2547 this.closeEl = this.el.select('.modal-header .close', true).first();
2548 this.footerEl = this.el.select('.modal-footer',true).first();
2549 this.titleEl = this.el.select('.modal-title',true).first();
2553 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2554 this.maskEl.enableDisplayMode("block");
2556 //this.el.addClass("x-dlg-modal");
2558 if (this.buttons.length) {
2559 Roo.each(this.buttons, function(bb) {
2560 var b = Roo.apply({}, bb);
2561 b.xns = b.xns || Roo.bootstrap;
2562 b.xtype = b.xtype || 'Button';
2563 if (typeof(b.listeners) == 'undefined') {
2564 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2567 var btn = Roo.factory(b);
2569 btn.render(this.el.select('.modal-footer div').first());
2573 // render the children.
2576 if(typeof(this.items) != 'undefined'){
2577 var items = this.items;
2580 for(var i =0;i < items.length;i++) {
2581 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2585 this.items = nitems;
2587 // where are these used - they used to be body/close/footer
2591 //this.el.addClass([this.fieldClass, this.cls]);
2595 getAutoCreate : function(){
2600 html : this.html || ''
2605 cls : 'modal-title',
2609 if(this.specificTitle){
2615 if (this.allow_close) {
2626 style : 'display: none',
2629 cls: "modal-dialog",
2632 cls : "modal-content",
2635 cls : 'modal-header',
2640 cls : 'modal-footer',
2644 cls: 'btn-' + this.buttonPosition
2661 modal.cls += ' fade';
2667 getChildContainer : function() {
2672 getButtonContainer : function() {
2673 return this.el.select('.modal-footer div',true).first();
2676 initEvents : function()
2678 if (this.allow_close) {
2679 this.closeEl.on('click', this.hide, this);
2681 Roo.EventManager.onWindowResize(this.resize, this, true);
2688 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2689 if (this.fitwindow) {
2690 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2691 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 30;
2696 setSize : function(w,h)
2706 if (!this.rendered) {
2710 this.el.setStyle('display', 'block');
2712 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2715 this.el.addClass('in');
2718 this.el.addClass('in');
2722 // not sure how we can show data in here..
2724 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2727 Roo.get(document.body).addClass("x-body-masked");
2728 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2730 this.el.setStyle('zIndex', '10001');
2732 this.fireEvent('show', this);
2733 this.items.forEach(function(e) {
2734 e.layout ? e.layout() : false;
2745 Roo.get(document.body).removeClass("x-body-masked");
2746 this.el.removeClass('in');
2747 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2749 if(this.animate){ // why
2751 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2753 this.el.setStyle('display', 'none');
2756 this.fireEvent('hide', this);
2759 addButton : function(str, cb)
2763 var b = Roo.apply({}, { html : str } );
2764 b.xns = b.xns || Roo.bootstrap;
2765 b.xtype = b.xtype || 'Button';
2766 if (typeof(b.listeners) == 'undefined') {
2767 b.listeners = { click : cb.createDelegate(this) };
2770 var btn = Roo.factory(b);
2772 btn.render(this.el.select('.modal-footer div').first());
2778 setDefaultButton : function(btn)
2780 //this.el.select('.modal-footer').()
2784 resizeTo: function(w,h)
2788 this.dialogEl.setWidth(w);
2789 if (this.diff === false) {
2790 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2793 this.bodyEl.setHeight(h-this.diff);
2797 setContentSize : function(w, h)
2801 onButtonClick: function(btn,e)
2804 this.fireEvent('btnclick', btn.name, e);
2807 * Set the title of the Dialog
2808 * @param {String} str new Title
2810 setTitle: function(str) {
2811 this.titleEl.dom.innerHTML = str;
2814 * Set the body of the Dialog
2815 * @param {String} str new Title
2817 setBody: function(str) {
2818 this.bodyEl.dom.innerHTML = str;
2821 * Set the body of the Dialog using the template
2822 * @param {Obj} data - apply this data to the template and replace the body contents.
2824 applyBody: function(obj)
2827 Roo.log("Error - using apply Body without a template");
2830 this.tmpl.overwrite(this.bodyEl, obj);
2836 Roo.apply(Roo.bootstrap.Modal, {
2838 * Button config that displays a single OK button
2847 * Button config that displays Yes and No buttons
2863 * Button config that displays OK and Cancel buttons
2878 * Button config that displays Yes, No and Cancel buttons
2901 * messagebox - can be used as a replace
2905 * @class Roo.MessageBox
2906 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2910 Roo.Msg.alert('Status', 'Changes saved successfully.');
2912 // Prompt for user data:
2913 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2915 // process text value...
2919 // Show a dialog using config options:
2921 title:'Save Changes?',
2922 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2923 buttons: Roo.Msg.YESNOCANCEL,
2930 Roo.bootstrap.MessageBox = function(){
2931 var dlg, opt, mask, waitTimer;
2932 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2933 var buttons, activeTextEl, bwidth;
2937 var handleButton = function(button){
2939 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2943 var handleHide = function(){
2945 dlg.el.removeClass(opt.cls);
2948 // Roo.TaskMgr.stop(waitTimer);
2949 // waitTimer = null;
2954 var updateButtons = function(b){
2957 buttons["ok"].hide();
2958 buttons["cancel"].hide();
2959 buttons["yes"].hide();
2960 buttons["no"].hide();
2961 //dlg.footer.dom.style.display = 'none';
2964 dlg.footerEl.dom.style.display = '';
2965 for(var k in buttons){
2966 if(typeof buttons[k] != "function"){
2969 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2970 width += buttons[k].el.getWidth()+15;
2980 var handleEsc = function(d, k, e){
2981 if(opt && opt.closable !== false){
2991 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2992 * @return {Roo.BasicDialog} The BasicDialog element
2994 getDialog : function(){
2996 dlg = new Roo.bootstrap.Modal( {
2999 //constraintoviewport:false,
3001 //collapsible : false,
3006 //buttonAlign:"center",
3007 closeClick : function(){
3008 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3011 handleButton("cancel");
3016 dlg.on("hide", handleHide);
3018 //dlg.addKeyListener(27, handleEsc);
3020 this.buttons = buttons;
3021 var bt = this.buttonText;
3022 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3023 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3024 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3025 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3027 bodyEl = dlg.bodyEl.createChild({
3029 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3030 '<textarea class="roo-mb-textarea"></textarea>' +
3031 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3033 msgEl = bodyEl.dom.firstChild;
3034 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3035 textboxEl.enableDisplayMode();
3036 textboxEl.addKeyListener([10,13], function(){
3037 if(dlg.isVisible() && opt && opt.buttons){
3040 }else if(opt.buttons.yes){
3041 handleButton("yes");
3045 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3046 textareaEl.enableDisplayMode();
3047 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3048 progressEl.enableDisplayMode();
3049 var pf = progressEl.dom.firstChild;
3051 pp = Roo.get(pf.firstChild);
3052 pp.setHeight(pf.offsetHeight);
3060 * Updates the message box body text
3061 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3062 * the XHTML-compliant non-breaking space character '&#160;')
3063 * @return {Roo.MessageBox} This message box
3065 updateText : function(text){
3066 if(!dlg.isVisible() && !opt.width){
3067 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3069 msgEl.innerHTML = text || ' ';
3071 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3072 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3074 Math.min(opt.width || cw , this.maxWidth),
3075 Math.max(opt.minWidth || this.minWidth, bwidth)
3078 activeTextEl.setWidth(w);
3080 if(dlg.isVisible()){
3081 dlg.fixedcenter = false;
3083 // to big, make it scroll. = But as usual stupid IE does not support
3086 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3087 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3088 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3090 bodyEl.dom.style.height = '';
3091 bodyEl.dom.style.overflowY = '';
3094 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3096 bodyEl.dom.style.overflowX = '';
3099 dlg.setContentSize(w, bodyEl.getHeight());
3100 if(dlg.isVisible()){
3101 dlg.fixedcenter = true;
3107 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3108 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3109 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3110 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3111 * @return {Roo.MessageBox} This message box
3113 updateProgress : function(value, text){
3115 this.updateText(text);
3117 if (pp) { // weird bug on my firefox - for some reason this is not defined
3118 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3124 * Returns true if the message box is currently displayed
3125 * @return {Boolean} True if the message box is visible, else false
3127 isVisible : function(){
3128 return dlg && dlg.isVisible();
3132 * Hides the message box if it is displayed
3135 if(this.isVisible()){
3141 * Displays a new message box, or reinitializes an existing message box, based on the config options
3142 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3143 * The following config object properties are supported:
3145 Property Type Description
3146 ---------- --------------- ------------------------------------------------------------------------------------
3147 animEl String/Element An id or Element from which the message box should animate as it opens and
3148 closes (defaults to undefined)
3149 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3150 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3151 closable Boolean False to hide the top-right close button (defaults to true). Note that
3152 progress and wait dialogs will ignore this property and always hide the
3153 close button as they can only be closed programmatically.
3154 cls String A custom CSS class to apply to the message box element
3155 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3156 displayed (defaults to 75)
3157 fn Function A callback function to execute after closing the dialog. The arguments to the
3158 function will be btn (the name of the button that was clicked, if applicable,
3159 e.g. "ok"), and text (the value of the active text field, if applicable).
3160 Progress and wait dialogs will ignore this option since they do not respond to
3161 user actions and can only be closed programmatically, so any required function
3162 should be called by the same code after it closes the dialog.
3163 icon String A CSS class that provides a background image to be used as an icon for
3164 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3165 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3166 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3167 modal Boolean False to allow user interaction with the page while the message box is
3168 displayed (defaults to true)
3169 msg String A string that will replace the existing message box body text (defaults
3170 to the XHTML-compliant non-breaking space character ' ')
3171 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3172 progress Boolean True to display a progress bar (defaults to false)
3173 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3174 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3175 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3176 title String The title text
3177 value String The string value to set into the active textbox element if displayed
3178 wait Boolean True to display a progress bar (defaults to false)
3179 width Number The width of the dialog in pixels
3186 msg: 'Please enter your address:',
3188 buttons: Roo.MessageBox.OKCANCEL,
3191 animEl: 'addAddressBtn'
3194 * @param {Object} config Configuration options
3195 * @return {Roo.MessageBox} This message box
3197 show : function(options)
3200 // this causes nightmares if you show one dialog after another
3201 // especially on callbacks..
3203 if(this.isVisible()){
3206 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3207 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3208 Roo.log("New Dialog Message:" + options.msg )
3209 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3210 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3213 var d = this.getDialog();
3215 d.setTitle(opt.title || " ");
3216 d.closeEl.setDisplayed(opt.closable !== false);
3217 activeTextEl = textboxEl;
3218 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3223 textareaEl.setHeight(typeof opt.multiline == "number" ?
3224 opt.multiline : this.defaultTextHeight);
3225 activeTextEl = textareaEl;
3234 progressEl.setDisplayed(opt.progress === true);
3235 this.updateProgress(0);
3236 activeTextEl.dom.value = opt.value || "";
3238 dlg.setDefaultButton(activeTextEl);
3240 var bs = opt.buttons;
3244 }else if(bs && bs.yes){
3245 db = buttons["yes"];
3247 dlg.setDefaultButton(db);
3249 bwidth = updateButtons(opt.buttons);
3250 this.updateText(opt.msg);
3252 d.el.addClass(opt.cls);
3254 d.proxyDrag = opt.proxyDrag === true;
3255 d.modal = opt.modal !== false;
3256 d.mask = opt.modal !== false ? mask : false;
3258 // force it to the end of the z-index stack so it gets a cursor in FF
3259 document.body.appendChild(dlg.el.dom);
3260 d.animateTarget = null;
3261 d.show(options.animEl);
3267 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3268 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3269 * and closing the message box when the process is complete.
3270 * @param {String} title The title bar text
3271 * @param {String} msg The message box body text
3272 * @return {Roo.MessageBox} This message box
3274 progress : function(title, msg){
3281 minWidth: this.minProgressWidth,
3288 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3289 * If a callback function is passed it will be called after the user clicks the button, and the
3290 * id of the button that was clicked will be passed as the only parameter to the callback
3291 * (could also be the top-right close button).
3292 * @param {String} title The title bar text
3293 * @param {String} msg The message box body text
3294 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3295 * @param {Object} scope (optional) The scope of the callback function
3296 * @return {Roo.MessageBox} This message box
3298 alert : function(title, msg, fn, scope){
3311 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3312 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3313 * You are responsible for closing the message box when the process is complete.
3314 * @param {String} msg The message box body text
3315 * @param {String} title (optional) The title bar text
3316 * @return {Roo.MessageBox} This message box
3318 wait : function(msg, title){
3329 waitTimer = Roo.TaskMgr.start({
3331 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3339 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3340 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3341 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3342 * @param {String} title The title bar text
3343 * @param {String} msg The message box body text
3344 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3345 * @param {Object} scope (optional) The scope of the callback function
3346 * @return {Roo.MessageBox} This message box
3348 confirm : function(title, msg, fn, scope){
3352 buttons: this.YESNO,
3361 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3362 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3363 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3364 * (could also be the top-right close button) and the text that was entered will be passed as the two
3365 * parameters to the callback.
3366 * @param {String} title The title bar text
3367 * @param {String} msg The message box body text
3368 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3369 * @param {Object} scope (optional) The scope of the callback function
3370 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3371 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3372 * @return {Roo.MessageBox} This message box
3374 prompt : function(title, msg, fn, scope, multiline){
3378 buttons: this.OKCANCEL,
3383 multiline: multiline,
3390 * Button config that displays a single OK button
3395 * Button config that displays Yes and No buttons
3398 YESNO : {yes:true, no:true},
3400 * Button config that displays OK and Cancel buttons
3403 OKCANCEL : {ok:true, cancel:true},
3405 * Button config that displays Yes, No and Cancel buttons
3408 YESNOCANCEL : {yes:true, no:true, cancel:true},
3411 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3414 defaultTextHeight : 75,
3416 * The maximum width in pixels of the message box (defaults to 600)
3421 * The minimum width in pixels of the message box (defaults to 100)
3426 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3427 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3430 minProgressWidth : 250,
3432 * An object containing the default button text strings that can be overriden for localized language support.
3433 * Supported properties are: ok, cancel, yes and no.
3434 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3447 * Shorthand for {@link Roo.MessageBox}
3449 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3450 Roo.Msg = Roo.Msg || Roo.MessageBox;
3459 * @class Roo.bootstrap.Navbar
3460 * @extends Roo.bootstrap.Component
3461 * Bootstrap Navbar class
3464 * Create a new Navbar
3465 * @param {Object} config The config object
3469 Roo.bootstrap.Navbar = function(config){
3470 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3474 * @event beforetoggle
3475 * Fire before toggle the menu
3476 * @param {Roo.EventObject} e
3478 "beforetoggle" : true
3482 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3491 getAutoCreate : function(){
3494 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3498 initEvents :function ()
3500 //Roo.log(this.el.select('.navbar-toggle',true));
3501 this.el.select('.navbar-toggle',true).on('click', function() {
3502 if(this.fireEvent('beforetoggle', this) !== false){
3503 this.el.select('.navbar-collapse',true).toggleClass('in');
3513 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3515 var size = this.el.getSize();
3516 this.maskEl.setSize(size.width, size.height);
3517 this.maskEl.enableDisplayMode("block");
3526 getChildContainer : function()
3528 if (this.el.select('.collapse').getCount()) {
3529 return this.el.select('.collapse',true).first();
3562 * @class Roo.bootstrap.NavSimplebar
3563 * @extends Roo.bootstrap.Navbar
3564 * Bootstrap Sidebar class
3566 * @cfg {Boolean} inverse is inverted color
3568 * @cfg {String} type (nav | pills | tabs)
3569 * @cfg {Boolean} arrangement stacked | justified
3570 * @cfg {String} align (left | right) alignment
3572 * @cfg {Boolean} main (true|false) main nav bar? default false
3573 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3575 * @cfg {String} tag (header|footer|nav|div) default is nav
3581 * Create a new Sidebar
3582 * @param {Object} config The config object
3586 Roo.bootstrap.NavSimplebar = function(config){
3587 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3590 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3606 getAutoCreate : function(){
3610 tag : this.tag || 'div',
3623 this.type = this.type || 'nav';
3624 if (['tabs','pills'].indexOf(this.type)!==-1) {
3625 cfg.cn[0].cls += ' nav-' + this.type
3629 if (this.type!=='nav') {
3630 Roo.log('nav type must be nav/tabs/pills')
3632 cfg.cn[0].cls += ' navbar-nav'
3638 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3639 cfg.cn[0].cls += ' nav-' + this.arrangement;
3643 if (this.align === 'right') {
3644 cfg.cn[0].cls += ' navbar-right';
3648 cfg.cls += ' navbar-inverse';
3675 * @class Roo.bootstrap.NavHeaderbar
3676 * @extends Roo.bootstrap.NavSimplebar
3677 * Bootstrap Sidebar class
3679 * @cfg {String} brand what is brand
3680 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3681 * @cfg {String} brand_href href of the brand
3682 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3683 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3684 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3685 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3688 * Create a new Sidebar
3689 * @param {Object} config The config object
3693 Roo.bootstrap.NavHeaderbar = function(config){
3694 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3698 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3705 desktopCenter : false,
3708 getAutoCreate : function(){
3711 tag: this.nav || 'nav',
3718 if (this.desktopCenter) {
3719 cn.push({cls : 'container', cn : []});
3726 cls: 'navbar-header',
3731 cls: 'navbar-toggle',
3732 'data-toggle': 'collapse',
3737 html: 'Toggle navigation'
3759 cls: 'collapse navbar-collapse',
3763 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3765 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3766 cfg.cls += ' navbar-' + this.position;
3768 // tag can override this..
3770 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3773 if (this.brand !== '') {
3776 href: this.brand_href ? this.brand_href : '#',
3777 cls: 'navbar-brand',
3785 cfg.cls += ' main-nav';
3793 getHeaderChildContainer : function()
3795 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3796 return this.el.select('.navbar-header',true).first();
3799 return this.getChildContainer();
3803 initEvents : function()
3805 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3807 if (this.autohide) {
3812 Roo.get(document).on('scroll',function(e) {
3813 var ns = Roo.get(document).getScroll().top;
3814 var os = prevScroll;
3818 ft.removeClass('slideDown');
3819 ft.addClass('slideUp');
3822 ft.removeClass('slideUp');
3823 ft.addClass('slideDown');
3844 * @class Roo.bootstrap.NavSidebar
3845 * @extends Roo.bootstrap.Navbar
3846 * Bootstrap Sidebar class
3849 * Create a new Sidebar
3850 * @param {Object} config The config object
3854 Roo.bootstrap.NavSidebar = function(config){
3855 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3858 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3860 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3862 getAutoCreate : function(){
3867 cls: 'sidebar sidebar-nav'
3889 * @class Roo.bootstrap.NavGroup
3890 * @extends Roo.bootstrap.Component
3891 * Bootstrap NavGroup class
3892 * @cfg {String} align (left|right)
3893 * @cfg {Boolean} inverse
3894 * @cfg {String} type (nav|pills|tab) default nav
3895 * @cfg {String} navId - reference Id for navbar.
3899 * Create a new nav group
3900 * @param {Object} config The config object
3903 Roo.bootstrap.NavGroup = function(config){
3904 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3907 Roo.bootstrap.NavGroup.register(this);
3911 * Fires when the active item changes
3912 * @param {Roo.bootstrap.NavGroup} this
3913 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3914 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3921 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3932 getAutoCreate : function()
3934 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3941 if (['tabs','pills'].indexOf(this.type)!==-1) {
3942 cfg.cls += ' nav-' + this.type
3944 if (this.type!=='nav') {
3945 Roo.log('nav type must be nav/tabs/pills')
3947 cfg.cls += ' navbar-nav'
3950 if (this.parent().sidebar) {
3953 cls: 'dashboard-menu sidebar-menu'
3959 if (this.form === true) {
3965 if (this.align === 'right') {
3966 cfg.cls += ' navbar-right';
3968 cfg.cls += ' navbar-left';
3972 if (this.align === 'right') {
3973 cfg.cls += ' navbar-right';
3977 cfg.cls += ' navbar-inverse';
3985 * sets the active Navigation item
3986 * @param {Roo.bootstrap.NavItem} the new current navitem
3988 setActiveItem : function(item)
3991 Roo.each(this.navItems, function(v){
3996 v.setActive(false, true);
4003 item.setActive(true, true);
4004 this.fireEvent('changed', this, item, prev);
4009 * gets the active Navigation item
4010 * @return {Roo.bootstrap.NavItem} the current navitem
4012 getActive : function()
4016 Roo.each(this.navItems, function(v){
4027 indexOfNav : function()
4031 Roo.each(this.navItems, function(v,i){
4042 * adds a Navigation item
4043 * @param {Roo.bootstrap.NavItem} the navitem to add
4045 addItem : function(cfg)
4047 var cn = new Roo.bootstrap.NavItem(cfg);
4049 cn.parentId = this.id;
4050 cn.onRender(this.el, null);
4054 * register a Navigation item
4055 * @param {Roo.bootstrap.NavItem} the navitem to add
4057 register : function(item)
4059 this.navItems.push( item);
4060 item.navId = this.navId;
4065 * clear all the Navigation item
4068 clearAll : function()
4071 this.el.dom.innerHTML = '';
4074 getNavItem: function(tabId)
4077 Roo.each(this.navItems, function(e) {
4078 if (e.tabId == tabId) {
4088 setActiveNext : function()
4090 var i = this.indexOfNav(this.getActive());
4091 if (i > this.navItems.length) {
4094 this.setActiveItem(this.navItems[i+1]);
4096 setActivePrev : function()
4098 var i = this.indexOfNav(this.getActive());
4102 this.setActiveItem(this.navItems[i-1]);
4104 clearWasActive : function(except) {
4105 Roo.each(this.navItems, function(e) {
4106 if (e.tabId != except.tabId && e.was_active) {
4107 e.was_active = false;
4114 getWasActive : function ()
4117 Roo.each(this.navItems, function(e) {
4132 Roo.apply(Roo.bootstrap.NavGroup, {
4136 * register a Navigation Group
4137 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4139 register : function(navgrp)
4141 this.groups[navgrp.navId] = navgrp;
4145 * fetch a Navigation Group based on the navigation ID
4146 * @param {string} the navgroup to add
4147 * @returns {Roo.bootstrap.NavGroup} the navgroup
4149 get: function(navId) {
4150 if (typeof(this.groups[navId]) == 'undefined') {
4152 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4154 return this.groups[navId] ;
4169 * @class Roo.bootstrap.NavItem
4170 * @extends Roo.bootstrap.Component
4171 * Bootstrap Navbar.NavItem class
4172 * @cfg {String} href link to
4173 * @cfg {String} html content of button
4174 * @cfg {String} badge text inside badge
4175 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4176 * @cfg {String} glyphicon name of glyphicon
4177 * @cfg {String} icon name of font awesome icon
4178 * @cfg {Boolean} active Is item active
4179 * @cfg {Boolean} disabled Is item disabled
4181 * @cfg {Boolean} preventDefault (true | false) default false
4182 * @cfg {String} tabId the tab that this item activates.
4183 * @cfg {String} tagtype (a|span) render as a href or span?
4184 * @cfg {Boolean} animateRef (true|false) link to element default false
4187 * Create a new Navbar Item
4188 * @param {Object} config The config object
4190 Roo.bootstrap.NavItem = function(config){
4191 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4196 * The raw click event for the entire grid.
4197 * @param {Roo.EventObject} e
4202 * Fires when the active item active state changes
4203 * @param {Roo.bootstrap.NavItem} this
4204 * @param {boolean} state the new state
4210 * Fires when scroll to element
4211 * @param {Roo.bootstrap.NavItem} this
4212 * @param {Object} options
4213 * @param {Roo.EventObject} e
4221 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4229 preventDefault : false,
4236 getAutoCreate : function(){
4245 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4247 if (this.disabled) {
4248 cfg.cls += ' disabled';
4251 if (this.href || this.html || this.glyphicon || this.icon) {
4255 href : this.href || "#",
4256 html: this.html || ''
4261 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4264 if(this.glyphicon) {
4265 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4270 cfg.cn[0].html += " <span class='caret'></span>";
4274 if (this.badge !== '') {
4276 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4284 initEvents: function()
4286 if (typeof (this.menu) != 'undefined') {
4287 this.menu.parentType = this.xtype;
4288 this.menu.triggerEl = this.el;
4289 this.menu = this.addxtype(Roo.apply({}, this.menu));
4292 this.el.select('a',true).on('click', this.onClick, this);
4294 if(this.tagtype == 'span'){
4295 this.el.select('span',true).on('click', this.onClick, this);
4298 // at this point parent should be available..
4299 this.parent().register(this);
4302 onClick : function(e)
4304 if (e.getTarget('.dropdown-menu-item')) {
4305 // did you click on a menu itemm.... - then don't trigger onclick..
4310 this.preventDefault ||
4313 Roo.log("NavItem - prevent Default?");
4317 if (this.disabled) {
4321 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4322 if (tg && tg.transition) {
4323 Roo.log("waiting for the transitionend");
4329 //Roo.log("fire event clicked");
4330 if(this.fireEvent('click', this, e) === false){
4334 if(this.tagtype == 'span'){
4338 //Roo.log(this.href);
4339 var ael = this.el.select('a',true).first();
4342 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4343 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4344 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4345 return; // ignore... - it's a 'hash' to another page.
4347 Roo.log("NavItem - prevent Default?");
4349 this.scrollToElement(e);
4353 var p = this.parent();
4355 if (['tabs','pills'].indexOf(p.type)!==-1) {
4356 if (typeof(p.setActiveItem) !== 'undefined') {
4357 p.setActiveItem(this);
4361 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4362 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4363 // remove the collapsed menu expand...
4364 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4368 isActive: function () {
4371 setActive : function(state, fire, is_was_active)
4373 if (this.active && !state && this.navId) {
4374 this.was_active = true;
4375 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4377 nv.clearWasActive(this);
4381 this.active = state;
4384 this.el.removeClass('active');
4385 } else if (!this.el.hasClass('active')) {
4386 this.el.addClass('active');
4389 this.fireEvent('changed', this, state);
4392 // show a panel if it's registered and related..
4394 if (!this.navId || !this.tabId || !state || is_was_active) {
4398 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4402 var pan = tg.getPanelByName(this.tabId);
4406 // if we can not flip to new panel - go back to old nav highlight..
4407 if (false == tg.showPanel(pan)) {
4408 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4410 var onav = nv.getWasActive();
4412 onav.setActive(true, false, true);
4421 // this should not be here...
4422 setDisabled : function(state)
4424 this.disabled = state;
4426 this.el.removeClass('disabled');
4427 } else if (!this.el.hasClass('disabled')) {
4428 this.el.addClass('disabled');
4434 * Fetch the element to display the tooltip on.
4435 * @return {Roo.Element} defaults to this.el
4437 tooltipEl : function()
4439 return this.el.select('' + this.tagtype + '', true).first();
4442 scrollToElement : function(e)
4444 var c = document.body;
4447 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4449 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4450 c = document.documentElement;
4453 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4459 var o = target.calcOffsetsTo(c);
4466 this.fireEvent('scrollto', this, options, e);
4468 Roo.get(c).scrollTo('top', options.value, true);
4481 * <span> icon </span>
4482 * <span> text </span>
4483 * <span>badge </span>
4487 * @class Roo.bootstrap.NavSidebarItem
4488 * @extends Roo.bootstrap.NavItem
4489 * Bootstrap Navbar.NavSidebarItem class
4490 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4491 * {bool} open is the menu open
4493 * Create a new Navbar Button
4494 * @param {Object} config The config object
4496 Roo.bootstrap.NavSidebarItem = function(config){
4497 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4502 * The raw click event for the entire grid.
4503 * @param {Roo.EventObject} e
4508 * Fires when the active item active state changes
4509 * @param {Roo.bootstrap.NavSidebarItem} this
4510 * @param {boolean} state the new state
4518 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4520 badgeWeight : 'default',
4524 getAutoCreate : function(){
4529 href : this.href || '#',
4541 html : this.html || ''
4546 cfg.cls += ' active';
4549 if (this.disabled) {
4550 cfg.cls += ' disabled';
4553 cfg.cls += ' open x-open';
4556 if (this.glyphicon || this.icon) {
4557 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4558 a.cn.push({ tag : 'i', cls : c }) ;
4563 if (this.badge !== '') {
4565 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4569 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4570 a.cls += 'dropdown-toggle treeview' ;
4578 initEvents : function()
4580 if (typeof (this.menu) != 'undefined') {
4581 this.menu.parentType = this.xtype;
4582 this.menu.triggerEl = this.el;
4583 this.menu = this.addxtype(Roo.apply({}, this.menu));
4586 this.el.on('click', this.onClick, this);
4589 if(this.badge !== ''){
4591 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4596 onClick : function(e)
4603 if(this.preventDefault){
4607 this.fireEvent('click', this);
4610 disable : function()
4612 this.setDisabled(true);
4617 this.setDisabled(false);
4620 setDisabled : function(state)
4622 if(this.disabled == state){
4626 this.disabled = state;
4629 this.el.addClass('disabled');
4633 this.el.removeClass('disabled');
4638 setActive : function(state)
4640 if(this.active == state){
4644 this.active = state;
4647 this.el.addClass('active');
4651 this.el.removeClass('active');
4656 isActive: function ()
4661 setBadge : function(str)
4667 this.badgeEl.dom.innerHTML = str;
4684 * @class Roo.bootstrap.Row
4685 * @extends Roo.bootstrap.Component
4686 * Bootstrap Row class (contains columns...)
4690 * @param {Object} config The config object
4693 Roo.bootstrap.Row = function(config){
4694 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4697 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4699 getAutoCreate : function(){
4718 * @class Roo.bootstrap.Element
4719 * @extends Roo.bootstrap.Component
4720 * Bootstrap Element class
4721 * @cfg {String} html contents of the element
4722 * @cfg {String} tag tag of the element
4723 * @cfg {String} cls class of the element
4724 * @cfg {Boolean} preventDefault (true|false) default false
4725 * @cfg {Boolean} clickable (true|false) default false
4728 * Create a new Element
4729 * @param {Object} config The config object
4732 Roo.bootstrap.Element = function(config){
4733 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4739 * When a element is chick
4740 * @param {Roo.bootstrap.Element} this
4741 * @param {Roo.EventObject} e
4747 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4752 preventDefault: false,
4755 getAutoCreate : function(){
4766 initEvents: function()
4768 Roo.bootstrap.Element.superclass.initEvents.call(this);
4771 this.el.on('click', this.onClick, this);
4776 onClick : function(e)
4778 if(this.preventDefault){
4782 this.fireEvent('click', this, e);
4785 getValue : function()
4787 return this.el.dom.innerHTML;
4790 setValue : function(value)
4792 this.el.dom.innerHTML = value;
4807 * @class Roo.bootstrap.Pagination
4808 * @extends Roo.bootstrap.Component
4809 * Bootstrap Pagination class
4810 * @cfg {String} size xs | sm | md | lg
4811 * @cfg {Boolean} inverse false | true
4814 * Create a new Pagination
4815 * @param {Object} config The config object
4818 Roo.bootstrap.Pagination = function(config){
4819 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4822 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4828 getAutoCreate : function(){
4834 cfg.cls += ' inverse';
4840 cfg.cls += " " + this.cls;
4858 * @class Roo.bootstrap.PaginationItem
4859 * @extends Roo.bootstrap.Component
4860 * Bootstrap PaginationItem class
4861 * @cfg {String} html text
4862 * @cfg {String} href the link
4863 * @cfg {Boolean} preventDefault (true | false) default true
4864 * @cfg {Boolean} active (true | false) default false
4865 * @cfg {Boolean} disabled default false
4869 * Create a new PaginationItem
4870 * @param {Object} config The config object
4874 Roo.bootstrap.PaginationItem = function(config){
4875 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4880 * The raw click event for the entire grid.
4881 * @param {Roo.EventObject} e
4887 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4891 preventDefault: true,
4896 getAutoCreate : function(){
4902 href : this.href ? this.href : '#',
4903 html : this.html ? this.html : ''
4913 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4917 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4923 initEvents: function() {
4925 this.el.on('click', this.onClick, this);
4928 onClick : function(e)
4930 Roo.log('PaginationItem on click ');
4931 if(this.preventDefault){
4939 this.fireEvent('click', this, e);
4955 * @class Roo.bootstrap.Slider
4956 * @extends Roo.bootstrap.Component
4957 * Bootstrap Slider class
4960 * Create a new Slider
4961 * @param {Object} config The config object
4964 Roo.bootstrap.Slider = function(config){
4965 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4968 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4970 getAutoCreate : function(){
4974 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4978 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4990 * Ext JS Library 1.1.1
4991 * Copyright(c) 2006-2007, Ext JS, LLC.
4993 * Originally Released Under LGPL - original licence link has changed is not relivant.
4996 * <script type="text/javascript">
5001 * @class Roo.grid.ColumnModel
5002 * @extends Roo.util.Observable
5003 * This is the default implementation of a ColumnModel used by the Grid. It defines
5004 * the columns in the grid.
5007 var colModel = new Roo.grid.ColumnModel([
5008 {header: "Ticker", width: 60, sortable: true, locked: true},
5009 {header: "Company Name", width: 150, sortable: true},
5010 {header: "Market Cap.", width: 100, sortable: true},
5011 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5012 {header: "Employees", width: 100, sortable: true, resizable: false}
5017 * The config options listed for this class are options which may appear in each
5018 * individual column definition.
5019 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5021 * @param {Object} config An Array of column config objects. See this class's
5022 * config objects for details.
5024 Roo.grid.ColumnModel = function(config){
5026 * The config passed into the constructor
5028 this.config = config;
5031 // if no id, create one
5032 // if the column does not have a dataIndex mapping,
5033 // map it to the order it is in the config
5034 for(var i = 0, len = config.length; i < len; i++){
5036 if(typeof c.dataIndex == "undefined"){
5039 if(typeof c.renderer == "string"){
5040 c.renderer = Roo.util.Format[c.renderer];
5042 if(typeof c.id == "undefined"){
5045 if(c.editor && c.editor.xtype){
5046 c.editor = Roo.factory(c.editor, Roo.grid);
5048 if(c.editor && c.editor.isFormField){
5049 c.editor = new Roo.grid.GridEditor(c.editor);
5051 this.lookup[c.id] = c;
5055 * The width of columns which have no width specified (defaults to 100)
5058 this.defaultWidth = 100;
5061 * Default sortable of columns which have no sortable specified (defaults to false)
5064 this.defaultSortable = false;
5068 * @event widthchange
5069 * Fires when the width of a column changes.
5070 * @param {ColumnModel} this
5071 * @param {Number} columnIndex The column index
5072 * @param {Number} newWidth The new width
5074 "widthchange": true,
5076 * @event headerchange
5077 * Fires when the text of a header changes.
5078 * @param {ColumnModel} this
5079 * @param {Number} columnIndex The column index
5080 * @param {Number} newText The new header text
5082 "headerchange": true,
5084 * @event hiddenchange
5085 * Fires when a column is hidden or "unhidden".
5086 * @param {ColumnModel} this
5087 * @param {Number} columnIndex The column index
5088 * @param {Boolean} hidden true if hidden, false otherwise
5090 "hiddenchange": true,
5092 * @event columnmoved
5093 * Fires when a column is moved.
5094 * @param {ColumnModel} this
5095 * @param {Number} oldIndex
5096 * @param {Number} newIndex
5098 "columnmoved" : true,
5100 * @event columlockchange
5101 * Fires when a column's locked state is changed
5102 * @param {ColumnModel} this
5103 * @param {Number} colIndex
5104 * @param {Boolean} locked true if locked
5106 "columnlockchange" : true
5108 Roo.grid.ColumnModel.superclass.constructor.call(this);
5110 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5112 * @cfg {String} header The header text to display in the Grid view.
5115 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5116 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5117 * specified, the column's index is used as an index into the Record's data Array.
5120 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5121 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5124 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5125 * Defaults to the value of the {@link #defaultSortable} property.
5126 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5129 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5132 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5135 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5138 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5141 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5142 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5143 * default renderer uses the raw data value. If an object is returned (bootstrap only)
5144 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5147 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5150 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5153 * @cfg {String} cursor (Optional)
5156 * @cfg {String} tooltip (Optional)
5159 * @cfg {Number} xs (Optional)
5162 * @cfg {Number} sm (Optional)
5165 * @cfg {Number} md (Optional)
5168 * @cfg {Number} lg (Optional)
5171 * Returns the id of the column at the specified index.
5172 * @param {Number} index The column index
5173 * @return {String} the id
5175 getColumnId : function(index){
5176 return this.config[index].id;
5180 * Returns the column for a specified id.
5181 * @param {String} id The column id
5182 * @return {Object} the column
5184 getColumnById : function(id){
5185 return this.lookup[id];
5190 * Returns the column for a specified dataIndex.
5191 * @param {String} dataIndex The column dataIndex
5192 * @return {Object|Boolean} the column or false if not found
5194 getColumnByDataIndex: function(dataIndex){
5195 var index = this.findColumnIndex(dataIndex);
5196 return index > -1 ? this.config[index] : false;
5200 * Returns the index for a specified column id.
5201 * @param {String} id The column id
5202 * @return {Number} the index, or -1 if not found
5204 getIndexById : function(id){
5205 for(var i = 0, len = this.config.length; i < len; i++){
5206 if(this.config[i].id == id){
5214 * Returns the index for a specified column dataIndex.
5215 * @param {String} dataIndex The column dataIndex
5216 * @return {Number} the index, or -1 if not found
5219 findColumnIndex : function(dataIndex){
5220 for(var i = 0, len = this.config.length; i < len; i++){
5221 if(this.config[i].dataIndex == dataIndex){
5229 moveColumn : function(oldIndex, newIndex){
5230 var c = this.config[oldIndex];
5231 this.config.splice(oldIndex, 1);
5232 this.config.splice(newIndex, 0, c);
5233 this.dataMap = null;
5234 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5237 isLocked : function(colIndex){
5238 return this.config[colIndex].locked === true;
5241 setLocked : function(colIndex, value, suppressEvent){
5242 if(this.isLocked(colIndex) == value){
5245 this.config[colIndex].locked = value;
5247 this.fireEvent("columnlockchange", this, colIndex, value);
5251 getTotalLockedWidth : function(){
5253 for(var i = 0; i < this.config.length; i++){
5254 if(this.isLocked(i) && !this.isHidden(i)){
5255 this.totalWidth += this.getColumnWidth(i);
5261 getLockedCount : function(){
5262 for(var i = 0, len = this.config.length; i < len; i++){
5263 if(!this.isLocked(i)){
5268 return this.config.length;
5272 * Returns the number of columns.
5275 getColumnCount : function(visibleOnly){
5276 if(visibleOnly === true){
5278 for(var i = 0, len = this.config.length; i < len; i++){
5279 if(!this.isHidden(i)){
5285 return this.config.length;
5289 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5290 * @param {Function} fn
5291 * @param {Object} scope (optional)
5292 * @return {Array} result
5294 getColumnsBy : function(fn, scope){
5296 for(var i = 0, len = this.config.length; i < len; i++){
5297 var c = this.config[i];
5298 if(fn.call(scope||this, c, i) === true){
5306 * Returns true if the specified column is sortable.
5307 * @param {Number} col The column index
5310 isSortable : function(col){
5311 if(typeof this.config[col].sortable == "undefined"){
5312 return this.defaultSortable;
5314 return this.config[col].sortable;
5318 * Returns the rendering (formatting) function defined for the column.
5319 * @param {Number} col The column index.
5320 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5322 getRenderer : function(col){
5323 if(!this.config[col].renderer){
5324 return Roo.grid.ColumnModel.defaultRenderer;
5326 return this.config[col].renderer;
5330 * Sets the rendering (formatting) function for a column.
5331 * @param {Number} col The column index
5332 * @param {Function} fn The function to use to process the cell's raw data
5333 * to return HTML markup for the grid view. The render function is called with
5334 * the following parameters:<ul>
5335 * <li>Data value.</li>
5336 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5337 * <li>css A CSS style string to apply to the table cell.</li>
5338 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5339 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5340 * <li>Row index</li>
5341 * <li>Column index</li>
5342 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5344 setRenderer : function(col, fn){
5345 this.config[col].renderer = fn;
5349 * Returns the width for the specified column.
5350 * @param {Number} col The column index
5353 getColumnWidth : function(col){
5354 return this.config[col].width * 1 || this.defaultWidth;
5358 * Sets the width for a column.
5359 * @param {Number} col The column index
5360 * @param {Number} width The new width
5362 setColumnWidth : function(col, width, suppressEvent){
5363 this.config[col].width = width;
5364 this.totalWidth = null;
5366 this.fireEvent("widthchange", this, col, width);
5371 * Returns the total width of all columns.
5372 * @param {Boolean} includeHidden True to include hidden column widths
5375 getTotalWidth : function(includeHidden){
5376 if(!this.totalWidth){
5377 this.totalWidth = 0;
5378 for(var i = 0, len = this.config.length; i < len; i++){
5379 if(includeHidden || !this.isHidden(i)){
5380 this.totalWidth += this.getColumnWidth(i);
5384 return this.totalWidth;
5388 * Returns the header for the specified column.
5389 * @param {Number} col The column index
5392 getColumnHeader : function(col){
5393 return this.config[col].header;
5397 * Sets the header for a column.
5398 * @param {Number} col The column index
5399 * @param {String} header The new header
5401 setColumnHeader : function(col, header){
5402 this.config[col].header = header;
5403 this.fireEvent("headerchange", this, col, header);
5407 * Returns the tooltip for the specified column.
5408 * @param {Number} col The column index
5411 getColumnTooltip : function(col){
5412 return this.config[col].tooltip;
5415 * Sets the tooltip for a column.
5416 * @param {Number} col The column index
5417 * @param {String} tooltip The new tooltip
5419 setColumnTooltip : function(col, tooltip){
5420 this.config[col].tooltip = tooltip;
5424 * Returns the dataIndex for the specified column.
5425 * @param {Number} col The column index
5428 getDataIndex : function(col){
5429 return this.config[col].dataIndex;
5433 * Sets the dataIndex for a column.
5434 * @param {Number} col The column index
5435 * @param {Number} dataIndex The new dataIndex
5437 setDataIndex : function(col, dataIndex){
5438 this.config[col].dataIndex = dataIndex;
5444 * Returns true if the cell is editable.
5445 * @param {Number} colIndex The column index
5446 * @param {Number} rowIndex The row index - this is nto actually used..?
5449 isCellEditable : function(colIndex, rowIndex){
5450 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5454 * Returns the editor defined for the cell/column.
5455 * return false or null to disable editing.
5456 * @param {Number} colIndex The column index
5457 * @param {Number} rowIndex The row index
5460 getCellEditor : function(colIndex, rowIndex){
5461 return this.config[colIndex].editor;
5465 * Sets if a column is editable.
5466 * @param {Number} col The column index
5467 * @param {Boolean} editable True if the column is editable
5469 setEditable : function(col, editable){
5470 this.config[col].editable = editable;
5475 * Returns true if the column is hidden.
5476 * @param {Number} colIndex The column index
5479 isHidden : function(colIndex){
5480 return this.config[colIndex].hidden;
5485 * Returns true if the column width cannot be changed
5487 isFixed : function(colIndex){
5488 return this.config[colIndex].fixed;
5492 * Returns true if the column can be resized
5495 isResizable : function(colIndex){
5496 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5499 * Sets if a column is hidden.
5500 * @param {Number} colIndex The column index
5501 * @param {Boolean} hidden True if the column is hidden
5503 setHidden : function(colIndex, hidden){
5504 this.config[colIndex].hidden = hidden;
5505 this.totalWidth = null;
5506 this.fireEvent("hiddenchange", this, colIndex, hidden);
5510 * Sets the editor for a column.
5511 * @param {Number} col The column index
5512 * @param {Object} editor The editor object
5514 setEditor : function(col, editor){
5515 this.config[col].editor = editor;
5519 Roo.grid.ColumnModel.defaultRenderer = function(value){
5520 if(typeof value == "string" && value.length < 1){
5526 // Alias for backwards compatibility
5527 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5530 * Ext JS Library 1.1.1
5531 * Copyright(c) 2006-2007, Ext JS, LLC.
5533 * Originally Released Under LGPL - original licence link has changed is not relivant.
5536 * <script type="text/javascript">
5540 * @class Roo.LoadMask
5541 * A simple utility class for generically masking elements while loading data. If the element being masked has
5542 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5543 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5544 * element's UpdateManager load indicator and will be destroyed after the initial load.
5546 * Create a new LoadMask
5547 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5548 * @param {Object} config The config object
5550 Roo.LoadMask = function(el, config){
5551 this.el = Roo.get(el);
5552 Roo.apply(this, config);
5554 this.store.on('beforeload', this.onBeforeLoad, this);
5555 this.store.on('load', this.onLoad, this);
5556 this.store.on('loadexception', this.onLoadException, this);
5557 this.removeMask = false;
5559 var um = this.el.getUpdateManager();
5560 um.showLoadIndicator = false; // disable the default indicator
5561 um.on('beforeupdate', this.onBeforeLoad, this);
5562 um.on('update', this.onLoad, this);
5563 um.on('failure', this.onLoad, this);
5564 this.removeMask = true;
5568 Roo.LoadMask.prototype = {
5570 * @cfg {Boolean} removeMask
5571 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5572 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5576 * The text to display in a centered loading message box (defaults to 'Loading...')
5580 * @cfg {String} msgCls
5581 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5583 msgCls : 'x-mask-loading',
5586 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5592 * Disables the mask to prevent it from being displayed
5594 disable : function(){
5595 this.disabled = true;
5599 * Enables the mask so that it can be displayed
5601 enable : function(){
5602 this.disabled = false;
5605 onLoadException : function()
5609 if (typeof(arguments[3]) != 'undefined') {
5610 Roo.MessageBox.alert("Error loading",arguments[3]);
5614 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5615 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5624 this.el.unmask(this.removeMask);
5629 this.el.unmask(this.removeMask);
5633 onBeforeLoad : function(){
5635 this.el.mask(this.msg, this.msgCls);
5640 destroy : function(){
5642 this.store.un('beforeload', this.onBeforeLoad, this);
5643 this.store.un('load', this.onLoad, this);
5644 this.store.un('loadexception', this.onLoadException, this);
5646 var um = this.el.getUpdateManager();
5647 um.un('beforeupdate', this.onBeforeLoad, this);
5648 um.un('update', this.onLoad, this);
5649 um.un('failure', this.onLoad, this);
5660 * @class Roo.bootstrap.Table
5661 * @extends Roo.bootstrap.Component
5662 * Bootstrap Table class
5663 * @cfg {String} cls table class
5664 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5665 * @cfg {String} bgcolor Specifies the background color for a table
5666 * @cfg {Number} border Specifies whether the table cells should have borders or not
5667 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5668 * @cfg {Number} cellspacing Specifies the space between cells
5669 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5670 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5671 * @cfg {String} sortable Specifies that the table should be sortable
5672 * @cfg {String} summary Specifies a summary of the content of a table
5673 * @cfg {Number} width Specifies the width of a table
5674 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5676 * @cfg {boolean} striped Should the rows be alternative striped
5677 * @cfg {boolean} bordered Add borders to the table
5678 * @cfg {boolean} hover Add hover highlighting
5679 * @cfg {boolean} condensed Format condensed
5680 * @cfg {boolean} responsive Format condensed
5681 * @cfg {Boolean} loadMask (true|false) default false
5682 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5683 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5684 * @cfg {Boolean} rowSelection (true|false) default false
5685 * @cfg {Boolean} cellSelection (true|false) default false
5686 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5687 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5691 * Create a new Table
5692 * @param {Object} config The config object
5695 Roo.bootstrap.Table = function(config){
5696 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5701 this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
5702 this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
5703 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5704 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5708 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5709 this.sm = this.selModel;
5710 this.sm.xmodule = this.xmodule || false;
5712 if (this.cm && typeof(this.cm.config) == 'undefined') {
5713 this.colModel = new Roo.grid.ColumnModel(this.cm);
5714 this.cm = this.colModel;
5715 this.cm.xmodule = this.xmodule || false;
5718 this.store= Roo.factory(this.store, Roo.data);
5719 this.ds = this.store;
5720 this.ds.xmodule = this.xmodule || false;
5723 if (this.footer && this.store) {
5724 this.footer.dataSource = this.ds;
5725 this.footer = Roo.factory(this.footer);
5732 * Fires when a cell is clicked
5733 * @param {Roo.bootstrap.Table} this
5734 * @param {Roo.Element} el
5735 * @param {Number} rowIndex
5736 * @param {Number} columnIndex
5737 * @param {Roo.EventObject} e
5741 * @event celldblclick
5742 * Fires when a cell is double clicked
5743 * @param {Roo.bootstrap.Table} this
5744 * @param {Roo.Element} el
5745 * @param {Number} rowIndex
5746 * @param {Number} columnIndex
5747 * @param {Roo.EventObject} e
5749 "celldblclick" : true,
5752 * Fires when a row is clicked
5753 * @param {Roo.bootstrap.Table} this
5754 * @param {Roo.Element} el
5755 * @param {Number} rowIndex
5756 * @param {Roo.EventObject} e
5760 * @event rowdblclick
5761 * Fires when a row is double clicked
5762 * @param {Roo.bootstrap.Table} this
5763 * @param {Roo.Element} el
5764 * @param {Number} rowIndex
5765 * @param {Roo.EventObject} e
5767 "rowdblclick" : true,
5770 * Fires when a mouseover occur
5771 * @param {Roo.bootstrap.Table} this
5772 * @param {Roo.Element} el
5773 * @param {Number} rowIndex
5774 * @param {Number} columnIndex
5775 * @param {Roo.EventObject} e
5780 * Fires when a mouseout occur
5781 * @param {Roo.bootstrap.Table} this
5782 * @param {Roo.Element} el
5783 * @param {Number} rowIndex
5784 * @param {Number} columnIndex
5785 * @param {Roo.EventObject} e
5790 * Fires when a row is rendered, so you can change add a style to it.
5791 * @param {Roo.bootstrap.Table} this
5792 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5796 * @event rowsrendered
5797 * Fires when all the rows have been rendered
5798 * @param {Roo.bootstrap.Table} this
5800 'rowsrendered' : true,
5802 * @event contextmenu
5803 * The raw contextmenu event for the entire grid.
5804 * @param {Roo.EventObject} e
5806 "contextmenu" : true,
5808 * @event rowcontextmenu
5809 * Fires when a row is right clicked
5810 * @param {Roo.bootstrap.Table} this
5811 * @param {Number} rowIndex
5812 * @param {Roo.EventObject} e
5814 "rowcontextmenu" : true,
5816 * @event cellcontextmenu
5817 * Fires when a cell is right clicked
5818 * @param {Roo.bootstrap.Table} this
5819 * @param {Number} rowIndex
5820 * @param {Number} cellIndex
5821 * @param {Roo.EventObject} e
5823 "cellcontextmenu" : true,
5825 * @event headercontextmenu
5826 * Fires when a header is right clicked
5827 * @param {Roo.bootstrap.Table} this
5828 * @param {Number} columnIndex
5829 * @param {Roo.EventObject} e
5831 "headercontextmenu" : true
5835 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5861 rowSelection : false,
5862 cellSelection : false,
5865 // Roo.Element - the tbody
5867 // Roo.Element - thead element
5870 container: false, // used by gridpanel...
5872 getAutoCreate : function()
5874 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5881 if (this.scrollBody) {
5882 cfg.cls += ' table-body-fixed';
5885 cfg.cls += ' table-striped';
5889 cfg.cls += ' table-hover';
5891 if (this.bordered) {
5892 cfg.cls += ' table-bordered';
5894 if (this.condensed) {
5895 cfg.cls += ' table-condensed';
5897 if (this.responsive) {
5898 cfg.cls += ' table-responsive';
5902 cfg.cls+= ' ' +this.cls;
5905 // this lot should be simplifed...
5908 cfg.align=this.align;
5911 cfg.bgcolor=this.bgcolor;
5914 cfg.border=this.border;
5916 if (this.cellpadding) {
5917 cfg.cellpadding=this.cellpadding;
5919 if (this.cellspacing) {
5920 cfg.cellspacing=this.cellspacing;
5923 cfg.frame=this.frame;
5926 cfg.rules=this.rules;
5928 if (this.sortable) {
5929 cfg.sortable=this.sortable;
5932 cfg.summary=this.summary;
5935 cfg.width=this.width;
5938 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5941 if(this.store || this.cm){
5942 if(this.headerShow){
5943 cfg.cn.push(this.renderHeader());
5946 cfg.cn.push(this.renderBody());
5948 if(this.footerShow){
5949 cfg.cn.push(this.renderFooter());
5951 // where does this come from?
5952 //cfg.cls+= ' TableGrid';
5955 return { cn : [ cfg ] };
5958 initEvents : function()
5960 if(!this.store || !this.cm){
5964 //Roo.log('initEvents with ds!!!!');
5966 this.mainBody = this.el.select('tbody', true).first();
5967 this.mainHead = this.el.select('thead', true).first();
5973 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5974 e.on('click', _this.sort, _this);
5977 this.el.on("click", this.onClick, this);
5978 this.el.on("dblclick", this.onDblClick, this);
5980 // why is this done????? = it breaks dialogs??
5981 //this.parent().el.setStyle('position', 'relative');
5985 this.footer.parentId = this.id;
5986 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5989 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5991 this.store.on('load', this.onLoad, this);
5992 this.store.on('beforeload', this.onBeforeLoad, this);
5993 this.store.on('update', this.onUpdate, this);
5994 this.store.on('add', this.onAdd, this);
5996 this.el.on("contextmenu", this.onContextMenu, this);
5998 this.mainBody.on('scroll', this.onBodyScroll, this);
6003 onContextMenu : function(e, t)
6005 this.processEvent("contextmenu", e);
6008 processEvent : function(name, e)
6010 if (name != 'touchstart' ) {
6011 this.fireEvent(name, e);
6014 var t = e.getTarget();
6016 var cell = Roo.get(t);
6022 if(cell.findParent('tfoot', false, true)){
6026 if(cell.findParent('thead', false, true)){
6028 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6029 cell = Roo.get(t).findParent('th', false, true);
6031 Roo.log("failed to find th in thead?");
6032 Roo.log(e.getTarget());
6037 var cellIndex = cell.dom.cellIndex;
6039 var ename = name == 'touchstart' ? 'click' : name;
6040 this.fireEvent("header" + ename, this, cellIndex, e);
6045 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6046 cell = Roo.get(t).findParent('td', false, true);
6048 Roo.log("failed to find th in tbody?");
6049 Roo.log(e.getTarget());
6054 var row = cell.findParent('tr', false, true);
6055 var cellIndex = cell.dom.cellIndex;
6056 var rowIndex = row.dom.rowIndex - 1;
6060 this.fireEvent("row" + name, this, rowIndex, e);
6064 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6070 onMouseover : function(e, el)
6072 var cell = Roo.get(el);
6078 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6079 cell = cell.findParent('td', false, true);
6082 var row = cell.findParent('tr', false, true);
6083 var cellIndex = cell.dom.cellIndex;
6084 var rowIndex = row.dom.rowIndex - 1; // start from 0
6086 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6090 onMouseout : function(e, el)
6092 var cell = Roo.get(el);
6098 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6099 cell = cell.findParent('td', false, true);
6102 var row = cell.findParent('tr', false, true);
6103 var cellIndex = cell.dom.cellIndex;
6104 var rowIndex = row.dom.rowIndex - 1; // start from 0
6106 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6110 onClick : function(e, el)
6112 var cell = Roo.get(el);
6114 if(!cell || (!this.cellSelection && !this.rowSelection)){
6118 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6119 cell = cell.findParent('td', false, true);
6122 if(!cell || typeof(cell) == 'undefined'){
6126 var row = cell.findParent('tr', false, true);
6128 if(!row || typeof(row) == 'undefined'){
6132 var cellIndex = cell.dom.cellIndex;
6133 var rowIndex = this.getRowIndex(row);
6135 // why??? - should these not be based on SelectionModel?
6136 if(this.cellSelection){
6137 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6140 if(this.rowSelection){
6141 this.fireEvent('rowclick', this, row, rowIndex, e);
6147 onDblClick : function(e,el)
6149 var cell = Roo.get(el);
6151 if(!cell || (!this.CellSelection && !this.RowSelection)){
6155 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6156 cell = cell.findParent('td', false, true);
6159 if(!cell || typeof(cell) == 'undefined'){
6163 var row = cell.findParent('tr', false, true);
6165 if(!row || typeof(row) == 'undefined'){
6169 var cellIndex = cell.dom.cellIndex;
6170 var rowIndex = this.getRowIndex(row);
6172 if(this.CellSelection){
6173 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6176 if(this.RowSelection){
6177 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6181 sort : function(e,el)
6183 var col = Roo.get(el);
6185 if(!col.hasClass('sortable')){
6189 var sort = col.attr('sort');
6192 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6196 this.store.sortInfo = {field : sort, direction : dir};
6199 Roo.log("calling footer first");
6200 this.footer.onClick('first');
6203 this.store.load({ params : { start : 0 } });
6207 renderHeader : function()
6215 this.totalWidth = 0;
6217 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6219 var config = cm.config[i];
6224 html: cm.getColumnHeader(i)
6229 if(typeof(config.sortable) != 'undefined' && config.sortable){
6231 c.html = '<i class="glyphicon"></i>' + c.html;
6234 if(typeof(config.lgHeader) != 'undefined'){
6235 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6238 if(typeof(config.mdHeader) != 'undefined'){
6239 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6242 if(typeof(config.smHeader) != 'undefined'){
6243 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6246 if(typeof(config.xsHeader) != 'undefined'){
6247 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6254 if(typeof(config.tooltip) != 'undefined'){
6255 c.tooltip = config.tooltip;
6258 if(typeof(config.colspan) != 'undefined'){
6259 c.colspan = config.colspan;
6262 if(typeof(config.hidden) != 'undefined' && config.hidden){
6263 c.style += ' display:none;';
6266 if(typeof(config.dataIndex) != 'undefined'){
6267 c.sort = config.dataIndex;
6272 if(typeof(config.align) != 'undefined' && config.align.length){
6273 c.style += ' text-align:' + config.align + ';';
6276 if(typeof(config.width) != 'undefined'){
6277 c.style += ' width:' + config.width + 'px;';
6278 this.totalWidth += config.width;
6280 this.totalWidth += 100; // assume minimum of 100 per column?
6283 if(typeof(config.cls) != 'undefined'){
6284 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6287 ['xs','sm','md','lg'].map(function(size){
6289 if(typeof(config[size]) == 'undefined'){
6293 if (!config[size]) { // 0 = hidden
6294 c.cls += ' hidden-' + size;
6298 c.cls += ' col-' + size + '-' + config[size];
6308 renderBody : function()
6318 colspan : this.cm.getColumnCount()
6328 renderFooter : function()
6338 colspan : this.cm.getColumnCount()
6352 // Roo.log('ds onload');
6357 var ds = this.store;
6359 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6360 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6361 if (_this.store.sortInfo) {
6363 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6364 e.select('i', true).addClass(['glyphicon-arrow-up']);
6367 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6368 e.select('i', true).addClass(['glyphicon-arrow-down']);
6373 var tbody = this.mainBody;
6375 if(ds.getCount() > 0){
6376 ds.data.each(function(d,rowIndex){
6377 var row = this.renderRow(cm, ds, rowIndex);
6379 tbody.createChild(row);
6383 if(row.cellObjects.length){
6384 Roo.each(row.cellObjects, function(r){
6385 _this.renderCellObject(r);
6392 Roo.each(this.el.select('tbody td', true).elements, function(e){
6393 e.on('mouseover', _this.onMouseover, _this);
6396 Roo.each(this.el.select('tbody td', true).elements, function(e){
6397 e.on('mouseout', _this.onMouseout, _this);
6399 this.fireEvent('rowsrendered', this);
6400 //if(this.loadMask){
6401 // this.maskEl.hide();
6408 onUpdate : function(ds,record)
6410 this.refreshRow(record);
6413 onRemove : function(ds, record, index, isUpdate){
6414 if(isUpdate !== true){
6415 this.fireEvent("beforerowremoved", this, index, record);
6417 var bt = this.mainBody.dom;
6419 var rows = this.el.select('tbody > tr', true).elements;
6421 if(typeof(rows[index]) != 'undefined'){
6422 bt.removeChild(rows[index].dom);
6425 // if(bt.rows[index]){
6426 // bt.removeChild(bt.rows[index]);
6429 if(isUpdate !== true){
6430 //this.stripeRows(index);
6431 //this.syncRowHeights(index, index);
6433 this.fireEvent("rowremoved", this, index, record);
6437 onAdd : function(ds, records, rowIndex)
6439 //Roo.log('on Add called');
6440 // - note this does not handle multiple adding very well..
6441 var bt = this.mainBody.dom;
6442 for (var i =0 ; i < records.length;i++) {
6443 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6444 //Roo.log(records[i]);
6445 //Roo.log(this.store.getAt(rowIndex+i));
6446 this.insertRow(this.store, rowIndex + i, false);
6453 refreshRow : function(record){
6454 var ds = this.store, index;
6455 if(typeof record == 'number'){
6457 record = ds.getAt(index);
6459 index = ds.indexOf(record);
6461 this.insertRow(ds, index, true);
6462 this.onRemove(ds, record, index+1, true);
6463 //this.syncRowHeights(index, index);
6465 this.fireEvent("rowupdated", this, index, record);
6468 insertRow : function(dm, rowIndex, isUpdate){
6471 this.fireEvent("beforerowsinserted", this, rowIndex);
6473 //var s = this.getScrollState();
6474 var row = this.renderRow(this.cm, this.store, rowIndex);
6475 // insert before rowIndex..
6476 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6480 if(row.cellObjects.length){
6481 Roo.each(row.cellObjects, function(r){
6482 _this.renderCellObject(r);
6487 this.fireEvent("rowsinserted", this, rowIndex);
6488 //this.syncRowHeights(firstRow, lastRow);
6489 //this.stripeRows(firstRow);
6496 getRowDom : function(rowIndex)
6498 var rows = this.el.select('tbody > tr', true).elements;
6500 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6503 // returns the object tree for a tr..
6506 renderRow : function(cm, ds, rowIndex)
6509 var d = ds.getAt(rowIndex);
6516 var cellObjects = [];
6518 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6519 var config = cm.config[i];
6521 var renderer = cm.getRenderer(i);
6525 if(typeof(renderer) !== 'undefined'){
6526 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6528 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6529 // and are rendered into the cells after the row is rendered - using the id for the element.
6531 if(typeof(value) === 'object'){
6541 rowIndex : rowIndex,
6546 this.fireEvent('rowclass', this, rowcfg);
6550 cls : rowcfg.rowClass,
6552 html: (typeof(value) === 'object') ? '' : value
6559 if(typeof(config.colspan) != 'undefined'){
6560 td.colspan = config.colspan;
6563 if(typeof(config.hidden) != 'undefined' && config.hidden){
6564 td.style += ' display:none;';
6567 if(typeof(config.align) != 'undefined' && config.align.length){
6568 td.style += ' text-align:' + config.align + ';';
6571 if(typeof(config.width) != 'undefined'){
6572 td.style += ' width:' + config.width + 'px;';
6575 if(typeof(config.cursor) != 'undefined'){
6576 td.style += ' cursor:' + config.cursor + ';';
6579 if(typeof(config.cls) != 'undefined'){
6580 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6583 ['xs','sm','md','lg'].map(function(size){
6585 if(typeof(config[size]) == 'undefined'){
6589 if (!config[size]) { // 0 = hidden
6590 td.cls += ' hidden-' + size;
6594 td.cls += ' col-' + size + '-' + config[size];
6602 row.cellObjects = cellObjects;
6610 onBeforeLoad : function()
6612 //Roo.log('ds onBeforeLoad');
6616 //if(this.loadMask){
6617 // this.maskEl.show();
6625 this.el.select('tbody', true).first().dom.innerHTML = '';
6628 * Show or hide a row.
6629 * @param {Number} rowIndex to show or hide
6630 * @param {Boolean} state hide
6632 setRowVisibility : function(rowIndex, state)
6634 var bt = this.mainBody.dom;
6636 var rows = this.el.select('tbody > tr', true).elements;
6638 if(typeof(rows[rowIndex]) == 'undefined'){
6641 rows[rowIndex].dom.style.display = state ? '' : 'none';
6645 getSelectionModel : function(){
6647 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6649 return this.selModel;
6652 * Render the Roo.bootstrap object from renderder
6654 renderCellObject : function(r)
6658 var t = r.cfg.render(r.container);
6661 Roo.each(r.cfg.cn, function(c){
6663 container: t.getChildContainer(),
6666 _this.renderCellObject(child);
6671 getRowIndex : function(row)
6675 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6686 * Returns the grid's underlying element = used by panel.Grid
6687 * @return {Element} The element
6689 getGridEl : function(){
6693 * Forces a resize - used by panel.Grid
6694 * @return {Element} The element
6696 autoSize : function(){
6697 //var ctr = Roo.get(this.container.dom.parentElement);
6698 var ctr = Roo.get(this.el.dom);
6700 var thd = this.getGridEl().select('thead',true).first();
6701 var tbd = this.getGridEl().select('tbody', true).first();
6704 var cw = ctr.getWidth();
6708 tbd.setSize(ctr.getWidth(), ctr.getHeight() - thd.getHeight());
6709 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6712 cw = Math.max(cw, this.totalWidth);
6713 this.getGridEl().select('tr',true).setWidth(cw);
6715 return; // we doe not have a view in this design..
6718 onBodyScroll: function()
6721 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6722 this.mainHead.setStyle({
6723 'position' : 'relative',
6724 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6741 * @class Roo.bootstrap.TableCell
6742 * @extends Roo.bootstrap.Component
6743 * Bootstrap TableCell class
6744 * @cfg {String} html cell contain text
6745 * @cfg {String} cls cell class
6746 * @cfg {String} tag cell tag (td|th) default td
6747 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6748 * @cfg {String} align Aligns the content in a cell
6749 * @cfg {String} axis Categorizes cells
6750 * @cfg {String} bgcolor Specifies the background color of a cell
6751 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6752 * @cfg {Number} colspan Specifies the number of columns a cell should span
6753 * @cfg {String} headers Specifies one or more header cells a cell is related to
6754 * @cfg {Number} height Sets the height of a cell
6755 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6756 * @cfg {Number} rowspan Sets the number of rows a cell should span
6757 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6758 * @cfg {String} valign Vertical aligns the content in a cell
6759 * @cfg {Number} width Specifies the width of a cell
6762 * Create a new TableCell
6763 * @param {Object} config The config object
6766 Roo.bootstrap.TableCell = function(config){
6767 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6770 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6790 getAutoCreate : function(){
6791 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6811 cfg.align=this.align
6817 cfg.bgcolor=this.bgcolor
6820 cfg.charoff=this.charoff
6823 cfg.colspan=this.colspan
6826 cfg.headers=this.headers
6829 cfg.height=this.height
6832 cfg.nowrap=this.nowrap
6835 cfg.rowspan=this.rowspan
6838 cfg.scope=this.scope
6841 cfg.valign=this.valign
6844 cfg.width=this.width
6863 * @class Roo.bootstrap.TableRow
6864 * @extends Roo.bootstrap.Component
6865 * Bootstrap TableRow class
6866 * @cfg {String} cls row class
6867 * @cfg {String} align Aligns the content in a table row
6868 * @cfg {String} bgcolor Specifies a background color for a table row
6869 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6870 * @cfg {String} valign Vertical aligns the content in a table row
6873 * Create a new TableRow
6874 * @param {Object} config The config object
6877 Roo.bootstrap.TableRow = function(config){
6878 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6881 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6889 getAutoCreate : function(){
6890 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6900 cfg.align = this.align;
6903 cfg.bgcolor = this.bgcolor;
6906 cfg.charoff = this.charoff;
6909 cfg.valign = this.valign;
6927 * @class Roo.bootstrap.TableBody
6928 * @extends Roo.bootstrap.Component
6929 * Bootstrap TableBody class
6930 * @cfg {String} cls element class
6931 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6932 * @cfg {String} align Aligns the content inside the element
6933 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6934 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6937 * Create a new TableBody
6938 * @param {Object} config The config object
6941 Roo.bootstrap.TableBody = function(config){
6942 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6945 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6968 cfg.align = this.align;
6971 cfg.charoff = this.charoff;
6974 cfg.valign = this.valign;
6981 // initEvents : function()
6988 // this.store = Roo.factory(this.store, Roo.data);
6989 // this.store.on('load', this.onLoad, this);
6991 // this.store.load();
6995 // onLoad: function ()
6997 // this.fireEvent('load', this);
7007 * Ext JS Library 1.1.1
7008 * Copyright(c) 2006-2007, Ext JS, LLC.
7010 * Originally Released Under LGPL - original licence link has changed is not relivant.
7013 * <script type="text/javascript">
7016 // as we use this in bootstrap.
7017 Roo.namespace('Roo.form');
7019 * @class Roo.form.Action
7020 * Internal Class used to handle form actions
7022 * @param {Roo.form.BasicForm} el The form element or its id
7023 * @param {Object} config Configuration options
7028 // define the action interface
7029 Roo.form.Action = function(form, options){
7031 this.options = options || {};
7034 * Client Validation Failed
7037 Roo.form.Action.CLIENT_INVALID = 'client';
7039 * Server Validation Failed
7042 Roo.form.Action.SERVER_INVALID = 'server';
7044 * Connect to Server Failed
7047 Roo.form.Action.CONNECT_FAILURE = 'connect';
7049 * Reading Data from Server Failed
7052 Roo.form.Action.LOAD_FAILURE = 'load';
7054 Roo.form.Action.prototype = {
7056 failureType : undefined,
7057 response : undefined,
7061 run : function(options){
7066 success : function(response){
7071 handleResponse : function(response){
7075 // default connection failure
7076 failure : function(response){
7078 this.response = response;
7079 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7080 this.form.afterAction(this, false);
7083 processResponse : function(response){
7084 this.response = response;
7085 if(!response.responseText){
7088 this.result = this.handleResponse(response);
7092 // utility functions used internally
7093 getUrl : function(appendParams){
7094 var url = this.options.url || this.form.url || this.form.el.dom.action;
7096 var p = this.getParams();
7098 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7104 getMethod : function(){
7105 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7108 getParams : function(){
7109 var bp = this.form.baseParams;
7110 var p = this.options.params;
7112 if(typeof p == "object"){
7113 p = Roo.urlEncode(Roo.applyIf(p, bp));
7114 }else if(typeof p == 'string' && bp){
7115 p += '&' + Roo.urlEncode(bp);
7118 p = Roo.urlEncode(bp);
7123 createCallback : function(){
7125 success: this.success,
7126 failure: this.failure,
7128 timeout: (this.form.timeout*1000),
7129 upload: this.form.fileUpload ? this.success : undefined
7134 Roo.form.Action.Submit = function(form, options){
7135 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7138 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7141 haveProgress : false,
7142 uploadComplete : false,
7144 // uploadProgress indicator.
7145 uploadProgress : function()
7147 if (!this.form.progressUrl) {
7151 if (!this.haveProgress) {
7152 Roo.MessageBox.progress("Uploading", "Uploading");
7154 if (this.uploadComplete) {
7155 Roo.MessageBox.hide();
7159 this.haveProgress = true;
7161 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7163 var c = new Roo.data.Connection();
7165 url : this.form.progressUrl,
7170 success : function(req){
7171 //console.log(data);
7175 rdata = Roo.decode(req.responseText)
7177 Roo.log("Invalid data from server..");
7181 if (!rdata || !rdata.success) {
7183 Roo.MessageBox.alert(Roo.encode(rdata));
7186 var data = rdata.data;
7188 if (this.uploadComplete) {
7189 Roo.MessageBox.hide();
7194 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7195 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7198 this.uploadProgress.defer(2000,this);
7201 failure: function(data) {
7202 Roo.log('progress url failed ');
7213 // run get Values on the form, so it syncs any secondary forms.
7214 this.form.getValues();
7216 var o = this.options;
7217 var method = this.getMethod();
7218 var isPost = method == 'POST';
7219 if(o.clientValidation === false || this.form.isValid()){
7221 if (this.form.progressUrl) {
7222 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7223 (new Date() * 1) + '' + Math.random());
7228 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7229 form:this.form.el.dom,
7230 url:this.getUrl(!isPost),
7232 params:isPost ? this.getParams() : null,
7233 isUpload: this.form.fileUpload
7236 this.uploadProgress();
7238 }else if (o.clientValidation !== false){ // client validation failed
7239 this.failureType = Roo.form.Action.CLIENT_INVALID;
7240 this.form.afterAction(this, false);
7244 success : function(response)
7246 this.uploadComplete= true;
7247 if (this.haveProgress) {
7248 Roo.MessageBox.hide();
7252 var result = this.processResponse(response);
7253 if(result === true || result.success){
7254 this.form.afterAction(this, true);
7258 this.form.markInvalid(result.errors);
7259 this.failureType = Roo.form.Action.SERVER_INVALID;
7261 this.form.afterAction(this, false);
7263 failure : function(response)
7265 this.uploadComplete= true;
7266 if (this.haveProgress) {
7267 Roo.MessageBox.hide();
7270 this.response = response;
7271 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7272 this.form.afterAction(this, false);
7275 handleResponse : function(response){
7276 if(this.form.errorReader){
7277 var rs = this.form.errorReader.read(response);
7280 for(var i = 0, len = rs.records.length; i < len; i++) {
7281 var r = rs.records[i];
7285 if(errors.length < 1){
7289 success : rs.success,
7295 ret = Roo.decode(response.responseText);
7299 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7309 Roo.form.Action.Load = function(form, options){
7310 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7311 this.reader = this.form.reader;
7314 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7319 Roo.Ajax.request(Roo.apply(
7320 this.createCallback(), {
7321 method:this.getMethod(),
7322 url:this.getUrl(false),
7323 params:this.getParams()
7327 success : function(response){
7329 var result = this.processResponse(response);
7330 if(result === true || !result.success || !result.data){
7331 this.failureType = Roo.form.Action.LOAD_FAILURE;
7332 this.form.afterAction(this, false);
7335 this.form.clearInvalid();
7336 this.form.setValues(result.data);
7337 this.form.afterAction(this, true);
7340 handleResponse : function(response){
7341 if(this.form.reader){
7342 var rs = this.form.reader.read(response);
7343 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7345 success : rs.success,
7349 return Roo.decode(response.responseText);
7353 Roo.form.Action.ACTION_TYPES = {
7354 'load' : Roo.form.Action.Load,
7355 'submit' : Roo.form.Action.Submit
7364 * @class Roo.bootstrap.Form
7365 * @extends Roo.bootstrap.Component
7366 * Bootstrap Form class
7367 * @cfg {String} method GET | POST (default POST)
7368 * @cfg {String} labelAlign top | left (default top)
7369 * @cfg {String} align left | right - for navbars
7370 * @cfg {Boolean} loadMask load mask when submit (default true)
7375 * @param {Object} config The config object
7379 Roo.bootstrap.Form = function(config){
7380 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7383 * @event clientvalidation
7384 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7385 * @param {Form} this
7386 * @param {Boolean} valid true if the form has passed client-side validation
7388 clientvalidation: true,
7390 * @event beforeaction
7391 * Fires before any action is performed. Return false to cancel the action.
7392 * @param {Form} this
7393 * @param {Action} action The action to be performed
7397 * @event actionfailed
7398 * Fires when an action fails.
7399 * @param {Form} this
7400 * @param {Action} action The action that failed
7402 actionfailed : true,
7404 * @event actioncomplete
7405 * Fires when an action is completed.
7406 * @param {Form} this
7407 * @param {Action} action The action that completed
7409 actioncomplete : true
7414 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7417 * @cfg {String} method
7418 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7423 * The URL to use for form actions if one isn't supplied in the action options.
7426 * @cfg {Boolean} fileUpload
7427 * Set to true if this form is a file upload.
7431 * @cfg {Object} baseParams
7432 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7436 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7440 * @cfg {Sting} align (left|right) for navbar forms
7445 activeAction : null,
7448 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7449 * element by passing it or its id or mask the form itself by passing in true.
7452 waitMsgTarget : false,
7456 getAutoCreate : function(){
7460 method : this.method || 'POST',
7461 id : this.id || Roo.id(),
7464 if (this.parent().xtype.match(/^Nav/)) {
7465 cfg.cls = 'navbar-form navbar-' + this.align;
7469 if (this.labelAlign == 'left' ) {
7470 cfg.cls += ' form-horizontal';
7476 initEvents : function()
7478 this.el.on('submit', this.onSubmit, this);
7479 // this was added as random key presses on the form where triggering form submit.
7480 this.el.on('keypress', function(e) {
7481 if (e.getCharCode() != 13) {
7484 // we might need to allow it for textareas.. and some other items.
7485 // check e.getTarget().
7487 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7491 Roo.log("keypress blocked");
7499 onSubmit : function(e){
7504 * Returns true if client-side validation on the form is successful.
7507 isValid : function(){
7508 var items = this.getItems();
7510 items.each(function(f){
7519 * Returns true if any fields in this form have changed since their original load.
7522 isDirty : function(){
7524 var items = this.getItems();
7525 items.each(function(f){
7535 * Performs a predefined action (submit or load) or custom actions you define on this form.
7536 * @param {String} actionName The name of the action type
7537 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7538 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7539 * accept other config options):
7541 Property Type Description
7542 ---------------- --------------- ----------------------------------------------------------------------------------
7543 url String The url for the action (defaults to the form's url)
7544 method String The form method to use (defaults to the form's method, or POST if not defined)
7545 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7546 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7547 validate the form on the client (defaults to false)
7549 * @return {BasicForm} this
7551 doAction : function(action, options){
7552 if(typeof action == 'string'){
7553 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7555 if(this.fireEvent('beforeaction', this, action) !== false){
7556 this.beforeAction(action);
7557 action.run.defer(100, action);
7563 beforeAction : function(action){
7564 var o = action.options;
7567 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7569 // not really supported yet.. ??
7571 //if(this.waitMsgTarget === true){
7572 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7573 //}else if(this.waitMsgTarget){
7574 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7575 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7577 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7583 afterAction : function(action, success){
7584 this.activeAction = null;
7585 var o = action.options;
7587 //if(this.waitMsgTarget === true){
7589 //}else if(this.waitMsgTarget){
7590 // this.waitMsgTarget.unmask();
7592 // Roo.MessageBox.updateProgress(1);
7593 // Roo.MessageBox.hide();
7600 Roo.callback(o.success, o.scope, [this, action]);
7601 this.fireEvent('actioncomplete', this, action);
7605 // failure condition..
7606 // we have a scenario where updates need confirming.
7607 // eg. if a locking scenario exists..
7608 // we look for { errors : { needs_confirm : true }} in the response.
7610 (typeof(action.result) != 'undefined') &&
7611 (typeof(action.result.errors) != 'undefined') &&
7612 (typeof(action.result.errors.needs_confirm) != 'undefined')
7615 Roo.log("not supported yet");
7618 Roo.MessageBox.confirm(
7619 "Change requires confirmation",
7620 action.result.errorMsg,
7625 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7635 Roo.callback(o.failure, o.scope, [this, action]);
7636 // show an error message if no failed handler is set..
7637 if (!this.hasListener('actionfailed')) {
7638 Roo.log("need to add dialog support");
7640 Roo.MessageBox.alert("Error",
7641 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7642 action.result.errorMsg :
7643 "Saving Failed, please check your entries or try again"
7648 this.fireEvent('actionfailed', this, action);
7653 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7654 * @param {String} id The value to search for
7657 findField : function(id){
7658 var items = this.getItems();
7659 var field = items.get(id);
7661 items.each(function(f){
7662 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7669 return field || null;
7672 * Mark fields in this form invalid in bulk.
7673 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7674 * @return {BasicForm} this
7676 markInvalid : function(errors){
7677 if(errors instanceof Array){
7678 for(var i = 0, len = errors.length; i < len; i++){
7679 var fieldError = errors[i];
7680 var f = this.findField(fieldError.id);
7682 f.markInvalid(fieldError.msg);
7688 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7689 field.markInvalid(errors[id]);
7693 //Roo.each(this.childForms || [], function (f) {
7694 // f.markInvalid(errors);
7701 * Set values for fields in this form in bulk.
7702 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7703 * @return {BasicForm} this
7705 setValues : function(values){
7706 if(values instanceof Array){ // array of objects
7707 for(var i = 0, len = values.length; i < len; i++){
7709 var f = this.findField(v.id);
7711 f.setValue(v.value);
7712 if(this.trackResetOnLoad){
7713 f.originalValue = f.getValue();
7717 }else{ // object hash
7720 if(typeof values[id] != 'function' && (field = this.findField(id))){
7722 if (field.setFromData &&
7724 field.displayField &&
7725 // combos' with local stores can
7726 // be queried via setValue()
7727 // to set their value..
7728 (field.store && !field.store.isLocal)
7732 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7733 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7734 field.setFromData(sd);
7737 field.setValue(values[id]);
7741 if(this.trackResetOnLoad){
7742 field.originalValue = field.getValue();
7748 //Roo.each(this.childForms || [], function (f) {
7749 // f.setValues(values);
7756 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7757 * they are returned as an array.
7758 * @param {Boolean} asString
7761 getValues : function(asString){
7762 //if (this.childForms) {
7763 // copy values from the child forms
7764 // Roo.each(this.childForms, function (f) {
7765 // this.setValues(f.getValues());
7771 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7772 if(asString === true){
7775 return Roo.urlDecode(fs);
7779 * Returns the fields in this form as an object with key/value pairs.
7780 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7783 getFieldValues : function(with_hidden)
7785 var items = this.getItems();
7787 items.each(function(f){
7791 var v = f.getValue();
7792 if (f.inputType =='radio') {
7793 if (typeof(ret[f.getName()]) == 'undefined') {
7794 ret[f.getName()] = ''; // empty..
7797 if (!f.el.dom.checked) {
7805 // not sure if this supported any more..
7806 if ((typeof(v) == 'object') && f.getRawValue) {
7807 v = f.getRawValue() ; // dates..
7809 // combo boxes where name != hiddenName...
7810 if (f.name != f.getName()) {
7811 ret[f.name] = f.getRawValue();
7813 ret[f.getName()] = v;
7820 * Clears all invalid messages in this form.
7821 * @return {BasicForm} this
7823 clearInvalid : function(){
7824 var items = this.getItems();
7826 items.each(function(f){
7837 * @return {BasicForm} this
7840 var items = this.getItems();
7841 items.each(function(f){
7845 Roo.each(this.childForms || [], function (f) {
7852 getItems : function()
7854 var r=new Roo.util.MixedCollection(false, function(o){
7855 return o.id || (o.id = Roo.id());
7857 var iter = function(el) {
7864 Roo.each(el.items,function(e) {
7884 * Ext JS Library 1.1.1
7885 * Copyright(c) 2006-2007, Ext JS, LLC.
7887 * Originally Released Under LGPL - original licence link has changed is not relivant.
7890 * <script type="text/javascript">
7893 * @class Roo.form.VTypes
7894 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7897 Roo.form.VTypes = function(){
7898 // closure these in so they are only created once.
7899 var alpha = /^[a-zA-Z_]+$/;
7900 var alphanum = /^[a-zA-Z0-9_]+$/;
7901 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7902 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7904 // All these messages and functions are configurable
7907 * The function used to validate email addresses
7908 * @param {String} value The email address
7910 'email' : function(v){
7911 return email.test(v);
7914 * The error text to display when the email validation function returns false
7917 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7919 * The keystroke filter mask to be applied on email input
7922 'emailMask' : /[a-z0-9_\.\-@]/i,
7925 * The function used to validate URLs
7926 * @param {String} value The URL
7928 'url' : function(v){
7932 * The error text to display when the url validation function returns false
7935 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7938 * The function used to validate alpha values
7939 * @param {String} value The value
7941 'alpha' : function(v){
7942 return alpha.test(v);
7945 * The error text to display when the alpha validation function returns false
7948 'alphaText' : 'This field should only contain letters and _',
7950 * The keystroke filter mask to be applied on alpha input
7953 'alphaMask' : /[a-z_]/i,
7956 * The function used to validate alphanumeric values
7957 * @param {String} value The value
7959 'alphanum' : function(v){
7960 return alphanum.test(v);
7963 * The error text to display when the alphanumeric validation function returns false
7966 'alphanumText' : 'This field should only contain letters, numbers and _',
7968 * The keystroke filter mask to be applied on alphanumeric input
7971 'alphanumMask' : /[a-z0-9_]/i
7981 * @class Roo.bootstrap.Input
7982 * @extends Roo.bootstrap.Component
7983 * Bootstrap Input class
7984 * @cfg {Boolean} disabled is it disabled
7985 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7986 * @cfg {String} name name of the input
7987 * @cfg {string} fieldLabel - the label associated
7988 * @cfg {string} placeholder - placeholder to put in text.
7989 * @cfg {string} before - input group add on before
7990 * @cfg {string} after - input group add on after
7991 * @cfg {string} size - (lg|sm) or leave empty..
7992 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7993 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7994 * @cfg {Number} md colspan out of 12 for computer-sized screens
7995 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7996 * @cfg {string} value default value of the input
7997 * @cfg {Number} labelWidth set the width of label (0-12)
7998 * @cfg {String} labelAlign (top|left)
7999 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8000 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8002 * @cfg {String} align (left|center|right) Default left
8003 * @cfg {Boolean} forceFeedback (true|false) Default false
8009 * Create a new Input
8010 * @param {Object} config The config object
8013 Roo.bootstrap.Input = function(config){
8014 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8019 * Fires when this field receives input focus.
8020 * @param {Roo.form.Field} this
8025 * Fires when this field loses input focus.
8026 * @param {Roo.form.Field} this
8031 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8032 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8033 * @param {Roo.form.Field} this
8034 * @param {Roo.EventObject} e The event object
8039 * Fires just before the field blurs if the field value has changed.
8040 * @param {Roo.form.Field} this
8041 * @param {Mixed} newValue The new value
8042 * @param {Mixed} oldValue The original value
8047 * Fires after the field has been marked as invalid.
8048 * @param {Roo.form.Field} this
8049 * @param {String} msg The validation message
8054 * Fires after the field has been validated with no errors.
8055 * @param {Roo.form.Field} this
8060 * Fires after the key up
8061 * @param {Roo.form.Field} this
8062 * @param {Roo.EventObject} e The event Object
8068 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8070 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8071 automatic validation (defaults to "keyup").
8073 validationEvent : "keyup",
8075 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8077 validateOnBlur : true,
8079 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8081 validationDelay : 250,
8083 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8085 focusClass : "x-form-focus", // not needed???
8089 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8091 invalidClass : "has-warning",
8094 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8096 validClass : "has-success",
8099 * @cfg {Boolean} hasFeedback (true|false) default true
8104 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8106 invalidFeedbackClass : "glyphicon-warning-sign",
8109 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8111 validFeedbackClass : "glyphicon-ok",
8114 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8116 selectOnFocus : false,
8119 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8123 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8128 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8130 disableKeyFilter : false,
8133 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8137 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8141 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8143 blankText : "This field is required",
8146 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8150 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8152 maxLength : Number.MAX_VALUE,
8154 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8156 minLengthText : "The minimum length for this field is {0}",
8158 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8160 maxLengthText : "The maximum length for this field is {0}",
8164 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8165 * If available, this function will be called only after the basic validators all return true, and will be passed the
8166 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8170 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8171 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8172 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8176 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8180 autocomplete: false,
8199 formatedValue : false,
8200 forceFeedback : false,
8202 parentLabelAlign : function()
8205 while (parent.parent()) {
8206 parent = parent.parent();
8207 if (typeof(parent.labelAlign) !='undefined') {
8208 return parent.labelAlign;
8215 getAutoCreate : function(){
8217 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8225 if(this.inputType != 'hidden'){
8226 cfg.cls = 'form-group' //input-group
8232 type : this.inputType,
8234 cls : 'form-control',
8235 placeholder : this.placeholder || '',
8236 autocomplete : this.autocomplete || 'new-password'
8241 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8244 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8245 input.maxLength = this.maxLength;
8248 if (this.disabled) {
8249 input.disabled=true;
8252 if (this.readOnly) {
8253 input.readonly=true;
8257 input.name = this.name;
8260 input.cls += ' input-' + this.size;
8263 ['xs','sm','md','lg'].map(function(size){
8264 if (settings[size]) {
8265 cfg.cls += ' col-' + size + '-' + settings[size];
8269 var inputblock = input;
8273 cls: 'glyphicon form-control-feedback'
8276 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8279 cls : 'has-feedback',
8287 if (this.before || this.after) {
8290 cls : 'input-group',
8294 if (this.before && typeof(this.before) == 'string') {
8296 inputblock.cn.push({
8298 cls : 'roo-input-before input-group-addon',
8302 if (this.before && typeof(this.before) == 'object') {
8303 this.before = Roo.factory(this.before);
8305 inputblock.cn.push({
8307 cls : 'roo-input-before input-group-' +
8308 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8312 inputblock.cn.push(input);
8314 if (this.after && typeof(this.after) == 'string') {
8315 inputblock.cn.push({
8317 cls : 'roo-input-after input-group-addon',
8321 if (this.after && typeof(this.after) == 'object') {
8322 this.after = Roo.factory(this.after);
8324 inputblock.cn.push({
8326 cls : 'roo-input-after input-group-' +
8327 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8331 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8332 inputblock.cls += ' has-feedback';
8333 inputblock.cn.push(feedback);
8337 if (align ==='left' && this.fieldLabel.length) {
8344 cls : 'control-label col-sm-' + this.labelWidth,
8345 html : this.fieldLabel
8349 cls : "col-sm-" + (12 - this.labelWidth),
8356 } else if ( this.fieldLabel.length) {
8362 //cls : 'input-group-addon',
8363 html : this.fieldLabel
8382 if (this.parentType === 'Navbar' && this.parent().bar) {
8383 cfg.cls += ' navbar-form';
8385 if (this.parentType === 'NavGroup') {
8386 cfg.cls += ' navbar-form';
8393 * return the real input element.
8395 inputEl: function ()
8397 return this.el.select('input.form-control',true).first();
8400 tooltipEl : function()
8402 return this.inputEl();
8405 setDisabled : function(v)
8407 var i = this.inputEl().dom;
8409 i.removeAttribute('disabled');
8413 i.setAttribute('disabled','true');
8415 initEvents : function()
8418 this.inputEl().on("keydown" , this.fireKey, this);
8419 this.inputEl().on("focus", this.onFocus, this);
8420 this.inputEl().on("blur", this.onBlur, this);
8422 this.inputEl().relayEvent('keyup', this);
8424 // reference to original value for reset
8425 this.originalValue = this.getValue();
8426 //Roo.form.TextField.superclass.initEvents.call(this);
8427 if(this.validationEvent == 'keyup'){
8428 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8429 this.inputEl().on('keyup', this.filterValidation, this);
8431 else if(this.validationEvent !== false){
8432 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8435 if(this.selectOnFocus){
8436 this.on("focus", this.preFocus, this);
8439 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8440 this.inputEl().on("keypress", this.filterKeys, this);
8443 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8444 this.el.on("click", this.autoSize, this);
8447 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8448 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8451 if (typeof(this.before) == 'object') {
8452 this.before.render(this.el.select('.roo-input-before',true).first());
8454 if (typeof(this.after) == 'object') {
8455 this.after.render(this.el.select('.roo-input-after',true).first());
8460 filterValidation : function(e){
8461 if(!e.isNavKeyPress()){
8462 this.validationTask.delay(this.validationDelay);
8466 * Validates the field value
8467 * @return {Boolean} True if the value is valid, else false
8469 validate : function(){
8470 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8471 if(this.disabled || this.validateValue(this.getRawValue())){
8482 * Validates a value according to the field's validation rules and marks the field as invalid
8483 * if the validation fails
8484 * @param {Mixed} value The value to validate
8485 * @return {Boolean} True if the value is valid, else false
8487 validateValue : function(value){
8488 if(value.length < 1) { // if it's blank
8489 if(this.allowBlank){
8495 if(value.length < this.minLength){
8498 if(value.length > this.maxLength){
8502 var vt = Roo.form.VTypes;
8503 if(!vt[this.vtype](value, this)){
8507 if(typeof this.validator == "function"){
8508 var msg = this.validator(value);
8514 if(this.regex && !this.regex.test(value)){
8524 fireKey : function(e){
8525 //Roo.log('field ' + e.getKey());
8526 if(e.isNavKeyPress()){
8527 this.fireEvent("specialkey", this, e);
8530 focus : function (selectText){
8532 this.inputEl().focus();
8533 if(selectText === true){
8534 this.inputEl().dom.select();
8540 onFocus : function(){
8541 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8542 // this.el.addClass(this.focusClass);
8545 this.hasFocus = true;
8546 this.startValue = this.getValue();
8547 this.fireEvent("focus", this);
8551 beforeBlur : Roo.emptyFn,
8555 onBlur : function(){
8557 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8558 //this.el.removeClass(this.focusClass);
8560 this.hasFocus = false;
8561 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8564 var v = this.getValue();
8565 if(String(v) !== String(this.startValue)){
8566 this.fireEvent('change', this, v, this.startValue);
8568 this.fireEvent("blur", this);
8572 * Resets the current field value to the originally loaded value and clears any validation messages
8575 this.setValue(this.originalValue);
8579 * Returns the name of the field
8580 * @return {Mixed} name The name field
8582 getName: function(){
8586 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8587 * @return {Mixed} value The field value
8589 getValue : function(){
8591 var v = this.inputEl().getValue();
8596 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8597 * @return {Mixed} value The field value
8599 getRawValue : function(){
8600 var v = this.inputEl().getValue();
8606 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8607 * @param {Mixed} value The value to set
8609 setRawValue : function(v){
8610 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8613 selectText : function(start, end){
8614 var v = this.getRawValue();
8616 start = start === undefined ? 0 : start;
8617 end = end === undefined ? v.length : end;
8618 var d = this.inputEl().dom;
8619 if(d.setSelectionRange){
8620 d.setSelectionRange(start, end);
8621 }else if(d.createTextRange){
8622 var range = d.createTextRange();
8623 range.moveStart("character", start);
8624 range.moveEnd("character", v.length-end);
8631 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8632 * @param {Mixed} value The value to set
8634 setValue : function(v){
8637 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8643 processValue : function(value){
8644 if(this.stripCharsRe){
8645 var newValue = value.replace(this.stripCharsRe, '');
8646 if(newValue !== value){
8647 this.setRawValue(newValue);
8654 preFocus : function(){
8656 if(this.selectOnFocus){
8657 this.inputEl().dom.select();
8660 filterKeys : function(e){
8662 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8665 var c = e.getCharCode(), cc = String.fromCharCode(c);
8666 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8669 if(!this.maskRe.test(cc)){
8674 * Clear any invalid styles/messages for this field
8676 clearInvalid : function(){
8678 if(!this.el || this.preventMark){ // not rendered
8682 var label = this.el.select('label', true).first();
8683 var icon = this.el.select('i.fa-star', true).first();
8689 this.el.removeClass(this.invalidClass);
8691 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8693 var feedback = this.el.select('.form-control-feedback', true).first();
8696 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8701 this.fireEvent('valid', this);
8705 * Mark this field as valid
8707 markValid : function()
8709 if(!this.el || this.preventMark){ // not rendered
8713 this.el.removeClass([this.invalidClass, this.validClass]);
8715 var feedback = this.el.select('.form-control-feedback', true).first();
8718 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8721 if(this.disabled || this.allowBlank){
8725 var formGroup = this.el.findParent('.form-group', false, true);
8729 var label = formGroup.select('label', true).first();
8730 var icon = formGroup.select('i.fa-star', true).first();
8737 this.el.addClass(this.validClass);
8739 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8741 var feedback = this.el.select('.form-control-feedback', true).first();
8744 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8745 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8750 this.fireEvent('valid', this);
8754 * Mark this field as invalid
8755 * @param {String} msg The validation message
8757 markInvalid : function(msg)
8759 if(!this.el || this.preventMark){ // not rendered
8763 this.el.removeClass([this.invalidClass, this.validClass]);
8765 var feedback = this.el.select('.form-control-feedback', true).first();
8768 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8771 if(this.disabled || this.allowBlank){
8775 var formGroup = this.el.findParent('.form-group', false, true);
8778 var label = formGroup.select('label', true).first();
8779 var icon = formGroup.select('i.fa-star', true).first();
8781 if(!this.getValue().length && label && !icon){
8782 this.el.findParent('.form-group', false, true).createChild({
8784 cls : 'text-danger fa fa-lg fa-star',
8785 tooltip : 'This field is required',
8786 style : 'margin-right:5px;'
8792 this.el.addClass(this.invalidClass);
8794 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8796 var feedback = this.el.select('.form-control-feedback', true).first();
8799 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8801 if(this.getValue().length || this.forceFeedback){
8802 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8809 this.fireEvent('invalid', this, msg);
8812 SafariOnKeyDown : function(event)
8814 // this is a workaround for a password hang bug on chrome/ webkit.
8816 var isSelectAll = false;
8818 if(this.inputEl().dom.selectionEnd > 0){
8819 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8821 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8822 event.preventDefault();
8827 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8829 event.preventDefault();
8830 // this is very hacky as keydown always get's upper case.
8832 var cc = String.fromCharCode(event.getCharCode());
8833 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8837 adjustWidth : function(tag, w){
8838 tag = tag.toLowerCase();
8839 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8840 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8844 if(tag == 'textarea'){
8847 }else if(Roo.isOpera){
8851 if(tag == 'textarea'){
8870 * @class Roo.bootstrap.TextArea
8871 * @extends Roo.bootstrap.Input
8872 * Bootstrap TextArea class
8873 * @cfg {Number} cols Specifies the visible width of a text area
8874 * @cfg {Number} rows Specifies the visible number of lines in a text area
8875 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8876 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8877 * @cfg {string} html text
8880 * Create a new TextArea
8881 * @param {Object} config The config object
8884 Roo.bootstrap.TextArea = function(config){
8885 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8889 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8899 getAutoCreate : function(){
8901 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8912 value : this.value || '',
8913 html: this.html || '',
8914 cls : 'form-control',
8915 placeholder : this.placeholder || ''
8919 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8920 input.maxLength = this.maxLength;
8924 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8928 input.cols = this.cols;
8931 if (this.readOnly) {
8932 input.readonly = true;
8936 input.name = this.name;
8940 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8944 ['xs','sm','md','lg'].map(function(size){
8945 if (settings[size]) {
8946 cfg.cls += ' col-' + size + '-' + settings[size];
8950 var inputblock = input;
8952 if(this.hasFeedback && !this.allowBlank){
8956 cls: 'glyphicon form-control-feedback'
8960 cls : 'has-feedback',
8969 if (this.before || this.after) {
8972 cls : 'input-group',
8976 inputblock.cn.push({
8978 cls : 'input-group-addon',
8983 inputblock.cn.push(input);
8985 if(this.hasFeedback && !this.allowBlank){
8986 inputblock.cls += ' has-feedback';
8987 inputblock.cn.push(feedback);
8991 inputblock.cn.push({
8993 cls : 'input-group-addon',
9000 if (align ==='left' && this.fieldLabel.length) {
9001 // Roo.log("left and has label");
9007 cls : 'control-label col-sm-' + this.labelWidth,
9008 html : this.fieldLabel
9012 cls : "col-sm-" + (12 - this.labelWidth),
9019 } else if ( this.fieldLabel.length) {
9020 // Roo.log(" label");
9025 //cls : 'input-group-addon',
9026 html : this.fieldLabel
9036 // Roo.log(" no label && no align");
9046 if (this.disabled) {
9047 input.disabled=true;
9054 * return the real textarea element.
9056 inputEl: function ()
9058 return this.el.select('textarea.form-control',true).first();
9062 * Clear any invalid styles/messages for this field
9064 clearInvalid : function()
9067 if(!this.el || this.preventMark){ // not rendered
9071 var label = this.el.select('label', true).first();
9072 var icon = this.el.select('i.fa-star', true).first();
9078 this.el.removeClass(this.invalidClass);
9080 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9082 var feedback = this.el.select('.form-control-feedback', true).first();
9085 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9090 this.fireEvent('valid', this);
9094 * Mark this field as valid
9096 markValid : function()
9098 if(!this.el || this.preventMark){ // not rendered
9102 this.el.removeClass([this.invalidClass, this.validClass]);
9104 var feedback = this.el.select('.form-control-feedback', true).first();
9107 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9110 if(this.disabled || this.allowBlank){
9114 var label = this.el.select('label', true).first();
9115 var icon = this.el.select('i.fa-star', true).first();
9121 this.el.addClass(this.validClass);
9123 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9125 var feedback = this.el.select('.form-control-feedback', true).first();
9128 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9129 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9134 this.fireEvent('valid', this);
9138 * Mark this field as invalid
9139 * @param {String} msg The validation message
9141 markInvalid : function(msg)
9143 if(!this.el || this.preventMark){ // not rendered
9147 this.el.removeClass([this.invalidClass, this.validClass]);
9149 var feedback = this.el.select('.form-control-feedback', true).first();
9152 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9155 if(this.disabled || this.allowBlank){
9159 var label = this.el.select('label', true).first();
9160 var icon = this.el.select('i.fa-star', true).first();
9162 if(!this.getValue().length && label && !icon){
9163 this.el.createChild({
9165 cls : 'text-danger fa fa-lg fa-star',
9166 tooltip : 'This field is required',
9167 style : 'margin-right:5px;'
9171 this.el.addClass(this.invalidClass);
9173 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9175 var feedback = this.el.select('.form-control-feedback', true).first();
9178 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9180 if(this.getValue().length || this.forceFeedback){
9181 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9188 this.fireEvent('invalid', this, msg);
9196 * trigger field - base class for combo..
9201 * @class Roo.bootstrap.TriggerField
9202 * @extends Roo.bootstrap.Input
9203 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9204 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9205 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9206 * for which you can provide a custom implementation. For example:
9208 var trigger = new Roo.bootstrap.TriggerField();
9209 trigger.onTriggerClick = myTriggerFn;
9210 trigger.applyTo('my-field');
9213 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9214 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9215 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9216 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9217 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9220 * Create a new TriggerField.
9221 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9222 * to the base TextField)
9224 Roo.bootstrap.TriggerField = function(config){
9225 this.mimicing = false;
9226 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9229 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9231 * @cfg {String} triggerClass A CSS class to apply to the trigger
9234 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9239 * @cfg {Boolean} removable (true|false) special filter default false
9243 /** @cfg {Boolean} grow @hide */
9244 /** @cfg {Number} growMin @hide */
9245 /** @cfg {Number} growMax @hide */
9251 autoSize: Roo.emptyFn,
9258 actionMode : 'wrap',
9263 getAutoCreate : function(){
9265 var align = this.labelAlign || this.parentLabelAlign();
9270 cls: 'form-group' //input-group
9277 type : this.inputType,
9278 cls : 'form-control',
9279 autocomplete: 'new-password',
9280 placeholder : this.placeholder || ''
9284 input.name = this.name;
9287 input.cls += ' input-' + this.size;
9290 if (this.disabled) {
9291 input.disabled=true;
9294 var inputblock = input;
9296 if(this.hasFeedback && !this.allowBlank){
9300 cls: 'glyphicon form-control-feedback'
9303 if(this.removable && !this.editable && !this.tickable){
9305 cls : 'has-feedback',
9311 cls : 'roo-combo-removable-btn close'
9318 cls : 'has-feedback',
9327 if(this.removable && !this.editable && !this.tickable){
9329 cls : 'roo-removable',
9335 cls : 'roo-combo-removable-btn close'
9342 if (this.before || this.after) {
9345 cls : 'input-group',
9349 inputblock.cn.push({
9351 cls : 'input-group-addon',
9356 inputblock.cn.push(input);
9358 if(this.hasFeedback && !this.allowBlank){
9359 inputblock.cls += ' has-feedback';
9360 inputblock.cn.push(feedback);
9364 inputblock.cn.push({
9366 cls : 'input-group-addon',
9379 cls: 'form-hidden-field'
9393 cls: 'form-hidden-field'
9397 cls: 'roo-select2-choices',
9401 cls: 'roo-select2-search-field',
9414 cls: 'roo-select2-container input-group',
9419 // cls: 'typeahead typeahead-long dropdown-menu',
9420 // style: 'display:none'
9425 if(!this.multiple && this.showToggleBtn){
9431 if (this.caret != false) {
9434 cls: 'fa fa-' + this.caret
9441 cls : 'input-group-addon btn dropdown-toggle',
9446 cls: 'combobox-clear',
9460 combobox.cls += ' roo-select2-container-multi';
9463 if (align ==='left' && this.fieldLabel.length) {
9465 // Roo.log("left and has label");
9471 cls : 'control-label col-sm-' + this.labelWidth,
9472 html : this.fieldLabel
9476 cls : "col-sm-" + (12 - this.labelWidth),
9483 } else if ( this.fieldLabel.length) {
9484 // Roo.log(" label");
9489 //cls : 'input-group-addon',
9490 html : this.fieldLabel
9500 // Roo.log(" no label && no align");
9507 ['xs','sm','md','lg'].map(function(size){
9508 if (settings[size]) {
9509 cfg.cls += ' col-' + size + '-' + settings[size];
9520 onResize : function(w, h){
9521 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9522 // if(typeof w == 'number'){
9523 // var x = w - this.trigger.getWidth();
9524 // this.inputEl().setWidth(this.adjustWidth('input', x));
9525 // this.trigger.setStyle('left', x+'px');
9530 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9533 getResizeEl : function(){
9534 return this.inputEl();
9538 getPositionEl : function(){
9539 return this.inputEl();
9543 alignErrorIcon : function(){
9544 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9548 initEvents : function(){
9552 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9553 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9554 if(!this.multiple && this.showToggleBtn){
9555 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9556 if(this.hideTrigger){
9557 this.trigger.setDisplayed(false);
9559 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9563 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9566 if(this.removable && !this.editable && !this.tickable){
9567 var close = this.closeTriggerEl();
9570 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9571 close.on('click', this.removeBtnClick, this, close);
9575 //this.trigger.addClassOnOver('x-form-trigger-over');
9576 //this.trigger.addClassOnClick('x-form-trigger-click');
9579 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9583 closeTriggerEl : function()
9585 var close = this.el.select('.roo-combo-removable-btn', true).first();
9586 return close ? close : false;
9589 removeBtnClick : function(e, h, el)
9593 if(this.fireEvent("remove", this) !== false){
9595 this.fireEvent("afterremove", this)
9599 createList : function()
9601 this.list = Roo.get(document.body).createChild({
9603 cls: 'typeahead typeahead-long dropdown-menu',
9604 style: 'display:none'
9607 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9612 initTrigger : function(){
9617 onDestroy : function(){
9619 this.trigger.removeAllListeners();
9620 // this.trigger.remove();
9623 // this.wrap.remove();
9625 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9629 onFocus : function(){
9630 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9633 this.wrap.addClass('x-trigger-wrap-focus');
9634 this.mimicing = true;
9635 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9636 if(this.monitorTab){
9637 this.el.on("keydown", this.checkTab, this);
9644 checkTab : function(e){
9645 if(e.getKey() == e.TAB){
9651 onBlur : function(){
9656 mimicBlur : function(e, t){
9658 if(!this.wrap.contains(t) && this.validateBlur()){
9665 triggerBlur : function(){
9666 this.mimicing = false;
9667 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9668 if(this.monitorTab){
9669 this.el.un("keydown", this.checkTab, this);
9671 //this.wrap.removeClass('x-trigger-wrap-focus');
9672 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9676 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9677 validateBlur : function(e, t){
9682 onDisable : function(){
9683 this.inputEl().dom.disabled = true;
9684 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9686 // this.wrap.addClass('x-item-disabled');
9691 onEnable : function(){
9692 this.inputEl().dom.disabled = false;
9693 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9695 // this.el.removeClass('x-item-disabled');
9700 onShow : function(){
9701 var ae = this.getActionEl();
9704 ae.dom.style.display = '';
9705 ae.dom.style.visibility = 'visible';
9711 onHide : function(){
9712 var ae = this.getActionEl();
9713 ae.dom.style.display = 'none';
9717 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9718 * by an implementing function.
9720 * @param {EventObject} e
9722 onTriggerClick : Roo.emptyFn
9726 * Ext JS Library 1.1.1
9727 * Copyright(c) 2006-2007, Ext JS, LLC.
9729 * Originally Released Under LGPL - original licence link has changed is not relivant.
9732 * <script type="text/javascript">
9737 * @class Roo.data.SortTypes
9739 * Defines the default sorting (casting?) comparison functions used when sorting data.
9741 Roo.data.SortTypes = {
9743 * Default sort that does nothing
9744 * @param {Mixed} s The value being converted
9745 * @return {Mixed} The comparison value
9752 * The regular expression used to strip tags
9756 stripTagsRE : /<\/?[^>]+>/gi,
9759 * Strips all HTML tags to sort on text only
9760 * @param {Mixed} s The value being converted
9761 * @return {String} The comparison value
9763 asText : function(s){
9764 return String(s).replace(this.stripTagsRE, "");
9768 * Strips all HTML tags to sort on text only - Case insensitive
9769 * @param {Mixed} s The value being converted
9770 * @return {String} The comparison value
9772 asUCText : function(s){
9773 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9777 * Case insensitive string
9778 * @param {Mixed} s The value being converted
9779 * @return {String} The comparison value
9781 asUCString : function(s) {
9782 return String(s).toUpperCase();
9787 * @param {Mixed} s The value being converted
9788 * @return {Number} The comparison value
9790 asDate : function(s) {
9794 if(s instanceof Date){
9797 return Date.parse(String(s));
9802 * @param {Mixed} s The value being converted
9803 * @return {Float} The comparison value
9805 asFloat : function(s) {
9806 var val = parseFloat(String(s).replace(/,/g, ""));
9815 * @param {Mixed} s The value being converted
9816 * @return {Number} The comparison value
9818 asInt : function(s) {
9819 var val = parseInt(String(s).replace(/,/g, ""));
9827 * Ext JS Library 1.1.1
9828 * Copyright(c) 2006-2007, Ext JS, LLC.
9830 * Originally Released Under LGPL - original licence link has changed is not relivant.
9833 * <script type="text/javascript">
9837 * @class Roo.data.Record
9838 * Instances of this class encapsulate both record <em>definition</em> information, and record
9839 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9840 * to access Records cached in an {@link Roo.data.Store} object.<br>
9842 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9843 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9846 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9848 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9849 * {@link #create}. The parameters are the same.
9850 * @param {Array} data An associative Array of data values keyed by the field name.
9851 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9852 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9853 * not specified an integer id is generated.
9855 Roo.data.Record = function(data, id){
9856 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9861 * Generate a constructor for a specific record layout.
9862 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9863 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9864 * Each field definition object may contain the following properties: <ul>
9865 * <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,
9866 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9867 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9868 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9869 * is being used, then this is a string containing the javascript expression to reference the data relative to
9870 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9871 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9872 * this may be omitted.</p></li>
9873 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9874 * <ul><li>auto (Default, implies no conversion)</li>
9879 * <li>date</li></ul></p></li>
9880 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9881 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9882 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9883 * by the Reader into an object that will be stored in the Record. It is passed the
9884 * following parameters:<ul>
9885 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9887 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9889 * <br>usage:<br><pre><code>
9890 var TopicRecord = Roo.data.Record.create(
9891 {name: 'title', mapping: 'topic_title'},
9892 {name: 'author', mapping: 'username'},
9893 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9894 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9895 {name: 'lastPoster', mapping: 'user2'},
9896 {name: 'excerpt', mapping: 'post_text'}
9899 var myNewRecord = new TopicRecord({
9900 title: 'Do my job please',
9903 lastPost: new Date(),
9904 lastPoster: 'Animal',
9905 excerpt: 'No way dude!'
9907 myStore.add(myNewRecord);
9912 Roo.data.Record.create = function(o){
9914 f.superclass.constructor.apply(this, arguments);
9916 Roo.extend(f, Roo.data.Record);
9917 var p = f.prototype;
9918 p.fields = new Roo.util.MixedCollection(false, function(field){
9921 for(var i = 0, len = o.length; i < len; i++){
9922 p.fields.add(new Roo.data.Field(o[i]));
9924 f.getField = function(name){
9925 return p.fields.get(name);
9930 Roo.data.Record.AUTO_ID = 1000;
9931 Roo.data.Record.EDIT = 'edit';
9932 Roo.data.Record.REJECT = 'reject';
9933 Roo.data.Record.COMMIT = 'commit';
9935 Roo.data.Record.prototype = {
9937 * Readonly flag - true if this record has been modified.
9946 join : function(store){
9951 * Set the named field to the specified value.
9952 * @param {String} name The name of the field to set.
9953 * @param {Object} value The value to set the field to.
9955 set : function(name, value){
9956 if(this.data[name] == value){
9963 if(typeof this.modified[name] == 'undefined'){
9964 this.modified[name] = this.data[name];
9966 this.data[name] = value;
9967 if(!this.editing && this.store){
9968 this.store.afterEdit(this);
9973 * Get the value of the named field.
9974 * @param {String} name The name of the field to get the value of.
9975 * @return {Object} The value of the field.
9977 get : function(name){
9978 return this.data[name];
9982 beginEdit : function(){
9983 this.editing = true;
9988 cancelEdit : function(){
9989 this.editing = false;
9990 delete this.modified;
9994 endEdit : function(){
9995 this.editing = false;
9996 if(this.dirty && this.store){
9997 this.store.afterEdit(this);
10002 * Usually called by the {@link Roo.data.Store} which owns the Record.
10003 * Rejects all changes made to the Record since either creation, or the last commit operation.
10004 * Modified fields are reverted to their original values.
10006 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10007 * of reject operations.
10009 reject : function(){
10010 var m = this.modified;
10012 if(typeof m[n] != "function"){
10013 this.data[n] = m[n];
10016 this.dirty = false;
10017 delete this.modified;
10018 this.editing = false;
10020 this.store.afterReject(this);
10025 * Usually called by the {@link Roo.data.Store} which owns the Record.
10026 * Commits all changes made to the Record since either creation, or the last commit operation.
10028 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10029 * of commit operations.
10031 commit : function(){
10032 this.dirty = false;
10033 delete this.modified;
10034 this.editing = false;
10036 this.store.afterCommit(this);
10041 hasError : function(){
10042 return this.error != null;
10046 clearError : function(){
10051 * Creates a copy of this record.
10052 * @param {String} id (optional) A new record id if you don't want to use this record's id
10055 copy : function(newId) {
10056 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10060 * Ext JS Library 1.1.1
10061 * Copyright(c) 2006-2007, Ext JS, LLC.
10063 * Originally Released Under LGPL - original licence link has changed is not relivant.
10066 * <script type="text/javascript">
10072 * @class Roo.data.Store
10073 * @extends Roo.util.Observable
10074 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10075 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10077 * 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
10078 * has no knowledge of the format of the data returned by the Proxy.<br>
10080 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10081 * instances from the data object. These records are cached and made available through accessor functions.
10083 * Creates a new Store.
10084 * @param {Object} config A config object containing the objects needed for the Store to access data,
10085 * and read the data into Records.
10087 Roo.data.Store = function(config){
10088 this.data = new Roo.util.MixedCollection(false);
10089 this.data.getKey = function(o){
10092 this.baseParams = {};
10094 this.paramNames = {
10099 "multisort" : "_multisort"
10102 if(config && config.data){
10103 this.inlineData = config.data;
10104 delete config.data;
10107 Roo.apply(this, config);
10109 if(this.reader){ // reader passed
10110 this.reader = Roo.factory(this.reader, Roo.data);
10111 this.reader.xmodule = this.xmodule || false;
10112 if(!this.recordType){
10113 this.recordType = this.reader.recordType;
10115 if(this.reader.onMetaChange){
10116 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10120 if(this.recordType){
10121 this.fields = this.recordType.prototype.fields;
10123 this.modified = [];
10127 * @event datachanged
10128 * Fires when the data cache has changed, and a widget which is using this Store
10129 * as a Record cache should refresh its view.
10130 * @param {Store} this
10132 datachanged : true,
10134 * @event metachange
10135 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10136 * @param {Store} this
10137 * @param {Object} meta The JSON metadata
10142 * Fires when Records have been added to the Store
10143 * @param {Store} this
10144 * @param {Roo.data.Record[]} records The array of Records added
10145 * @param {Number} index The index at which the record(s) were added
10150 * Fires when a Record has been removed from the Store
10151 * @param {Store} this
10152 * @param {Roo.data.Record} record The Record that was removed
10153 * @param {Number} index The index at which the record was removed
10158 * Fires when a Record has been updated
10159 * @param {Store} this
10160 * @param {Roo.data.Record} record The Record that was updated
10161 * @param {String} operation The update operation being performed. Value may be one of:
10163 Roo.data.Record.EDIT
10164 Roo.data.Record.REJECT
10165 Roo.data.Record.COMMIT
10171 * Fires when the data cache has been cleared.
10172 * @param {Store} this
10176 * @event beforeload
10177 * Fires before a request is made for a new data object. If the beforeload handler returns false
10178 * the load action will be canceled.
10179 * @param {Store} this
10180 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10184 * @event beforeloadadd
10185 * Fires after a new set of Records has been loaded.
10186 * @param {Store} this
10187 * @param {Roo.data.Record[]} records The Records that were loaded
10188 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10190 beforeloadadd : true,
10193 * Fires after a new set of Records has been loaded, before they are added to the store.
10194 * @param {Store} this
10195 * @param {Roo.data.Record[]} records The Records that were loaded
10196 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10197 * @params {Object} return from reader
10201 * @event loadexception
10202 * Fires if an exception occurs in the Proxy during loading.
10203 * Called with the signature of the Proxy's "loadexception" event.
10204 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10207 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10208 * @param {Object} load options
10209 * @param {Object} jsonData from your request (normally this contains the Exception)
10211 loadexception : true
10215 this.proxy = Roo.factory(this.proxy, Roo.data);
10216 this.proxy.xmodule = this.xmodule || false;
10217 this.relayEvents(this.proxy, ["loadexception"]);
10219 this.sortToggle = {};
10220 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10222 Roo.data.Store.superclass.constructor.call(this);
10224 if(this.inlineData){
10225 this.loadData(this.inlineData);
10226 delete this.inlineData;
10230 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10232 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10233 * without a remote query - used by combo/forms at present.
10237 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10240 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10243 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10244 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10247 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10248 * on any HTTP request
10251 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10254 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10258 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10259 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10261 remoteSort : false,
10264 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10265 * loaded or when a record is removed. (defaults to false).
10267 pruneModifiedRecords : false,
10270 lastOptions : null,
10273 * Add Records to the Store and fires the add event.
10274 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10276 add : function(records){
10277 records = [].concat(records);
10278 for(var i = 0, len = records.length; i < len; i++){
10279 records[i].join(this);
10281 var index = this.data.length;
10282 this.data.addAll(records);
10283 this.fireEvent("add", this, records, index);
10287 * Remove a Record from the Store and fires the remove event.
10288 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10290 remove : function(record){
10291 var index = this.data.indexOf(record);
10292 this.data.removeAt(index);
10293 if(this.pruneModifiedRecords){
10294 this.modified.remove(record);
10296 this.fireEvent("remove", this, record, index);
10300 * Remove all Records from the Store and fires the clear event.
10302 removeAll : function(){
10304 if(this.pruneModifiedRecords){
10305 this.modified = [];
10307 this.fireEvent("clear", this);
10311 * Inserts Records to the Store at the given index and fires the add event.
10312 * @param {Number} index The start index at which to insert the passed Records.
10313 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10315 insert : function(index, records){
10316 records = [].concat(records);
10317 for(var i = 0, len = records.length; i < len; i++){
10318 this.data.insert(index, records[i]);
10319 records[i].join(this);
10321 this.fireEvent("add", this, records, index);
10325 * Get the index within the cache of the passed Record.
10326 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10327 * @return {Number} The index of the passed Record. Returns -1 if not found.
10329 indexOf : function(record){
10330 return this.data.indexOf(record);
10334 * Get the index within the cache of the Record with the passed id.
10335 * @param {String} id The id of the Record to find.
10336 * @return {Number} The index of the Record. Returns -1 if not found.
10338 indexOfId : function(id){
10339 return this.data.indexOfKey(id);
10343 * Get the Record with the specified id.
10344 * @param {String} id The id of the Record to find.
10345 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10347 getById : function(id){
10348 return this.data.key(id);
10352 * Get the Record at the specified index.
10353 * @param {Number} index The index of the Record to find.
10354 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10356 getAt : function(index){
10357 return this.data.itemAt(index);
10361 * Returns a range of Records between specified indices.
10362 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10363 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10364 * @return {Roo.data.Record[]} An array of Records
10366 getRange : function(start, end){
10367 return this.data.getRange(start, end);
10371 storeOptions : function(o){
10372 o = Roo.apply({}, o);
10375 this.lastOptions = o;
10379 * Loads the Record cache from the configured Proxy using the configured Reader.
10381 * If using remote paging, then the first load call must specify the <em>start</em>
10382 * and <em>limit</em> properties in the options.params property to establish the initial
10383 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10385 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10386 * and this call will return before the new data has been loaded. Perform any post-processing
10387 * in a callback function, or in a "load" event handler.</strong>
10389 * @param {Object} options An object containing properties which control loading options:<ul>
10390 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10391 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10392 * passed the following arguments:<ul>
10393 * <li>r : Roo.data.Record[]</li>
10394 * <li>options: Options object from the load call</li>
10395 * <li>success: Boolean success indicator</li></ul></li>
10396 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10397 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10400 load : function(options){
10401 options = options || {};
10402 if(this.fireEvent("beforeload", this, options) !== false){
10403 this.storeOptions(options);
10404 var p = Roo.apply(options.params || {}, this.baseParams);
10405 // if meta was not loaded from remote source.. try requesting it.
10406 if (!this.reader.metaFromRemote) {
10407 p._requestMeta = 1;
10409 if(this.sortInfo && this.remoteSort){
10410 var pn = this.paramNames;
10411 p[pn["sort"]] = this.sortInfo.field;
10412 p[pn["dir"]] = this.sortInfo.direction;
10414 if (this.multiSort) {
10415 var pn = this.paramNames;
10416 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10419 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10424 * Reloads the Record cache from the configured Proxy using the configured Reader and
10425 * the options from the last load operation performed.
10426 * @param {Object} options (optional) An object containing properties which may override the options
10427 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10428 * the most recently used options are reused).
10430 reload : function(options){
10431 this.load(Roo.applyIf(options||{}, this.lastOptions));
10435 // Called as a callback by the Reader during a load operation.
10436 loadRecords : function(o, options, success){
10437 if(!o || success === false){
10438 if(success !== false){
10439 this.fireEvent("load", this, [], options, o);
10441 if(options.callback){
10442 options.callback.call(options.scope || this, [], options, false);
10446 // if data returned failure - throw an exception.
10447 if (o.success === false) {
10448 // show a message if no listener is registered.
10449 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10450 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10452 // loadmask wil be hooked into this..
10453 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10456 var r = o.records, t = o.totalRecords || r.length;
10458 this.fireEvent("beforeloadadd", this, r, options, o);
10460 if(!options || options.add !== true){
10461 if(this.pruneModifiedRecords){
10462 this.modified = [];
10464 for(var i = 0, len = r.length; i < len; i++){
10468 this.data = this.snapshot;
10469 delete this.snapshot;
10472 this.data.addAll(r);
10473 this.totalLength = t;
10475 this.fireEvent("datachanged", this);
10477 this.totalLength = Math.max(t, this.data.length+r.length);
10480 this.fireEvent("load", this, r, options, o);
10481 if(options.callback){
10482 options.callback.call(options.scope || this, r, options, true);
10488 * Loads data from a passed data block. A Reader which understands the format of the data
10489 * must have been configured in the constructor.
10490 * @param {Object} data The data block from which to read the Records. The format of the data expected
10491 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10492 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10494 loadData : function(o, append){
10495 var r = this.reader.readRecords(o);
10496 this.loadRecords(r, {add: append}, true);
10500 * Gets the number of cached records.
10502 * <em>If using paging, this may not be the total size of the dataset. If the data object
10503 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10504 * the data set size</em>
10506 getCount : function(){
10507 return this.data.length || 0;
10511 * Gets the total number of records in the dataset as returned by the server.
10513 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10514 * the dataset size</em>
10516 getTotalCount : function(){
10517 return this.totalLength || 0;
10521 * Returns the sort state of the Store as an object with two properties:
10523 field {String} The name of the field by which the Records are sorted
10524 direction {String} The sort order, "ASC" or "DESC"
10527 getSortState : function(){
10528 return this.sortInfo;
10532 applySort : function(){
10533 if(this.sortInfo && !this.remoteSort){
10534 var s = this.sortInfo, f = s.field;
10535 var st = this.fields.get(f).sortType;
10536 var fn = function(r1, r2){
10537 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10538 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10540 this.data.sort(s.direction, fn);
10541 if(this.snapshot && this.snapshot != this.data){
10542 this.snapshot.sort(s.direction, fn);
10548 * Sets the default sort column and order to be used by the next load operation.
10549 * @param {String} fieldName The name of the field to sort by.
10550 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10552 setDefaultSort : function(field, dir){
10553 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10557 * Sort the Records.
10558 * If remote sorting is used, the sort is performed on the server, and the cache is
10559 * reloaded. If local sorting is used, the cache is sorted internally.
10560 * @param {String} fieldName The name of the field to sort by.
10561 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10563 sort : function(fieldName, dir){
10564 var f = this.fields.get(fieldName);
10566 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10568 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10569 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10574 this.sortToggle[f.name] = dir;
10575 this.sortInfo = {field: f.name, direction: dir};
10576 if(!this.remoteSort){
10578 this.fireEvent("datachanged", this);
10580 this.load(this.lastOptions);
10585 * Calls the specified function for each of the Records in the cache.
10586 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10587 * Returning <em>false</em> aborts and exits the iteration.
10588 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10590 each : function(fn, scope){
10591 this.data.each(fn, scope);
10595 * Gets all records modified since the last commit. Modified records are persisted across load operations
10596 * (e.g., during paging).
10597 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10599 getModifiedRecords : function(){
10600 return this.modified;
10604 createFilterFn : function(property, value, anyMatch){
10605 if(!value.exec){ // not a regex
10606 value = String(value);
10607 if(value.length == 0){
10610 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10612 return function(r){
10613 return value.test(r.data[property]);
10618 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10619 * @param {String} property A field on your records
10620 * @param {Number} start The record index to start at (defaults to 0)
10621 * @param {Number} end The last record index to include (defaults to length - 1)
10622 * @return {Number} The sum
10624 sum : function(property, start, end){
10625 var rs = this.data.items, v = 0;
10626 start = start || 0;
10627 end = (end || end === 0) ? end : rs.length-1;
10629 for(var i = start; i <= end; i++){
10630 v += (rs[i].data[property] || 0);
10636 * Filter the records by a specified property.
10637 * @param {String} field A field on your records
10638 * @param {String/RegExp} value Either a string that the field
10639 * should start with or a RegExp to test against the field
10640 * @param {Boolean} anyMatch True to match any part not just the beginning
10642 filter : function(property, value, anyMatch){
10643 var fn = this.createFilterFn(property, value, anyMatch);
10644 return fn ? this.filterBy(fn) : this.clearFilter();
10648 * Filter by a function. The specified function will be called with each
10649 * record in this data source. If the function returns true the record is included,
10650 * otherwise it is filtered.
10651 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10652 * @param {Object} scope (optional) The scope of the function (defaults to this)
10654 filterBy : function(fn, scope){
10655 this.snapshot = this.snapshot || this.data;
10656 this.data = this.queryBy(fn, scope||this);
10657 this.fireEvent("datachanged", this);
10661 * Query the records by a specified property.
10662 * @param {String} field A field on your records
10663 * @param {String/RegExp} value Either a string that the field
10664 * should start with or a RegExp to test against the field
10665 * @param {Boolean} anyMatch True to match any part not just the beginning
10666 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10668 query : function(property, value, anyMatch){
10669 var fn = this.createFilterFn(property, value, anyMatch);
10670 return fn ? this.queryBy(fn) : this.data.clone();
10674 * Query by a function. The specified function will be called with each
10675 * record in this data source. If the function returns true the record is included
10677 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10678 * @param {Object} scope (optional) The scope of the function (defaults to this)
10679 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10681 queryBy : function(fn, scope){
10682 var data = this.snapshot || this.data;
10683 return data.filterBy(fn, scope||this);
10687 * Collects unique values for a particular dataIndex from this store.
10688 * @param {String} dataIndex The property to collect
10689 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10690 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10691 * @return {Array} An array of the unique values
10693 collect : function(dataIndex, allowNull, bypassFilter){
10694 var d = (bypassFilter === true && this.snapshot) ?
10695 this.snapshot.items : this.data.items;
10696 var v, sv, r = [], l = {};
10697 for(var i = 0, len = d.length; i < len; i++){
10698 v = d[i].data[dataIndex];
10700 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10709 * Revert to a view of the Record cache with no filtering applied.
10710 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10712 clearFilter : function(suppressEvent){
10713 if(this.snapshot && this.snapshot != this.data){
10714 this.data = this.snapshot;
10715 delete this.snapshot;
10716 if(suppressEvent !== true){
10717 this.fireEvent("datachanged", this);
10723 afterEdit : function(record){
10724 if(this.modified.indexOf(record) == -1){
10725 this.modified.push(record);
10727 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10731 afterReject : function(record){
10732 this.modified.remove(record);
10733 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10737 afterCommit : function(record){
10738 this.modified.remove(record);
10739 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10743 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10744 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10746 commitChanges : function(){
10747 var m = this.modified.slice(0);
10748 this.modified = [];
10749 for(var i = 0, len = m.length; i < len; i++){
10755 * Cancel outstanding changes on all changed records.
10757 rejectChanges : function(){
10758 var m = this.modified.slice(0);
10759 this.modified = [];
10760 for(var i = 0, len = m.length; i < len; i++){
10765 onMetaChange : function(meta, rtype, o){
10766 this.recordType = rtype;
10767 this.fields = rtype.prototype.fields;
10768 delete this.snapshot;
10769 this.sortInfo = meta.sortInfo || this.sortInfo;
10770 this.modified = [];
10771 this.fireEvent('metachange', this, this.reader.meta);
10774 moveIndex : function(data, type)
10776 var index = this.indexOf(data);
10778 var newIndex = index + type;
10782 this.insert(newIndex, data);
10787 * Ext JS Library 1.1.1
10788 * Copyright(c) 2006-2007, Ext JS, LLC.
10790 * Originally Released Under LGPL - original licence link has changed is not relivant.
10793 * <script type="text/javascript">
10797 * @class Roo.data.SimpleStore
10798 * @extends Roo.data.Store
10799 * Small helper class to make creating Stores from Array data easier.
10800 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10801 * @cfg {Array} fields An array of field definition objects, or field name strings.
10802 * @cfg {Array} data The multi-dimensional array of data
10804 * @param {Object} config
10806 Roo.data.SimpleStore = function(config){
10807 Roo.data.SimpleStore.superclass.constructor.call(this, {
10809 reader: new Roo.data.ArrayReader({
10812 Roo.data.Record.create(config.fields)
10814 proxy : new Roo.data.MemoryProxy(config.data)
10818 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10820 * Ext JS Library 1.1.1
10821 * Copyright(c) 2006-2007, Ext JS, LLC.
10823 * Originally Released Under LGPL - original licence link has changed is not relivant.
10826 * <script type="text/javascript">
10831 * @extends Roo.data.Store
10832 * @class Roo.data.JsonStore
10833 * Small helper class to make creating Stores for JSON data easier. <br/>
10835 var store = new Roo.data.JsonStore({
10836 url: 'get-images.php',
10838 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10841 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10842 * JsonReader and HttpProxy (unless inline data is provided).</b>
10843 * @cfg {Array} fields An array of field definition objects, or field name strings.
10845 * @param {Object} config
10847 Roo.data.JsonStore = function(c){
10848 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10849 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10850 reader: new Roo.data.JsonReader(c, c.fields)
10853 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10855 * Ext JS Library 1.1.1
10856 * Copyright(c) 2006-2007, Ext JS, LLC.
10858 * Originally Released Under LGPL - original licence link has changed is not relivant.
10861 * <script type="text/javascript">
10865 Roo.data.Field = function(config){
10866 if(typeof config == "string"){
10867 config = {name: config};
10869 Roo.apply(this, config);
10872 this.type = "auto";
10875 var st = Roo.data.SortTypes;
10876 // named sortTypes are supported, here we look them up
10877 if(typeof this.sortType == "string"){
10878 this.sortType = st[this.sortType];
10881 // set default sortType for strings and dates
10882 if(!this.sortType){
10885 this.sortType = st.asUCString;
10888 this.sortType = st.asDate;
10891 this.sortType = st.none;
10896 var stripRe = /[\$,%]/g;
10898 // prebuilt conversion function for this field, instead of
10899 // switching every time we're reading a value
10901 var cv, dateFormat = this.dateFormat;
10906 cv = function(v){ return v; };
10909 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10913 return v !== undefined && v !== null && v !== '' ?
10914 parseInt(String(v).replace(stripRe, ""), 10) : '';
10919 return v !== undefined && v !== null && v !== '' ?
10920 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10925 cv = function(v){ return v === true || v === "true" || v == 1; };
10932 if(v instanceof Date){
10936 if(dateFormat == "timestamp"){
10937 return new Date(v*1000);
10939 return Date.parseDate(v, dateFormat);
10941 var parsed = Date.parse(v);
10942 return parsed ? new Date(parsed) : null;
10951 Roo.data.Field.prototype = {
10959 * Ext JS Library 1.1.1
10960 * Copyright(c) 2006-2007, Ext JS, LLC.
10962 * Originally Released Under LGPL - original licence link has changed is not relivant.
10965 * <script type="text/javascript">
10968 // Base class for reading structured data from a data source. This class is intended to be
10969 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10972 * @class Roo.data.DataReader
10973 * Base class for reading structured data from a data source. This class is intended to be
10974 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10977 Roo.data.DataReader = function(meta, recordType){
10981 this.recordType = recordType instanceof Array ?
10982 Roo.data.Record.create(recordType) : recordType;
10985 Roo.data.DataReader.prototype = {
10987 * Create an empty record
10988 * @param {Object} data (optional) - overlay some values
10989 * @return {Roo.data.Record} record created.
10991 newRow : function(d) {
10993 this.recordType.prototype.fields.each(function(c) {
10995 case 'int' : da[c.name] = 0; break;
10996 case 'date' : da[c.name] = new Date(); break;
10997 case 'float' : da[c.name] = 0.0; break;
10998 case 'boolean' : da[c.name] = false; break;
10999 default : da[c.name] = ""; break;
11003 return new this.recordType(Roo.apply(da, d));
11008 * Ext JS Library 1.1.1
11009 * Copyright(c) 2006-2007, Ext JS, LLC.
11011 * Originally Released Under LGPL - original licence link has changed is not relivant.
11014 * <script type="text/javascript">
11018 * @class Roo.data.DataProxy
11019 * @extends Roo.data.Observable
11020 * This class is an abstract base class for implementations which provide retrieval of
11021 * unformatted data objects.<br>
11023 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11024 * (of the appropriate type which knows how to parse the data object) to provide a block of
11025 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11027 * Custom implementations must implement the load method as described in
11028 * {@link Roo.data.HttpProxy#load}.
11030 Roo.data.DataProxy = function(){
11033 * @event beforeload
11034 * Fires before a network request is made to retrieve a data object.
11035 * @param {Object} This DataProxy object.
11036 * @param {Object} params The params parameter to the load function.
11041 * Fires before the load method's callback is called.
11042 * @param {Object} This DataProxy object.
11043 * @param {Object} o The data object.
11044 * @param {Object} arg The callback argument object passed to the load function.
11048 * @event loadexception
11049 * Fires if an Exception occurs during data retrieval.
11050 * @param {Object} This DataProxy object.
11051 * @param {Object} o The data object.
11052 * @param {Object} arg The callback argument object passed to the load function.
11053 * @param {Object} e The Exception.
11055 loadexception : true
11057 Roo.data.DataProxy.superclass.constructor.call(this);
11060 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11063 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11067 * Ext JS Library 1.1.1
11068 * Copyright(c) 2006-2007, Ext JS, LLC.
11070 * Originally Released Under LGPL - original licence link has changed is not relivant.
11073 * <script type="text/javascript">
11076 * @class Roo.data.MemoryProxy
11077 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11078 * to the Reader when its load method is called.
11080 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11082 Roo.data.MemoryProxy = function(data){
11086 Roo.data.MemoryProxy.superclass.constructor.call(this);
11090 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11093 * Load data from the requested source (in this case an in-memory
11094 * data object passed to the constructor), read the data object into
11095 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11096 * process that block using the passed callback.
11097 * @param {Object} params This parameter is not used by the MemoryProxy class.
11098 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11099 * object into a block of Roo.data.Records.
11100 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11101 * The function must be passed <ul>
11102 * <li>The Record block object</li>
11103 * <li>The "arg" argument from the load function</li>
11104 * <li>A boolean success indicator</li>
11106 * @param {Object} scope The scope in which to call the callback
11107 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11109 load : function(params, reader, callback, scope, arg){
11110 params = params || {};
11113 result = reader.readRecords(this.data);
11115 this.fireEvent("loadexception", this, arg, null, e);
11116 callback.call(scope, null, arg, false);
11119 callback.call(scope, result, arg, true);
11123 update : function(params, records){
11128 * Ext JS Library 1.1.1
11129 * Copyright(c) 2006-2007, Ext JS, LLC.
11131 * Originally Released Under LGPL - original licence link has changed is not relivant.
11134 * <script type="text/javascript">
11137 * @class Roo.data.HttpProxy
11138 * @extends Roo.data.DataProxy
11139 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11140 * configured to reference a certain URL.<br><br>
11142 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11143 * from which the running page was served.<br><br>
11145 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11147 * Be aware that to enable the browser to parse an XML document, the server must set
11148 * the Content-Type header in the HTTP response to "text/xml".
11150 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11151 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11152 * will be used to make the request.
11154 Roo.data.HttpProxy = function(conn){
11155 Roo.data.HttpProxy.superclass.constructor.call(this);
11156 // is conn a conn config or a real conn?
11158 this.useAjax = !conn || !conn.events;
11162 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11163 // thse are take from connection...
11166 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11169 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11170 * extra parameters to each request made by this object. (defaults to undefined)
11173 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11174 * to each request made by this object. (defaults to undefined)
11177 * @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)
11180 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11183 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11189 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11193 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11194 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11195 * a finer-grained basis than the DataProxy events.
11197 getConnection : function(){
11198 return this.useAjax ? Roo.Ajax : this.conn;
11202 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11203 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11204 * process that block using the passed callback.
11205 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11206 * for the request to the remote server.
11207 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11208 * object into a block of Roo.data.Records.
11209 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11210 * The function must be passed <ul>
11211 * <li>The Record block object</li>
11212 * <li>The "arg" argument from the load function</li>
11213 * <li>A boolean success indicator</li>
11215 * @param {Object} scope The scope in which to call the callback
11216 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11218 load : function(params, reader, callback, scope, arg){
11219 if(this.fireEvent("beforeload", this, params) !== false){
11221 params : params || {},
11223 callback : callback,
11228 callback : this.loadResponse,
11232 Roo.applyIf(o, this.conn);
11233 if(this.activeRequest){
11234 Roo.Ajax.abort(this.activeRequest);
11236 this.activeRequest = Roo.Ajax.request(o);
11238 this.conn.request(o);
11241 callback.call(scope||this, null, arg, false);
11246 loadResponse : function(o, success, response){
11247 delete this.activeRequest;
11249 this.fireEvent("loadexception", this, o, response);
11250 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11255 result = o.reader.read(response);
11257 this.fireEvent("loadexception", this, o, response, e);
11258 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11262 this.fireEvent("load", this, o, o.request.arg);
11263 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11267 update : function(dataSet){
11272 updateResponse : function(dataSet){
11277 * Ext JS Library 1.1.1
11278 * Copyright(c) 2006-2007, Ext JS, LLC.
11280 * Originally Released Under LGPL - original licence link has changed is not relivant.
11283 * <script type="text/javascript">
11287 * @class Roo.data.ScriptTagProxy
11288 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11289 * other than the originating domain of the running page.<br><br>
11291 * <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
11292 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11294 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11295 * source code that is used as the source inside a <script> tag.<br><br>
11297 * In order for the browser to process the returned data, the server must wrap the data object
11298 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11299 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11300 * depending on whether the callback name was passed:
11303 boolean scriptTag = false;
11304 String cb = request.getParameter("callback");
11307 response.setContentType("text/javascript");
11309 response.setContentType("application/x-json");
11311 Writer out = response.getWriter();
11313 out.write(cb + "(");
11315 out.print(dataBlock.toJsonString());
11322 * @param {Object} config A configuration object.
11324 Roo.data.ScriptTagProxy = function(config){
11325 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11326 Roo.apply(this, config);
11327 this.head = document.getElementsByTagName("head")[0];
11330 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11332 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11334 * @cfg {String} url The URL from which to request the data object.
11337 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11341 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11342 * the server the name of the callback function set up by the load call to process the returned data object.
11343 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11344 * javascript output which calls this named function passing the data object as its only parameter.
11346 callbackParam : "callback",
11348 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11349 * name to the request.
11354 * Load data from the configured URL, read the data object into
11355 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11356 * process that block using the passed callback.
11357 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11358 * for the request to the remote server.
11359 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11360 * object into a block of Roo.data.Records.
11361 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11362 * The function must be passed <ul>
11363 * <li>The Record block object</li>
11364 * <li>The "arg" argument from the load function</li>
11365 * <li>A boolean success indicator</li>
11367 * @param {Object} scope The scope in which to call the callback
11368 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11370 load : function(params, reader, callback, scope, arg){
11371 if(this.fireEvent("beforeload", this, params) !== false){
11373 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11375 var url = this.url;
11376 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11378 url += "&_dc=" + (new Date().getTime());
11380 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11383 cb : "stcCallback"+transId,
11384 scriptId : "stcScript"+transId,
11388 callback : callback,
11394 window[trans.cb] = function(o){
11395 conn.handleResponse(o, trans);
11398 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11400 if(this.autoAbort !== false){
11404 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11406 var script = document.createElement("script");
11407 script.setAttribute("src", url);
11408 script.setAttribute("type", "text/javascript");
11409 script.setAttribute("id", trans.scriptId);
11410 this.head.appendChild(script);
11412 this.trans = trans;
11414 callback.call(scope||this, null, arg, false);
11419 isLoading : function(){
11420 return this.trans ? true : false;
11424 * Abort the current server request.
11426 abort : function(){
11427 if(this.isLoading()){
11428 this.destroyTrans(this.trans);
11433 destroyTrans : function(trans, isLoaded){
11434 this.head.removeChild(document.getElementById(trans.scriptId));
11435 clearTimeout(trans.timeoutId);
11437 window[trans.cb] = undefined;
11439 delete window[trans.cb];
11442 // if hasn't been loaded, wait for load to remove it to prevent script error
11443 window[trans.cb] = function(){
11444 window[trans.cb] = undefined;
11446 delete window[trans.cb];
11453 handleResponse : function(o, trans){
11454 this.trans = false;
11455 this.destroyTrans(trans, true);
11458 result = trans.reader.readRecords(o);
11460 this.fireEvent("loadexception", this, o, trans.arg, e);
11461 trans.callback.call(trans.scope||window, null, trans.arg, false);
11464 this.fireEvent("load", this, o, trans.arg);
11465 trans.callback.call(trans.scope||window, result, trans.arg, true);
11469 handleFailure : function(trans){
11470 this.trans = false;
11471 this.destroyTrans(trans, false);
11472 this.fireEvent("loadexception", this, null, trans.arg);
11473 trans.callback.call(trans.scope||window, null, trans.arg, false);
11477 * Ext JS Library 1.1.1
11478 * Copyright(c) 2006-2007, Ext JS, LLC.
11480 * Originally Released Under LGPL - original licence link has changed is not relivant.
11483 * <script type="text/javascript">
11487 * @class Roo.data.JsonReader
11488 * @extends Roo.data.DataReader
11489 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11490 * based on mappings in a provided Roo.data.Record constructor.
11492 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11493 * in the reply previously.
11498 var RecordDef = Roo.data.Record.create([
11499 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11500 {name: 'occupation'} // This field will use "occupation" as the mapping.
11502 var myReader = new Roo.data.JsonReader({
11503 totalProperty: "results", // The property which contains the total dataset size (optional)
11504 root: "rows", // The property which contains an Array of row objects
11505 id: "id" // The property within each row object that provides an ID for the record (optional)
11509 * This would consume a JSON file like this:
11511 { 'results': 2, 'rows': [
11512 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11513 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11516 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11517 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11518 * paged from the remote server.
11519 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11520 * @cfg {String} root name of the property which contains the Array of row objects.
11521 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11522 * @cfg {Array} fields Array of field definition objects
11524 * Create a new JsonReader
11525 * @param {Object} meta Metadata configuration options
11526 * @param {Object} recordType Either an Array of field definition objects,
11527 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11529 Roo.data.JsonReader = function(meta, recordType){
11532 // set some defaults:
11533 Roo.applyIf(meta, {
11534 totalProperty: 'total',
11535 successProperty : 'success',
11540 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11542 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11545 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11546 * Used by Store query builder to append _requestMeta to params.
11549 metaFromRemote : false,
11551 * This method is only used by a DataProxy which has retrieved data from a remote server.
11552 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11553 * @return {Object} data A data block which is used by an Roo.data.Store object as
11554 * a cache of Roo.data.Records.
11556 read : function(response){
11557 var json = response.responseText;
11559 var o = /* eval:var:o */ eval("("+json+")");
11561 throw {message: "JsonReader.read: Json object not found"};
11567 this.metaFromRemote = true;
11568 this.meta = o.metaData;
11569 this.recordType = Roo.data.Record.create(o.metaData.fields);
11570 this.onMetaChange(this.meta, this.recordType, o);
11572 return this.readRecords(o);
11575 // private function a store will implement
11576 onMetaChange : function(meta, recordType, o){
11583 simpleAccess: function(obj, subsc) {
11590 getJsonAccessor: function(){
11592 return function(expr) {
11594 return(re.test(expr))
11595 ? new Function("obj", "return obj." + expr)
11600 return Roo.emptyFn;
11605 * Create a data block containing Roo.data.Records from an XML document.
11606 * @param {Object} o An object which contains an Array of row objects in the property specified
11607 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11608 * which contains the total size of the dataset.
11609 * @return {Object} data A data block which is used by an Roo.data.Store object as
11610 * a cache of Roo.data.Records.
11612 readRecords : function(o){
11614 * After any data loads, the raw JSON data is available for further custom processing.
11618 var s = this.meta, Record = this.recordType,
11619 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11621 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11623 if(s.totalProperty) {
11624 this.getTotal = this.getJsonAccessor(s.totalProperty);
11626 if(s.successProperty) {
11627 this.getSuccess = this.getJsonAccessor(s.successProperty);
11629 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11631 var g = this.getJsonAccessor(s.id);
11632 this.getId = function(rec) {
11634 return (r === undefined || r === "") ? null : r;
11637 this.getId = function(){return null;};
11640 for(var jj = 0; jj < fl; jj++){
11642 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11643 this.ef[jj] = this.getJsonAccessor(map);
11647 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11648 if(s.totalProperty){
11649 var vt = parseInt(this.getTotal(o), 10);
11654 if(s.successProperty){
11655 var vs = this.getSuccess(o);
11656 if(vs === false || vs === 'false'){
11661 for(var i = 0; i < c; i++){
11664 var id = this.getId(n);
11665 for(var j = 0; j < fl; j++){
11667 var v = this.ef[j](n);
11669 Roo.log('missing convert for ' + f.name);
11673 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11675 var record = new Record(values, id);
11677 records[i] = record;
11683 totalRecords : totalRecords
11688 * Ext JS Library 1.1.1
11689 * Copyright(c) 2006-2007, Ext JS, LLC.
11691 * Originally Released Under LGPL - original licence link has changed is not relivant.
11694 * <script type="text/javascript">
11698 * @class Roo.data.ArrayReader
11699 * @extends Roo.data.DataReader
11700 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11701 * Each element of that Array represents a row of data fields. The
11702 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11703 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11707 var RecordDef = Roo.data.Record.create([
11708 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11709 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11711 var myReader = new Roo.data.ArrayReader({
11712 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11716 * This would consume an Array like this:
11718 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11720 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11722 * Create a new JsonReader
11723 * @param {Object} meta Metadata configuration options.
11724 * @param {Object} recordType Either an Array of field definition objects
11725 * as specified to {@link Roo.data.Record#create},
11726 * or an {@link Roo.data.Record} object
11727 * created using {@link Roo.data.Record#create}.
11729 Roo.data.ArrayReader = function(meta, recordType){
11730 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11733 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11735 * Create a data block containing Roo.data.Records from an XML document.
11736 * @param {Object} o An Array of row objects which represents the dataset.
11737 * @return {Object} data A data block which is used by an Roo.data.Store object as
11738 * a cache of Roo.data.Records.
11740 readRecords : function(o){
11741 var sid = this.meta ? this.meta.id : null;
11742 var recordType = this.recordType, fields = recordType.prototype.fields;
11745 for(var i = 0; i < root.length; i++){
11748 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11749 for(var j = 0, jlen = fields.length; j < jlen; j++){
11750 var f = fields.items[j];
11751 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11752 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11754 values[f.name] = v;
11756 var record = new recordType(values, id);
11758 records[records.length] = record;
11762 totalRecords : records.length
11771 * @class Roo.bootstrap.ComboBox
11772 * @extends Roo.bootstrap.TriggerField
11773 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11774 * @cfg {Boolean} append (true|false) default false
11775 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11776 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11777 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11778 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11779 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11780 * @cfg {Boolean} animate default true
11781 * @cfg {Boolean} emptyResultText only for touch device
11782 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11784 * Create a new ComboBox.
11785 * @param {Object} config Configuration options
11787 Roo.bootstrap.ComboBox = function(config){
11788 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11792 * Fires when the dropdown list is expanded
11793 * @param {Roo.bootstrap.ComboBox} combo This combo box
11798 * Fires when the dropdown list is collapsed
11799 * @param {Roo.bootstrap.ComboBox} combo This combo box
11803 * @event beforeselect
11804 * Fires before a list item is selected. Return false to cancel the selection.
11805 * @param {Roo.bootstrap.ComboBox} combo This combo box
11806 * @param {Roo.data.Record} record The data record returned from the underlying store
11807 * @param {Number} index The index of the selected item in the dropdown list
11809 'beforeselect' : true,
11812 * Fires when a list item is selected
11813 * @param {Roo.bootstrap.ComboBox} combo This combo box
11814 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11815 * @param {Number} index The index of the selected item in the dropdown list
11819 * @event beforequery
11820 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11821 * The event object passed has these properties:
11822 * @param {Roo.bootstrap.ComboBox} combo This combo box
11823 * @param {String} query The query
11824 * @param {Boolean} forceAll true to force "all" query
11825 * @param {Boolean} cancel true to cancel the query
11826 * @param {Object} e The query event object
11828 'beforequery': true,
11831 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11832 * @param {Roo.bootstrap.ComboBox} combo This combo box
11837 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11838 * @param {Roo.bootstrap.ComboBox} combo This combo box
11839 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11844 * Fires when the remove value from the combobox array
11845 * @param {Roo.bootstrap.ComboBox} combo This combo box
11849 * @event afterremove
11850 * Fires when the remove value from the combobox array
11851 * @param {Roo.bootstrap.ComboBox} combo This combo box
11853 'afterremove' : true,
11855 * @event specialfilter
11856 * Fires when specialfilter
11857 * @param {Roo.bootstrap.ComboBox} combo This combo box
11859 'specialfilter' : true,
11862 * Fires when tick the element
11863 * @param {Roo.bootstrap.ComboBox} combo This combo box
11867 * @event touchviewdisplay
11868 * Fires when touch view require special display (default is using displayField)
11869 * @param {Roo.bootstrap.ComboBox} combo This combo box
11870 * @param {Object} cfg set html .
11872 'touchviewdisplay' : true
11877 this.tickItems = [];
11879 this.selectedIndex = -1;
11880 if(this.mode == 'local'){
11881 if(config.queryDelay === undefined){
11882 this.queryDelay = 10;
11884 if(config.minChars === undefined){
11890 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11893 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11894 * rendering into an Roo.Editor, defaults to false)
11897 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11898 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11901 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11904 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11905 * the dropdown list (defaults to undefined, with no header element)
11909 * @cfg {String/Roo.Template} tpl The template to use to render the output
11913 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11915 listWidth: undefined,
11917 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11918 * mode = 'remote' or 'text' if mode = 'local')
11920 displayField: undefined,
11923 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11924 * mode = 'remote' or 'value' if mode = 'local').
11925 * Note: use of a valueField requires the user make a selection
11926 * in order for a value to be mapped.
11928 valueField: undefined,
11932 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11933 * field's data value (defaults to the underlying DOM element's name)
11935 hiddenName: undefined,
11937 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11941 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11943 selectedClass: 'active',
11946 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11950 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11951 * anchor positions (defaults to 'tl-bl')
11953 listAlign: 'tl-bl?',
11955 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11959 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11960 * query specified by the allQuery config option (defaults to 'query')
11962 triggerAction: 'query',
11964 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11965 * (defaults to 4, does not apply if editable = false)
11969 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11970 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11974 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11975 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11979 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11980 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11984 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11985 * when editable = true (defaults to false)
11987 selectOnFocus:false,
11989 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11991 queryParam: 'query',
11993 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11994 * when mode = 'remote' (defaults to 'Loading...')
11996 loadingText: 'Loading...',
11998 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12002 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12006 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12007 * traditional select (defaults to true)
12011 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12015 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12019 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12020 * listWidth has a higher value)
12024 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12025 * allow the user to set arbitrary text into the field (defaults to false)
12027 forceSelection:false,
12029 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12030 * if typeAhead = true (defaults to 250)
12032 typeAheadDelay : 250,
12034 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12035 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12037 valueNotFoundText : undefined,
12039 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12041 blockFocus : false,
12044 * @cfg {Boolean} disableClear Disable showing of clear button.
12046 disableClear : false,
12048 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12050 alwaysQuery : false,
12053 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12058 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12060 invalidClass : "has-warning",
12063 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12065 validClass : "has-success",
12068 * @cfg {Boolean} specialFilter (true|false) special filter default false
12070 specialFilter : false,
12073 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12075 mobileTouchView : true,
12087 btnPosition : 'right',
12088 triggerList : true,
12089 showToggleBtn : true,
12091 emptyResultText: 'Empty',
12092 triggerText : 'Select',
12094 // element that contains real text value.. (when hidden is used..)
12096 getAutoCreate : function()
12104 if(Roo.isTouch && this.mobileTouchView){
12105 cfg = this.getAutoCreateTouchView();
12112 if(!this.tickable){
12113 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12118 * ComboBox with tickable selections
12121 var align = this.labelAlign || this.parentLabelAlign();
12124 cls : 'form-group roo-combobox-tickable' //input-group
12129 cls : 'tickable-buttons',
12134 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12135 html : this.triggerText
12141 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12148 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12155 buttons.cn.unshift({
12157 cls: 'roo-select2-search-field-input'
12163 Roo.each(buttons.cn, function(c){
12165 c.cls += ' btn-' + _this.size;
12168 if (_this.disabled) {
12179 cls: 'form-hidden-field'
12183 cls: 'roo-select2-choices',
12187 cls: 'roo-select2-search-field',
12199 cls: 'roo-select2-container input-group roo-select2-container-multi',
12204 // cls: 'typeahead typeahead-long dropdown-menu',
12205 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12210 if(this.hasFeedback && !this.allowBlank){
12214 cls: 'glyphicon form-control-feedback'
12217 combobox.cn.push(feedback);
12220 if (align ==='left' && this.fieldLabel.length) {
12222 // Roo.log("left and has label");
12228 cls : 'control-label col-sm-' + this.labelWidth,
12229 html : this.fieldLabel
12233 cls : "col-sm-" + (12 - this.labelWidth),
12240 } else if ( this.fieldLabel.length) {
12241 // Roo.log(" label");
12246 //cls : 'input-group-addon',
12247 html : this.fieldLabel
12257 // Roo.log(" no label && no align");
12264 ['xs','sm','md','lg'].map(function(size){
12265 if (settings[size]) {
12266 cfg.cls += ' col-' + size + '-' + settings[size];
12274 _initEventsCalled : false,
12277 initEvents: function()
12280 if (this._initEventsCalled) { // as we call render... prevent looping...
12283 this._initEventsCalled = true;
12286 throw "can not find store for combo";
12289 this.store = Roo.factory(this.store, Roo.data);
12291 // if we are building from html. then this element is so complex, that we can not really
12292 // use the rendered HTML.
12293 // so we have to trash and replace the previous code.
12294 if (Roo.XComponent.build_from_html) {
12296 // remove this element....
12297 var e = this.el.dom, k=0;
12298 while (e ) { e = e.previousSibling; ++k;}
12303 this.rendered = false;
12305 this.render(this.parent().getChildContainer(true), k);
12316 if(Roo.isTouch && this.mobileTouchView){
12317 this.initTouchView();
12322 this.initTickableEvents();
12326 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12328 if(this.hiddenName){
12330 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12332 this.hiddenField.dom.value =
12333 this.hiddenValue !== undefined ? this.hiddenValue :
12334 this.value !== undefined ? this.value : '';
12336 // prevent input submission
12337 this.el.dom.removeAttribute('name');
12338 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12343 // this.el.dom.setAttribute('autocomplete', 'off');
12346 var cls = 'x-combo-list';
12348 //this.list = new Roo.Layer({
12349 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12355 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12356 _this.list.setWidth(lw);
12359 this.list.on('mouseover', this.onViewOver, this);
12360 this.list.on('mousemove', this.onViewMove, this);
12362 this.list.on('scroll', this.onViewScroll, this);
12365 this.list.swallowEvent('mousewheel');
12366 this.assetHeight = 0;
12369 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12370 this.assetHeight += this.header.getHeight();
12373 this.innerList = this.list.createChild({cls:cls+'-inner'});
12374 this.innerList.on('mouseover', this.onViewOver, this);
12375 this.innerList.on('mousemove', this.onViewMove, this);
12376 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12378 if(this.allowBlank && !this.pageSize && !this.disableClear){
12379 this.footer = this.list.createChild({cls:cls+'-ft'});
12380 this.pageTb = new Roo.Toolbar(this.footer);
12384 this.footer = this.list.createChild({cls:cls+'-ft'});
12385 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12386 {pageSize: this.pageSize});
12390 if (this.pageTb && this.allowBlank && !this.disableClear) {
12392 this.pageTb.add(new Roo.Toolbar.Fill(), {
12393 cls: 'x-btn-icon x-btn-clear',
12395 handler: function()
12398 _this.clearValue();
12399 _this.onSelect(false, -1);
12404 this.assetHeight += this.footer.getHeight();
12409 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12412 this.view = new Roo.View(this.list, this.tpl, {
12413 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12415 //this.view.wrapEl.setDisplayed(false);
12416 this.view.on('click', this.onViewClick, this);
12420 this.store.on('beforeload', this.onBeforeLoad, this);
12421 this.store.on('load', this.onLoad, this);
12422 this.store.on('loadexception', this.onLoadException, this);
12424 if(this.resizable){
12425 this.resizer = new Roo.Resizable(this.list, {
12426 pinned:true, handles:'se'
12428 this.resizer.on('resize', function(r, w, h){
12429 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12430 this.listWidth = w;
12431 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12432 this.restrictHeight();
12434 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12437 if(!this.editable){
12438 this.editable = true;
12439 this.setEditable(false);
12444 if (typeof(this.events.add.listeners) != 'undefined') {
12446 this.addicon = this.wrap.createChild(
12447 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12449 this.addicon.on('click', function(e) {
12450 this.fireEvent('add', this);
12453 if (typeof(this.events.edit.listeners) != 'undefined') {
12455 this.editicon = this.wrap.createChild(
12456 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12457 if (this.addicon) {
12458 this.editicon.setStyle('margin-left', '40px');
12460 this.editicon.on('click', function(e) {
12462 // we fire even if inothing is selected..
12463 this.fireEvent('edit', this, this.lastData );
12469 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12470 "up" : function(e){
12471 this.inKeyMode = true;
12475 "down" : function(e){
12476 if(!this.isExpanded()){
12477 this.onTriggerClick();
12479 this.inKeyMode = true;
12484 "enter" : function(e){
12485 // this.onViewClick();
12489 if(this.fireEvent("specialkey", this, e)){
12490 this.onViewClick(false);
12496 "esc" : function(e){
12500 "tab" : function(e){
12503 if(this.fireEvent("specialkey", this, e)){
12504 this.onViewClick(false);
12512 doRelay : function(foo, bar, hname){
12513 if(hname == 'down' || this.scope.isExpanded()){
12514 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12523 this.queryDelay = Math.max(this.queryDelay || 10,
12524 this.mode == 'local' ? 10 : 250);
12527 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12529 if(this.typeAhead){
12530 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12532 if(this.editable !== false){
12533 this.inputEl().on("keyup", this.onKeyUp, this);
12535 if(this.forceSelection){
12536 this.inputEl().on('blur', this.doForce, this);
12540 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12541 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12545 initTickableEvents: function()
12549 if(this.hiddenName){
12551 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12553 this.hiddenField.dom.value =
12554 this.hiddenValue !== undefined ? this.hiddenValue :
12555 this.value !== undefined ? this.value : '';
12557 // prevent input submission
12558 this.el.dom.removeAttribute('name');
12559 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12564 // this.list = this.el.select('ul.dropdown-menu',true).first();
12566 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12567 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12568 if(this.triggerList){
12569 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12572 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12573 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12575 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12576 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12578 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12579 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12581 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12582 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12583 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12586 this.cancelBtn.hide();
12591 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12592 _this.list.setWidth(lw);
12595 this.list.on('mouseover', this.onViewOver, this);
12596 this.list.on('mousemove', this.onViewMove, this);
12598 this.list.on('scroll', this.onViewScroll, this);
12601 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>';
12604 this.view = new Roo.View(this.list, this.tpl, {
12605 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12608 //this.view.wrapEl.setDisplayed(false);
12609 this.view.on('click', this.onViewClick, this);
12613 this.store.on('beforeload', this.onBeforeLoad, this);
12614 this.store.on('load', this.onLoad, this);
12615 this.store.on('loadexception', this.onLoadException, this);
12618 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12619 "up" : function(e){
12620 this.inKeyMode = true;
12624 "down" : function(e){
12625 this.inKeyMode = true;
12629 "enter" : function(e){
12630 if(this.fireEvent("specialkey", this, e)){
12631 this.onViewClick(false);
12637 "esc" : function(e){
12638 this.onTickableFooterButtonClick(e, false, false);
12641 "tab" : function(e){
12642 this.fireEvent("specialkey", this, e);
12644 this.onTickableFooterButtonClick(e, false, false);
12651 doRelay : function(e, fn, key){
12652 if(this.scope.isExpanded()){
12653 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12662 this.queryDelay = Math.max(this.queryDelay || 10,
12663 this.mode == 'local' ? 10 : 250);
12666 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12668 if(this.typeAhead){
12669 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12672 if(this.editable !== false){
12673 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12678 onDestroy : function(){
12680 this.view.setStore(null);
12681 this.view.el.removeAllListeners();
12682 this.view.el.remove();
12683 this.view.purgeListeners();
12686 this.list.dom.innerHTML = '';
12690 this.store.un('beforeload', this.onBeforeLoad, this);
12691 this.store.un('load', this.onLoad, this);
12692 this.store.un('loadexception', this.onLoadException, this);
12694 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12698 fireKey : function(e){
12699 if(e.isNavKeyPress() && !this.list.isVisible()){
12700 this.fireEvent("specialkey", this, e);
12705 onResize: function(w, h){
12706 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12708 // if(typeof w != 'number'){
12709 // // we do not handle it!?!?
12712 // var tw = this.trigger.getWidth();
12713 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12714 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12716 // this.inputEl().setWidth( this.adjustWidth('input', x));
12718 // //this.trigger.setStyle('left', x+'px');
12720 // if(this.list && this.listWidth === undefined){
12721 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12722 // this.list.setWidth(lw);
12723 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12731 * Allow or prevent the user from directly editing the field text. If false is passed,
12732 * the user will only be able to select from the items defined in the dropdown list. This method
12733 * is the runtime equivalent of setting the 'editable' config option at config time.
12734 * @param {Boolean} value True to allow the user to directly edit the field text
12736 setEditable : function(value){
12737 if(value == this.editable){
12740 this.editable = value;
12742 this.inputEl().dom.setAttribute('readOnly', true);
12743 this.inputEl().on('mousedown', this.onTriggerClick, this);
12744 this.inputEl().addClass('x-combo-noedit');
12746 this.inputEl().dom.setAttribute('readOnly', false);
12747 this.inputEl().un('mousedown', this.onTriggerClick, this);
12748 this.inputEl().removeClass('x-combo-noedit');
12754 onBeforeLoad : function(combo,opts){
12755 if(!this.hasFocus){
12759 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12761 this.restrictHeight();
12762 this.selectedIndex = -1;
12766 onLoad : function(){
12768 this.hasQuery = false;
12770 if(!this.hasFocus){
12774 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12775 this.loading.hide();
12778 if(this.store.getCount() > 0){
12780 this.restrictHeight();
12781 if(this.lastQuery == this.allQuery){
12782 if(this.editable && !this.tickable){
12783 this.inputEl().dom.select();
12787 !this.selectByValue(this.value, true) &&
12790 !this.store.lastOptions ||
12791 typeof(this.store.lastOptions.add) == 'undefined' ||
12792 this.store.lastOptions.add != true
12795 this.select(0, true);
12798 if(this.autoFocus){
12801 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12802 this.taTask.delay(this.typeAheadDelay);
12806 this.onEmptyResults();
12812 onLoadException : function()
12814 this.hasQuery = false;
12816 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12817 this.loading.hide();
12820 if(this.tickable && this.editable){
12825 // only causes errors at present
12826 //Roo.log(this.store.reader.jsonData);
12827 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12829 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12835 onTypeAhead : function(){
12836 if(this.store.getCount() > 0){
12837 var r = this.store.getAt(0);
12838 var newValue = r.data[this.displayField];
12839 var len = newValue.length;
12840 var selStart = this.getRawValue().length;
12842 if(selStart != len){
12843 this.setRawValue(newValue);
12844 this.selectText(selStart, newValue.length);
12850 onSelect : function(record, index){
12852 if(this.fireEvent('beforeselect', this, record, index) !== false){
12854 this.setFromData(index > -1 ? record.data : false);
12857 this.fireEvent('select', this, record, index);
12862 * Returns the currently selected field value or empty string if no value is set.
12863 * @return {String} value The selected value
12865 getValue : function(){
12868 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12871 if(this.valueField){
12872 return typeof this.value != 'undefined' ? this.value : '';
12874 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12879 * Clears any text/value currently set in the field
12881 clearValue : function(){
12882 if(this.hiddenField){
12883 this.hiddenField.dom.value = '';
12886 this.setRawValue('');
12887 this.lastSelectionText = '';
12888 this.lastData = false;
12890 var close = this.closeTriggerEl();
12899 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12900 * will be displayed in the field. If the value does not match the data value of an existing item,
12901 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12902 * Otherwise the field will be blank (although the value will still be set).
12903 * @param {String} value The value to match
12905 setValue : function(v){
12912 if(this.valueField){
12913 var r = this.findRecord(this.valueField, v);
12915 text = r.data[this.displayField];
12916 }else if(this.valueNotFoundText !== undefined){
12917 text = this.valueNotFoundText;
12920 this.lastSelectionText = text;
12921 if(this.hiddenField){
12922 this.hiddenField.dom.value = v;
12924 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12927 var close = this.closeTriggerEl();
12930 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12934 * @property {Object} the last set data for the element
12939 * Sets the value of the field based on a object which is related to the record format for the store.
12940 * @param {Object} value the value to set as. or false on reset?
12942 setFromData : function(o){
12949 var dv = ''; // display value
12950 var vv = ''; // value value..
12952 if (this.displayField) {
12953 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12955 // this is an error condition!!!
12956 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12959 if(this.valueField){
12960 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12963 var close = this.closeTriggerEl();
12966 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12969 if(this.hiddenField){
12970 this.hiddenField.dom.value = vv;
12972 this.lastSelectionText = dv;
12973 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12977 // no hidden field.. - we store the value in 'value', but still display
12978 // display field!!!!
12979 this.lastSelectionText = dv;
12980 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12987 reset : function(){
12988 // overridden so that last data is reset..
12995 this.setValue(this.originalValue);
12996 this.clearInvalid();
12997 this.lastData = false;
12999 this.view.clearSelections();
13003 findRecord : function(prop, value){
13005 if(this.store.getCount() > 0){
13006 this.store.each(function(r){
13007 if(r.data[prop] == value){
13017 getName: function()
13019 // returns hidden if it's set..
13020 if (!this.rendered) {return ''};
13021 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13025 onViewMove : function(e, t){
13026 this.inKeyMode = false;
13030 onViewOver : function(e, t){
13031 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13034 var item = this.view.findItemFromChild(t);
13037 var index = this.view.indexOf(item);
13038 this.select(index, false);
13043 onViewClick : function(view, doFocus, el, e)
13045 var index = this.view.getSelectedIndexes()[0];
13047 var r = this.store.getAt(index);
13051 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13058 Roo.each(this.tickItems, function(v,k){
13060 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13062 _this.tickItems.splice(k, 1);
13064 if(typeof(e) == 'undefined' && view == false){
13065 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13077 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13078 this.tickItems.push(r.data);
13081 if(typeof(e) == 'undefined' && view == false){
13082 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13089 this.onSelect(r, index);
13091 if(doFocus !== false && !this.blockFocus){
13092 this.inputEl().focus();
13097 restrictHeight : function(){
13098 //this.innerList.dom.style.height = '';
13099 //var inner = this.innerList.dom;
13100 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13101 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13102 //this.list.beginUpdate();
13103 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13104 this.list.alignTo(this.inputEl(), this.listAlign);
13105 this.list.alignTo(this.inputEl(), this.listAlign);
13106 //this.list.endUpdate();
13110 onEmptyResults : function(){
13112 if(this.tickable && this.editable){
13113 this.restrictHeight();
13121 * Returns true if the dropdown list is expanded, else false.
13123 isExpanded : function(){
13124 return this.list.isVisible();
13128 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13129 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13130 * @param {String} value The data value of the item to select
13131 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13132 * selected item if it is not currently in view (defaults to true)
13133 * @return {Boolean} True if the value matched an item in the list, else false
13135 selectByValue : function(v, scrollIntoView){
13136 if(v !== undefined && v !== null){
13137 var r = this.findRecord(this.valueField || this.displayField, v);
13139 this.select(this.store.indexOf(r), scrollIntoView);
13147 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13148 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13149 * @param {Number} index The zero-based index of the list item to select
13150 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13151 * selected item if it is not currently in view (defaults to true)
13153 select : function(index, scrollIntoView){
13154 this.selectedIndex = index;
13155 this.view.select(index);
13156 if(scrollIntoView !== false){
13157 var el = this.view.getNode(index);
13159 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13162 this.list.scrollChildIntoView(el, false);
13168 selectNext : function(){
13169 var ct = this.store.getCount();
13171 if(this.selectedIndex == -1){
13173 }else if(this.selectedIndex < ct-1){
13174 this.select(this.selectedIndex+1);
13180 selectPrev : function(){
13181 var ct = this.store.getCount();
13183 if(this.selectedIndex == -1){
13185 }else if(this.selectedIndex != 0){
13186 this.select(this.selectedIndex-1);
13192 onKeyUp : function(e){
13193 if(this.editable !== false && !e.isSpecialKey()){
13194 this.lastKey = e.getKey();
13195 this.dqTask.delay(this.queryDelay);
13200 validateBlur : function(){
13201 return !this.list || !this.list.isVisible();
13205 initQuery : function(){
13207 var v = this.getRawValue();
13209 if(this.tickable && this.editable){
13210 v = this.tickableInputEl().getValue();
13217 doForce : function(){
13218 if(this.inputEl().dom.value.length > 0){
13219 this.inputEl().dom.value =
13220 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13226 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13227 * query allowing the query action to be canceled if needed.
13228 * @param {String} query The SQL query to execute
13229 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13230 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13231 * saved in the current store (defaults to false)
13233 doQuery : function(q, forceAll){
13235 if(q === undefined || q === null){
13240 forceAll: forceAll,
13244 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13249 forceAll = qe.forceAll;
13250 if(forceAll === true || (q.length >= this.minChars)){
13252 this.hasQuery = true;
13254 if(this.lastQuery != q || this.alwaysQuery){
13255 this.lastQuery = q;
13256 if(this.mode == 'local'){
13257 this.selectedIndex = -1;
13259 this.store.clearFilter();
13262 if(this.specialFilter){
13263 this.fireEvent('specialfilter', this);
13268 this.store.filter(this.displayField, q);
13271 this.store.fireEvent("datachanged", this.store);
13278 this.store.baseParams[this.queryParam] = q;
13280 var options = {params : this.getParams(q)};
13283 options.add = true;
13284 options.params.start = this.page * this.pageSize;
13287 this.store.load(options);
13290 * this code will make the page width larger, at the beginning, the list not align correctly,
13291 * we should expand the list on onLoad
13292 * so command out it
13297 this.selectedIndex = -1;
13302 this.loadNext = false;
13306 getParams : function(q){
13308 //p[this.queryParam] = q;
13312 p.limit = this.pageSize;
13318 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13320 collapse : function(){
13321 if(!this.isExpanded()){
13328 this.hasFocus = false;
13330 this.cancelBtn.hide();
13331 this.trigger.show();
13334 this.tickableInputEl().dom.value = '';
13335 this.tickableInputEl().blur();
13340 Roo.get(document).un('mousedown', this.collapseIf, this);
13341 Roo.get(document).un('mousewheel', this.collapseIf, this);
13342 if (!this.editable) {
13343 Roo.get(document).un('keydown', this.listKeyPress, this);
13345 this.fireEvent('collapse', this);
13349 collapseIf : function(e){
13350 var in_combo = e.within(this.el);
13351 var in_list = e.within(this.list);
13352 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13354 if (in_combo || in_list || is_list) {
13355 //e.stopPropagation();
13360 this.onTickableFooterButtonClick(e, false, false);
13368 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13370 expand : function(){
13372 if(this.isExpanded() || !this.hasFocus){
13376 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13377 this.list.setWidth(lw);
13384 this.restrictHeight();
13388 this.tickItems = Roo.apply([], this.item);
13391 this.cancelBtn.show();
13392 this.trigger.hide();
13395 this.tickableInputEl().focus();
13400 Roo.get(document).on('mousedown', this.collapseIf, this);
13401 Roo.get(document).on('mousewheel', this.collapseIf, this);
13402 if (!this.editable) {
13403 Roo.get(document).on('keydown', this.listKeyPress, this);
13406 this.fireEvent('expand', this);
13410 // Implements the default empty TriggerField.onTriggerClick function
13411 onTriggerClick : function(e)
13413 Roo.log('trigger click');
13415 if(this.disabled || !this.triggerList){
13420 this.loadNext = false;
13422 if(this.isExpanded()){
13424 if (!this.blockFocus) {
13425 this.inputEl().focus();
13429 this.hasFocus = true;
13430 if(this.triggerAction == 'all') {
13431 this.doQuery(this.allQuery, true);
13433 this.doQuery(this.getRawValue());
13435 if (!this.blockFocus) {
13436 this.inputEl().focus();
13441 onTickableTriggerClick : function(e)
13448 this.loadNext = false;
13449 this.hasFocus = true;
13451 if(this.triggerAction == 'all') {
13452 this.doQuery(this.allQuery, true);
13454 this.doQuery(this.getRawValue());
13458 onSearchFieldClick : function(e)
13460 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13461 this.onTickableFooterButtonClick(e, false, false);
13465 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13470 this.loadNext = false;
13471 this.hasFocus = true;
13473 if(this.triggerAction == 'all') {
13474 this.doQuery(this.allQuery, true);
13476 this.doQuery(this.getRawValue());
13480 listKeyPress : function(e)
13482 //Roo.log('listkeypress');
13483 // scroll to first matching element based on key pres..
13484 if (e.isSpecialKey()) {
13487 var k = String.fromCharCode(e.getKey()).toUpperCase();
13490 var csel = this.view.getSelectedNodes();
13491 var cselitem = false;
13493 var ix = this.view.indexOf(csel[0]);
13494 cselitem = this.store.getAt(ix);
13495 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13501 this.store.each(function(v) {
13503 // start at existing selection.
13504 if (cselitem.id == v.id) {
13510 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13511 match = this.store.indexOf(v);
13517 if (match === false) {
13518 return true; // no more action?
13521 this.view.select(match);
13522 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13523 sn.scrollIntoView(sn.dom.parentNode, false);
13526 onViewScroll : function(e, t){
13528 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){
13532 this.hasQuery = true;
13534 this.loading = this.list.select('.loading', true).first();
13536 if(this.loading === null){
13537 this.list.createChild({
13539 cls: 'loading roo-select2-more-results roo-select2-active',
13540 html: 'Loading more results...'
13543 this.loading = this.list.select('.loading', true).first();
13545 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13547 this.loading.hide();
13550 this.loading.show();
13555 this.loadNext = true;
13557 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13562 addItem : function(o)
13564 var dv = ''; // display value
13566 if (this.displayField) {
13567 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13569 // this is an error condition!!!
13570 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13577 var choice = this.choices.createChild({
13579 cls: 'roo-select2-search-choice',
13588 cls: 'roo-select2-search-choice-close',
13593 }, this.searchField);
13595 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13597 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13605 this.inputEl().dom.value = '';
13610 onRemoveItem : function(e, _self, o)
13612 e.preventDefault();
13614 this.lastItem = Roo.apply([], this.item);
13616 var index = this.item.indexOf(o.data) * 1;
13619 Roo.log('not this item?!');
13623 this.item.splice(index, 1);
13628 this.fireEvent('remove', this, e);
13634 syncValue : function()
13636 if(!this.item.length){
13643 Roo.each(this.item, function(i){
13644 if(_this.valueField){
13645 value.push(i[_this.valueField]);
13652 this.value = value.join(',');
13654 if(this.hiddenField){
13655 this.hiddenField.dom.value = this.value;
13658 this.store.fireEvent("datachanged", this.store);
13661 clearItem : function()
13663 if(!this.multiple){
13669 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13677 if(this.tickable && !Roo.isTouch){
13678 this.view.refresh();
13682 inputEl: function ()
13684 if(Roo.isTouch && this.mobileTouchView){
13685 return this.el.select('input.form-control',true).first();
13689 return this.searchField;
13692 return this.el.select('input.form-control',true).first();
13696 onTickableFooterButtonClick : function(e, btn, el)
13698 e.preventDefault();
13700 this.lastItem = Roo.apply([], this.item);
13702 if(btn && btn.name == 'cancel'){
13703 this.tickItems = Roo.apply([], this.item);
13712 Roo.each(this.tickItems, function(o){
13720 validate : function()
13722 var v = this.getRawValue();
13725 v = this.getValue();
13728 if(this.disabled || this.allowBlank || v.length){
13733 this.markInvalid();
13737 tickableInputEl : function()
13739 if(!this.tickable || !this.editable){
13740 return this.inputEl();
13743 return this.inputEl().select('.roo-select2-search-field-input', true).first();
13747 getAutoCreateTouchView : function()
13752 cls: 'form-group' //input-group
13758 type : this.inputType,
13759 cls : 'form-control x-combo-noedit',
13760 autocomplete: 'new-password',
13761 placeholder : this.placeholder || '',
13766 input.name = this.name;
13770 input.cls += ' input-' + this.size;
13773 if (this.disabled) {
13774 input.disabled = true;
13785 inputblock.cls += ' input-group';
13787 inputblock.cn.unshift({
13789 cls : 'input-group-addon',
13794 if(this.removable && !this.multiple){
13795 inputblock.cls += ' roo-removable';
13797 inputblock.cn.push({
13800 cls : 'roo-combo-removable-btn close'
13804 if(this.hasFeedback && !this.allowBlank){
13806 inputblock.cls += ' has-feedback';
13808 inputblock.cn.push({
13810 cls: 'glyphicon form-control-feedback'
13817 inputblock.cls += (this.before) ? '' : ' input-group';
13819 inputblock.cn.push({
13821 cls : 'input-group-addon',
13832 cls: 'form-hidden-field'
13846 cls: 'form-hidden-field'
13850 cls: 'roo-select2-choices',
13854 cls: 'roo-select2-search-field',
13867 cls: 'roo-select2-container input-group',
13874 combobox.cls += ' roo-select2-container-multi';
13877 var align = this.labelAlign || this.parentLabelAlign();
13881 if(this.fieldLabel.length){
13883 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13884 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13889 cls : 'control-label ' + lw,
13890 html : this.fieldLabel
13902 var settings = this;
13904 ['xs','sm','md','lg'].map(function(size){
13905 if (settings[size]) {
13906 cfg.cls += ' col-' + size + '-' + settings[size];
13913 initTouchView : function()
13915 this.renderTouchView();
13917 this.touchViewEl.on('scroll', function(){
13918 this.el.dom.scrollTop = 0;
13921 this.originalValue = this.getValue();
13923 this.inputEl().on("click", this.showTouchView, this);
13925 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13926 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13928 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13930 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13931 this.store.on('load', this.onTouchViewLoad, this);
13932 this.store.on('loadexception', this.onTouchViewLoadException, this);
13934 if(this.hiddenName){
13936 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13938 this.hiddenField.dom.value =
13939 this.hiddenValue !== undefined ? this.hiddenValue :
13940 this.value !== undefined ? this.value : '';
13942 this.el.dom.removeAttribute('name');
13943 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13947 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13948 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13951 if(this.removable && !this.multiple){
13952 var close = this.closeTriggerEl();
13954 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13955 close.on('click', this.removeBtnClick, this, close);
13959 * fix the bug in Safari iOS8
13961 this.inputEl().on("focus", function(e){
13962 document.activeElement.blur();
13970 renderTouchView : function()
13972 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13973 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13975 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13976 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13978 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13979 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13980 this.touchViewBodyEl.setStyle('overflow', 'auto');
13982 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13983 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13985 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13986 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13990 showTouchView : function()
13996 this.touchViewHeaderEl.hide();
13998 if(this.fieldLabel.length){
13999 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
14000 this.touchViewHeaderEl.show();
14003 this.touchViewEl.show();
14005 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14006 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14008 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14010 if(this.fieldLabel.length){
14011 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14014 this.touchViewBodyEl.setHeight(bodyHeight);
14018 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14020 this.touchViewEl.addClass('in');
14023 this.doTouchViewQuery();
14027 hideTouchView : function()
14029 this.touchViewEl.removeClass('in');
14033 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14035 this.touchViewEl.setStyle('display', 'none');
14040 setTouchViewValue : function()
14047 Roo.each(this.tickItems, function(o){
14052 this.hideTouchView();
14055 doTouchViewQuery : function()
14064 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14068 if(!this.alwaysQuery || this.mode == 'local'){
14069 this.onTouchViewLoad();
14076 onTouchViewBeforeLoad : function(combo,opts)
14082 onTouchViewLoad : function()
14084 if(this.store.getCount() < 1){
14085 this.onTouchViewEmptyResults();
14089 this.clearTouchView();
14091 var rawValue = this.getRawValue();
14093 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14095 this.tickItems = [];
14097 this.store.data.each(function(d, rowIndex){
14098 var row = this.touchViewListGroup.createChild(template);
14100 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14101 row.addClass(d.data.cls);
14104 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14107 html : d.data[this.displayField]
14110 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14111 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14115 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
14116 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14119 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
14120 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14121 this.tickItems.push(d.data);
14124 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14128 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14130 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14132 if(this.fieldLabel.length){
14133 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14136 var listHeight = this.touchViewListGroup.getHeight();
14140 if(firstChecked && listHeight > bodyHeight){
14141 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14146 onTouchViewLoadException : function()
14148 this.hideTouchView();
14151 onTouchViewEmptyResults : function()
14153 this.clearTouchView();
14155 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14157 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14161 clearTouchView : function()
14163 this.touchViewListGroup.dom.innerHTML = '';
14166 onTouchViewClick : function(e, el, o)
14168 e.preventDefault();
14171 var rowIndex = o.rowIndex;
14173 var r = this.store.getAt(rowIndex);
14175 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14177 if(!this.multiple){
14178 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14179 c.dom.removeAttribute('checked');
14182 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14184 this.setFromData(r.data);
14186 var close = this.closeTriggerEl();
14192 this.hideTouchView();
14194 this.fireEvent('select', this, r, rowIndex);
14199 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14200 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14201 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14205 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14206 this.addItem(r.data);
14207 this.tickItems.push(r.data);
14213 * @cfg {Boolean} grow
14217 * @cfg {Number} growMin
14221 * @cfg {Number} growMax
14230 Roo.apply(Roo.bootstrap.ComboBox, {
14234 cls: 'modal-header',
14256 cls: 'list-group-item',
14260 cls: 'roo-combobox-list-group-item-value'
14264 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14278 listItemCheckbox : {
14280 cls: 'list-group-item',
14284 cls: 'roo-combobox-list-group-item-value'
14288 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14304 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14309 cls: 'modal-footer',
14317 cls: 'col-xs-6 text-left',
14320 cls: 'btn btn-danger roo-touch-view-cancel',
14326 cls: 'col-xs-6 text-right',
14329 cls: 'btn btn-success roo-touch-view-ok',
14340 Roo.apply(Roo.bootstrap.ComboBox, {
14342 touchViewTemplate : {
14344 cls: 'modal fade roo-combobox-touch-view',
14348 cls: 'modal-dialog',
14349 style : 'position:fixed', // we have to fix position....
14353 cls: 'modal-content',
14355 Roo.bootstrap.ComboBox.header,
14356 Roo.bootstrap.ComboBox.body,
14357 Roo.bootstrap.ComboBox.footer
14366 * Ext JS Library 1.1.1
14367 * Copyright(c) 2006-2007, Ext JS, LLC.
14369 * Originally Released Under LGPL - original licence link has changed is not relivant.
14372 * <script type="text/javascript">
14377 * @extends Roo.util.Observable
14378 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14379 * This class also supports single and multi selection modes. <br>
14380 * Create a data model bound view:
14382 var store = new Roo.data.Store(...);
14384 var view = new Roo.View({
14386 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14388 singleSelect: true,
14389 selectedClass: "ydataview-selected",
14393 // listen for node click?
14394 view.on("click", function(vw, index, node, e){
14395 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14399 dataModel.load("foobar.xml");
14401 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14403 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14404 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14406 * Note: old style constructor is still suported (container, template, config)
14409 * Create a new View
14410 * @param {Object} config The config object
14413 Roo.View = function(config, depreciated_tpl, depreciated_config){
14415 this.parent = false;
14417 if (typeof(depreciated_tpl) == 'undefined') {
14418 // new way.. - universal constructor.
14419 Roo.apply(this, config);
14420 this.el = Roo.get(this.el);
14423 this.el = Roo.get(config);
14424 this.tpl = depreciated_tpl;
14425 Roo.apply(this, depreciated_config);
14427 this.wrapEl = this.el.wrap().wrap();
14428 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14431 if(typeof(this.tpl) == "string"){
14432 this.tpl = new Roo.Template(this.tpl);
14434 // support xtype ctors..
14435 this.tpl = new Roo.factory(this.tpl, Roo);
14439 this.tpl.compile();
14444 * @event beforeclick
14445 * Fires before a click is processed. Returns false to cancel the default action.
14446 * @param {Roo.View} this
14447 * @param {Number} index The index of the target node
14448 * @param {HTMLElement} node The target node
14449 * @param {Roo.EventObject} e The raw event object
14451 "beforeclick" : true,
14454 * Fires when a template node is clicked.
14455 * @param {Roo.View} this
14456 * @param {Number} index The index of the target node
14457 * @param {HTMLElement} node The target node
14458 * @param {Roo.EventObject} e The raw event object
14463 * Fires when a template node is double clicked.
14464 * @param {Roo.View} this
14465 * @param {Number} index The index of the target node
14466 * @param {HTMLElement} node The target node
14467 * @param {Roo.EventObject} e The raw event object
14471 * @event contextmenu
14472 * Fires when a template node is right clicked.
14473 * @param {Roo.View} this
14474 * @param {Number} index The index of the target node
14475 * @param {HTMLElement} node The target node
14476 * @param {Roo.EventObject} e The raw event object
14478 "contextmenu" : true,
14480 * @event selectionchange
14481 * Fires when the selected nodes change.
14482 * @param {Roo.View} this
14483 * @param {Array} selections Array of the selected nodes
14485 "selectionchange" : true,
14488 * @event beforeselect
14489 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14490 * @param {Roo.View} this
14491 * @param {HTMLElement} node The node to be selected
14492 * @param {Array} selections Array of currently selected nodes
14494 "beforeselect" : true,
14496 * @event preparedata
14497 * Fires on every row to render, to allow you to change the data.
14498 * @param {Roo.View} this
14499 * @param {Object} data to be rendered (change this)
14501 "preparedata" : true
14509 "click": this.onClick,
14510 "dblclick": this.onDblClick,
14511 "contextmenu": this.onContextMenu,
14515 this.selections = [];
14517 this.cmp = new Roo.CompositeElementLite([]);
14519 this.store = Roo.factory(this.store, Roo.data);
14520 this.setStore(this.store, true);
14523 if ( this.footer && this.footer.xtype) {
14525 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14527 this.footer.dataSource = this.store;
14528 this.footer.container = fctr;
14529 this.footer = Roo.factory(this.footer, Roo);
14530 fctr.insertFirst(this.el);
14532 // this is a bit insane - as the paging toolbar seems to detach the el..
14533 // dom.parentNode.parentNode.parentNode
14534 // they get detached?
14538 Roo.View.superclass.constructor.call(this);
14543 Roo.extend(Roo.View, Roo.util.Observable, {
14546 * @cfg {Roo.data.Store} store Data store to load data from.
14551 * @cfg {String|Roo.Element} el The container element.
14556 * @cfg {String|Roo.Template} tpl The template used by this View
14560 * @cfg {String} dataName the named area of the template to use as the data area
14561 * Works with domtemplates roo-name="name"
14565 * @cfg {String} selectedClass The css class to add to selected nodes
14567 selectedClass : "x-view-selected",
14569 * @cfg {String} emptyText The empty text to show when nothing is loaded.
14574 * @cfg {String} text to display on mask (default Loading)
14578 * @cfg {Boolean} multiSelect Allow multiple selection
14580 multiSelect : false,
14582 * @cfg {Boolean} singleSelect Allow single selection
14584 singleSelect: false,
14587 * @cfg {Boolean} toggleSelect - selecting
14589 toggleSelect : false,
14592 * @cfg {Boolean} tickable - selecting
14597 * Returns the element this view is bound to.
14598 * @return {Roo.Element}
14600 getEl : function(){
14601 return this.wrapEl;
14607 * Refreshes the view. - called by datachanged on the store. - do not call directly.
14609 refresh : function(){
14610 //Roo.log('refresh');
14613 // if we are using something like 'domtemplate', then
14614 // the what gets used is:
14615 // t.applySubtemplate(NAME, data, wrapping data..)
14616 // the outer template then get' applied with
14617 // the store 'extra data'
14618 // and the body get's added to the
14619 // roo-name="data" node?
14620 // <span class='roo-tpl-{name}'></span> ?????
14624 this.clearSelections();
14625 this.el.update("");
14627 var records = this.store.getRange();
14628 if(records.length < 1) {
14630 // is this valid?? = should it render a template??
14632 this.el.update(this.emptyText);
14636 if (this.dataName) {
14637 this.el.update(t.apply(this.store.meta)); //????
14638 el = this.el.child('.roo-tpl-' + this.dataName);
14641 for(var i = 0, len = records.length; i < len; i++){
14642 var data = this.prepareData(records[i].data, i, records[i]);
14643 this.fireEvent("preparedata", this, data, i, records[i]);
14645 var d = Roo.apply({}, data);
14648 Roo.apply(d, {'roo-id' : Roo.id()});
14652 Roo.each(this.parent.item, function(item){
14653 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
14656 Roo.apply(d, {'roo-data-checked' : 'checked'});
14660 html[html.length] = Roo.util.Format.trim(
14662 t.applySubtemplate(this.dataName, d, this.store.meta) :
14669 el.update(html.join(""));
14670 this.nodes = el.dom.childNodes;
14671 this.updateIndexes(0);
14676 * Function to override to reformat the data that is sent to
14677 * the template for each node.
14678 * DEPRICATED - use the preparedata event handler.
14679 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
14680 * a JSON object for an UpdateManager bound view).
14682 prepareData : function(data, index, record)
14684 this.fireEvent("preparedata", this, data, index, record);
14688 onUpdate : function(ds, record){
14689 // Roo.log('on update');
14690 this.clearSelections();
14691 var index = this.store.indexOf(record);
14692 var n = this.nodes[index];
14693 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
14694 n.parentNode.removeChild(n);
14695 this.updateIndexes(index, index);
14701 onAdd : function(ds, records, index)
14703 //Roo.log(['on Add', ds, records, index] );
14704 this.clearSelections();
14705 if(this.nodes.length == 0){
14709 var n = this.nodes[index];
14710 for(var i = 0, len = records.length; i < len; i++){
14711 var d = this.prepareData(records[i].data, i, records[i]);
14713 this.tpl.insertBefore(n, d);
14716 this.tpl.append(this.el, d);
14719 this.updateIndexes(index);
14722 onRemove : function(ds, record, index){
14723 // Roo.log('onRemove');
14724 this.clearSelections();
14725 var el = this.dataName ?
14726 this.el.child('.roo-tpl-' + this.dataName) :
14729 el.dom.removeChild(this.nodes[index]);
14730 this.updateIndexes(index);
14734 * Refresh an individual node.
14735 * @param {Number} index
14737 refreshNode : function(index){
14738 this.onUpdate(this.store, this.store.getAt(index));
14741 updateIndexes : function(startIndex, endIndex){
14742 var ns = this.nodes;
14743 startIndex = startIndex || 0;
14744 endIndex = endIndex || ns.length - 1;
14745 for(var i = startIndex; i <= endIndex; i++){
14746 ns[i].nodeIndex = i;
14751 * Changes the data store this view uses and refresh the view.
14752 * @param {Store} store
14754 setStore : function(store, initial){
14755 if(!initial && this.store){
14756 this.store.un("datachanged", this.refresh);
14757 this.store.un("add", this.onAdd);
14758 this.store.un("remove", this.onRemove);
14759 this.store.un("update", this.onUpdate);
14760 this.store.un("clear", this.refresh);
14761 this.store.un("beforeload", this.onBeforeLoad);
14762 this.store.un("load", this.onLoad);
14763 this.store.un("loadexception", this.onLoad);
14767 store.on("datachanged", this.refresh, this);
14768 store.on("add", this.onAdd, this);
14769 store.on("remove", this.onRemove, this);
14770 store.on("update", this.onUpdate, this);
14771 store.on("clear", this.refresh, this);
14772 store.on("beforeload", this.onBeforeLoad, this);
14773 store.on("load", this.onLoad, this);
14774 store.on("loadexception", this.onLoad, this);
14782 * onbeforeLoad - masks the loading area.
14785 onBeforeLoad : function(store,opts)
14787 //Roo.log('onBeforeLoad');
14789 this.el.update("");
14791 this.el.mask(this.mask ? this.mask : "Loading" );
14793 onLoad : function ()
14800 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
14801 * @param {HTMLElement} node
14802 * @return {HTMLElement} The template node
14804 findItemFromChild : function(node){
14805 var el = this.dataName ?
14806 this.el.child('.roo-tpl-' + this.dataName,true) :
14809 if(!node || node.parentNode == el){
14812 var p = node.parentNode;
14813 while(p && p != el){
14814 if(p.parentNode == el){
14823 onClick : function(e){
14824 var item = this.findItemFromChild(e.getTarget());
14826 var index = this.indexOf(item);
14827 if(this.onItemClick(item, index, e) !== false){
14828 this.fireEvent("click", this, index, item, e);
14831 this.clearSelections();
14836 onContextMenu : function(e){
14837 var item = this.findItemFromChild(e.getTarget());
14839 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14844 onDblClick : function(e){
14845 var item = this.findItemFromChild(e.getTarget());
14847 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14851 onItemClick : function(item, index, e)
14853 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14856 if (this.toggleSelect) {
14857 var m = this.isSelected(item) ? 'unselect' : 'select';
14860 _t[m](item, true, false);
14863 if(this.multiSelect || this.singleSelect){
14864 if(this.multiSelect && e.shiftKey && this.lastSelection){
14865 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14867 this.select(item, this.multiSelect && e.ctrlKey);
14868 this.lastSelection = item;
14871 if(!this.tickable){
14872 e.preventDefault();
14880 * Get the number of selected nodes.
14883 getSelectionCount : function(){
14884 return this.selections.length;
14888 * Get the currently selected nodes.
14889 * @return {Array} An array of HTMLElements
14891 getSelectedNodes : function(){
14892 return this.selections;
14896 * Get the indexes of the selected nodes.
14899 getSelectedIndexes : function(){
14900 var indexes = [], s = this.selections;
14901 for(var i = 0, len = s.length; i < len; i++){
14902 indexes.push(s[i].nodeIndex);
14908 * Clear all selections
14909 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14911 clearSelections : function(suppressEvent){
14912 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14913 this.cmp.elements = this.selections;
14914 this.cmp.removeClass(this.selectedClass);
14915 this.selections = [];
14916 if(!suppressEvent){
14917 this.fireEvent("selectionchange", this, this.selections);
14923 * Returns true if the passed node is selected
14924 * @param {HTMLElement/Number} node The node or node index
14925 * @return {Boolean}
14927 isSelected : function(node){
14928 var s = this.selections;
14932 node = this.getNode(node);
14933 return s.indexOf(node) !== -1;
14938 * @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
14939 * @param {Boolean} keepExisting (optional) true to keep existing selections
14940 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14942 select : function(nodeInfo, keepExisting, suppressEvent){
14943 if(nodeInfo instanceof Array){
14945 this.clearSelections(true);
14947 for(var i = 0, len = nodeInfo.length; i < len; i++){
14948 this.select(nodeInfo[i], true, true);
14952 var node = this.getNode(nodeInfo);
14953 if(!node || this.isSelected(node)){
14954 return; // already selected.
14957 this.clearSelections(true);
14960 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14961 Roo.fly(node).addClass(this.selectedClass);
14962 this.selections.push(node);
14963 if(!suppressEvent){
14964 this.fireEvent("selectionchange", this, this.selections);
14972 * @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
14973 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14974 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14976 unselect : function(nodeInfo, keepExisting, suppressEvent)
14978 if(nodeInfo instanceof Array){
14979 Roo.each(this.selections, function(s) {
14980 this.unselect(s, nodeInfo);
14984 var node = this.getNode(nodeInfo);
14985 if(!node || !this.isSelected(node)){
14986 //Roo.log("not selected");
14987 return; // not selected.
14991 Roo.each(this.selections, function(s) {
14993 Roo.fly(node).removeClass(this.selectedClass);
15000 this.selections= ns;
15001 this.fireEvent("selectionchange", this, this.selections);
15005 * Gets a template node.
15006 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15007 * @return {HTMLElement} The node or null if it wasn't found
15009 getNode : function(nodeInfo){
15010 if(typeof nodeInfo == "string"){
15011 return document.getElementById(nodeInfo);
15012 }else if(typeof nodeInfo == "number"){
15013 return this.nodes[nodeInfo];
15019 * Gets a range template nodes.
15020 * @param {Number} startIndex
15021 * @param {Number} endIndex
15022 * @return {Array} An array of nodes
15024 getNodes : function(start, end){
15025 var ns = this.nodes;
15026 start = start || 0;
15027 end = typeof end == "undefined" ? ns.length - 1 : end;
15030 for(var i = start; i <= end; i++){
15034 for(var i = start; i >= end; i--){
15042 * Finds the index of the passed node
15043 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15044 * @return {Number} The index of the node or -1
15046 indexOf : function(node){
15047 node = this.getNode(node);
15048 if(typeof node.nodeIndex == "number"){
15049 return node.nodeIndex;
15051 var ns = this.nodes;
15052 for(var i = 0, len = ns.length; i < len; i++){
15063 * based on jquery fullcalendar
15067 Roo.bootstrap = Roo.bootstrap || {};
15069 * @class Roo.bootstrap.Calendar
15070 * @extends Roo.bootstrap.Component
15071 * Bootstrap Calendar class
15072 * @cfg {Boolean} loadMask (true|false) default false
15073 * @cfg {Object} header generate the user specific header of the calendar, default false
15076 * Create a new Container
15077 * @param {Object} config The config object
15082 Roo.bootstrap.Calendar = function(config){
15083 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15087 * Fires when a date is selected
15088 * @param {DatePicker} this
15089 * @param {Date} date The selected date
15093 * @event monthchange
15094 * Fires when the displayed month changes
15095 * @param {DatePicker} this
15096 * @param {Date} date The selected month
15098 'monthchange': true,
15100 * @event evententer
15101 * Fires when mouse over an event
15102 * @param {Calendar} this
15103 * @param {event} Event
15105 'evententer': true,
15107 * @event eventleave
15108 * Fires when the mouse leaves an
15109 * @param {Calendar} this
15112 'eventleave': true,
15114 * @event eventclick
15115 * Fires when the mouse click an
15116 * @param {Calendar} this
15125 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15128 * @cfg {Number} startDay
15129 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15137 getAutoCreate : function(){
15140 var fc_button = function(name, corner, style, content ) {
15141 return Roo.apply({},{
15143 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15145 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15148 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15159 style : 'width:100%',
15166 cls : 'fc-header-left',
15168 fc_button('prev', 'left', 'arrow', '‹' ),
15169 fc_button('next', 'right', 'arrow', '›' ),
15170 { tag: 'span', cls: 'fc-header-space' },
15171 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15179 cls : 'fc-header-center',
15183 cls: 'fc-header-title',
15186 html : 'month / year'
15194 cls : 'fc-header-right',
15196 /* fc_button('month', 'left', '', 'month' ),
15197 fc_button('week', '', '', 'week' ),
15198 fc_button('day', 'right', '', 'day' )
15210 header = this.header;
15213 var cal_heads = function() {
15215 // fixme - handle this.
15217 for (var i =0; i < Date.dayNames.length; i++) {
15218 var d = Date.dayNames[i];
15221 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15222 html : d.substring(0,3)
15226 ret[0].cls += ' fc-first';
15227 ret[6].cls += ' fc-last';
15230 var cal_cell = function(n) {
15233 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15238 cls: 'fc-day-number',
15242 cls: 'fc-day-content',
15246 style: 'position: relative;' // height: 17px;
15258 var cal_rows = function() {
15261 for (var r = 0; r < 6; r++) {
15268 for (var i =0; i < Date.dayNames.length; i++) {
15269 var d = Date.dayNames[i];
15270 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15273 row.cn[0].cls+=' fc-first';
15274 row.cn[0].cn[0].style = 'min-height:90px';
15275 row.cn[6].cls+=' fc-last';
15279 ret[0].cls += ' fc-first';
15280 ret[4].cls += ' fc-prev-last';
15281 ret[5].cls += ' fc-last';
15288 cls: 'fc-border-separate',
15289 style : 'width:100%',
15297 cls : 'fc-first fc-last',
15315 cls : 'fc-content',
15316 style : "position: relative;",
15319 cls : 'fc-view fc-view-month fc-grid',
15320 style : 'position: relative',
15321 unselectable : 'on',
15324 cls : 'fc-event-container',
15325 style : 'position:absolute;z-index:8;top:0;left:0;'
15343 initEvents : function()
15346 throw "can not find store for calendar";
15352 style: "text-align:center",
15356 style: "background-color:white;width:50%;margin:250 auto",
15360 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15371 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15373 var size = this.el.select('.fc-content', true).first().getSize();
15374 this.maskEl.setSize(size.width, size.height);
15375 this.maskEl.enableDisplayMode("block");
15376 if(!this.loadMask){
15377 this.maskEl.hide();
15380 this.store = Roo.factory(this.store, Roo.data);
15381 this.store.on('load', this.onLoad, this);
15382 this.store.on('beforeload', this.onBeforeLoad, this);
15386 this.cells = this.el.select('.fc-day',true);
15387 //Roo.log(this.cells);
15388 this.textNodes = this.el.query('.fc-day-number');
15389 this.cells.addClassOnOver('fc-state-hover');
15391 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15392 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15393 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15394 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15396 this.on('monthchange', this.onMonthChange, this);
15398 this.update(new Date().clearTime());
15401 resize : function() {
15402 var sz = this.el.getSize();
15404 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15405 this.el.select('.fc-day-content div',true).setHeight(34);
15410 showPrevMonth : function(e){
15411 this.update(this.activeDate.add("mo", -1));
15413 showToday : function(e){
15414 this.update(new Date().clearTime());
15417 showNextMonth : function(e){
15418 this.update(this.activeDate.add("mo", 1));
15422 showPrevYear : function(){
15423 this.update(this.activeDate.add("y", -1));
15427 showNextYear : function(){
15428 this.update(this.activeDate.add("y", 1));
15433 update : function(date)
15435 var vd = this.activeDate;
15436 this.activeDate = date;
15437 // if(vd && this.el){
15438 // var t = date.getTime();
15439 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15440 // Roo.log('using add remove');
15442 // this.fireEvent('monthchange', this, date);
15444 // this.cells.removeClass("fc-state-highlight");
15445 // this.cells.each(function(c){
15446 // if(c.dateValue == t){
15447 // c.addClass("fc-state-highlight");
15448 // setTimeout(function(){
15449 // try{c.dom.firstChild.focus();}catch(e){}
15459 var days = date.getDaysInMonth();
15461 var firstOfMonth = date.getFirstDateOfMonth();
15462 var startingPos = firstOfMonth.getDay()-this.startDay;
15464 if(startingPos < this.startDay){
15468 var pm = date.add(Date.MONTH, -1);
15469 var prevStart = pm.getDaysInMonth()-startingPos;
15471 this.cells = this.el.select('.fc-day',true);
15472 this.textNodes = this.el.query('.fc-day-number');
15473 this.cells.addClassOnOver('fc-state-hover');
15475 var cells = this.cells.elements;
15476 var textEls = this.textNodes;
15478 Roo.each(cells, function(cell){
15479 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15482 days += startingPos;
15484 // convert everything to numbers so it's fast
15485 var day = 86400000;
15486 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15489 //Roo.log(prevStart);
15491 var today = new Date().clearTime().getTime();
15492 var sel = date.clearTime().getTime();
15493 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15494 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15495 var ddMatch = this.disabledDatesRE;
15496 var ddText = this.disabledDatesText;
15497 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15498 var ddaysText = this.disabledDaysText;
15499 var format = this.format;
15501 var setCellClass = function(cal, cell){
15505 //Roo.log('set Cell Class');
15507 var t = d.getTime();
15511 cell.dateValue = t;
15513 cell.className += " fc-today";
15514 cell.className += " fc-state-highlight";
15515 cell.title = cal.todayText;
15518 // disable highlight in other month..
15519 //cell.className += " fc-state-highlight";
15524 cell.className = " fc-state-disabled";
15525 cell.title = cal.minText;
15529 cell.className = " fc-state-disabled";
15530 cell.title = cal.maxText;
15534 if(ddays.indexOf(d.getDay()) != -1){
15535 cell.title = ddaysText;
15536 cell.className = " fc-state-disabled";
15539 if(ddMatch && format){
15540 var fvalue = d.dateFormat(format);
15541 if(ddMatch.test(fvalue)){
15542 cell.title = ddText.replace("%0", fvalue);
15543 cell.className = " fc-state-disabled";
15547 if (!cell.initialClassName) {
15548 cell.initialClassName = cell.dom.className;
15551 cell.dom.className = cell.initialClassName + ' ' + cell.className;
15556 for(; i < startingPos; i++) {
15557 textEls[i].innerHTML = (++prevStart);
15558 d.setDate(d.getDate()+1);
15560 cells[i].className = "fc-past fc-other-month";
15561 setCellClass(this, cells[i]);
15566 for(; i < days; i++){
15567 intDay = i - startingPos + 1;
15568 textEls[i].innerHTML = (intDay);
15569 d.setDate(d.getDate()+1);
15571 cells[i].className = ''; // "x-date-active";
15572 setCellClass(this, cells[i]);
15576 for(; i < 42; i++) {
15577 textEls[i].innerHTML = (++extraDays);
15578 d.setDate(d.getDate()+1);
15580 cells[i].className = "fc-future fc-other-month";
15581 setCellClass(this, cells[i]);
15584 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
15586 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
15588 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
15589 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
15591 if(totalRows != 6){
15592 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
15593 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
15596 this.fireEvent('monthchange', this, date);
15600 if(!this.internalRender){
15601 var main = this.el.dom.firstChild;
15602 var w = main.offsetWidth;
15603 this.el.setWidth(w + this.el.getBorderWidth("lr"));
15604 Roo.fly(main).setWidth(w);
15605 this.internalRender = true;
15606 // opera does not respect the auto grow header center column
15607 // then, after it gets a width opera refuses to recalculate
15608 // without a second pass
15609 if(Roo.isOpera && !this.secondPass){
15610 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
15611 this.secondPass = true;
15612 this.update.defer(10, this, [date]);
15619 findCell : function(dt) {
15620 dt = dt.clearTime().getTime();
15622 this.cells.each(function(c){
15623 //Roo.log("check " +c.dateValue + '?=' + dt);
15624 if(c.dateValue == dt){
15634 findCells : function(ev) {
15635 var s = ev.start.clone().clearTime().getTime();
15637 var e= ev.end.clone().clearTime().getTime();
15640 this.cells.each(function(c){
15641 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
15643 if(c.dateValue > e){
15646 if(c.dateValue < s){
15655 // findBestRow: function(cells)
15659 // for (var i =0 ; i < cells.length;i++) {
15660 // ret = Math.max(cells[i].rows || 0,ret);
15667 addItem : function(ev)
15669 // look for vertical location slot in
15670 var cells = this.findCells(ev);
15672 // ev.row = this.findBestRow(cells);
15674 // work out the location.
15678 for(var i =0; i < cells.length; i++) {
15680 cells[i].row = cells[0].row;
15683 cells[i].row = cells[i].row + 1;
15693 if (crow.start.getY() == cells[i].getY()) {
15695 crow.end = cells[i];
15712 cells[0].events.push(ev);
15714 this.calevents.push(ev);
15717 clearEvents: function() {
15719 if(!this.calevents){
15723 Roo.each(this.cells.elements, function(c){
15729 Roo.each(this.calevents, function(e) {
15730 Roo.each(e.els, function(el) {
15731 el.un('mouseenter' ,this.onEventEnter, this);
15732 el.un('mouseleave' ,this.onEventLeave, this);
15737 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
15743 renderEvents: function()
15747 this.cells.each(function(c) {
15756 if(c.row != c.events.length){
15757 r = 4 - (4 - (c.row - c.events.length));
15760 c.events = ev.slice(0, r);
15761 c.more = ev.slice(r);
15763 if(c.more.length && c.more.length == 1){
15764 c.events.push(c.more.pop());
15767 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
15771 this.cells.each(function(c) {
15773 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
15776 for (var e = 0; e < c.events.length; e++){
15777 var ev = c.events[e];
15778 var rows = ev.rows;
15780 for(var i = 0; i < rows.length; i++) {
15782 // how many rows should it span..
15785 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
15786 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
15788 unselectable : "on",
15791 cls: 'fc-event-inner',
15795 // cls: 'fc-event-time',
15796 // html : cells.length > 1 ? '' : ev.time
15800 cls: 'fc-event-title',
15801 html : String.format('{0}', ev.title)
15808 cls: 'ui-resizable-handle ui-resizable-e',
15809 html : '  '
15816 cfg.cls += ' fc-event-start';
15818 if ((i+1) == rows.length) {
15819 cfg.cls += ' fc-event-end';
15822 var ctr = _this.el.select('.fc-event-container',true).first();
15823 var cg = ctr.createChild(cfg);
15825 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
15826 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
15828 var r = (c.more.length) ? 1 : 0;
15829 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
15830 cg.setWidth(ebox.right - sbox.x -2);
15832 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
15833 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
15834 cg.on('click', _this.onEventClick, _this, ev);
15845 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15846 style : 'position: absolute',
15847 unselectable : "on",
15850 cls: 'fc-event-inner',
15854 cls: 'fc-event-title',
15862 cls: 'ui-resizable-handle ui-resizable-e',
15863 html : '  '
15869 var ctr = _this.el.select('.fc-event-container',true).first();
15870 var cg = ctr.createChild(cfg);
15872 var sbox = c.select('.fc-day-content',true).first().getBox();
15873 var ebox = c.select('.fc-day-content',true).first().getBox();
15875 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15876 cg.setWidth(ebox.right - sbox.x -2);
15878 cg.on('click', _this.onMoreEventClick, _this, c.more);
15888 onEventEnter: function (e, el,event,d) {
15889 this.fireEvent('evententer', this, el, event);
15892 onEventLeave: function (e, el,event,d) {
15893 this.fireEvent('eventleave', this, el, event);
15896 onEventClick: function (e, el,event,d) {
15897 this.fireEvent('eventclick', this, el, event);
15900 onMonthChange: function () {
15904 onMoreEventClick: function(e, el, more)
15908 this.calpopover.placement = 'right';
15909 this.calpopover.setTitle('More');
15911 this.calpopover.setContent('');
15913 var ctr = this.calpopover.el.select('.popover-content', true).first();
15915 Roo.each(more, function(m){
15917 cls : 'fc-event-hori fc-event-draggable',
15920 var cg = ctr.createChild(cfg);
15922 cg.on('click', _this.onEventClick, _this, m);
15925 this.calpopover.show(el);
15930 onLoad: function ()
15932 this.calevents = [];
15935 if(this.store.getCount() > 0){
15936 this.store.data.each(function(d){
15939 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15940 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15941 time : d.data.start_time,
15942 title : d.data.title,
15943 description : d.data.description,
15944 venue : d.data.venue
15949 this.renderEvents();
15951 if(this.calevents.length && this.loadMask){
15952 this.maskEl.hide();
15956 onBeforeLoad: function()
15958 this.clearEvents();
15960 this.maskEl.show();
15974 * @class Roo.bootstrap.Popover
15975 * @extends Roo.bootstrap.Component
15976 * Bootstrap Popover class
15977 * @cfg {String} html contents of the popover (or false to use children..)
15978 * @cfg {String} title of popover (or false to hide)
15979 * @cfg {String} placement how it is placed
15980 * @cfg {String} trigger click || hover (or false to trigger manually)
15981 * @cfg {String} over what (parent or false to trigger manually.)
15982 * @cfg {Number} delay - delay before showing
15985 * Create a new Popover
15986 * @param {Object} config The config object
15989 Roo.bootstrap.Popover = function(config){
15990 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15996 * After the popover show
15998 * @param {Roo.bootstrap.Popover} this
16003 * After the popover hide
16005 * @param {Roo.bootstrap.Popover} this
16011 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16013 title: 'Fill in a title',
16016 placement : 'right',
16017 trigger : 'hover', // hover
16023 can_build_overlaid : false,
16025 getChildContainer : function()
16027 return this.el.select('.popover-content',true).first();
16030 getAutoCreate : function(){
16033 cls : 'popover roo-dynamic',
16034 style: 'display:block',
16040 cls : 'popover-inner',
16044 cls: 'popover-title',
16048 cls : 'popover-content',
16059 setTitle: function(str)
16062 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16064 setContent: function(str)
16067 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16069 // as it get's added to the bottom of the page.
16070 onRender : function(ct, position)
16072 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16074 var cfg = Roo.apply({}, this.getAutoCreate());
16078 cfg.cls += ' ' + this.cls;
16081 cfg.style = this.style;
16083 //Roo.log("adding to ");
16084 this.el = Roo.get(document.body).createChild(cfg, position);
16085 // Roo.log(this.el);
16090 initEvents : function()
16092 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16093 this.el.enableDisplayMode('block');
16095 if (this.over === false) {
16098 if (this.triggers === false) {
16101 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16102 var triggers = this.trigger ? this.trigger.split(' ') : [];
16103 Roo.each(triggers, function(trigger) {
16105 if (trigger == 'click') {
16106 on_el.on('click', this.toggle, this);
16107 } else if (trigger != 'manual') {
16108 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16109 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16111 on_el.on(eventIn ,this.enter, this);
16112 on_el.on(eventOut, this.leave, this);
16123 toggle : function () {
16124 this.hoverState == 'in' ? this.leave() : this.enter();
16127 enter : function () {
16129 clearTimeout(this.timeout);
16131 this.hoverState = 'in';
16133 if (!this.delay || !this.delay.show) {
16138 this.timeout = setTimeout(function () {
16139 if (_t.hoverState == 'in') {
16142 }, this.delay.show)
16145 leave : function() {
16146 clearTimeout(this.timeout);
16148 this.hoverState = 'out';
16150 if (!this.delay || !this.delay.hide) {
16155 this.timeout = setTimeout(function () {
16156 if (_t.hoverState == 'out') {
16159 }, this.delay.hide)
16162 show : function (on_el)
16165 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16169 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16170 if (this.html !== false) {
16171 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16173 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16174 if (!this.title.length) {
16175 this.el.select('.popover-title',true).hide();
16178 var placement = typeof this.placement == 'function' ?
16179 this.placement.call(this, this.el, on_el) :
16182 var autoToken = /\s?auto?\s?/i;
16183 var autoPlace = autoToken.test(placement);
16185 placement = placement.replace(autoToken, '') || 'top';
16189 //this.el.setXY([0,0]);
16191 this.el.dom.style.display='block';
16192 this.el.addClass(placement);
16194 //this.el.appendTo(on_el);
16196 var p = this.getPosition();
16197 var box = this.el.getBox();
16202 var align = Roo.bootstrap.Popover.alignment[placement];
16203 this.el.alignTo(on_el, align[0],align[1]);
16204 //var arrow = this.el.select('.arrow',true).first();
16205 //arrow.set(align[2],
16207 this.el.addClass('in');
16210 if (this.el.hasClass('fade')) {
16214 this.hoverState = 'in';
16216 this.fireEvent('show', this);
16221 this.el.setXY([0,0]);
16222 this.el.removeClass('in');
16224 this.hoverState = null;
16226 this.fireEvent('hide', this);
16231 Roo.bootstrap.Popover.alignment = {
16232 'left' : ['r-l', [-10,0], 'right'],
16233 'right' : ['l-r', [10,0], 'left'],
16234 'bottom' : ['t-b', [0,10], 'top'],
16235 'top' : [ 'b-t', [0,-10], 'bottom']
16246 * @class Roo.bootstrap.Progress
16247 * @extends Roo.bootstrap.Component
16248 * Bootstrap Progress class
16249 * @cfg {Boolean} striped striped of the progress bar
16250 * @cfg {Boolean} active animated of the progress bar
16254 * Create a new Progress
16255 * @param {Object} config The config object
16258 Roo.bootstrap.Progress = function(config){
16259 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16262 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16267 getAutoCreate : function(){
16275 cfg.cls += ' progress-striped';
16279 cfg.cls += ' active';
16298 * @class Roo.bootstrap.ProgressBar
16299 * @extends Roo.bootstrap.Component
16300 * Bootstrap ProgressBar class
16301 * @cfg {Number} aria_valuenow aria-value now
16302 * @cfg {Number} aria_valuemin aria-value min
16303 * @cfg {Number} aria_valuemax aria-value max
16304 * @cfg {String} label label for the progress bar
16305 * @cfg {String} panel (success | info | warning | danger )
16306 * @cfg {String} role role of the progress bar
16307 * @cfg {String} sr_only text
16311 * Create a new ProgressBar
16312 * @param {Object} config The config object
16315 Roo.bootstrap.ProgressBar = function(config){
16316 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16319 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16323 aria_valuemax : 100,
16329 getAutoCreate : function()
16334 cls: 'progress-bar',
16335 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16347 cfg.role = this.role;
16350 if(this.aria_valuenow){
16351 cfg['aria-valuenow'] = this.aria_valuenow;
16354 if(this.aria_valuemin){
16355 cfg['aria-valuemin'] = this.aria_valuemin;
16358 if(this.aria_valuemax){
16359 cfg['aria-valuemax'] = this.aria_valuemax;
16362 if(this.label && !this.sr_only){
16363 cfg.html = this.label;
16367 cfg.cls += ' progress-bar-' + this.panel;
16373 update : function(aria_valuenow)
16375 this.aria_valuenow = aria_valuenow;
16377 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16392 * @class Roo.bootstrap.TabGroup
16393 * @extends Roo.bootstrap.Column
16394 * Bootstrap Column class
16395 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16396 * @cfg {Boolean} carousel true to make the group behave like a carousel
16397 * @cfg {Boolean} bullets show bullets for the panels
16398 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16399 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16400 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16403 * Create a new TabGroup
16404 * @param {Object} config The config object
16407 Roo.bootstrap.TabGroup = function(config){
16408 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16410 this.navId = Roo.id();
16413 Roo.bootstrap.TabGroup.register(this);
16417 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16420 transition : false,
16425 slideOnTouch : false,
16427 getAutoCreate : function()
16429 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16431 cfg.cls += ' tab-content';
16433 if (this.carousel) {
16434 cfg.cls += ' carousel slide';
16437 cls : 'carousel-inner'
16440 if(this.bullets && !Roo.isTouch){
16443 cls : 'carousel-bullets',
16447 if(this.bullets_cls){
16448 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16451 for (var i = 0; i < this.bullets; i++){
16453 cls : 'bullet bullet-' + i
16461 cfg.cn[0].cn = bullets;
16468 initEvents: function()
16470 if(Roo.isTouch && this.slideOnTouch){
16471 this.el.on("touchstart", this.onTouchStart, this);
16474 if(this.autoslide){
16477 this.slideFn = window.setInterval(function() {
16478 _this.showPanelNext();
16482 if(this.tabs.length < 2){
16483 var bulletsEl = this.el.select('.carousel-bullets',true).first();
16484 bulletsEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
16489 onTouchStart : function(e, el, o)
16491 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16495 this.showPanelNext();
16498 getChildContainer : function()
16500 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
16504 * register a Navigation item
16505 * @param {Roo.bootstrap.NavItem} the navitem to add
16507 register : function(item)
16509 this.tabs.push( item);
16510 item.navId = this.navId; // not really needed..
16515 getActivePanel : function()
16518 Roo.each(this.tabs, function(t) {
16528 getPanelByName : function(n)
16531 Roo.each(this.tabs, function(t) {
16532 if (t.tabId == n) {
16540 indexOfPanel : function(p)
16543 Roo.each(this.tabs, function(t,i) {
16544 if (t.tabId == p.tabId) {
16553 * show a specific panel
16554 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
16555 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
16557 showPanel : function (pan)
16559 if(this.transition || typeof(pan) == 'undefined'){
16560 Roo.log("waiting for the transitionend");
16564 if (typeof(pan) == 'number') {
16565 pan = this.tabs[pan];
16568 if (typeof(pan) == 'string') {
16569 pan = this.getPanelByName(pan);
16572 var cur = this.getActivePanel();
16575 Roo.log('pan or acitve pan is undefined');
16579 if (pan.tabId == this.getActivePanel().tabId) {
16583 if (false === cur.fireEvent('beforedeactivate')) {
16587 if(this.bullets > 0 && !Roo.isTouch){
16588 this.setActiveBullet(this.indexOfPanel(pan));
16591 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
16593 this.transition = true;
16594 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
16595 var lr = dir == 'next' ? 'left' : 'right';
16596 pan.el.addClass(dir); // or prev
16597 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
16598 cur.el.addClass(lr); // or right
16599 pan.el.addClass(lr);
16602 cur.el.on('transitionend', function() {
16603 Roo.log("trans end?");
16605 pan.el.removeClass([lr,dir]);
16606 pan.setActive(true);
16608 cur.el.removeClass([lr]);
16609 cur.setActive(false);
16611 _this.transition = false;
16613 }, this, { single: true } );
16618 cur.setActive(false);
16619 pan.setActive(true);
16624 showPanelNext : function()
16626 var i = this.indexOfPanel(this.getActivePanel());
16628 if (i >= this.tabs.length - 1 && !this.autoslide) {
16632 if (i >= this.tabs.length - 1 && this.autoslide) {
16636 this.showPanel(this.tabs[i+1]);
16639 showPanelPrev : function()
16641 var i = this.indexOfPanel(this.getActivePanel());
16643 if (i < 1 && !this.autoslide) {
16647 if (i < 1 && this.autoslide) {
16648 i = this.tabs.length;
16651 this.showPanel(this.tabs[i-1]);
16655 addBullet: function()
16657 if(!this.bullets || Roo.isTouch){
16660 var ctr = this.el.select('.carousel-bullets',true).first();
16661 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
16662 var bullet = ctr.createChild({
16663 cls : 'bullet bullet-' + i
16664 },ctr.dom.lastChild);
16669 bullet.on('click', (function(e, el, o, ii, t){
16671 e.preventDefault();
16673 this.showPanel(ii);
16675 if(this.autoslide && this.slideFn){
16676 clearInterval(this.slideFn);
16677 this.slideFn = window.setInterval(function() {
16678 _this.showPanelNext();
16682 }).createDelegate(this, [i, bullet], true));
16687 setActiveBullet : function(i)
16693 Roo.each(this.el.select('.bullet', true).elements, function(el){
16694 el.removeClass('selected');
16697 var bullet = this.el.select('.bullet-' + i, true).first();
16703 bullet.addClass('selected');
16714 Roo.apply(Roo.bootstrap.TabGroup, {
16718 * register a Navigation Group
16719 * @param {Roo.bootstrap.NavGroup} the navgroup to add
16721 register : function(navgrp)
16723 this.groups[navgrp.navId] = navgrp;
16727 * fetch a Navigation Group based on the navigation ID
16728 * if one does not exist , it will get created.
16729 * @param {string} the navgroup to add
16730 * @returns {Roo.bootstrap.NavGroup} the navgroup
16732 get: function(navId) {
16733 if (typeof(this.groups[navId]) == 'undefined') {
16734 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
16736 return this.groups[navId] ;
16751 * @class Roo.bootstrap.TabPanel
16752 * @extends Roo.bootstrap.Component
16753 * Bootstrap TabPanel class
16754 * @cfg {Boolean} active panel active
16755 * @cfg {String} html panel content
16756 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
16757 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
16761 * Create a new TabPanel
16762 * @param {Object} config The config object
16765 Roo.bootstrap.TabPanel = function(config){
16766 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
16770 * Fires when the active status changes
16771 * @param {Roo.bootstrap.TabPanel} this
16772 * @param {Boolean} state the new state
16777 * @event beforedeactivate
16778 * Fires before a tab is de-activated - can be used to do validation on a form.
16779 * @param {Roo.bootstrap.TabPanel} this
16780 * @return {Boolean} false if there is an error
16783 'beforedeactivate': true
16786 this.tabId = this.tabId || Roo.id();
16790 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
16797 getAutoCreate : function(){
16800 // item is needed for carousel - not sure if it has any effect otherwise
16801 cls: 'tab-pane item',
16802 html: this.html || ''
16806 cfg.cls += ' active';
16810 cfg.tabId = this.tabId;
16817 initEvents: function()
16819 var p = this.parent();
16820 this.navId = this.navId || p.navId;
16822 if (typeof(this.navId) != 'undefined') {
16823 // not really needed.. but just in case.. parent should be a NavGroup.
16824 var tg = Roo.bootstrap.TabGroup.get(this.navId);
16828 var i = tg.tabs.length - 1;
16830 if(this.active && tg.bullets > 0 && i < tg.bullets){
16831 tg.setActiveBullet(i);
16838 onRender : function(ct, position)
16840 // Roo.log("Call onRender: " + this.xtype);
16842 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
16850 setActive: function(state)
16852 Roo.log("panel - set active " + this.tabId + "=" + state);
16854 this.active = state;
16856 this.el.removeClass('active');
16858 } else if (!this.el.hasClass('active')) {
16859 this.el.addClass('active');
16862 this.fireEvent('changed', this, state);
16879 * @class Roo.bootstrap.DateField
16880 * @extends Roo.bootstrap.Input
16881 * Bootstrap DateField class
16882 * @cfg {Number} weekStart default 0
16883 * @cfg {String} viewMode default empty, (months|years)
16884 * @cfg {String} minViewMode default empty, (months|years)
16885 * @cfg {Number} startDate default -Infinity
16886 * @cfg {Number} endDate default Infinity
16887 * @cfg {Boolean} todayHighlight default false
16888 * @cfg {Boolean} todayBtn default false
16889 * @cfg {Boolean} calendarWeeks default false
16890 * @cfg {Object} daysOfWeekDisabled default empty
16891 * @cfg {Boolean} singleMode default false (true | false)
16893 * @cfg {Boolean} keyboardNavigation default true
16894 * @cfg {String} language default en
16897 * Create a new DateField
16898 * @param {Object} config The config object
16901 Roo.bootstrap.DateField = function(config){
16902 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16906 * Fires when this field show.
16907 * @param {Roo.bootstrap.DateField} this
16908 * @param {Mixed} date The date value
16913 * Fires when this field hide.
16914 * @param {Roo.bootstrap.DateField} this
16915 * @param {Mixed} date The date value
16920 * Fires when select a date.
16921 * @param {Roo.bootstrap.DateField} this
16922 * @param {Mixed} date The date value
16926 * @event beforeselect
16927 * Fires when before select a date.
16928 * @param {Roo.bootstrap.DateField} this
16929 * @param {Mixed} date The date value
16931 beforeselect : true
16935 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16938 * @cfg {String} format
16939 * The default date format string which can be overriden for localization support. The format must be
16940 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16944 * @cfg {String} altFormats
16945 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16946 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16948 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16956 todayHighlight : false,
16962 keyboardNavigation: true,
16964 calendarWeeks: false,
16966 startDate: -Infinity,
16970 daysOfWeekDisabled: [],
16974 singleMode : false,
16976 UTCDate: function()
16978 return new Date(Date.UTC.apply(Date, arguments));
16981 UTCToday: function()
16983 var today = new Date();
16984 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16987 getDate: function() {
16988 var d = this.getUTCDate();
16989 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16992 getUTCDate: function() {
16996 setDate: function(d) {
16997 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17000 setUTCDate: function(d) {
17002 this.setValue(this.formatDate(this.date));
17005 onRender: function(ct, position)
17008 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17010 this.language = this.language || 'en';
17011 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17012 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17014 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17015 this.format = this.format || 'm/d/y';
17016 this.isInline = false;
17017 this.isInput = true;
17018 this.component = this.el.select('.add-on', true).first() || false;
17019 this.component = (this.component && this.component.length === 0) ? false : this.component;
17020 this.hasInput = this.component && this.inputEL().length;
17022 if (typeof(this.minViewMode === 'string')) {
17023 switch (this.minViewMode) {
17025 this.minViewMode = 1;
17028 this.minViewMode = 2;
17031 this.minViewMode = 0;
17036 if (typeof(this.viewMode === 'string')) {
17037 switch (this.viewMode) {
17050 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17052 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17054 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17056 this.picker().on('mousedown', this.onMousedown, this);
17057 this.picker().on('click', this.onClick, this);
17059 this.picker().addClass('datepicker-dropdown');
17061 this.startViewMode = this.viewMode;
17063 if(this.singleMode){
17064 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17065 v.setVisibilityMode(Roo.Element.DISPLAY);
17069 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17070 v.setStyle('width', '189px');
17074 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17075 if(!this.calendarWeeks){
17080 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17081 v.attr('colspan', function(i, val){
17082 return parseInt(val) + 1;
17087 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17089 this.setStartDate(this.startDate);
17090 this.setEndDate(this.endDate);
17092 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17099 if(this.isInline) {
17104 picker : function()
17106 return this.pickerEl;
17107 // return this.el.select('.datepicker', true).first();
17110 fillDow: function()
17112 var dowCnt = this.weekStart;
17121 if(this.calendarWeeks){
17129 while (dowCnt < this.weekStart + 7) {
17133 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17137 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17140 fillMonths: function()
17143 var months = this.picker().select('>.datepicker-months td', true).first();
17145 months.dom.innerHTML = '';
17151 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17154 months.createChild(month);
17161 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;
17163 if (this.date < this.startDate) {
17164 this.viewDate = new Date(this.startDate);
17165 } else if (this.date > this.endDate) {
17166 this.viewDate = new Date(this.endDate);
17168 this.viewDate = new Date(this.date);
17176 var d = new Date(this.viewDate),
17177 year = d.getUTCFullYear(),
17178 month = d.getUTCMonth(),
17179 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17180 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17181 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17182 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17183 currentDate = this.date && this.date.valueOf(),
17184 today = this.UTCToday();
17186 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17188 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17190 // this.picker.select('>tfoot th.today').
17191 // .text(dates[this.language].today)
17192 // .toggle(this.todayBtn !== false);
17194 this.updateNavArrows();
17197 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17199 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17201 prevMonth.setUTCDate(day);
17203 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17205 var nextMonth = new Date(prevMonth);
17207 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17209 nextMonth = nextMonth.valueOf();
17211 var fillMonths = false;
17213 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17215 while(prevMonth.valueOf() < nextMonth) {
17218 if (prevMonth.getUTCDay() === this.weekStart) {
17220 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17228 if(this.calendarWeeks){
17229 // ISO 8601: First week contains first thursday.
17230 // ISO also states week starts on Monday, but we can be more abstract here.
17232 // Start of current week: based on weekstart/current date
17233 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17234 // Thursday of this week
17235 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17236 // First Thursday of year, year from thursday
17237 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17238 // Calendar week: ms between thursdays, div ms per day, div 7 days
17239 calWeek = (th - yth) / 864e5 / 7 + 1;
17241 fillMonths.cn.push({
17249 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17251 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17254 if (this.todayHighlight &&
17255 prevMonth.getUTCFullYear() == today.getFullYear() &&
17256 prevMonth.getUTCMonth() == today.getMonth() &&
17257 prevMonth.getUTCDate() == today.getDate()) {
17258 clsName += ' today';
17261 if (currentDate && prevMonth.valueOf() === currentDate) {
17262 clsName += ' active';
17265 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17266 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17267 clsName += ' disabled';
17270 fillMonths.cn.push({
17272 cls: 'day ' + clsName,
17273 html: prevMonth.getDate()
17276 prevMonth.setDate(prevMonth.getDate()+1);
17279 var currentYear = this.date && this.date.getUTCFullYear();
17280 var currentMonth = this.date && this.date.getUTCMonth();
17282 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17284 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17285 v.removeClass('active');
17287 if(currentYear === year && k === currentMonth){
17288 v.addClass('active');
17291 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17292 v.addClass('disabled');
17298 year = parseInt(year/10, 10) * 10;
17300 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17302 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17305 for (var i = -1; i < 11; i++) {
17306 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17308 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17316 showMode: function(dir)
17319 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17322 Roo.each(this.picker().select('>div',true).elements, function(v){
17323 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17326 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17331 if(this.isInline) {
17335 this.picker().removeClass(['bottom', 'top']);
17337 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17339 * place to the top of element!
17343 this.picker().addClass('top');
17344 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17349 this.picker().addClass('bottom');
17351 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17354 parseDate : function(value)
17356 if(!value || value instanceof Date){
17359 var v = Date.parseDate(value, this.format);
17360 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17361 v = Date.parseDate(value, 'Y-m-d');
17363 if(!v && this.altFormats){
17364 if(!this.altFormatsArray){
17365 this.altFormatsArray = this.altFormats.split("|");
17367 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17368 v = Date.parseDate(value, this.altFormatsArray[i]);
17374 formatDate : function(date, fmt)
17376 return (!date || !(date instanceof Date)) ?
17377 date : date.dateFormat(fmt || this.format);
17380 onFocus : function()
17382 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17386 onBlur : function()
17388 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17390 var d = this.inputEl().getValue();
17399 this.picker().show();
17403 this.fireEvent('show', this, this.date);
17408 if(this.isInline) {
17411 this.picker().hide();
17412 this.viewMode = this.startViewMode;
17415 this.fireEvent('hide', this, this.date);
17419 onMousedown: function(e)
17421 e.stopPropagation();
17422 e.preventDefault();
17427 Roo.bootstrap.DateField.superclass.keyup.call(this);
17431 setValue: function(v)
17433 if(this.fireEvent('beforeselect', this, v) !== false){
17434 var d = new Date(this.parseDate(v) ).clearTime();
17436 if(isNaN(d.getTime())){
17437 this.date = this.viewDate = '';
17438 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17442 v = this.formatDate(d);
17444 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17446 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17450 this.fireEvent('select', this, this.date);
17454 getValue: function()
17456 return this.formatDate(this.date);
17459 fireKey: function(e)
17461 if (!this.picker().isVisible()){
17462 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17468 var dateChanged = false,
17470 newDate, newViewDate;
17475 e.preventDefault();
17479 if (!this.keyboardNavigation) {
17482 dir = e.keyCode == 37 ? -1 : 1;
17485 newDate = this.moveYear(this.date, dir);
17486 newViewDate = this.moveYear(this.viewDate, dir);
17487 } else if (e.shiftKey){
17488 newDate = this.moveMonth(this.date, dir);
17489 newViewDate = this.moveMonth(this.viewDate, dir);
17491 newDate = new Date(this.date);
17492 newDate.setUTCDate(this.date.getUTCDate() + dir);
17493 newViewDate = new Date(this.viewDate);
17494 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
17496 if (this.dateWithinRange(newDate)){
17497 this.date = newDate;
17498 this.viewDate = newViewDate;
17499 this.setValue(this.formatDate(this.date));
17501 e.preventDefault();
17502 dateChanged = true;
17507 if (!this.keyboardNavigation) {
17510 dir = e.keyCode == 38 ? -1 : 1;
17512 newDate = this.moveYear(this.date, dir);
17513 newViewDate = this.moveYear(this.viewDate, dir);
17514 } else if (e.shiftKey){
17515 newDate = this.moveMonth(this.date, dir);
17516 newViewDate = this.moveMonth(this.viewDate, dir);
17518 newDate = new Date(this.date);
17519 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
17520 newViewDate = new Date(this.viewDate);
17521 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
17523 if (this.dateWithinRange(newDate)){
17524 this.date = newDate;
17525 this.viewDate = newViewDate;
17526 this.setValue(this.formatDate(this.date));
17528 e.preventDefault();
17529 dateChanged = true;
17533 this.setValue(this.formatDate(this.date));
17535 e.preventDefault();
17538 this.setValue(this.formatDate(this.date));
17552 onClick: function(e)
17554 e.stopPropagation();
17555 e.preventDefault();
17557 var target = e.getTarget();
17559 if(target.nodeName.toLowerCase() === 'i'){
17560 target = Roo.get(target).dom.parentNode;
17563 var nodeName = target.nodeName;
17564 var className = target.className;
17565 var html = target.innerHTML;
17566 //Roo.log(nodeName);
17568 switch(nodeName.toLowerCase()) {
17570 switch(className) {
17576 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
17577 switch(this.viewMode){
17579 this.viewDate = this.moveMonth(this.viewDate, dir);
17583 this.viewDate = this.moveYear(this.viewDate, dir);
17589 var date = new Date();
17590 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
17592 this.setValue(this.formatDate(this.date));
17599 if (className.indexOf('disabled') < 0) {
17600 this.viewDate.setUTCDate(1);
17601 if (className.indexOf('month') > -1) {
17602 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
17604 var year = parseInt(html, 10) || 0;
17605 this.viewDate.setUTCFullYear(year);
17609 if(this.singleMode){
17610 this.setValue(this.formatDate(this.viewDate));
17621 //Roo.log(className);
17622 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
17623 var day = parseInt(html, 10) || 1;
17624 var year = this.viewDate.getUTCFullYear(),
17625 month = this.viewDate.getUTCMonth();
17627 if (className.indexOf('old') > -1) {
17634 } else if (className.indexOf('new') > -1) {
17642 //Roo.log([year,month,day]);
17643 this.date = this.UTCDate(year, month, day,0,0,0,0);
17644 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
17646 //Roo.log(this.formatDate(this.date));
17647 this.setValue(this.formatDate(this.date));
17654 setStartDate: function(startDate)
17656 this.startDate = startDate || -Infinity;
17657 if (this.startDate !== -Infinity) {
17658 this.startDate = this.parseDate(this.startDate);
17661 this.updateNavArrows();
17664 setEndDate: function(endDate)
17666 this.endDate = endDate || Infinity;
17667 if (this.endDate !== Infinity) {
17668 this.endDate = this.parseDate(this.endDate);
17671 this.updateNavArrows();
17674 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
17676 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
17677 if (typeof(this.daysOfWeekDisabled) !== 'object') {
17678 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
17680 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
17681 return parseInt(d, 10);
17684 this.updateNavArrows();
17687 updateNavArrows: function()
17689 if(this.singleMode){
17693 var d = new Date(this.viewDate),
17694 year = d.getUTCFullYear(),
17695 month = d.getUTCMonth();
17697 Roo.each(this.picker().select('.prev', true).elements, function(v){
17699 switch (this.viewMode) {
17702 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
17708 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
17715 Roo.each(this.picker().select('.next', true).elements, function(v){
17717 switch (this.viewMode) {
17720 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
17726 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
17734 moveMonth: function(date, dir)
17739 var new_date = new Date(date.valueOf()),
17740 day = new_date.getUTCDate(),
17741 month = new_date.getUTCMonth(),
17742 mag = Math.abs(dir),
17744 dir = dir > 0 ? 1 : -1;
17747 // If going back one month, make sure month is not current month
17748 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
17750 return new_date.getUTCMonth() == month;
17752 // If going forward one month, make sure month is as expected
17753 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
17755 return new_date.getUTCMonth() != new_month;
17757 new_month = month + dir;
17758 new_date.setUTCMonth(new_month);
17759 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
17760 if (new_month < 0 || new_month > 11) {
17761 new_month = (new_month + 12) % 12;
17764 // For magnitudes >1, move one month at a time...
17765 for (var i=0; i<mag; i++) {
17766 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
17767 new_date = this.moveMonth(new_date, dir);
17769 // ...then reset the day, keeping it in the new month
17770 new_month = new_date.getUTCMonth();
17771 new_date.setUTCDate(day);
17773 return new_month != new_date.getUTCMonth();
17776 // Common date-resetting loop -- if date is beyond end of month, make it
17779 new_date.setUTCDate(--day);
17780 new_date.setUTCMonth(new_month);
17785 moveYear: function(date, dir)
17787 return this.moveMonth(date, dir*12);
17790 dateWithinRange: function(date)
17792 return date >= this.startDate && date <= this.endDate;
17798 this.picker().remove();
17803 Roo.apply(Roo.bootstrap.DateField, {
17814 html: '<i class="fa fa-arrow-left"/>'
17824 html: '<i class="fa fa-arrow-right"/>'
17866 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
17867 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17868 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
17869 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17870 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17883 navFnc: 'FullYear',
17888 navFnc: 'FullYear',
17893 Roo.apply(Roo.bootstrap.DateField, {
17897 cls: 'datepicker dropdown-menu roo-dynamic',
17901 cls: 'datepicker-days',
17905 cls: 'table-condensed',
17907 Roo.bootstrap.DateField.head,
17911 Roo.bootstrap.DateField.footer
17918 cls: 'datepicker-months',
17922 cls: 'table-condensed',
17924 Roo.bootstrap.DateField.head,
17925 Roo.bootstrap.DateField.content,
17926 Roo.bootstrap.DateField.footer
17933 cls: 'datepicker-years',
17937 cls: 'table-condensed',
17939 Roo.bootstrap.DateField.head,
17940 Roo.bootstrap.DateField.content,
17941 Roo.bootstrap.DateField.footer
17960 * @class Roo.bootstrap.TimeField
17961 * @extends Roo.bootstrap.Input
17962 * Bootstrap DateField class
17966 * Create a new TimeField
17967 * @param {Object} config The config object
17970 Roo.bootstrap.TimeField = function(config){
17971 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17975 * Fires when this field show.
17976 * @param {Roo.bootstrap.DateField} thisthis
17977 * @param {Mixed} date The date value
17982 * Fires when this field hide.
17983 * @param {Roo.bootstrap.DateField} this
17984 * @param {Mixed} date The date value
17989 * Fires when select a date.
17990 * @param {Roo.bootstrap.DateField} this
17991 * @param {Mixed} date The date value
17997 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18000 * @cfg {String} format
18001 * The default time format string which can be overriden for localization support. The format must be
18002 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18006 onRender: function(ct, position)
18009 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18011 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18013 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18015 this.pop = this.picker().select('>.datepicker-time',true).first();
18016 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18018 this.picker().on('mousedown', this.onMousedown, this);
18019 this.picker().on('click', this.onClick, this);
18021 this.picker().addClass('datepicker-dropdown');
18026 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18027 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18028 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18029 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18030 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18031 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18035 fireKey: function(e){
18036 if (!this.picker().isVisible()){
18037 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18043 e.preventDefault();
18051 this.onTogglePeriod();
18054 this.onIncrementMinutes();
18057 this.onDecrementMinutes();
18066 onClick: function(e) {
18067 e.stopPropagation();
18068 e.preventDefault();
18071 picker : function()
18073 return this.el.select('.datepicker', true).first();
18076 fillTime: function()
18078 var time = this.pop.select('tbody', true).first();
18080 time.dom.innerHTML = '';
18095 cls: 'hours-up glyphicon glyphicon-chevron-up'
18115 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18136 cls: 'timepicker-hour',
18151 cls: 'timepicker-minute',
18166 cls: 'btn btn-primary period',
18188 cls: 'hours-down glyphicon glyphicon-chevron-down'
18208 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18226 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18233 var hours = this.time.getHours();
18234 var minutes = this.time.getMinutes();
18247 hours = hours - 12;
18251 hours = '0' + hours;
18255 minutes = '0' + minutes;
18258 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18259 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18260 this.pop.select('button', true).first().dom.innerHTML = period;
18266 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18268 var cls = ['bottom'];
18270 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18277 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18282 this.picker().addClass(cls.join('-'));
18286 Roo.each(cls, function(c){
18288 _this.picker().setTop(_this.inputEl().getHeight());
18292 _this.picker().setTop(0 - _this.picker().getHeight());
18297 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18301 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18308 onFocus : function()
18310 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18314 onBlur : function()
18316 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18322 this.picker().show();
18327 this.fireEvent('show', this, this.date);
18332 this.picker().hide();
18335 this.fireEvent('hide', this, this.date);
18338 setTime : function()
18341 this.setValue(this.time.format(this.format));
18343 this.fireEvent('select', this, this.date);
18348 onMousedown: function(e){
18349 e.stopPropagation();
18350 e.preventDefault();
18353 onIncrementHours: function()
18355 Roo.log('onIncrementHours');
18356 this.time = this.time.add(Date.HOUR, 1);
18361 onDecrementHours: function()
18363 Roo.log('onDecrementHours');
18364 this.time = this.time.add(Date.HOUR, -1);
18368 onIncrementMinutes: function()
18370 Roo.log('onIncrementMinutes');
18371 this.time = this.time.add(Date.MINUTE, 1);
18375 onDecrementMinutes: function()
18377 Roo.log('onDecrementMinutes');
18378 this.time = this.time.add(Date.MINUTE, -1);
18382 onTogglePeriod: function()
18384 Roo.log('onTogglePeriod');
18385 this.time = this.time.add(Date.HOUR, 12);
18392 Roo.apply(Roo.bootstrap.TimeField, {
18422 cls: 'btn btn-info ok',
18434 Roo.apply(Roo.bootstrap.TimeField, {
18438 cls: 'datepicker dropdown-menu',
18442 cls: 'datepicker-time',
18446 cls: 'table-condensed',
18448 Roo.bootstrap.TimeField.content,
18449 Roo.bootstrap.TimeField.footer
18468 * @class Roo.bootstrap.MonthField
18469 * @extends Roo.bootstrap.Input
18470 * Bootstrap MonthField class
18472 * @cfg {String} language default en
18475 * Create a new MonthField
18476 * @param {Object} config The config object
18479 Roo.bootstrap.MonthField = function(config){
18480 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
18485 * Fires when this field show.
18486 * @param {Roo.bootstrap.MonthField} this
18487 * @param {Mixed} date The date value
18492 * Fires when this field hide.
18493 * @param {Roo.bootstrap.MonthField} this
18494 * @param {Mixed} date The date value
18499 * Fires when select a date.
18500 * @param {Roo.bootstrap.MonthField} this
18501 * @param {String} oldvalue The old value
18502 * @param {String} newvalue The new value
18508 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
18510 onRender: function(ct, position)
18513 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
18515 this.language = this.language || 'en';
18516 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
18517 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
18519 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
18520 this.isInline = false;
18521 this.isInput = true;
18522 this.component = this.el.select('.add-on', true).first() || false;
18523 this.component = (this.component && this.component.length === 0) ? false : this.component;
18524 this.hasInput = this.component && this.inputEL().length;
18526 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
18528 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18530 this.picker().on('mousedown', this.onMousedown, this);
18531 this.picker().on('click', this.onClick, this);
18533 this.picker().addClass('datepicker-dropdown');
18535 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18536 v.setStyle('width', '189px');
18543 if(this.isInline) {
18549 setValue: function(v, suppressEvent)
18551 var o = this.getValue();
18553 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
18557 if(suppressEvent !== true){
18558 this.fireEvent('select', this, o, v);
18563 getValue: function()
18568 onClick: function(e)
18570 e.stopPropagation();
18571 e.preventDefault();
18573 var target = e.getTarget();
18575 if(target.nodeName.toLowerCase() === 'i'){
18576 target = Roo.get(target).dom.parentNode;
18579 var nodeName = target.nodeName;
18580 var className = target.className;
18581 var html = target.innerHTML;
18583 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
18587 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
18589 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18595 picker : function()
18597 return this.pickerEl;
18600 fillMonths: function()
18603 var months = this.picker().select('>.datepicker-months td', true).first();
18605 months.dom.innerHTML = '';
18611 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
18614 months.createChild(month);
18623 if(typeof(this.vIndex) == 'undefined' && this.value.length){
18624 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
18627 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
18628 e.removeClass('active');
18630 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
18631 e.addClass('active');
18638 if(this.isInline) {
18642 this.picker().removeClass(['bottom', 'top']);
18644 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18646 * place to the top of element!
18650 this.picker().addClass('top');
18651 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18656 this.picker().addClass('bottom');
18658 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18661 onFocus : function()
18663 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
18667 onBlur : function()
18669 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
18671 var d = this.inputEl().getValue();
18680 this.picker().show();
18681 this.picker().select('>.datepicker-months', true).first().show();
18685 this.fireEvent('show', this, this.date);
18690 if(this.isInline) {
18693 this.picker().hide();
18694 this.fireEvent('hide', this, this.date);
18698 onMousedown: function(e)
18700 e.stopPropagation();
18701 e.preventDefault();
18706 Roo.bootstrap.MonthField.superclass.keyup.call(this);
18710 fireKey: function(e)
18712 if (!this.picker().isVisible()){
18713 if (e.keyCode == 27) {// allow escape to hide and re-show picker
18724 e.preventDefault();
18728 dir = e.keyCode == 37 ? -1 : 1;
18730 this.vIndex = this.vIndex + dir;
18732 if(this.vIndex < 0){
18736 if(this.vIndex > 11){
18740 if(isNaN(this.vIndex)){
18744 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18750 dir = e.keyCode == 38 ? -1 : 1;
18752 this.vIndex = this.vIndex + dir * 4;
18754 if(this.vIndex < 0){
18758 if(this.vIndex > 11){
18762 if(isNaN(this.vIndex)){
18766 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18771 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18772 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18776 e.preventDefault();
18779 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18780 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18796 this.picker().remove();
18801 Roo.apply(Roo.bootstrap.MonthField, {
18820 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18821 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
18826 Roo.apply(Roo.bootstrap.MonthField, {
18830 cls: 'datepicker dropdown-menu roo-dynamic',
18834 cls: 'datepicker-months',
18838 cls: 'table-condensed',
18840 Roo.bootstrap.DateField.content
18860 * @class Roo.bootstrap.CheckBox
18861 * @extends Roo.bootstrap.Input
18862 * Bootstrap CheckBox class
18864 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
18865 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
18866 * @cfg {String} boxLabel The text that appears beside the checkbox
18867 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
18868 * @cfg {Boolean} checked initnal the element
18869 * @cfg {Boolean} inline inline the element (default false)
18870 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
18873 * Create a new CheckBox
18874 * @param {Object} config The config object
18877 Roo.bootstrap.CheckBox = function(config){
18878 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18883 * Fires when the element is checked or unchecked.
18884 * @param {Roo.bootstrap.CheckBox} this This input
18885 * @param {Boolean} checked The new checked value
18892 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18894 inputType: 'checkbox',
18902 getAutoCreate : function()
18904 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18910 cfg.cls = 'form-group ' + this.inputType; //input-group
18913 cfg.cls += ' ' + this.inputType + '-inline';
18919 type : this.inputType,
18920 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18921 cls : 'roo-' + this.inputType, //'form-box',
18922 placeholder : this.placeholder || ''
18926 if (this.weight) { // Validity check?
18927 cfg.cls += " " + this.inputType + "-" + this.weight;
18930 if (this.disabled) {
18931 input.disabled=true;
18935 input.checked = this.checked;
18939 input.name = this.name;
18943 input.cls += ' input-' + this.size;
18948 ['xs','sm','md','lg'].map(function(size){
18949 if (settings[size]) {
18950 cfg.cls += ' col-' + size + '-' + settings[size];
18954 var inputblock = input;
18956 if (this.before || this.after) {
18959 cls : 'input-group',
18964 inputblock.cn.push({
18966 cls : 'input-group-addon',
18971 inputblock.cn.push(input);
18974 inputblock.cn.push({
18976 cls : 'input-group-addon',
18983 if (align ==='left' && this.fieldLabel.length) {
18984 // Roo.log("left and has label");
18990 cls : 'control-label col-md-' + this.labelWidth,
18991 html : this.fieldLabel
18995 cls : "col-md-" + (12 - this.labelWidth),
19002 } else if ( this.fieldLabel.length) {
19003 // Roo.log(" label");
19007 tag: this.boxLabel ? 'span' : 'label',
19009 cls: 'control-label box-input-label',
19010 //cls : 'input-group-addon',
19011 html : this.fieldLabel
19021 // Roo.log(" no label && no align");
19022 cfg.cn = [ inputblock ] ;
19028 var boxLabelCfg = {
19030 //'for': id, // box label is handled by onclick - so no for...
19032 html: this.boxLabel
19036 boxLabelCfg.tooltip = this.tooltip;
19039 cfg.cn.push(boxLabelCfg);
19049 * return the real input element.
19051 inputEl: function ()
19053 return this.el.select('input.roo-' + this.inputType,true).first();
19056 labelEl: function()
19058 return this.el.select('label.control-label',true).first();
19060 /* depricated... */
19064 return this.labelEl();
19067 boxLabelEl: function()
19069 return this.el.select('label.box-label',true).first();
19072 initEvents : function()
19074 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19076 this.inputEl().on('click', this.onClick, this);
19078 if (this.boxLabel) {
19079 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19082 this.startValue = this.getValue();
19085 Roo.bootstrap.CheckBox.register(this);
19089 onClick : function()
19091 this.setChecked(!this.checked);
19094 setChecked : function(state,suppressEvent)
19096 this.startValue = this.getValue();
19098 if(this.inputType == 'radio'){
19100 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19101 e.dom.checked = false;
19104 this.inputEl().dom.checked = true;
19106 this.inputEl().dom.value = this.inputValue;
19108 if(suppressEvent !== true){
19109 this.fireEvent('check', this, true);
19117 this.checked = state;
19119 this.inputEl().dom.checked = state;
19121 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19123 if(suppressEvent !== true){
19124 this.fireEvent('check', this, state);
19130 getValue : function()
19132 if(this.inputType == 'radio'){
19133 return this.getGroupValue();
19136 return this.inputEl().getValue();
19140 getGroupValue : function()
19142 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19146 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19149 setValue : function(v,suppressEvent)
19151 if(this.inputType == 'radio'){
19152 this.setGroupValue(v, suppressEvent);
19156 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19161 setGroupValue : function(v, suppressEvent)
19163 this.startValue = this.getValue();
19165 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19166 e.dom.checked = false;
19168 if(e.dom.value == v){
19169 e.dom.checked = true;
19173 if(suppressEvent !== true){
19174 this.fireEvent('check', this, true);
19182 validate : function()
19186 (this.inputType == 'radio' && this.validateRadio()) ||
19187 (this.inputType == 'checkbox' && this.validateCheckbox())
19193 this.markInvalid();
19197 validateRadio : function()
19201 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19202 if(!e.dom.checked){
19214 validateCheckbox : function()
19217 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19220 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19228 for(var i in group){
19233 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19240 * Mark this field as valid
19242 markValid : function()
19244 if(this.allowBlank){
19250 this.fireEvent('valid', this);
19252 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19255 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19262 if(this.inputType == 'radio'){
19263 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19264 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19265 e.findParent('.form-group', false, true).addClass(_this.validClass);
19272 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19273 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19277 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19283 for(var i in group){
19284 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19285 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19290 * Mark this field as invalid
19291 * @param {String} msg The validation message
19293 markInvalid : function(msg)
19295 if(this.allowBlank){
19301 this.fireEvent('invalid', this, msg);
19303 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19306 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19310 label.markInvalid();
19313 if(this.inputType == 'radio'){
19314 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19315 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19316 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19323 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19324 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19328 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19334 for(var i in group){
19335 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19336 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19343 Roo.apply(Roo.bootstrap.CheckBox, {
19348 * register a CheckBox Group
19349 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19351 register : function(checkbox)
19353 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19354 this.groups[checkbox.groupId] = {};
19357 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19361 this.groups[checkbox.groupId][checkbox.name] = checkbox;
19365 * fetch a CheckBox Group based on the group ID
19366 * @param {string} the group ID
19367 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
19369 get: function(groupId) {
19370 if (typeof(this.groups[groupId]) == 'undefined') {
19374 return this.groups[groupId] ;
19386 *<div class="radio">
19388 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
19389 Option one is this and that—be sure to include why it's great
19396 *<label class="radio-inline">fieldLabel</label>
19397 *<label class="radio-inline">
19398 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
19406 * @class Roo.bootstrap.Radio
19407 * @extends Roo.bootstrap.CheckBox
19408 * Bootstrap Radio class
19411 * Create a new Radio
19412 * @param {Object} config The config object
19415 Roo.bootstrap.Radio = function(config){
19416 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
19420 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
19422 inputType: 'radio',
19426 getAutoCreate : function()
19428 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19429 align = align || 'left'; // default...
19436 tag : this.inline ? 'span' : 'div',
19441 var inline = this.inline ? ' radio-inline' : '';
19445 // does not need for, as we wrap the input with it..
19447 cls : 'control-label box-label' + inline,
19450 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
19454 //cls : 'control-label' + inline,
19455 html : this.fieldLabel,
19456 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
19465 type : this.inputType,
19466 //value : (!this.checked) ? this.valueOff : this.inputValue,
19467 value : this.inputValue,
19469 placeholder : this.placeholder || '' // ?? needed????
19472 if (this.weight) { // Validity check?
19473 input.cls += " radio-" + this.weight;
19475 if (this.disabled) {
19476 input.disabled=true;
19480 input.checked = this.checked;
19484 input.name = this.name;
19488 input.cls += ' input-' + this.size;
19491 //?? can span's inline have a width??
19494 ['xs','sm','md','lg'].map(function(size){
19495 if (settings[size]) {
19496 cfg.cls += ' col-' + size + '-' + settings[size];
19500 var inputblock = input;
19502 if (this.before || this.after) {
19505 cls : 'input-group',
19510 inputblock.cn.push({
19512 cls : 'input-group-addon',
19516 inputblock.cn.push(input);
19518 inputblock.cn.push({
19520 cls : 'input-group-addon',
19528 if (this.fieldLabel && this.fieldLabel.length) {
19529 cfg.cn.push(fieldLabel);
19532 // normal bootstrap puts the input inside the label.
19533 // however with our styled version - it has to go after the input.
19535 //lbl.cn.push(inputblock);
19539 cls: 'radio' + inline,
19546 cfg.cn.push( lblwrap);
19551 html: this.boxLabel
19560 initEvents : function()
19562 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19564 this.inputEl().on('click', this.onClick, this);
19565 if (this.boxLabel) {
19566 //Roo.log('find label');
19567 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
19572 inputEl: function ()
19574 return this.el.select('input.roo-radio',true).first();
19576 onClick : function()
19579 this.setChecked(true);
19582 setChecked : function(state,suppressEvent)
19585 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19586 v.dom.checked = false;
19589 Roo.log(this.inputEl().dom);
19590 this.checked = state;
19591 this.inputEl().dom.checked = state;
19593 if(suppressEvent !== true){
19594 this.fireEvent('check', this, state);
19597 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19601 getGroupValue : function()
19604 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19605 if(v.dom.checked == true){
19606 value = v.dom.value;
19614 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19615 * @return {Mixed} value The field value
19617 getValue : function(){
19618 return this.getGroupValue();
19624 //<script type="text/javascript">
19627 * Based Ext JS Library 1.1.1
19628 * Copyright(c) 2006-2007, Ext JS, LLC.
19634 * @class Roo.HtmlEditorCore
19635 * @extends Roo.Component
19636 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
19638 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
19641 Roo.HtmlEditorCore = function(config){
19644 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
19649 * @event initialize
19650 * Fires when the editor is fully initialized (including the iframe)
19651 * @param {Roo.HtmlEditorCore} this
19656 * Fires when the editor is first receives the focus. Any insertion must wait
19657 * until after this event.
19658 * @param {Roo.HtmlEditorCore} this
19662 * @event beforesync
19663 * Fires before the textarea is updated with content from the editor iframe. Return false
19664 * to cancel the sync.
19665 * @param {Roo.HtmlEditorCore} this
19666 * @param {String} html
19670 * @event beforepush
19671 * Fires before the iframe editor is updated with content from the textarea. Return false
19672 * to cancel the push.
19673 * @param {Roo.HtmlEditorCore} this
19674 * @param {String} html
19679 * Fires when the textarea is updated with content from the editor iframe.
19680 * @param {Roo.HtmlEditorCore} this
19681 * @param {String} html
19686 * Fires when the iframe editor is updated with content from the textarea.
19687 * @param {Roo.HtmlEditorCore} this
19688 * @param {String} html
19693 * @event editorevent
19694 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19695 * @param {Roo.HtmlEditorCore} this
19701 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
19703 // defaults : white / black...
19704 this.applyBlacklists();
19711 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
19715 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
19721 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19726 * @cfg {Number} height (in pixels)
19730 * @cfg {Number} width (in pixels)
19735 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19738 stylesheets: false,
19743 // private properties
19744 validationEvent : false,
19746 initialized : false,
19748 sourceEditMode : false,
19749 onFocus : Roo.emptyFn,
19751 hideMode:'offsets',
19755 // blacklist + whitelisted elements..
19762 * Protected method that will not generally be called directly. It
19763 * is called when the editor initializes the iframe with HTML contents. Override this method if you
19764 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
19766 getDocMarkup : function(){
19770 // inherit styels from page...??
19771 if (this.stylesheets === false) {
19773 Roo.get(document.head).select('style').each(function(node) {
19774 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19777 Roo.get(document.head).select('link').each(function(node) {
19778 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19781 } else if (!this.stylesheets.length) {
19783 st = '<style type="text/css">' +
19784 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19790 st += '<style type="text/css">' +
19791 'IMG { cursor: pointer } ' +
19795 return '<html><head>' + st +
19796 //<style type="text/css">' +
19797 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19799 ' </head><body class="roo-htmleditor-body"></body></html>';
19803 onRender : function(ct, position)
19806 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
19807 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
19810 this.el.dom.style.border = '0 none';
19811 this.el.dom.setAttribute('tabIndex', -1);
19812 this.el.addClass('x-hidden hide');
19816 if(Roo.isIE){ // fix IE 1px bogus margin
19817 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
19821 this.frameId = Roo.id();
19825 var iframe = this.owner.wrap.createChild({
19827 cls: 'form-control', // bootstrap..
19829 name: this.frameId,
19830 frameBorder : 'no',
19831 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
19836 this.iframe = iframe.dom;
19838 this.assignDocWin();
19840 this.doc.designMode = 'on';
19843 this.doc.write(this.getDocMarkup());
19847 var task = { // must defer to wait for browser to be ready
19849 //console.log("run task?" + this.doc.readyState);
19850 this.assignDocWin();
19851 if(this.doc.body || this.doc.readyState == 'complete'){
19853 this.doc.designMode="on";
19857 Roo.TaskMgr.stop(task);
19858 this.initEditor.defer(10, this);
19865 Roo.TaskMgr.start(task);
19870 onResize : function(w, h)
19872 Roo.log('resize: ' +w + ',' + h );
19873 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
19877 if(typeof w == 'number'){
19879 this.iframe.style.width = w + 'px';
19881 if(typeof h == 'number'){
19883 this.iframe.style.height = h + 'px';
19885 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
19892 * Toggles the editor between standard and source edit mode.
19893 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19895 toggleSourceEdit : function(sourceEditMode){
19897 this.sourceEditMode = sourceEditMode === true;
19899 if(this.sourceEditMode){
19901 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19904 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19905 //this.iframe.className = '';
19908 //this.setSize(this.owner.wrap.getSize());
19909 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19916 * Protected method that will not generally be called directly. If you need/want
19917 * custom HTML cleanup, this is the method you should override.
19918 * @param {String} html The HTML to be cleaned
19919 * return {String} The cleaned HTML
19921 cleanHtml : function(html){
19922 html = String(html);
19923 if(html.length > 5){
19924 if(Roo.isSafari){ // strip safari nonsense
19925 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19928 if(html == ' '){
19935 * HTML Editor -> Textarea
19936 * Protected method that will not generally be called directly. Syncs the contents
19937 * of the editor iframe with the textarea.
19939 syncValue : function(){
19940 if(this.initialized){
19941 var bd = (this.doc.body || this.doc.documentElement);
19942 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19943 var html = bd.innerHTML;
19945 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19946 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19948 html = '<div style="'+m[0]+'">' + html + '</div>';
19951 html = this.cleanHtml(html);
19952 // fix up the special chars.. normaly like back quotes in word...
19953 // however we do not want to do this with chinese..
19954 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19955 var cc = b.charCodeAt();
19957 (cc >= 0x4E00 && cc < 0xA000 ) ||
19958 (cc >= 0x3400 && cc < 0x4E00 ) ||
19959 (cc >= 0xf900 && cc < 0xfb00 )
19965 if(this.owner.fireEvent('beforesync', this, html) !== false){
19966 this.el.dom.value = html;
19967 this.owner.fireEvent('sync', this, html);
19973 * Protected method that will not generally be called directly. Pushes the value of the textarea
19974 * into the iframe editor.
19976 pushValue : function(){
19977 if(this.initialized){
19978 var v = this.el.dom.value.trim();
19980 // if(v.length < 1){
19984 if(this.owner.fireEvent('beforepush', this, v) !== false){
19985 var d = (this.doc.body || this.doc.documentElement);
19987 this.cleanUpPaste();
19988 this.el.dom.value = d.innerHTML;
19989 this.owner.fireEvent('push', this, v);
19995 deferFocus : function(){
19996 this.focus.defer(10, this);
20000 focus : function(){
20001 if(this.win && !this.sourceEditMode){
20008 assignDocWin: function()
20010 var iframe = this.iframe;
20013 this.doc = iframe.contentWindow.document;
20014 this.win = iframe.contentWindow;
20016 // if (!Roo.get(this.frameId)) {
20019 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20020 // this.win = Roo.get(this.frameId).dom.contentWindow;
20022 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20026 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20027 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20032 initEditor : function(){
20033 //console.log("INIT EDITOR");
20034 this.assignDocWin();
20038 this.doc.designMode="on";
20040 this.doc.write(this.getDocMarkup());
20043 var dbody = (this.doc.body || this.doc.documentElement);
20044 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20045 // this copies styles from the containing element into thsi one..
20046 // not sure why we need all of this..
20047 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20049 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20050 //ss['background-attachment'] = 'fixed'; // w3c
20051 dbody.bgProperties = 'fixed'; // ie
20052 //Roo.DomHelper.applyStyles(dbody, ss);
20053 Roo.EventManager.on(this.doc, {
20054 //'mousedown': this.onEditorEvent,
20055 'mouseup': this.onEditorEvent,
20056 'dblclick': this.onEditorEvent,
20057 'click': this.onEditorEvent,
20058 'keyup': this.onEditorEvent,
20063 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20065 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20066 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20068 this.initialized = true;
20070 this.owner.fireEvent('initialize', this);
20075 onDestroy : function(){
20081 //for (var i =0; i < this.toolbars.length;i++) {
20082 // // fixme - ask toolbars for heights?
20083 // this.toolbars[i].onDestroy();
20086 //this.wrap.dom.innerHTML = '';
20087 //this.wrap.remove();
20092 onFirstFocus : function(){
20094 this.assignDocWin();
20097 this.activated = true;
20100 if(Roo.isGecko){ // prevent silly gecko errors
20102 var s = this.win.getSelection();
20103 if(!s.focusNode || s.focusNode.nodeType != 3){
20104 var r = s.getRangeAt(0);
20105 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20110 this.execCmd('useCSS', true);
20111 this.execCmd('styleWithCSS', false);
20114 this.owner.fireEvent('activate', this);
20118 adjustFont: function(btn){
20119 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20120 //if(Roo.isSafari){ // safari
20123 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20124 if(Roo.isSafari){ // safari
20125 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20126 v = (v < 10) ? 10 : v;
20127 v = (v > 48) ? 48 : v;
20128 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20133 v = Math.max(1, v+adjust);
20135 this.execCmd('FontSize', v );
20138 onEditorEvent : function(e)
20140 this.owner.fireEvent('editorevent', this, e);
20141 // this.updateToolbar();
20142 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20145 insertTag : function(tg)
20147 // could be a bit smarter... -> wrap the current selected tRoo..
20148 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20150 range = this.createRange(this.getSelection());
20151 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20152 wrappingNode.appendChild(range.extractContents());
20153 range.insertNode(wrappingNode);
20160 this.execCmd("formatblock", tg);
20164 insertText : function(txt)
20168 var range = this.createRange();
20169 range.deleteContents();
20170 //alert(Sender.getAttribute('label'));
20172 range.insertNode(this.doc.createTextNode(txt));
20178 * Executes a Midas editor command on the editor document and performs necessary focus and
20179 * toolbar updates. <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 relayCmd : function(cmd, value){
20185 this.execCmd(cmd, value);
20186 this.owner.fireEvent('editorevent', this);
20187 //this.updateToolbar();
20188 this.owner.deferFocus();
20192 * Executes a Midas editor command directly on the editor document.
20193 * For visual commands, you should use {@link #relayCmd} instead.
20194 * <b>This should only be called after the editor is initialized.</b>
20195 * @param {String} cmd The Midas command
20196 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20198 execCmd : function(cmd, value){
20199 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20206 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20208 * @param {String} text | dom node..
20210 insertAtCursor : function(text)
20215 if(!this.activated){
20221 var r = this.doc.selection.createRange();
20232 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20236 // from jquery ui (MIT licenced)
20238 var win = this.win;
20240 if (win.getSelection && win.getSelection().getRangeAt) {
20241 range = win.getSelection().getRangeAt(0);
20242 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20243 range.insertNode(node);
20244 } else if (win.document.selection && win.document.selection.createRange) {
20245 // no firefox support
20246 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20247 win.document.selection.createRange().pasteHTML(txt);
20249 // no firefox support
20250 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20251 this.execCmd('InsertHTML', txt);
20260 mozKeyPress : function(e){
20262 var c = e.getCharCode(), cmd;
20265 c = String.fromCharCode(c).toLowerCase();
20279 this.cleanUpPaste.defer(100, this);
20287 e.preventDefault();
20295 fixKeys : function(){ // load time branching for fastest keydown performance
20297 return function(e){
20298 var k = e.getKey(), r;
20301 r = this.doc.selection.createRange();
20304 r.pasteHTML('    ');
20311 r = this.doc.selection.createRange();
20313 var target = r.parentElement();
20314 if(!target || target.tagName.toLowerCase() != 'li'){
20316 r.pasteHTML('<br />');
20322 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20323 this.cleanUpPaste.defer(100, this);
20329 }else if(Roo.isOpera){
20330 return function(e){
20331 var k = e.getKey();
20335 this.execCmd('InsertHTML','    ');
20338 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20339 this.cleanUpPaste.defer(100, this);
20344 }else if(Roo.isSafari){
20345 return function(e){
20346 var k = e.getKey();
20350 this.execCmd('InsertText','\t');
20354 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20355 this.cleanUpPaste.defer(100, this);
20363 getAllAncestors: function()
20365 var p = this.getSelectedNode();
20368 a.push(p); // push blank onto stack..
20369 p = this.getParentElement();
20373 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
20377 a.push(this.doc.body);
20381 lastSelNode : false,
20384 getSelection : function()
20386 this.assignDocWin();
20387 return Roo.isIE ? this.doc.selection : this.win.getSelection();
20390 getSelectedNode: function()
20392 // this may only work on Gecko!!!
20394 // should we cache this!!!!
20399 var range = this.createRange(this.getSelection()).cloneRange();
20402 var parent = range.parentElement();
20404 var testRange = range.duplicate();
20405 testRange.moveToElementText(parent);
20406 if (testRange.inRange(range)) {
20409 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
20412 parent = parent.parentElement;
20417 // is ancestor a text element.
20418 var ac = range.commonAncestorContainer;
20419 if (ac.nodeType == 3) {
20420 ac = ac.parentNode;
20423 var ar = ac.childNodes;
20426 var other_nodes = [];
20427 var has_other_nodes = false;
20428 for (var i=0;i<ar.length;i++) {
20429 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
20432 // fullly contained node.
20434 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
20439 // probably selected..
20440 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
20441 other_nodes.push(ar[i]);
20445 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
20450 has_other_nodes = true;
20452 if (!nodes.length && other_nodes.length) {
20453 nodes= other_nodes;
20455 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
20461 createRange: function(sel)
20463 // this has strange effects when using with
20464 // top toolbar - not sure if it's a great idea.
20465 //this.editor.contentWindow.focus();
20466 if (typeof sel != "undefined") {
20468 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
20470 return this.doc.createRange();
20473 return this.doc.createRange();
20476 getParentElement: function()
20479 this.assignDocWin();
20480 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
20482 var range = this.createRange(sel);
20485 var p = range.commonAncestorContainer;
20486 while (p.nodeType == 3) { // text node
20497 * Range intersection.. the hard stuff...
20501 * [ -- selected range --- ]
20505 * if end is before start or hits it. fail.
20506 * if start is after end or hits it fail.
20508 * if either hits (but other is outside. - then it's not
20514 // @see http://www.thismuchiknow.co.uk/?p=64.
20515 rangeIntersectsNode : function(range, node)
20517 var nodeRange = node.ownerDocument.createRange();
20519 nodeRange.selectNode(node);
20521 nodeRange.selectNodeContents(node);
20524 var rangeStartRange = range.cloneRange();
20525 rangeStartRange.collapse(true);
20527 var rangeEndRange = range.cloneRange();
20528 rangeEndRange.collapse(false);
20530 var nodeStartRange = nodeRange.cloneRange();
20531 nodeStartRange.collapse(true);
20533 var nodeEndRange = nodeRange.cloneRange();
20534 nodeEndRange.collapse(false);
20536 return rangeStartRange.compareBoundaryPoints(
20537 Range.START_TO_START, nodeEndRange) == -1 &&
20538 rangeEndRange.compareBoundaryPoints(
20539 Range.START_TO_START, nodeStartRange) == 1;
20543 rangeCompareNode : function(range, node)
20545 var nodeRange = node.ownerDocument.createRange();
20547 nodeRange.selectNode(node);
20549 nodeRange.selectNodeContents(node);
20553 range.collapse(true);
20555 nodeRange.collapse(true);
20557 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
20558 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
20560 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
20562 var nodeIsBefore = ss == 1;
20563 var nodeIsAfter = ee == -1;
20565 if (nodeIsBefore && nodeIsAfter) {
20568 if (!nodeIsBefore && nodeIsAfter) {
20569 return 1; //right trailed.
20572 if (nodeIsBefore && !nodeIsAfter) {
20573 return 2; // left trailed.
20579 // private? - in a new class?
20580 cleanUpPaste : function()
20582 // cleans up the whole document..
20583 Roo.log('cleanuppaste');
20585 this.cleanUpChildren(this.doc.body);
20586 var clean = this.cleanWordChars(this.doc.body.innerHTML);
20587 if (clean != this.doc.body.innerHTML) {
20588 this.doc.body.innerHTML = clean;
20593 cleanWordChars : function(input) {// change the chars to hex code
20594 var he = Roo.HtmlEditorCore;
20596 var output = input;
20597 Roo.each(he.swapCodes, function(sw) {
20598 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
20600 output = output.replace(swapper, sw[1]);
20607 cleanUpChildren : function (n)
20609 if (!n.childNodes.length) {
20612 for (var i = n.childNodes.length-1; i > -1 ; i--) {
20613 this.cleanUpChild(n.childNodes[i]);
20620 cleanUpChild : function (node)
20623 //console.log(node);
20624 if (node.nodeName == "#text") {
20625 // clean up silly Windows -- stuff?
20628 if (node.nodeName == "#comment") {
20629 node.parentNode.removeChild(node);
20630 // clean up silly Windows -- stuff?
20633 var lcname = node.tagName.toLowerCase();
20634 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
20635 // whitelist of tags..
20637 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
20639 node.parentNode.removeChild(node);
20644 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
20646 // remove <a name=....> as rendering on yahoo mailer is borked with this.
20647 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
20649 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
20650 // remove_keep_children = true;
20653 if (remove_keep_children) {
20654 this.cleanUpChildren(node);
20655 // inserts everything just before this node...
20656 while (node.childNodes.length) {
20657 var cn = node.childNodes[0];
20658 node.removeChild(cn);
20659 node.parentNode.insertBefore(cn, node);
20661 node.parentNode.removeChild(node);
20665 if (!node.attributes || !node.attributes.length) {
20666 this.cleanUpChildren(node);
20670 function cleanAttr(n,v)
20673 if (v.match(/^\./) || v.match(/^\//)) {
20676 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
20679 if (v.match(/^#/)) {
20682 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
20683 node.removeAttribute(n);
20687 var cwhite = this.cwhite;
20688 var cblack = this.cblack;
20690 function cleanStyle(n,v)
20692 if (v.match(/expression/)) { //XSS?? should we even bother..
20693 node.removeAttribute(n);
20697 var parts = v.split(/;/);
20700 Roo.each(parts, function(p) {
20701 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
20705 var l = p.split(':').shift().replace(/\s+/g,'');
20706 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
20708 if ( cwhite.length && cblack.indexOf(l) > -1) {
20709 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20710 //node.removeAttribute(n);
20714 // only allow 'c whitelisted system attributes'
20715 if ( cwhite.length && cwhite.indexOf(l) < 0) {
20716 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20717 //node.removeAttribute(n);
20727 if (clean.length) {
20728 node.setAttribute(n, clean.join(';'));
20730 node.removeAttribute(n);
20736 for (var i = node.attributes.length-1; i > -1 ; i--) {
20737 var a = node.attributes[i];
20740 if (a.name.toLowerCase().substr(0,2)=='on') {
20741 node.removeAttribute(a.name);
20744 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
20745 node.removeAttribute(a.name);
20748 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
20749 cleanAttr(a.name,a.value); // fixme..
20752 if (a.name == 'style') {
20753 cleanStyle(a.name,a.value);
20756 /// clean up MS crap..
20757 // tecnically this should be a list of valid class'es..
20760 if (a.name == 'class') {
20761 if (a.value.match(/^Mso/)) {
20762 node.className = '';
20765 if (a.value.match(/body/)) {
20766 node.className = '';
20777 this.cleanUpChildren(node);
20783 * Clean up MS wordisms...
20785 cleanWord : function(node)
20790 this.cleanWord(this.doc.body);
20793 if (node.nodeName == "#text") {
20794 // clean up silly Windows -- stuff?
20797 if (node.nodeName == "#comment") {
20798 node.parentNode.removeChild(node);
20799 // clean up silly Windows -- stuff?
20803 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
20804 node.parentNode.removeChild(node);
20808 // remove - but keep children..
20809 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
20810 while (node.childNodes.length) {
20811 var cn = node.childNodes[0];
20812 node.removeChild(cn);
20813 node.parentNode.insertBefore(cn, node);
20815 node.parentNode.removeChild(node);
20816 this.iterateChildren(node, this.cleanWord);
20820 if (node.className.length) {
20822 var cn = node.className.split(/\W+/);
20824 Roo.each(cn, function(cls) {
20825 if (cls.match(/Mso[a-zA-Z]+/)) {
20830 node.className = cna.length ? cna.join(' ') : '';
20832 node.removeAttribute("class");
20836 if (node.hasAttribute("lang")) {
20837 node.removeAttribute("lang");
20840 if (node.hasAttribute("style")) {
20842 var styles = node.getAttribute("style").split(";");
20844 Roo.each(styles, function(s) {
20845 if (!s.match(/:/)) {
20848 var kv = s.split(":");
20849 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
20852 // what ever is left... we allow.
20855 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20856 if (!nstyle.length) {
20857 node.removeAttribute('style');
20860 this.iterateChildren(node, this.cleanWord);
20866 * iterateChildren of a Node, calling fn each time, using this as the scole..
20867 * @param {DomNode} node node to iterate children of.
20868 * @param {Function} fn method of this class to call on each item.
20870 iterateChildren : function(node, fn)
20872 if (!node.childNodes.length) {
20875 for (var i = node.childNodes.length-1; i > -1 ; i--) {
20876 fn.call(this, node.childNodes[i])
20882 * cleanTableWidths.
20884 * Quite often pasting from word etc.. results in tables with column and widths.
20885 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
20888 cleanTableWidths : function(node)
20893 this.cleanTableWidths(this.doc.body);
20898 if (node.nodeName == "#text" || node.nodeName == "#comment") {
20901 Roo.log(node.tagName);
20902 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
20903 this.iterateChildren(node, this.cleanTableWidths);
20906 if (node.hasAttribute('width')) {
20907 node.removeAttribute('width');
20911 if (node.hasAttribute("style")) {
20914 var styles = node.getAttribute("style").split(";");
20916 Roo.each(styles, function(s) {
20917 if (!s.match(/:/)) {
20920 var kv = s.split(":");
20921 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20924 // what ever is left... we allow.
20927 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20928 if (!nstyle.length) {
20929 node.removeAttribute('style');
20933 this.iterateChildren(node, this.cleanTableWidths);
20941 domToHTML : function(currentElement, depth, nopadtext) {
20943 depth = depth || 0;
20944 nopadtext = nopadtext || false;
20946 if (!currentElement) {
20947 return this.domToHTML(this.doc.body);
20950 //Roo.log(currentElement);
20952 var allText = false;
20953 var nodeName = currentElement.nodeName;
20954 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20956 if (nodeName == '#text') {
20958 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20963 if (nodeName != 'BODY') {
20966 // Prints the node tagName, such as <A>, <IMG>, etc
20969 for(i = 0; i < currentElement.attributes.length;i++) {
20971 var aname = currentElement.attributes.item(i).name;
20972 if (!currentElement.attributes.item(i).value.length) {
20975 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20978 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20987 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20990 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20995 // Traverse the tree
20997 var currentElementChild = currentElement.childNodes.item(i);
20998 var allText = true;
20999 var innerHTML = '';
21001 while (currentElementChild) {
21002 // Formatting code (indent the tree so it looks nice on the screen)
21003 var nopad = nopadtext;
21004 if (lastnode == 'SPAN') {
21008 if (currentElementChild.nodeName == '#text') {
21009 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21010 toadd = nopadtext ? toadd : toadd.trim();
21011 if (!nopad && toadd.length > 80) {
21012 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21014 innerHTML += toadd;
21017 currentElementChild = currentElement.childNodes.item(i);
21023 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21025 // Recursively traverse the tree structure of the child node
21026 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21027 lastnode = currentElementChild.nodeName;
21029 currentElementChild=currentElement.childNodes.item(i);
21035 // The remaining code is mostly for formatting the tree
21036 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21041 ret+= "</"+tagName+">";
21047 applyBlacklists : function()
21049 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21050 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21054 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21055 if (b.indexOf(tag) > -1) {
21058 this.white.push(tag);
21062 Roo.each(w, function(tag) {
21063 if (b.indexOf(tag) > -1) {
21066 if (this.white.indexOf(tag) > -1) {
21069 this.white.push(tag);
21074 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21075 if (w.indexOf(tag) > -1) {
21078 this.black.push(tag);
21082 Roo.each(b, function(tag) {
21083 if (w.indexOf(tag) > -1) {
21086 if (this.black.indexOf(tag) > -1) {
21089 this.black.push(tag);
21094 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21095 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21099 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21100 if (b.indexOf(tag) > -1) {
21103 this.cwhite.push(tag);
21107 Roo.each(w, function(tag) {
21108 if (b.indexOf(tag) > -1) {
21111 if (this.cwhite.indexOf(tag) > -1) {
21114 this.cwhite.push(tag);
21119 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21120 if (w.indexOf(tag) > -1) {
21123 this.cblack.push(tag);
21127 Roo.each(b, function(tag) {
21128 if (w.indexOf(tag) > -1) {
21131 if (this.cblack.indexOf(tag) > -1) {
21134 this.cblack.push(tag);
21139 setStylesheets : function(stylesheets)
21141 if(typeof(stylesheets) == 'string'){
21142 Roo.get(this.iframe.contentDocument.head).createChild({
21144 rel : 'stylesheet',
21153 Roo.each(stylesheets, function(s) {
21158 Roo.get(_this.iframe.contentDocument.head).createChild({
21160 rel : 'stylesheet',
21169 removeStylesheets : function()
21173 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21178 // hide stuff that is not compatible
21192 * @event specialkey
21196 * @cfg {String} fieldClass @hide
21199 * @cfg {String} focusClass @hide
21202 * @cfg {String} autoCreate @hide
21205 * @cfg {String} inputType @hide
21208 * @cfg {String} invalidClass @hide
21211 * @cfg {String} invalidText @hide
21214 * @cfg {String} msgFx @hide
21217 * @cfg {String} validateOnBlur @hide
21221 Roo.HtmlEditorCore.white = [
21222 'area', 'br', 'img', 'input', 'hr', 'wbr',
21224 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21225 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21226 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21227 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21228 'table', 'ul', 'xmp',
21230 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21233 'dir', 'menu', 'ol', 'ul', 'dl',
21239 Roo.HtmlEditorCore.black = [
21240 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21242 'base', 'basefont', 'bgsound', 'blink', 'body',
21243 'frame', 'frameset', 'head', 'html', 'ilayer',
21244 'iframe', 'layer', 'link', 'meta', 'object',
21245 'script', 'style' ,'title', 'xml' // clean later..
21247 Roo.HtmlEditorCore.clean = [
21248 'script', 'style', 'title', 'xml'
21250 Roo.HtmlEditorCore.remove = [
21255 Roo.HtmlEditorCore.ablack = [
21259 Roo.HtmlEditorCore.aclean = [
21260 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21264 Roo.HtmlEditorCore.pwhite= [
21265 'http', 'https', 'mailto'
21268 // white listed style attributes.
21269 Roo.HtmlEditorCore.cwhite= [
21270 // 'text-align', /// default is to allow most things..
21276 // black listed style attributes.
21277 Roo.HtmlEditorCore.cblack= [
21278 // 'font-size' -- this can be set by the project
21282 Roo.HtmlEditorCore.swapCodes =[
21301 * @class Roo.bootstrap.HtmlEditor
21302 * @extends Roo.bootstrap.TextArea
21303 * Bootstrap HtmlEditor class
21306 * Create a new HtmlEditor
21307 * @param {Object} config The config object
21310 Roo.bootstrap.HtmlEditor = function(config){
21311 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21312 if (!this.toolbars) {
21313 this.toolbars = [];
21315 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21318 * @event initialize
21319 * Fires when the editor is fully initialized (including the iframe)
21320 * @param {HtmlEditor} this
21325 * Fires when the editor is first receives the focus. Any insertion must wait
21326 * until after this event.
21327 * @param {HtmlEditor} this
21331 * @event beforesync
21332 * Fires before the textarea is updated with content from the editor iframe. Return false
21333 * to cancel the sync.
21334 * @param {HtmlEditor} this
21335 * @param {String} html
21339 * @event beforepush
21340 * Fires before the iframe editor is updated with content from the textarea. Return false
21341 * to cancel the push.
21342 * @param {HtmlEditor} this
21343 * @param {String} html
21348 * Fires when the textarea is updated with content from the editor iframe.
21349 * @param {HtmlEditor} this
21350 * @param {String} html
21355 * Fires when the iframe editor is updated with content from the textarea.
21356 * @param {HtmlEditor} this
21357 * @param {String} html
21361 * @event editmodechange
21362 * Fires when the editor switches edit modes
21363 * @param {HtmlEditor} this
21364 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21366 editmodechange: true,
21368 * @event editorevent
21369 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21370 * @param {HtmlEditor} this
21374 * @event firstfocus
21375 * Fires when on first focus - needed by toolbars..
21376 * @param {HtmlEditor} this
21381 * Auto save the htmlEditor value as a file into Events
21382 * @param {HtmlEditor} this
21386 * @event savedpreview
21387 * preview the saved version of htmlEditor
21388 * @param {HtmlEditor} this
21395 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
21399 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
21404 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21409 * @cfg {Number} height (in pixels)
21413 * @cfg {Number} width (in pixels)
21418 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21421 stylesheets: false,
21426 // private properties
21427 validationEvent : false,
21429 initialized : false,
21432 onFocus : Roo.emptyFn,
21434 hideMode:'offsets',
21437 tbContainer : false,
21439 toolbarContainer :function() {
21440 return this.wrap.select('.x-html-editor-tb',true).first();
21444 * Protected method that will not generally be called directly. It
21445 * is called when the editor creates its toolbar. Override this method if you need to
21446 * add custom toolbar buttons.
21447 * @param {HtmlEditor} editor
21449 createToolbar : function(){
21451 Roo.log("create toolbars");
21453 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
21454 this.toolbars[0].render(this.toolbarContainer());
21458 // if (!editor.toolbars || !editor.toolbars.length) {
21459 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
21462 // for (var i =0 ; i < editor.toolbars.length;i++) {
21463 // editor.toolbars[i] = Roo.factory(
21464 // typeof(editor.toolbars[i]) == 'string' ?
21465 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
21466 // Roo.bootstrap.HtmlEditor);
21467 // editor.toolbars[i].init(editor);
21473 onRender : function(ct, position)
21475 // Roo.log("Call onRender: " + this.xtype);
21477 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
21479 this.wrap = this.inputEl().wrap({
21480 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
21483 this.editorcore.onRender(ct, position);
21485 if (this.resizable) {
21486 this.resizeEl = new Roo.Resizable(this.wrap, {
21490 minHeight : this.height,
21491 height: this.height,
21492 handles : this.resizable,
21495 resize : function(r, w, h) {
21496 _t.onResize(w,h); // -something
21502 this.createToolbar(this);
21505 if(!this.width && this.resizable){
21506 this.setSize(this.wrap.getSize());
21508 if (this.resizeEl) {
21509 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
21510 // should trigger onReize..
21516 onResize : function(w, h)
21518 Roo.log('resize: ' +w + ',' + h );
21519 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
21523 if(this.inputEl() ){
21524 if(typeof w == 'number'){
21525 var aw = w - this.wrap.getFrameWidth('lr');
21526 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
21529 if(typeof h == 'number'){
21530 var tbh = -11; // fixme it needs to tool bar size!
21531 for (var i =0; i < this.toolbars.length;i++) {
21532 // fixme - ask toolbars for heights?
21533 tbh += this.toolbars[i].el.getHeight();
21534 //if (this.toolbars[i].footer) {
21535 // tbh += this.toolbars[i].footer.el.getHeight();
21543 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
21544 ah -= 5; // knock a few pixes off for look..
21545 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
21549 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
21550 this.editorcore.onResize(ew,eh);
21555 * Toggles the editor between standard and source edit mode.
21556 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21558 toggleSourceEdit : function(sourceEditMode)
21560 this.editorcore.toggleSourceEdit(sourceEditMode);
21562 if(this.editorcore.sourceEditMode){
21563 Roo.log('editor - showing textarea');
21566 // Roo.log(this.syncValue());
21568 this.inputEl().removeClass(['hide', 'x-hidden']);
21569 this.inputEl().dom.removeAttribute('tabIndex');
21570 this.inputEl().focus();
21572 Roo.log('editor - hiding textarea');
21574 // Roo.log(this.pushValue());
21577 this.inputEl().addClass(['hide', 'x-hidden']);
21578 this.inputEl().dom.setAttribute('tabIndex', -1);
21579 //this.deferFocus();
21582 if(this.resizable){
21583 this.setSize(this.wrap.getSize());
21586 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
21589 // private (for BoxComponent)
21590 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21592 // private (for BoxComponent)
21593 getResizeEl : function(){
21597 // private (for BoxComponent)
21598 getPositionEl : function(){
21603 initEvents : function(){
21604 this.originalValue = this.getValue();
21608 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21611 // markInvalid : Roo.emptyFn,
21613 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21616 // clearInvalid : Roo.emptyFn,
21618 setValue : function(v){
21619 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
21620 this.editorcore.pushValue();
21625 deferFocus : function(){
21626 this.focus.defer(10, this);
21630 focus : function(){
21631 this.editorcore.focus();
21637 onDestroy : function(){
21643 for (var i =0; i < this.toolbars.length;i++) {
21644 // fixme - ask toolbars for heights?
21645 this.toolbars[i].onDestroy();
21648 this.wrap.dom.innerHTML = '';
21649 this.wrap.remove();
21654 onFirstFocus : function(){
21655 //Roo.log("onFirstFocus");
21656 this.editorcore.onFirstFocus();
21657 for (var i =0; i < this.toolbars.length;i++) {
21658 this.toolbars[i].onFirstFocus();
21664 syncValue : function()
21666 this.editorcore.syncValue();
21669 pushValue : function()
21671 this.editorcore.pushValue();
21675 // hide stuff that is not compatible
21689 * @event specialkey
21693 * @cfg {String} fieldClass @hide
21696 * @cfg {String} focusClass @hide
21699 * @cfg {String} autoCreate @hide
21702 * @cfg {String} inputType @hide
21705 * @cfg {String} invalidClass @hide
21708 * @cfg {String} invalidText @hide
21711 * @cfg {String} msgFx @hide
21714 * @cfg {String} validateOnBlur @hide
21723 Roo.namespace('Roo.bootstrap.htmleditor');
21725 * @class Roo.bootstrap.HtmlEditorToolbar1
21730 new Roo.bootstrap.HtmlEditor({
21733 new Roo.bootstrap.HtmlEditorToolbar1({
21734 disable : { fonts: 1 , format: 1, ..., ... , ...],
21740 * @cfg {Object} disable List of elements to disable..
21741 * @cfg {Array} btns List of additional buttons.
21745 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
21748 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
21751 Roo.apply(this, config);
21753 // default disabled, based on 'good practice'..
21754 this.disable = this.disable || {};
21755 Roo.applyIf(this.disable, {
21758 specialElements : true
21760 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
21762 this.editor = config.editor;
21763 this.editorcore = config.editor.editorcore;
21765 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
21767 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
21768 // dont call parent... till later.
21770 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
21775 editorcore : false,
21780 "h1","h2","h3","h4","h5","h6",
21782 "abbr", "acronym", "address", "cite", "samp", "var",
21786 onRender : function(ct, position)
21788 // Roo.log("Call onRender: " + this.xtype);
21790 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
21792 this.el.dom.style.marginBottom = '0';
21794 var editorcore = this.editorcore;
21795 var editor= this.editor;
21798 var btn = function(id,cmd , toggle, handler){
21800 var event = toggle ? 'toggle' : 'click';
21805 xns: Roo.bootstrap,
21808 enableToggle:toggle !== false,
21810 pressed : toggle ? false : null,
21813 a.listeners[toggle ? 'toggle' : 'click'] = function() {
21814 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
21823 xns: Roo.bootstrap,
21824 glyphicon : 'font',
21828 xns: Roo.bootstrap,
21832 Roo.each(this.formats, function(f) {
21833 style.menu.items.push({
21835 xns: Roo.bootstrap,
21836 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
21841 editorcore.insertTag(this.tagname);
21848 children.push(style);
21851 btn('bold',false,true);
21852 btn('italic',false,true);
21853 btn('align-left', 'justifyleft',true);
21854 btn('align-center', 'justifycenter',true);
21855 btn('align-right' , 'justifyright',true);
21856 btn('link', false, false, function(btn) {
21857 //Roo.log("create link?");
21858 var url = prompt(this.createLinkText, this.defaultLinkValue);
21859 if(url && url != 'http:/'+'/'){
21860 this.editorcore.relayCmd('createlink', url);
21863 btn('list','insertunorderedlist',true);
21864 btn('pencil', false,true, function(btn){
21867 this.toggleSourceEdit(btn.pressed);
21873 xns: Roo.bootstrap,
21878 xns: Roo.bootstrap,
21883 cog.menu.items.push({
21885 xns: Roo.bootstrap,
21886 html : Clean styles,
21891 editorcore.insertTag(this.tagname);
21900 this.xtype = 'NavSimplebar';
21902 for(var i=0;i< children.length;i++) {
21904 this.buttons.add(this.addxtypeChild(children[i]));
21908 editor.on('editorevent', this.updateToolbar, this);
21910 onBtnClick : function(id)
21912 this.editorcore.relayCmd(id);
21913 this.editorcore.focus();
21917 * Protected method that will not generally be called directly. It triggers
21918 * a toolbar update by reading the markup state of the current selection in the editor.
21920 updateToolbar: function(){
21922 if(!this.editorcore.activated){
21923 this.editor.onFirstFocus(); // is this neeed?
21927 var btns = this.buttons;
21928 var doc = this.editorcore.doc;
21929 btns.get('bold').setActive(doc.queryCommandState('bold'));
21930 btns.get('italic').setActive(doc.queryCommandState('italic'));
21931 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21933 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21934 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21935 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21937 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21938 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21941 var ans = this.editorcore.getAllAncestors();
21942 if (this.formatCombo) {
21945 var store = this.formatCombo.store;
21946 this.formatCombo.setValue("");
21947 for (var i =0; i < ans.length;i++) {
21948 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21950 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21958 // hides menus... - so this cant be on a menu...
21959 Roo.bootstrap.MenuMgr.hideAll();
21961 Roo.bootstrap.MenuMgr.hideAll();
21962 //this.editorsyncValue();
21964 onFirstFocus: function() {
21965 this.buttons.each(function(item){
21969 toggleSourceEdit : function(sourceEditMode){
21972 if(sourceEditMode){
21973 Roo.log("disabling buttons");
21974 this.buttons.each( function(item){
21975 if(item.cmd != 'pencil'){
21981 Roo.log("enabling buttons");
21982 if(this.editorcore.initialized){
21983 this.buttons.each( function(item){
21989 Roo.log("calling toggole on editor");
21990 // tell the editor that it's been pressed..
21991 this.editor.toggleSourceEdit(sourceEditMode);
22001 * @class Roo.bootstrap.Table.AbstractSelectionModel
22002 * @extends Roo.util.Observable
22003 * Abstract base class for grid SelectionModels. It provides the interface that should be
22004 * implemented by descendant classes. This class should not be directly instantiated.
22007 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22008 this.locked = false;
22009 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22013 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22014 /** @ignore Called by the grid automatically. Do not call directly. */
22015 init : function(grid){
22021 * Locks the selections.
22024 this.locked = true;
22028 * Unlocks the selections.
22030 unlock : function(){
22031 this.locked = false;
22035 * Returns true if the selections are locked.
22036 * @return {Boolean}
22038 isLocked : function(){
22039 return this.locked;
22043 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22044 * @class Roo.bootstrap.Table.RowSelectionModel
22045 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22046 * It supports multiple selections and keyboard selection/navigation.
22048 * @param {Object} config
22051 Roo.bootstrap.Table.RowSelectionModel = function(config){
22052 Roo.apply(this, config);
22053 this.selections = new Roo.util.MixedCollection(false, function(o){
22058 this.lastActive = false;
22062 * @event selectionchange
22063 * Fires when the selection changes
22064 * @param {SelectionModel} this
22066 "selectionchange" : true,
22068 * @event afterselectionchange
22069 * Fires after the selection changes (eg. by key press or clicking)
22070 * @param {SelectionModel} this
22072 "afterselectionchange" : true,
22074 * @event beforerowselect
22075 * Fires when a row is selected being selected, return false to cancel.
22076 * @param {SelectionModel} this
22077 * @param {Number} rowIndex The selected index
22078 * @param {Boolean} keepExisting False if other selections will be cleared
22080 "beforerowselect" : true,
22083 * Fires when a row is selected.
22084 * @param {SelectionModel} this
22085 * @param {Number} rowIndex The selected index
22086 * @param {Roo.data.Record} r The record
22088 "rowselect" : true,
22090 * @event rowdeselect
22091 * Fires when a row is deselected.
22092 * @param {SelectionModel} this
22093 * @param {Number} rowIndex The selected index
22095 "rowdeselect" : true
22097 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22098 this.locked = false;
22101 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22103 * @cfg {Boolean} singleSelect
22104 * True to allow selection of only one row at a time (defaults to false)
22106 singleSelect : false,
22109 initEvents : function(){
22111 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22112 this.grid.on("mousedown", this.handleMouseDown, this);
22113 }else{ // allow click to work like normal
22114 this.grid.on("rowclick", this.handleDragableRowClick, this);
22117 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22118 "up" : function(e){
22120 this.selectPrevious(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);
22133 "down" : function(e){
22135 this.selectNext(e.shiftKey);
22136 }else if(this.last !== false && this.lastActive !== false){
22137 var last = this.last;
22138 this.selectRange(this.last, this.lastActive+1);
22139 this.grid.getView().focusRow(this.lastActive);
22140 if(last !== false){
22144 this.selectFirstRow();
22146 this.fireEvent("afterselectionchange", this);
22151 var view = this.grid.view;
22152 view.on("refresh", this.onRefresh, this);
22153 view.on("rowupdated", this.onRowUpdated, this);
22154 view.on("rowremoved", this.onRemove, this);
22158 onRefresh : function(){
22159 var ds = this.grid.dataSource, i, v = this.grid.view;
22160 var s = this.selections;
22161 s.each(function(r){
22162 if((i = ds.indexOfId(r.id)) != -1){
22171 onRemove : function(v, index, r){
22172 this.selections.remove(r);
22176 onRowUpdated : function(v, index, r){
22177 if(this.isSelected(r)){
22178 v.onRowSelect(index);
22184 * @param {Array} records The records to select
22185 * @param {Boolean} keepExisting (optional) True to keep existing selections
22187 selectRecords : function(records, keepExisting){
22189 this.clearSelections();
22191 var ds = this.grid.dataSource;
22192 for(var i = 0, len = records.length; i < len; i++){
22193 this.selectRow(ds.indexOf(records[i]), true);
22198 * Gets the number of selected rows.
22201 getCount : function(){
22202 return this.selections.length;
22206 * Selects the first row in the grid.
22208 selectFirstRow : function(){
22213 * Select the last row.
22214 * @param {Boolean} keepExisting (optional) True to keep existing selections
22216 selectLastRow : function(keepExisting){
22217 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22221 * Selects the row immediately following the last selected row.
22222 * @param {Boolean} keepExisting (optional) True to keep existing selections
22224 selectNext : function(keepExisting){
22225 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
22226 this.selectRow(this.last+1, keepExisting);
22227 this.grid.getView().focusRow(this.last);
22232 * Selects the row that precedes the last selected row.
22233 * @param {Boolean} keepExisting (optional) True to keep existing selections
22235 selectPrevious : function(keepExisting){
22237 this.selectRow(this.last-1, keepExisting);
22238 this.grid.getView().focusRow(this.last);
22243 * Returns the selected records
22244 * @return {Array} Array of selected records
22246 getSelections : function(){
22247 return [].concat(this.selections.items);
22251 * Returns the first selected record.
22254 getSelected : function(){
22255 return this.selections.itemAt(0);
22260 * Clears all selections.
22262 clearSelections : function(fast){
22267 var ds = this.grid.dataSource;
22268 var s = this.selections;
22269 s.each(function(r){
22270 this.deselectRow(ds.indexOfId(r.id));
22274 this.selections.clear();
22281 * Selects all rows.
22283 selectAll : function(){
22287 this.selections.clear();
22288 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
22289 this.selectRow(i, true);
22294 * Returns True if there is a selection.
22295 * @return {Boolean}
22297 hasSelection : function(){
22298 return this.selections.length > 0;
22302 * Returns True if the specified row is selected.
22303 * @param {Number/Record} record The record or index of the record to check
22304 * @return {Boolean}
22306 isSelected : function(index){
22307 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
22308 return (r && this.selections.key(r.id) ? true : false);
22312 * Returns True if the specified record id is selected.
22313 * @param {String} id The id of record to check
22314 * @return {Boolean}
22316 isIdSelected : function(id){
22317 return (this.selections.key(id) ? true : false);
22321 handleMouseDown : function(e, t){
22322 var view = this.grid.getView(), rowIndex;
22323 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
22326 if(e.shiftKey && this.last !== false){
22327 var last = this.last;
22328 this.selectRange(last, rowIndex, e.ctrlKey);
22329 this.last = last; // reset the last
22330 view.focusRow(rowIndex);
22332 var isSelected = this.isSelected(rowIndex);
22333 if(e.button !== 0 && isSelected){
22334 view.focusRow(rowIndex);
22335 }else if(e.ctrlKey && isSelected){
22336 this.deselectRow(rowIndex);
22337 }else if(!isSelected){
22338 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22339 view.focusRow(rowIndex);
22342 this.fireEvent("afterselectionchange", this);
22345 handleDragableRowClick : function(grid, rowIndex, e)
22347 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
22348 this.selectRow(rowIndex, false);
22349 grid.view.focusRow(rowIndex);
22350 this.fireEvent("afterselectionchange", this);
22355 * Selects multiple rows.
22356 * @param {Array} rows Array of the indexes of the row to select
22357 * @param {Boolean} keepExisting (optional) True to keep existing selections
22359 selectRows : function(rows, keepExisting){
22361 this.clearSelections();
22363 for(var i = 0, len = rows.length; i < len; i++){
22364 this.selectRow(rows[i], true);
22369 * Selects a range of rows. All rows in between startRow and endRow are also selected.
22370 * @param {Number} startRow The index of the first row in the range
22371 * @param {Number} endRow The index of the last row in the range
22372 * @param {Boolean} keepExisting (optional) True to retain existing selections
22374 selectRange : function(startRow, endRow, keepExisting){
22379 this.clearSelections();
22381 if(startRow <= endRow){
22382 for(var i = startRow; i <= endRow; i++){
22383 this.selectRow(i, true);
22386 for(var i = startRow; i >= endRow; i--){
22387 this.selectRow(i, true);
22393 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
22394 * @param {Number} startRow The index of the first row in the range
22395 * @param {Number} endRow The index of the last row in the range
22397 deselectRange : function(startRow, endRow, preventViewNotify){
22401 for(var i = startRow; i <= endRow; i++){
22402 this.deselectRow(i, preventViewNotify);
22408 * @param {Number} row The index of the row to select
22409 * @param {Boolean} keepExisting (optional) True to keep existing selections
22411 selectRow : function(index, keepExisting, preventViewNotify){
22412 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
22415 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
22416 if(!keepExisting || this.singleSelect){
22417 this.clearSelections();
22419 var r = this.grid.dataSource.getAt(index);
22420 this.selections.add(r);
22421 this.last = this.lastActive = index;
22422 if(!preventViewNotify){
22423 this.grid.getView().onRowSelect(index);
22425 this.fireEvent("rowselect", this, index, r);
22426 this.fireEvent("selectionchange", this);
22432 * @param {Number} row The index of the row to deselect
22434 deselectRow : function(index, preventViewNotify){
22438 if(this.last == index){
22441 if(this.lastActive == index){
22442 this.lastActive = false;
22444 var r = this.grid.dataSource.getAt(index);
22445 this.selections.remove(r);
22446 if(!preventViewNotify){
22447 this.grid.getView().onRowDeselect(index);
22449 this.fireEvent("rowdeselect", this, index);
22450 this.fireEvent("selectionchange", this);
22454 restoreLast : function(){
22456 this.last = this._last;
22461 acceptsNav : function(row, col, cm){
22462 return !cm.isHidden(col) && cm.isCellEditable(col, row);
22466 onEditorKey : function(field, e){
22467 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
22472 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
22474 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
22476 }else if(k == e.ENTER && !e.ctrlKey){
22480 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
22482 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
22484 }else if(k == e.ESC){
22488 g.startEditing(newCell[0], newCell[1]);
22493 * Ext JS Library 1.1.1
22494 * Copyright(c) 2006-2007, Ext JS, LLC.
22496 * Originally Released Under LGPL - original licence link has changed is not relivant.
22499 * <script type="text/javascript">
22503 * @class Roo.bootstrap.PagingToolbar
22504 * @extends Roo.bootstrap.NavSimplebar
22505 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
22507 * Create a new PagingToolbar
22508 * @param {Object} config The config object
22509 * @param {Roo.data.Store} store
22511 Roo.bootstrap.PagingToolbar = function(config)
22513 // old args format still supported... - xtype is prefered..
22514 // created from xtype...
22516 this.ds = config.dataSource;
22518 if (config.store && !this.ds) {
22519 this.store= Roo.factory(config.store, Roo.data);
22520 this.ds = this.store;
22521 this.ds.xmodule = this.xmodule || false;
22524 this.toolbarItems = [];
22525 if (config.items) {
22526 this.toolbarItems = config.items;
22529 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
22534 this.bind(this.ds);
22537 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
22541 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
22543 * @cfg {Roo.data.Store} dataSource
22544 * The underlying data store providing the paged data
22547 * @cfg {String/HTMLElement/Element} container
22548 * container The id or element that will contain the toolbar
22551 * @cfg {Boolean} displayInfo
22552 * True to display the displayMsg (defaults to false)
22555 * @cfg {Number} pageSize
22556 * The number of records to display per page (defaults to 20)
22560 * @cfg {String} displayMsg
22561 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
22563 displayMsg : 'Displaying {0} - {1} of {2}',
22565 * @cfg {String} emptyMsg
22566 * The message to display when no records are found (defaults to "No data to display")
22568 emptyMsg : 'No data to display',
22570 * Customizable piece of the default paging text (defaults to "Page")
22573 beforePageText : "Page",
22575 * Customizable piece of the default paging text (defaults to "of %0")
22578 afterPageText : "of {0}",
22580 * Customizable piece of the default paging text (defaults to "First Page")
22583 firstText : "First Page",
22585 * Customizable piece of the default paging text (defaults to "Previous Page")
22588 prevText : "Previous Page",
22590 * Customizable piece of the default paging text (defaults to "Next Page")
22593 nextText : "Next Page",
22595 * Customizable piece of the default paging text (defaults to "Last Page")
22598 lastText : "Last Page",
22600 * Customizable piece of the default paging text (defaults to "Refresh")
22603 refreshText : "Refresh",
22607 onRender : function(ct, position)
22609 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
22610 this.navgroup.parentId = this.id;
22611 this.navgroup.onRender(this.el, null);
22612 // add the buttons to the navgroup
22614 if(this.displayInfo){
22615 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
22616 this.displayEl = this.el.select('.x-paging-info', true).first();
22617 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
22618 // this.displayEl = navel.el.select('span',true).first();
22624 Roo.each(_this.buttons, function(e){ // this might need to use render????
22625 Roo.factory(e).onRender(_this.el, null);
22629 Roo.each(_this.toolbarItems, function(e) {
22630 _this.navgroup.addItem(e);
22634 this.first = this.navgroup.addItem({
22635 tooltip: this.firstText,
22637 icon : 'fa fa-backward',
22639 preventDefault: true,
22640 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
22643 this.prev = this.navgroup.addItem({
22644 tooltip: this.prevText,
22646 icon : 'fa fa-step-backward',
22648 preventDefault: true,
22649 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
22651 //this.addSeparator();
22654 var field = this.navgroup.addItem( {
22656 cls : 'x-paging-position',
22658 html : this.beforePageText +
22659 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
22660 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
22663 this.field = field.el.select('input', true).first();
22664 this.field.on("keydown", this.onPagingKeydown, this);
22665 this.field.on("focus", function(){this.dom.select();});
22668 this.afterTextEl = field.el.select('.x-paging-after',true).first();
22669 //this.field.setHeight(18);
22670 //this.addSeparator();
22671 this.next = this.navgroup.addItem({
22672 tooltip: this.nextText,
22674 html : ' <i class="fa fa-step-forward">',
22676 preventDefault: true,
22677 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
22679 this.last = this.navgroup.addItem({
22680 tooltip: this.lastText,
22681 icon : 'fa fa-forward',
22684 preventDefault: true,
22685 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
22687 //this.addSeparator();
22688 this.loading = this.navgroup.addItem({
22689 tooltip: this.refreshText,
22690 icon: 'fa fa-refresh',
22691 preventDefault: true,
22692 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
22698 updateInfo : function(){
22699 if(this.displayEl){
22700 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
22701 var msg = count == 0 ?
22705 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
22707 this.displayEl.update(msg);
22712 onLoad : function(ds, r, o){
22713 this.cursor = o.params ? o.params.start : 0;
22714 var d = this.getPageData(),
22718 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
22719 this.field.dom.value = ap;
22720 this.first.setDisabled(ap == 1);
22721 this.prev.setDisabled(ap == 1);
22722 this.next.setDisabled(ap == ps);
22723 this.last.setDisabled(ap == ps);
22724 this.loading.enable();
22729 getPageData : function(){
22730 var total = this.ds.getTotalCount();
22733 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
22734 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
22739 onLoadError : function(){
22740 this.loading.enable();
22744 onPagingKeydown : function(e){
22745 var k = e.getKey();
22746 var d = this.getPageData();
22748 var v = this.field.dom.value, pageNum;
22749 if(!v || isNaN(pageNum = parseInt(v, 10))){
22750 this.field.dom.value = d.activePage;
22753 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
22754 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22757 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))
22759 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
22760 this.field.dom.value = pageNum;
22761 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
22764 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
22766 var v = this.field.dom.value, pageNum;
22767 var increment = (e.shiftKey) ? 10 : 1;
22768 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
22771 if(!v || isNaN(pageNum = parseInt(v, 10))) {
22772 this.field.dom.value = d.activePage;
22775 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
22777 this.field.dom.value = parseInt(v, 10) + increment;
22778 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
22779 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22786 beforeLoad : function(){
22788 this.loading.disable();
22793 onClick : function(which){
22802 ds.load({params:{start: 0, limit: this.pageSize}});
22805 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
22808 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
22811 var total = ds.getTotalCount();
22812 var extra = total % this.pageSize;
22813 var lastStart = extra ? (total - extra) : total-this.pageSize;
22814 ds.load({params:{start: lastStart, limit: this.pageSize}});
22817 ds.load({params:{start: this.cursor, limit: this.pageSize}});
22823 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
22824 * @param {Roo.data.Store} store The data store to unbind
22826 unbind : function(ds){
22827 ds.un("beforeload", this.beforeLoad, this);
22828 ds.un("load", this.onLoad, this);
22829 ds.un("loadexception", this.onLoadError, this);
22830 ds.un("remove", this.updateInfo, this);
22831 ds.un("add", this.updateInfo, this);
22832 this.ds = undefined;
22836 * Binds the paging toolbar to the specified {@link Roo.data.Store}
22837 * @param {Roo.data.Store} store The data store to bind
22839 bind : function(ds){
22840 ds.on("beforeload", this.beforeLoad, this);
22841 ds.on("load", this.onLoad, this);
22842 ds.on("loadexception", this.onLoadError, this);
22843 ds.on("remove", this.updateInfo, this);
22844 ds.on("add", this.updateInfo, this);
22855 * @class Roo.bootstrap.MessageBar
22856 * @extends Roo.bootstrap.Component
22857 * Bootstrap MessageBar class
22858 * @cfg {String} html contents of the MessageBar
22859 * @cfg {String} weight (info | success | warning | danger) default info
22860 * @cfg {String} beforeClass insert the bar before the given class
22861 * @cfg {Boolean} closable (true | false) default false
22862 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
22865 * Create a new Element
22866 * @param {Object} config The config object
22869 Roo.bootstrap.MessageBar = function(config){
22870 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
22873 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
22879 beforeClass: 'bootstrap-sticky-wrap',
22881 getAutoCreate : function(){
22885 cls: 'alert alert-dismissable alert-' + this.weight,
22890 html: this.html || ''
22896 cfg.cls += ' alert-messages-fixed';
22910 onRender : function(ct, position)
22912 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
22915 var cfg = Roo.apply({}, this.getAutoCreate());
22919 cfg.cls += ' ' + this.cls;
22922 cfg.style = this.style;
22924 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22926 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22929 this.el.select('>button.close').on('click', this.hide, this);
22935 if (!this.rendered) {
22941 this.fireEvent('show', this);
22947 if (!this.rendered) {
22953 this.fireEvent('hide', this);
22956 update : function()
22958 // var e = this.el.dom.firstChild;
22960 // if(this.closable){
22961 // e = e.nextSibling;
22964 // e.data = this.html || '';
22966 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22982 * @class Roo.bootstrap.Graph
22983 * @extends Roo.bootstrap.Component
22984 * Bootstrap Graph class
22988 @cfg {String} graphtype bar | vbar | pie
22989 @cfg {number} g_x coodinator | centre x (pie)
22990 @cfg {number} g_y coodinator | centre y (pie)
22991 @cfg {number} g_r radius (pie)
22992 @cfg {number} g_height height of the chart (respected by all elements in the set)
22993 @cfg {number} g_width width of the chart (respected by all elements in the set)
22994 @cfg {Object} title The title of the chart
22997 -opts (object) options for the chart
22999 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23000 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23002 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.
23003 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23005 o stretch (boolean)
23007 -opts (object) options for the pie
23010 o startAngle (number)
23011 o endAngle (number)
23015 * Create a new Input
23016 * @param {Object} config The config object
23019 Roo.bootstrap.Graph = function(config){
23020 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23026 * The img click event for the img.
23027 * @param {Roo.EventObject} e
23033 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23044 //g_colors: this.colors,
23051 getAutoCreate : function(){
23062 onRender : function(ct,position){
23065 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23067 if (typeof(Raphael) == 'undefined') {
23068 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23072 this.raphael = Raphael(this.el.dom);
23074 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23075 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23076 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23077 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23079 r.text(160, 10, "Single Series Chart").attr(txtattr);
23080 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23081 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23082 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23084 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23085 r.barchart(330, 10, 300, 220, data1);
23086 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23087 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23090 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23091 // r.barchart(30, 30, 560, 250, xdata, {
23092 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23093 // axis : "0 0 1 1",
23094 // axisxlabels : xdata
23095 // //yvalues : cols,
23098 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23100 // this.load(null,xdata,{
23101 // axis : "0 0 1 1",
23102 // axisxlabels : xdata
23107 load : function(graphtype,xdata,opts)
23109 this.raphael.clear();
23111 graphtype = this.graphtype;
23116 var r = this.raphael,
23117 fin = function () {
23118 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23120 fout = function () {
23121 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23123 pfin = function() {
23124 this.sector.stop();
23125 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23128 this.label[0].stop();
23129 this.label[0].attr({ r: 7.5 });
23130 this.label[1].attr({ "font-weight": 800 });
23133 pfout = function() {
23134 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23137 this.label[0].animate({ r: 5 }, 500, "bounce");
23138 this.label[1].attr({ "font-weight": 400 });
23144 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23147 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23150 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23151 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23153 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23160 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23165 setTitle: function(o)
23170 initEvents: function() {
23173 this.el.on('click', this.onClick, this);
23177 onClick : function(e)
23179 Roo.log('img onclick');
23180 this.fireEvent('click', this, e);
23192 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23195 * @class Roo.bootstrap.dash.NumberBox
23196 * @extends Roo.bootstrap.Component
23197 * Bootstrap NumberBox class
23198 * @cfg {String} headline Box headline
23199 * @cfg {String} content Box content
23200 * @cfg {String} icon Box icon
23201 * @cfg {String} footer Footer text
23202 * @cfg {String} fhref Footer href
23205 * Create a new NumberBox
23206 * @param {Object} config The config object
23210 Roo.bootstrap.dash.NumberBox = function(config){
23211 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23215 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23224 getAutoCreate : function(){
23228 cls : 'small-box ',
23236 cls : 'roo-headline',
23237 html : this.headline
23241 cls : 'roo-content',
23242 html : this.content
23256 cls : 'ion ' + this.icon
23265 cls : 'small-box-footer',
23266 href : this.fhref || '#',
23270 cfg.cn.push(footer);
23277 onRender : function(ct,position){
23278 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23285 setHeadline: function (value)
23287 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23290 setFooter: function (value, href)
23292 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23295 this.el.select('a.small-box-footer',true).first().attr('href', href);
23300 setContent: function (value)
23302 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23305 initEvents: function()
23319 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23322 * @class Roo.bootstrap.dash.TabBox
23323 * @extends Roo.bootstrap.Component
23324 * Bootstrap TabBox class
23325 * @cfg {String} title Title of the TabBox
23326 * @cfg {String} icon Icon of the TabBox
23327 * @cfg {Boolean} showtabs (true|false) show the tabs default true
23328 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
23331 * Create a new TabBox
23332 * @param {Object} config The config object
23336 Roo.bootstrap.dash.TabBox = function(config){
23337 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
23342 * When a pane is added
23343 * @param {Roo.bootstrap.dash.TabPane} pane
23347 * @event activatepane
23348 * When a pane is activated
23349 * @param {Roo.bootstrap.dash.TabPane} pane
23351 "activatepane" : true
23359 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
23364 tabScrollable : false,
23366 getChildContainer : function()
23368 return this.el.select('.tab-content', true).first();
23371 getAutoCreate : function(){
23375 cls: 'pull-left header',
23383 cls: 'fa ' + this.icon
23389 cls: 'nav nav-tabs pull-right',
23395 if(this.tabScrollable){
23402 cls: 'nav nav-tabs pull-right',
23413 cls: 'nav-tabs-custom',
23418 cls: 'tab-content no-padding',
23426 initEvents : function()
23428 //Roo.log('add add pane handler');
23429 this.on('addpane', this.onAddPane, this);
23432 * Updates the box title
23433 * @param {String} html to set the title to.
23435 setTitle : function(value)
23437 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
23439 onAddPane : function(pane)
23441 this.panes.push(pane);
23442 //Roo.log('addpane');
23444 // tabs are rendere left to right..
23445 if(!this.showtabs){
23449 var ctr = this.el.select('.nav-tabs', true).first();
23452 var existing = ctr.select('.nav-tab',true);
23453 var qty = existing.getCount();;
23456 var tab = ctr.createChild({
23458 cls : 'nav-tab' + (qty ? '' : ' active'),
23466 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
23469 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
23471 pane.el.addClass('active');
23476 onTabClick : function(ev,un,ob,pane)
23478 //Roo.log('tab - prev default');
23479 ev.preventDefault();
23482 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
23483 pane.tab.addClass('active');
23484 //Roo.log(pane.title);
23485 this.getChildContainer().select('.tab-pane',true).removeClass('active');
23486 // technically we should have a deactivate event.. but maybe add later.
23487 // and it should not de-activate the selected tab...
23488 this.fireEvent('activatepane', pane);
23489 pane.el.addClass('active');
23490 pane.fireEvent('activate');
23495 getActivePane : function()
23498 Roo.each(this.panes, function(p) {
23499 if(p.el.hasClass('active')){
23520 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23522 * @class Roo.bootstrap.TabPane
23523 * @extends Roo.bootstrap.Component
23524 * Bootstrap TabPane class
23525 * @cfg {Boolean} active (false | true) Default false
23526 * @cfg {String} title title of panel
23530 * Create a new TabPane
23531 * @param {Object} config The config object
23534 Roo.bootstrap.dash.TabPane = function(config){
23535 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
23541 * When a pane is activated
23542 * @param {Roo.bootstrap.dash.TabPane} pane
23549 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
23554 // the tabBox that this is attached to.
23557 getAutoCreate : function()
23565 cfg.cls += ' active';
23570 initEvents : function()
23572 //Roo.log('trigger add pane handler');
23573 this.parent().fireEvent('addpane', this)
23577 * Updates the tab title
23578 * @param {String} html to set the title to.
23580 setTitle: function(str)
23586 this.tab.select('a', true).first().dom.innerHTML = str;
23603 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23606 * @class Roo.bootstrap.menu.Menu
23607 * @extends Roo.bootstrap.Component
23608 * Bootstrap Menu class - container for Menu
23609 * @cfg {String} html Text of the menu
23610 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
23611 * @cfg {String} icon Font awesome icon
23612 * @cfg {String} pos Menu align to (top | bottom) default bottom
23616 * Create a new Menu
23617 * @param {Object} config The config object
23621 Roo.bootstrap.menu.Menu = function(config){
23622 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
23626 * @event beforeshow
23627 * Fires before this menu is displayed
23628 * @param {Roo.bootstrap.menu.Menu} this
23632 * @event beforehide
23633 * Fires before this menu is hidden
23634 * @param {Roo.bootstrap.menu.Menu} this
23639 * Fires after this menu is displayed
23640 * @param {Roo.bootstrap.menu.Menu} this
23645 * Fires after this menu is hidden
23646 * @param {Roo.bootstrap.menu.Menu} this
23651 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
23652 * @param {Roo.bootstrap.menu.Menu} this
23653 * @param {Roo.EventObject} e
23660 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
23664 weight : 'default',
23669 getChildContainer : function() {
23670 if(this.isSubMenu){
23674 return this.el.select('ul.dropdown-menu', true).first();
23677 getAutoCreate : function()
23682 cls : 'roo-menu-text',
23690 cls : 'fa ' + this.icon
23701 cls : 'dropdown-button btn btn-' + this.weight,
23706 cls : 'dropdown-toggle btn btn-' + this.weight,
23716 cls : 'dropdown-menu'
23722 if(this.pos == 'top'){
23723 cfg.cls += ' dropup';
23726 if(this.isSubMenu){
23729 cls : 'dropdown-menu'
23736 onRender : function(ct, position)
23738 this.isSubMenu = ct.hasClass('dropdown-submenu');
23740 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
23743 initEvents : function()
23745 if(this.isSubMenu){
23749 this.hidden = true;
23751 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
23752 this.triggerEl.on('click', this.onTriggerPress, this);
23754 this.buttonEl = this.el.select('button.dropdown-button', true).first();
23755 this.buttonEl.on('click', this.onClick, this);
23761 if(this.isSubMenu){
23765 return this.el.select('ul.dropdown-menu', true).first();
23768 onClick : function(e)
23770 this.fireEvent("click", this, e);
23773 onTriggerPress : function(e)
23775 if (this.isVisible()) {
23782 isVisible : function(){
23783 return !this.hidden;
23788 this.fireEvent("beforeshow", this);
23790 this.hidden = false;
23791 this.el.addClass('open');
23793 Roo.get(document).on("mouseup", this.onMouseUp, this);
23795 this.fireEvent("show", this);
23802 this.fireEvent("beforehide", this);
23804 this.hidden = true;
23805 this.el.removeClass('open');
23807 Roo.get(document).un("mouseup", this.onMouseUp);
23809 this.fireEvent("hide", this);
23812 onMouseUp : function()
23826 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23829 * @class Roo.bootstrap.menu.Item
23830 * @extends Roo.bootstrap.Component
23831 * Bootstrap MenuItem class
23832 * @cfg {Boolean} submenu (true | false) default false
23833 * @cfg {String} html text of the item
23834 * @cfg {String} href the link
23835 * @cfg {Boolean} disable (true | false) default false
23836 * @cfg {Boolean} preventDefault (true | false) default true
23837 * @cfg {String} icon Font awesome icon
23838 * @cfg {String} pos Submenu align to (left | right) default right
23842 * Create a new Item
23843 * @param {Object} config The config object
23847 Roo.bootstrap.menu.Item = function(config){
23848 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
23852 * Fires when the mouse is hovering over this menu
23853 * @param {Roo.bootstrap.menu.Item} this
23854 * @param {Roo.EventObject} e
23859 * Fires when the mouse exits this menu
23860 * @param {Roo.bootstrap.menu.Item} this
23861 * @param {Roo.EventObject} e
23867 * The raw click event for the entire grid.
23868 * @param {Roo.EventObject} e
23874 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
23879 preventDefault: true,
23884 getAutoCreate : function()
23889 cls : 'roo-menu-item-text',
23897 cls : 'fa ' + this.icon
23906 href : this.href || '#',
23913 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
23917 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
23919 if(this.pos == 'left'){
23920 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
23927 initEvents : function()
23929 this.el.on('mouseover', this.onMouseOver, this);
23930 this.el.on('mouseout', this.onMouseOut, this);
23932 this.el.select('a', true).first().on('click', this.onClick, this);
23936 onClick : function(e)
23938 if(this.preventDefault){
23939 e.preventDefault();
23942 this.fireEvent("click", this, e);
23945 onMouseOver : function(e)
23947 if(this.submenu && this.pos == 'left'){
23948 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23951 this.fireEvent("mouseover", this, e);
23954 onMouseOut : function(e)
23956 this.fireEvent("mouseout", this, e);
23968 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23971 * @class Roo.bootstrap.menu.Separator
23972 * @extends Roo.bootstrap.Component
23973 * Bootstrap Separator class
23976 * Create a new Separator
23977 * @param {Object} config The config object
23981 Roo.bootstrap.menu.Separator = function(config){
23982 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23985 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23987 getAutoCreate : function(){
24008 * @class Roo.bootstrap.Tooltip
24009 * Bootstrap Tooltip class
24010 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24011 * to determine which dom element triggers the tooltip.
24013 * It needs to add support for additional attributes like tooltip-position
24016 * Create a new Toolti
24017 * @param {Object} config The config object
24020 Roo.bootstrap.Tooltip = function(config){
24021 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24024 Roo.apply(Roo.bootstrap.Tooltip, {
24026 * @function init initialize tooltip monitoring.
24030 currentTip : false,
24031 currentRegion : false,
24037 Roo.get(document).on('mouseover', this.enter ,this);
24038 Roo.get(document).on('mouseout', this.leave, this);
24041 this.currentTip = new Roo.bootstrap.Tooltip();
24044 enter : function(ev)
24046 var dom = ev.getTarget();
24048 //Roo.log(['enter',dom]);
24049 var el = Roo.fly(dom);
24050 if (this.currentEl) {
24052 //Roo.log(this.currentEl);
24053 //Roo.log(this.currentEl.contains(dom));
24054 if (this.currentEl == el) {
24057 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24063 if (this.currentTip.el) {
24064 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24069 // you can not look for children, as if el is the body.. then everythign is the child..
24070 if (!el.attr('tooltip')) { //
24071 if (!el.select("[tooltip]").elements.length) {
24074 // is the mouse over this child...?
24075 bindEl = el.select("[tooltip]").first();
24076 var xy = ev.getXY();
24077 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24078 //Roo.log("not in region.");
24081 //Roo.log("child element over..");
24084 this.currentEl = bindEl;
24085 this.currentTip.bind(bindEl);
24086 this.currentRegion = Roo.lib.Region.getRegion(dom);
24087 this.currentTip.enter();
24090 leave : function(ev)
24092 var dom = ev.getTarget();
24093 //Roo.log(['leave',dom]);
24094 if (!this.currentEl) {
24099 if (dom != this.currentEl.dom) {
24102 var xy = ev.getXY();
24103 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24106 // only activate leave if mouse cursor is outside... bounding box..
24111 if (this.currentTip) {
24112 this.currentTip.leave();
24114 //Roo.log('clear currentEl');
24115 this.currentEl = false;
24120 'left' : ['r-l', [-2,0], 'right'],
24121 'right' : ['l-r', [2,0], 'left'],
24122 'bottom' : ['t-b', [0,2], 'top'],
24123 'top' : [ 'b-t', [0,-2], 'bottom']
24129 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24134 delay : null, // can be { show : 300 , hide: 500}
24138 hoverState : null, //???
24140 placement : 'bottom',
24142 getAutoCreate : function(){
24149 cls : 'tooltip-arrow'
24152 cls : 'tooltip-inner'
24159 bind : function(el)
24165 enter : function () {
24167 if (this.timeout != null) {
24168 clearTimeout(this.timeout);
24171 this.hoverState = 'in';
24172 //Roo.log("enter - show");
24173 if (!this.delay || !this.delay.show) {
24178 this.timeout = setTimeout(function () {
24179 if (_t.hoverState == 'in') {
24182 }, this.delay.show);
24186 clearTimeout(this.timeout);
24188 this.hoverState = 'out';
24189 if (!this.delay || !this.delay.hide) {
24195 this.timeout = setTimeout(function () {
24196 //Roo.log("leave - timeout");
24198 if (_t.hoverState == 'out') {
24200 Roo.bootstrap.Tooltip.currentEl = false;
24208 this.render(document.body);
24211 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24213 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24215 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24217 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24219 var placement = typeof this.placement == 'function' ?
24220 this.placement.call(this, this.el, on_el) :
24223 var autoToken = /\s?auto?\s?/i;
24224 var autoPlace = autoToken.test(placement);
24226 placement = placement.replace(autoToken, '') || 'top';
24230 //this.el.setXY([0,0]);
24232 //this.el.dom.style.display='block';
24234 //this.el.appendTo(on_el);
24236 var p = this.getPosition();
24237 var box = this.el.getBox();
24243 var align = Roo.bootstrap.Tooltip.alignment[placement];
24245 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24247 if(placement == 'top' || placement == 'bottom'){
24249 placement = 'right';
24252 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24253 placement = 'left';
24257 align = Roo.bootstrap.Tooltip.alignment[placement];
24259 this.el.alignTo(this.bindEl, align[0],align[1]);
24260 //var arrow = this.el.select('.arrow',true).first();
24261 //arrow.set(align[2],
24263 this.el.addClass(placement);
24265 this.el.addClass('in fade');
24267 this.hoverState = null;
24269 if (this.el.hasClass('fade')) {
24280 //this.el.setXY([0,0]);
24281 this.el.removeClass('in');
24297 * @class Roo.bootstrap.LocationPicker
24298 * @extends Roo.bootstrap.Component
24299 * Bootstrap LocationPicker class
24300 * @cfg {Number} latitude Position when init default 0
24301 * @cfg {Number} longitude Position when init default 0
24302 * @cfg {Number} zoom default 15
24303 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24304 * @cfg {Boolean} mapTypeControl default false
24305 * @cfg {Boolean} disableDoubleClickZoom default false
24306 * @cfg {Boolean} scrollwheel default true
24307 * @cfg {Boolean} streetViewControl default false
24308 * @cfg {Number} radius default 0
24309 * @cfg {String} locationName
24310 * @cfg {Boolean} draggable default true
24311 * @cfg {Boolean} enableAutocomplete default false
24312 * @cfg {Boolean} enableReverseGeocode default true
24313 * @cfg {String} markerTitle
24316 * Create a new LocationPicker
24317 * @param {Object} config The config object
24321 Roo.bootstrap.LocationPicker = function(config){
24323 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
24328 * Fires when the picker initialized.
24329 * @param {Roo.bootstrap.LocationPicker} this
24330 * @param {Google Location} location
24334 * @event positionchanged
24335 * Fires when the picker position changed.
24336 * @param {Roo.bootstrap.LocationPicker} this
24337 * @param {Google Location} location
24339 positionchanged : true,
24342 * Fires when the map resize.
24343 * @param {Roo.bootstrap.LocationPicker} this
24348 * Fires when the map show.
24349 * @param {Roo.bootstrap.LocationPicker} this
24354 * Fires when the map hide.
24355 * @param {Roo.bootstrap.LocationPicker} this
24360 * Fires when click the map.
24361 * @param {Roo.bootstrap.LocationPicker} this
24362 * @param {Map event} e
24366 * @event mapRightClick
24367 * Fires when right click the map.
24368 * @param {Roo.bootstrap.LocationPicker} this
24369 * @param {Map event} e
24371 mapRightClick : true,
24373 * @event markerClick
24374 * Fires when click the marker.
24375 * @param {Roo.bootstrap.LocationPicker} this
24376 * @param {Map event} e
24378 markerClick : true,
24380 * @event markerRightClick
24381 * Fires when right click the marker.
24382 * @param {Roo.bootstrap.LocationPicker} this
24383 * @param {Map event} e
24385 markerRightClick : true,
24387 * @event OverlayViewDraw
24388 * Fires when OverlayView Draw
24389 * @param {Roo.bootstrap.LocationPicker} this
24391 OverlayViewDraw : true,
24393 * @event OverlayViewOnAdd
24394 * Fires when OverlayView Draw
24395 * @param {Roo.bootstrap.LocationPicker} this
24397 OverlayViewOnAdd : true,
24399 * @event OverlayViewOnRemove
24400 * Fires when OverlayView Draw
24401 * @param {Roo.bootstrap.LocationPicker} this
24403 OverlayViewOnRemove : true,
24405 * @event OverlayViewShow
24406 * Fires when OverlayView Draw
24407 * @param {Roo.bootstrap.LocationPicker} this
24408 * @param {Pixel} cpx
24410 OverlayViewShow : true,
24412 * @event OverlayViewHide
24413 * Fires when OverlayView Draw
24414 * @param {Roo.bootstrap.LocationPicker} this
24416 OverlayViewHide : true,
24418 * @event loadexception
24419 * Fires when load google lib failed.
24420 * @param {Roo.bootstrap.LocationPicker} this
24422 loadexception : true
24427 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
24429 gMapContext: false,
24435 mapTypeControl: false,
24436 disableDoubleClickZoom: false,
24438 streetViewControl: false,
24442 enableAutocomplete: false,
24443 enableReverseGeocode: true,
24446 getAutoCreate: function()
24451 cls: 'roo-location-picker'
24457 initEvents: function(ct, position)
24459 if(!this.el.getWidth() || this.isApplied()){
24463 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24468 initial: function()
24470 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
24471 this.fireEvent('loadexception', this);
24475 if(!this.mapTypeId){
24476 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
24479 this.gMapContext = this.GMapContext();
24481 this.initOverlayView();
24483 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
24487 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
24488 _this.setPosition(_this.gMapContext.marker.position);
24491 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
24492 _this.fireEvent('mapClick', this, event);
24496 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
24497 _this.fireEvent('mapRightClick', this, event);
24501 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
24502 _this.fireEvent('markerClick', this, event);
24506 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
24507 _this.fireEvent('markerRightClick', this, event);
24511 this.setPosition(this.gMapContext.location);
24513 this.fireEvent('initial', this, this.gMapContext.location);
24516 initOverlayView: function()
24520 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
24524 _this.fireEvent('OverlayViewDraw', _this);
24529 _this.fireEvent('OverlayViewOnAdd', _this);
24532 onRemove: function()
24534 _this.fireEvent('OverlayViewOnRemove', _this);
24537 show: function(cpx)
24539 _this.fireEvent('OverlayViewShow', _this, cpx);
24544 _this.fireEvent('OverlayViewHide', _this);
24550 fromLatLngToContainerPixel: function(event)
24552 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
24555 isApplied: function()
24557 return this.getGmapContext() == false ? false : true;
24560 getGmapContext: function()
24562 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
24565 GMapContext: function()
24567 var position = new google.maps.LatLng(this.latitude, this.longitude);
24569 var _map = new google.maps.Map(this.el.dom, {
24572 mapTypeId: this.mapTypeId,
24573 mapTypeControl: this.mapTypeControl,
24574 disableDoubleClickZoom: this.disableDoubleClickZoom,
24575 scrollwheel: this.scrollwheel,
24576 streetViewControl: this.streetViewControl,
24577 locationName: this.locationName,
24578 draggable: this.draggable,
24579 enableAutocomplete: this.enableAutocomplete,
24580 enableReverseGeocode: this.enableReverseGeocode
24583 var _marker = new google.maps.Marker({
24584 position: position,
24586 title: this.markerTitle,
24587 draggable: this.draggable
24594 location: position,
24595 radius: this.radius,
24596 locationName: this.locationName,
24597 addressComponents: {
24598 formatted_address: null,
24599 addressLine1: null,
24600 addressLine2: null,
24602 streetNumber: null,
24606 stateOrProvince: null
24609 domContainer: this.el.dom,
24610 geodecoder: new google.maps.Geocoder()
24614 drawCircle: function(center, radius, options)
24616 if (this.gMapContext.circle != null) {
24617 this.gMapContext.circle.setMap(null);
24621 options = Roo.apply({}, options, {
24622 strokeColor: "#0000FF",
24623 strokeOpacity: .35,
24625 fillColor: "#0000FF",
24629 options.map = this.gMapContext.map;
24630 options.radius = radius;
24631 options.center = center;
24632 this.gMapContext.circle = new google.maps.Circle(options);
24633 return this.gMapContext.circle;
24639 setPosition: function(location)
24641 this.gMapContext.location = location;
24642 this.gMapContext.marker.setPosition(location);
24643 this.gMapContext.map.panTo(location);
24644 this.drawCircle(location, this.gMapContext.radius, {});
24648 if (this.gMapContext.settings.enableReverseGeocode) {
24649 this.gMapContext.geodecoder.geocode({
24650 latLng: this.gMapContext.location
24651 }, function(results, status) {
24653 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
24654 _this.gMapContext.locationName = results[0].formatted_address;
24655 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
24657 _this.fireEvent('positionchanged', this, location);
24664 this.fireEvent('positionchanged', this, location);
24669 google.maps.event.trigger(this.gMapContext.map, "resize");
24671 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
24673 this.fireEvent('resize', this);
24676 setPositionByLatLng: function(latitude, longitude)
24678 this.setPosition(new google.maps.LatLng(latitude, longitude));
24681 getCurrentPosition: function()
24684 latitude: this.gMapContext.location.lat(),
24685 longitude: this.gMapContext.location.lng()
24689 getAddressName: function()
24691 return this.gMapContext.locationName;
24694 getAddressComponents: function()
24696 return this.gMapContext.addressComponents;
24699 address_component_from_google_geocode: function(address_components)
24703 for (var i = 0; i < address_components.length; i++) {
24704 var component = address_components[i];
24705 if (component.types.indexOf("postal_code") >= 0) {
24706 result.postalCode = component.short_name;
24707 } else if (component.types.indexOf("street_number") >= 0) {
24708 result.streetNumber = component.short_name;
24709 } else if (component.types.indexOf("route") >= 0) {
24710 result.streetName = component.short_name;
24711 } else if (component.types.indexOf("neighborhood") >= 0) {
24712 result.city = component.short_name;
24713 } else if (component.types.indexOf("locality") >= 0) {
24714 result.city = component.short_name;
24715 } else if (component.types.indexOf("sublocality") >= 0) {
24716 result.district = component.short_name;
24717 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
24718 result.stateOrProvince = component.short_name;
24719 } else if (component.types.indexOf("country") >= 0) {
24720 result.country = component.short_name;
24724 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
24725 result.addressLine2 = "";
24729 setZoomLevel: function(zoom)
24731 this.gMapContext.map.setZoom(zoom);
24744 this.fireEvent('show', this);
24755 this.fireEvent('hide', this);
24760 Roo.apply(Roo.bootstrap.LocationPicker, {
24762 OverlayView : function(map, options)
24764 options = options || {};
24778 * @class Roo.bootstrap.Alert
24779 * @extends Roo.bootstrap.Component
24780 * Bootstrap Alert class
24781 * @cfg {String} title The title of alert
24782 * @cfg {String} html The content of alert
24783 * @cfg {String} weight ( success | info | warning | danger )
24784 * @cfg {String} faicon font-awesomeicon
24787 * Create a new alert
24788 * @param {Object} config The config object
24792 Roo.bootstrap.Alert = function(config){
24793 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
24797 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
24804 getAutoCreate : function()
24813 cls : 'roo-alert-icon'
24818 cls : 'roo-alert-title',
24823 cls : 'roo-alert-text',
24830 cfg.cn[0].cls += ' fa ' + this.faicon;
24834 cfg.cls += ' alert-' + this.weight;
24840 initEvents: function()
24842 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24845 setTitle : function(str)
24847 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
24850 setText : function(str)
24852 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
24855 setWeight : function(weight)
24858 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
24861 this.weight = weight;
24863 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
24866 setIcon : function(icon)
24869 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
24872 this.faicon = icon;
24874 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
24895 * @class Roo.bootstrap.UploadCropbox
24896 * @extends Roo.bootstrap.Component
24897 * Bootstrap UploadCropbox class
24898 * @cfg {String} emptyText show when image has been loaded
24899 * @cfg {String} rotateNotify show when image too small to rotate
24900 * @cfg {Number} errorTimeout default 3000
24901 * @cfg {Number} minWidth default 300
24902 * @cfg {Number} minHeight default 300
24903 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
24904 * @cfg {Boolean} isDocument (true|false) default false
24905 * @cfg {String} url action url
24906 * @cfg {String} paramName default 'imageUpload'
24907 * @cfg {String} method default POST
24908 * @cfg {Boolean} loadMask (true|false) default true
24909 * @cfg {Boolean} loadingText default 'Loading...'
24912 * Create a new UploadCropbox
24913 * @param {Object} config The config object
24916 Roo.bootstrap.UploadCropbox = function(config){
24917 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
24921 * @event beforeselectfile
24922 * Fire before select file
24923 * @param {Roo.bootstrap.UploadCropbox} this
24925 "beforeselectfile" : true,
24928 * Fire after initEvent
24929 * @param {Roo.bootstrap.UploadCropbox} this
24934 * Fire after initEvent
24935 * @param {Roo.bootstrap.UploadCropbox} this
24936 * @param {String} data
24941 * Fire when preparing the file data
24942 * @param {Roo.bootstrap.UploadCropbox} this
24943 * @param {Object} file
24948 * Fire when get exception
24949 * @param {Roo.bootstrap.UploadCropbox} this
24950 * @param {XMLHttpRequest} xhr
24952 "exception" : true,
24954 * @event beforeloadcanvas
24955 * Fire before load the canvas
24956 * @param {Roo.bootstrap.UploadCropbox} this
24957 * @param {String} src
24959 "beforeloadcanvas" : true,
24962 * Fire when trash image
24963 * @param {Roo.bootstrap.UploadCropbox} this
24968 * Fire when download the image
24969 * @param {Roo.bootstrap.UploadCropbox} this
24973 * @event footerbuttonclick
24974 * Fire when footerbuttonclick
24975 * @param {Roo.bootstrap.UploadCropbox} this
24976 * @param {String} type
24978 "footerbuttonclick" : true,
24982 * @param {Roo.bootstrap.UploadCropbox} this
24987 * Fire when rotate the image
24988 * @param {Roo.bootstrap.UploadCropbox} this
24989 * @param {String} pos
24994 * Fire when inspect the file
24995 * @param {Roo.bootstrap.UploadCropbox} this
24996 * @param {Object} file
25001 * Fire when xhr upload the file
25002 * @param {Roo.bootstrap.UploadCropbox} this
25003 * @param {Object} data
25008 * Fire when arrange the file data
25009 * @param {Roo.bootstrap.UploadCropbox} this
25010 * @param {Object} formData
25015 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25018 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25020 emptyText : 'Click to upload image',
25021 rotateNotify : 'Image is too small to rotate',
25022 errorTimeout : 3000,
25036 cropType : 'image/jpeg',
25038 canvasLoaded : false,
25039 isDocument : false,
25041 paramName : 'imageUpload',
25043 loadingText : 'Loading...',
25046 getAutoCreate : function()
25050 cls : 'roo-upload-cropbox',
25054 cls : 'roo-upload-cropbox-selector',
25059 cls : 'roo-upload-cropbox-body',
25060 style : 'cursor:pointer',
25064 cls : 'roo-upload-cropbox-preview'
25068 cls : 'roo-upload-cropbox-thumb'
25072 cls : 'roo-upload-cropbox-empty-notify',
25073 html : this.emptyText
25077 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25078 html : this.rotateNotify
25084 cls : 'roo-upload-cropbox-footer',
25087 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25097 onRender : function(ct, position)
25099 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25101 if (this.buttons.length) {
25103 Roo.each(this.buttons, function(bb) {
25105 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25107 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25113 this.maskEl = this.el;
25117 initEvents : function()
25119 this.urlAPI = (window.createObjectURL && window) ||
25120 (window.URL && URL.revokeObjectURL && URL) ||
25121 (window.webkitURL && webkitURL);
25123 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25124 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25126 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25127 this.selectorEl.hide();
25129 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25130 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25132 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25133 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25134 this.thumbEl.hide();
25136 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25137 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25139 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25140 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25141 this.errorEl.hide();
25143 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25144 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25145 this.footerEl.hide();
25147 this.setThumbBoxSize();
25153 this.fireEvent('initial', this);
25160 window.addEventListener("resize", function() { _this.resize(); } );
25162 this.bodyEl.on('click', this.beforeSelectFile, this);
25165 this.bodyEl.on('touchstart', this.onTouchStart, this);
25166 this.bodyEl.on('touchmove', this.onTouchMove, this);
25167 this.bodyEl.on('touchend', this.onTouchEnd, this);
25171 this.bodyEl.on('mousedown', this.onMouseDown, this);
25172 this.bodyEl.on('mousemove', this.onMouseMove, this);
25173 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25174 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25175 Roo.get(document).on('mouseup', this.onMouseUp, this);
25178 this.selectorEl.on('change', this.onFileSelected, this);
25184 this.baseScale = 1;
25186 this.baseRotate = 1;
25187 this.dragable = false;
25188 this.pinching = false;
25191 this.cropData = false;
25192 this.notifyEl.dom.innerHTML = this.emptyText;
25194 this.selectorEl.dom.value = '';
25198 resize : function()
25200 if(this.fireEvent('resize', this) != false){
25201 this.setThumbBoxPosition();
25202 this.setCanvasPosition();
25206 onFooterButtonClick : function(e, el, o, type)
25209 case 'rotate-left' :
25210 this.onRotateLeft(e);
25212 case 'rotate-right' :
25213 this.onRotateRight(e);
25216 this.beforeSelectFile(e);
25231 this.fireEvent('footerbuttonclick', this, type);
25234 beforeSelectFile : function(e)
25236 e.preventDefault();
25238 if(this.fireEvent('beforeselectfile', this) != false){
25239 this.selectorEl.dom.click();
25243 onFileSelected : function(e)
25245 e.preventDefault();
25247 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25251 var file = this.selectorEl.dom.files[0];
25253 if(this.fireEvent('inspect', this, file) != false){
25254 this.prepare(file);
25259 trash : function(e)
25261 this.fireEvent('trash', this);
25264 download : function(e)
25266 this.fireEvent('download', this);
25269 loadCanvas : function(src)
25271 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25275 this.imageEl = document.createElement('img');
25279 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25281 this.imageEl.src = src;
25285 onLoadCanvas : function()
25287 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25288 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25290 this.bodyEl.un('click', this.beforeSelectFile, this);
25292 this.notifyEl.hide();
25293 this.thumbEl.show();
25294 this.footerEl.show();
25296 this.baseRotateLevel();
25298 if(this.isDocument){
25299 this.setThumbBoxSize();
25302 this.setThumbBoxPosition();
25304 this.baseScaleLevel();
25310 this.canvasLoaded = true;
25313 this.maskEl.unmask();
25318 setCanvasPosition : function()
25320 if(!this.canvasEl){
25324 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
25325 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
25327 this.previewEl.setLeft(pw);
25328 this.previewEl.setTop(ph);
25332 onMouseDown : function(e)
25336 this.dragable = true;
25337 this.pinching = false;
25339 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
25340 this.dragable = false;
25344 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25345 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25349 onMouseMove : function(e)
25353 if(!this.canvasLoaded){
25357 if (!this.dragable){
25361 var minX = Math.ceil(this.thumbEl.getLeft(true));
25362 var minY = Math.ceil(this.thumbEl.getTop(true));
25364 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
25365 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
25367 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25368 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25370 x = x - this.mouseX;
25371 y = y - this.mouseY;
25373 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
25374 var bgY = Math.ceil(y + this.previewEl.getTop(true));
25376 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
25377 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
25379 this.previewEl.setLeft(bgX);
25380 this.previewEl.setTop(bgY);
25382 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25383 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25386 onMouseUp : function(e)
25390 this.dragable = false;
25393 onMouseWheel : function(e)
25397 this.startScale = this.scale;
25399 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
25401 if(!this.zoomable()){
25402 this.scale = this.startScale;
25411 zoomable : function()
25413 var minScale = this.thumbEl.getWidth() / this.minWidth;
25415 if(this.minWidth < this.minHeight){
25416 minScale = this.thumbEl.getHeight() / this.minHeight;
25419 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
25420 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
25424 (this.rotate == 0 || this.rotate == 180) &&
25426 width > this.imageEl.OriginWidth ||
25427 height > this.imageEl.OriginHeight ||
25428 (width < this.minWidth && height < this.minHeight)
25436 (this.rotate == 90 || this.rotate == 270) &&
25438 width > this.imageEl.OriginWidth ||
25439 height > this.imageEl.OriginHeight ||
25440 (width < this.minHeight && height < this.minWidth)
25447 !this.isDocument &&
25448 (this.rotate == 0 || this.rotate == 180) &&
25450 width < this.minWidth ||
25451 width > this.imageEl.OriginWidth ||
25452 height < this.minHeight ||
25453 height > this.imageEl.OriginHeight
25460 !this.isDocument &&
25461 (this.rotate == 90 || this.rotate == 270) &&
25463 width < this.minHeight ||
25464 width > this.imageEl.OriginWidth ||
25465 height < this.minWidth ||
25466 height > this.imageEl.OriginHeight
25476 onRotateLeft : function(e)
25478 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25480 var minScale = this.thumbEl.getWidth() / this.minWidth;
25482 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25483 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25485 this.startScale = this.scale;
25487 while (this.getScaleLevel() < minScale){
25489 this.scale = this.scale + 1;
25491 if(!this.zoomable()){
25496 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25497 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25502 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25509 this.scale = this.startScale;
25511 this.onRotateFail();
25516 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25518 if(this.isDocument){
25519 this.setThumbBoxSize();
25520 this.setThumbBoxPosition();
25521 this.setCanvasPosition();
25526 this.fireEvent('rotate', this, 'left');
25530 onRotateRight : function(e)
25532 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25534 var minScale = this.thumbEl.getWidth() / this.minWidth;
25536 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25537 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25539 this.startScale = this.scale;
25541 while (this.getScaleLevel() < minScale){
25543 this.scale = this.scale + 1;
25545 if(!this.zoomable()){
25550 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25551 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25556 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25563 this.scale = this.startScale;
25565 this.onRotateFail();
25570 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25572 if(this.isDocument){
25573 this.setThumbBoxSize();
25574 this.setThumbBoxPosition();
25575 this.setCanvasPosition();
25580 this.fireEvent('rotate', this, 'right');
25583 onRotateFail : function()
25585 this.errorEl.show(true);
25589 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
25594 this.previewEl.dom.innerHTML = '';
25596 var canvasEl = document.createElement("canvas");
25598 var contextEl = canvasEl.getContext("2d");
25600 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25601 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25602 var center = this.imageEl.OriginWidth / 2;
25604 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
25605 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25606 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25607 center = this.imageEl.OriginHeight / 2;
25610 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
25612 contextEl.translate(center, center);
25613 contextEl.rotate(this.rotate * Math.PI / 180);
25615 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25617 this.canvasEl = document.createElement("canvas");
25619 this.contextEl = this.canvasEl.getContext("2d");
25621 switch (this.rotate) {
25624 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25625 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25627 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25632 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25633 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25635 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25636 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);
25640 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25645 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25646 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25648 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25649 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);
25653 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);
25658 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25659 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25661 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25662 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25666 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);
25673 this.previewEl.appendChild(this.canvasEl);
25675 this.setCanvasPosition();
25680 if(!this.canvasLoaded){
25684 var imageCanvas = document.createElement("canvas");
25686 var imageContext = imageCanvas.getContext("2d");
25688 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25689 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25691 var center = imageCanvas.width / 2;
25693 imageContext.translate(center, center);
25695 imageContext.rotate(this.rotate * Math.PI / 180);
25697 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25699 var canvas = document.createElement("canvas");
25701 var context = canvas.getContext("2d");
25703 canvas.width = this.minWidth;
25704 canvas.height = this.minHeight;
25706 switch (this.rotate) {
25709 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25710 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25712 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25713 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25715 var targetWidth = this.minWidth - 2 * x;
25716 var targetHeight = this.minHeight - 2 * y;
25720 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25721 scale = targetWidth / width;
25724 if(x > 0 && y == 0){
25725 scale = targetHeight / height;
25728 if(x > 0 && y > 0){
25729 scale = targetWidth / width;
25731 if(width < height){
25732 scale = targetHeight / height;
25736 context.scale(scale, scale);
25738 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25739 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25741 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25742 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25744 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25749 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25750 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25752 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25753 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25755 var targetWidth = this.minWidth - 2 * x;
25756 var targetHeight = this.minHeight - 2 * y;
25760 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25761 scale = targetWidth / width;
25764 if(x > 0 && y == 0){
25765 scale = targetHeight / height;
25768 if(x > 0 && y > 0){
25769 scale = targetWidth / width;
25771 if(width < height){
25772 scale = targetHeight / height;
25776 context.scale(scale, scale);
25778 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25779 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25781 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25782 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25784 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25786 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25791 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25792 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25794 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25795 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25797 var targetWidth = this.minWidth - 2 * x;
25798 var targetHeight = this.minHeight - 2 * y;
25802 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25803 scale = targetWidth / width;
25806 if(x > 0 && y == 0){
25807 scale = targetHeight / height;
25810 if(x > 0 && y > 0){
25811 scale = targetWidth / width;
25813 if(width < height){
25814 scale = targetHeight / height;
25818 context.scale(scale, scale);
25820 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25821 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25823 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25824 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25826 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25827 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25829 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25834 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25835 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25837 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25838 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25840 var targetWidth = this.minWidth - 2 * x;
25841 var targetHeight = this.minHeight - 2 * y;
25845 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25846 scale = targetWidth / width;
25849 if(x > 0 && y == 0){
25850 scale = targetHeight / height;
25853 if(x > 0 && y > 0){
25854 scale = targetWidth / width;
25856 if(width < height){
25857 scale = targetHeight / height;
25861 context.scale(scale, scale);
25863 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25864 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25866 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25867 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25869 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25871 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25878 this.cropData = canvas.toDataURL(this.cropType);
25880 if(this.fireEvent('crop', this, this.cropData) !== false){
25881 this.process(this.file, this.cropData);
25888 setThumbBoxSize : function()
25892 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
25893 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
25894 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
25896 this.minWidth = width;
25897 this.minHeight = height;
25899 if(this.rotate == 90 || this.rotate == 270){
25900 this.minWidth = height;
25901 this.minHeight = width;
25906 width = Math.ceil(this.minWidth * height / this.minHeight);
25908 if(this.minWidth > this.minHeight){
25910 height = Math.ceil(this.minHeight * width / this.minWidth);
25913 this.thumbEl.setStyle({
25914 width : width + 'px',
25915 height : height + 'px'
25922 setThumbBoxPosition : function()
25924 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
25925 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
25927 this.thumbEl.setLeft(x);
25928 this.thumbEl.setTop(y);
25932 baseRotateLevel : function()
25934 this.baseRotate = 1;
25937 typeof(this.exif) != 'undefined' &&
25938 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
25939 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
25941 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
25944 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
25948 baseScaleLevel : function()
25952 if(this.isDocument){
25954 if(this.baseRotate == 6 || this.baseRotate == 8){
25956 height = this.thumbEl.getHeight();
25957 this.baseScale = height / this.imageEl.OriginWidth;
25959 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
25960 width = this.thumbEl.getWidth();
25961 this.baseScale = width / this.imageEl.OriginHeight;
25967 height = this.thumbEl.getHeight();
25968 this.baseScale = height / this.imageEl.OriginHeight;
25970 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
25971 width = this.thumbEl.getWidth();
25972 this.baseScale = width / this.imageEl.OriginWidth;
25978 if(this.baseRotate == 6 || this.baseRotate == 8){
25980 width = this.thumbEl.getHeight();
25981 this.baseScale = width / this.imageEl.OriginHeight;
25983 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
25984 height = this.thumbEl.getWidth();
25985 this.baseScale = height / this.imageEl.OriginHeight;
25988 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25989 height = this.thumbEl.getWidth();
25990 this.baseScale = height / this.imageEl.OriginHeight;
25992 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
25993 width = this.thumbEl.getHeight();
25994 this.baseScale = width / this.imageEl.OriginWidth;
26001 width = this.thumbEl.getWidth();
26002 this.baseScale = width / this.imageEl.OriginWidth;
26004 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26005 height = this.thumbEl.getHeight();
26006 this.baseScale = height / this.imageEl.OriginHeight;
26009 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26011 height = this.thumbEl.getHeight();
26012 this.baseScale = height / this.imageEl.OriginHeight;
26014 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26015 width = this.thumbEl.getWidth();
26016 this.baseScale = width / this.imageEl.OriginWidth;
26024 getScaleLevel : function()
26026 return this.baseScale * Math.pow(1.1, this.scale);
26029 onTouchStart : function(e)
26031 if(!this.canvasLoaded){
26032 this.beforeSelectFile(e);
26036 var touches = e.browserEvent.touches;
26042 if(touches.length == 1){
26043 this.onMouseDown(e);
26047 if(touches.length != 2){
26053 for(var i = 0, finger; finger = touches[i]; i++){
26054 coords.push(finger.pageX, finger.pageY);
26057 var x = Math.pow(coords[0] - coords[2], 2);
26058 var y = Math.pow(coords[1] - coords[3], 2);
26060 this.startDistance = Math.sqrt(x + y);
26062 this.startScale = this.scale;
26064 this.pinching = true;
26065 this.dragable = false;
26069 onTouchMove : function(e)
26071 if(!this.pinching && !this.dragable){
26075 var touches = e.browserEvent.touches;
26082 this.onMouseMove(e);
26088 for(var i = 0, finger; finger = touches[i]; i++){
26089 coords.push(finger.pageX, finger.pageY);
26092 var x = Math.pow(coords[0] - coords[2], 2);
26093 var y = Math.pow(coords[1] - coords[3], 2);
26095 this.endDistance = Math.sqrt(x + y);
26097 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26099 if(!this.zoomable()){
26100 this.scale = this.startScale;
26108 onTouchEnd : function(e)
26110 this.pinching = false;
26111 this.dragable = false;
26115 process : function(file, crop)
26118 this.maskEl.mask(this.loadingText);
26121 this.xhr = new XMLHttpRequest();
26123 file.xhr = this.xhr;
26125 this.xhr.open(this.method, this.url, true);
26128 "Accept": "application/json",
26129 "Cache-Control": "no-cache",
26130 "X-Requested-With": "XMLHttpRequest"
26133 for (var headerName in headers) {
26134 var headerValue = headers[headerName];
26136 this.xhr.setRequestHeader(headerName, headerValue);
26142 this.xhr.onload = function()
26144 _this.xhrOnLoad(_this.xhr);
26147 this.xhr.onerror = function()
26149 _this.xhrOnError(_this.xhr);
26152 var formData = new FormData();
26154 formData.append('returnHTML', 'NO');
26157 formData.append('crop', crop);
26160 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26161 formData.append(this.paramName, file, file.name);
26164 if(typeof(file.filename) != 'undefined'){
26165 formData.append('filename', file.filename);
26168 if(typeof(file.mimetype) != 'undefined'){
26169 formData.append('mimetype', file.mimetype);
26172 if(this.fireEvent('arrange', this, formData) != false){
26173 this.xhr.send(formData);
26177 xhrOnLoad : function(xhr)
26180 this.maskEl.unmask();
26183 if (xhr.readyState !== 4) {
26184 this.fireEvent('exception', this, xhr);
26188 var response = Roo.decode(xhr.responseText);
26190 if(!response.success){
26191 this.fireEvent('exception', this, xhr);
26195 var response = Roo.decode(xhr.responseText);
26197 this.fireEvent('upload', this, response);
26201 xhrOnError : function()
26204 this.maskEl.unmask();
26207 Roo.log('xhr on error');
26209 var response = Roo.decode(xhr.responseText);
26215 prepare : function(file)
26218 this.maskEl.mask(this.loadingText);
26224 if(typeof(file) === 'string'){
26225 this.loadCanvas(file);
26229 if(!file || !this.urlAPI){
26234 this.cropType = file.type;
26238 if(this.fireEvent('prepare', this, this.file) != false){
26240 var reader = new FileReader();
26242 reader.onload = function (e) {
26243 if (e.target.error) {
26244 Roo.log(e.target.error);
26248 var buffer = e.target.result,
26249 dataView = new DataView(buffer),
26251 maxOffset = dataView.byteLength - 4,
26255 if (dataView.getUint16(0) === 0xffd8) {
26256 while (offset < maxOffset) {
26257 markerBytes = dataView.getUint16(offset);
26259 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26260 markerLength = dataView.getUint16(offset + 2) + 2;
26261 if (offset + markerLength > dataView.byteLength) {
26262 Roo.log('Invalid meta data: Invalid segment size.');
26266 if(markerBytes == 0xffe1){
26267 _this.parseExifData(
26274 offset += markerLength;
26284 var url = _this.urlAPI.createObjectURL(_this.file);
26286 _this.loadCanvas(url);
26291 reader.readAsArrayBuffer(this.file);
26297 parseExifData : function(dataView, offset, length)
26299 var tiffOffset = offset + 10,
26303 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26304 // No Exif data, might be XMP data instead
26308 // Check for the ASCII code for "Exif" (0x45786966):
26309 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26310 // No Exif data, might be XMP data instead
26313 if (tiffOffset + 8 > dataView.byteLength) {
26314 Roo.log('Invalid Exif data: Invalid segment size.');
26317 // Check for the two null bytes:
26318 if (dataView.getUint16(offset + 8) !== 0x0000) {
26319 Roo.log('Invalid Exif data: Missing byte alignment offset.');
26322 // Check the byte alignment:
26323 switch (dataView.getUint16(tiffOffset)) {
26325 littleEndian = true;
26328 littleEndian = false;
26331 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
26334 // Check for the TIFF tag marker (0x002A):
26335 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
26336 Roo.log('Invalid Exif data: Missing TIFF marker.');
26339 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
26340 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
26342 this.parseExifTags(
26345 tiffOffset + dirOffset,
26350 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
26355 if (dirOffset + 6 > dataView.byteLength) {
26356 Roo.log('Invalid Exif data: Invalid directory offset.');
26359 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
26360 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
26361 if (dirEndOffset + 4 > dataView.byteLength) {
26362 Roo.log('Invalid Exif data: Invalid directory size.');
26365 for (i = 0; i < tagsNumber; i += 1) {
26369 dirOffset + 2 + 12 * i, // tag offset
26373 // Return the offset to the next directory:
26374 return dataView.getUint32(dirEndOffset, littleEndian);
26377 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
26379 var tag = dataView.getUint16(offset, littleEndian);
26381 this.exif[tag] = this.getExifValue(
26385 dataView.getUint16(offset + 2, littleEndian), // tag type
26386 dataView.getUint32(offset + 4, littleEndian), // tag length
26391 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
26393 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
26402 Roo.log('Invalid Exif data: Invalid tag type.');
26406 tagSize = tagType.size * length;
26407 // Determine if the value is contained in the dataOffset bytes,
26408 // or if the value at the dataOffset is a pointer to the actual data:
26409 dataOffset = tagSize > 4 ?
26410 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
26411 if (dataOffset + tagSize > dataView.byteLength) {
26412 Roo.log('Invalid Exif data: Invalid data offset.');
26415 if (length === 1) {
26416 return tagType.getValue(dataView, dataOffset, littleEndian);
26419 for (i = 0; i < length; i += 1) {
26420 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
26423 if (tagType.ascii) {
26425 // Concatenate the chars:
26426 for (i = 0; i < values.length; i += 1) {
26428 // Ignore the terminating NULL byte(s):
26429 if (c === '\u0000') {
26441 Roo.apply(Roo.bootstrap.UploadCropbox, {
26443 'Orientation': 0x0112
26447 1: 0, //'top-left',
26449 3: 180, //'bottom-right',
26450 // 4: 'bottom-left',
26452 6: 90, //'right-top',
26453 // 7: 'right-bottom',
26454 8: 270 //'left-bottom'
26458 // byte, 8-bit unsigned int:
26460 getValue: function (dataView, dataOffset) {
26461 return dataView.getUint8(dataOffset);
26465 // ascii, 8-bit byte:
26467 getValue: function (dataView, dataOffset) {
26468 return String.fromCharCode(dataView.getUint8(dataOffset));
26473 // short, 16 bit int:
26475 getValue: function (dataView, dataOffset, littleEndian) {
26476 return dataView.getUint16(dataOffset, littleEndian);
26480 // long, 32 bit int:
26482 getValue: function (dataView, dataOffset, littleEndian) {
26483 return dataView.getUint32(dataOffset, littleEndian);
26487 // rational = two long values, first is numerator, second is denominator:
26489 getValue: function (dataView, dataOffset, littleEndian) {
26490 return dataView.getUint32(dataOffset, littleEndian) /
26491 dataView.getUint32(dataOffset + 4, littleEndian);
26495 // slong, 32 bit signed int:
26497 getValue: function (dataView, dataOffset, littleEndian) {
26498 return dataView.getInt32(dataOffset, littleEndian);
26502 // srational, two slongs, first is numerator, second is denominator:
26504 getValue: function (dataView, dataOffset, littleEndian) {
26505 return dataView.getInt32(dataOffset, littleEndian) /
26506 dataView.getInt32(dataOffset + 4, littleEndian);
26516 cls : 'btn-group roo-upload-cropbox-rotate-left',
26517 action : 'rotate-left',
26521 cls : 'btn btn-default',
26522 html : '<i class="fa fa-undo"></i>'
26528 cls : 'btn-group roo-upload-cropbox-picture',
26529 action : 'picture',
26533 cls : 'btn btn-default',
26534 html : '<i class="fa fa-picture-o"></i>'
26540 cls : 'btn-group roo-upload-cropbox-rotate-right',
26541 action : 'rotate-right',
26545 cls : 'btn btn-default',
26546 html : '<i class="fa fa-repeat"></i>'
26554 cls : 'btn-group roo-upload-cropbox-rotate-left',
26555 action : 'rotate-left',
26559 cls : 'btn btn-default',
26560 html : '<i class="fa fa-undo"></i>'
26566 cls : 'btn-group roo-upload-cropbox-download',
26567 action : 'download',
26571 cls : 'btn btn-default',
26572 html : '<i class="fa fa-download"></i>'
26578 cls : 'btn-group roo-upload-cropbox-crop',
26583 cls : 'btn btn-default',
26584 html : '<i class="fa fa-crop"></i>'
26590 cls : 'btn-group roo-upload-cropbox-trash',
26595 cls : 'btn btn-default',
26596 html : '<i class="fa fa-trash"></i>'
26602 cls : 'btn-group roo-upload-cropbox-rotate-right',
26603 action : 'rotate-right',
26607 cls : 'btn btn-default',
26608 html : '<i class="fa fa-repeat"></i>'
26616 cls : 'btn-group roo-upload-cropbox-rotate-left',
26617 action : 'rotate-left',
26621 cls : 'btn btn-default',
26622 html : '<i class="fa fa-undo"></i>'
26628 cls : 'btn-group roo-upload-cropbox-rotate-right',
26629 action : 'rotate-right',
26633 cls : 'btn btn-default',
26634 html : '<i class="fa fa-repeat"></i>'
26647 * @class Roo.bootstrap.DocumentManager
26648 * @extends Roo.bootstrap.Component
26649 * Bootstrap DocumentManager class
26650 * @cfg {String} paramName default 'imageUpload'
26651 * @cfg {String} method default POST
26652 * @cfg {String} url action url
26653 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
26654 * @cfg {Boolean} multiple multiple upload default true
26655 * @cfg {Number} thumbSize default 300
26656 * @cfg {String} fieldLabel
26657 * @cfg {Number} labelWidth default 4
26658 * @cfg {String} labelAlign (left|top) default left
26659 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
26662 * Create a new DocumentManager
26663 * @param {Object} config The config object
26666 Roo.bootstrap.DocumentManager = function(config){
26667 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
26672 * Fire when initial the DocumentManager
26673 * @param {Roo.bootstrap.DocumentManager} this
26678 * inspect selected file
26679 * @param {Roo.bootstrap.DocumentManager} this
26680 * @param {File} file
26685 * Fire when xhr load exception
26686 * @param {Roo.bootstrap.DocumentManager} this
26687 * @param {XMLHttpRequest} xhr
26689 "exception" : true,
26692 * prepare the form data
26693 * @param {Roo.bootstrap.DocumentManager} this
26694 * @param {Object} formData
26699 * Fire when remove the file
26700 * @param {Roo.bootstrap.DocumentManager} this
26701 * @param {Object} file
26706 * Fire after refresh the file
26707 * @param {Roo.bootstrap.DocumentManager} this
26712 * Fire after click the image
26713 * @param {Roo.bootstrap.DocumentManager} this
26714 * @param {Object} file
26719 * Fire when upload a image and editable set to true
26720 * @param {Roo.bootstrap.DocumentManager} this
26721 * @param {Object} file
26725 * @event beforeselectfile
26726 * Fire before select file
26727 * @param {Roo.bootstrap.DocumentManager} this
26729 "beforeselectfile" : true,
26732 * Fire before process file
26733 * @param {Roo.bootstrap.DocumentManager} this
26734 * @param {Object} file
26741 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
26750 paramName : 'imageUpload',
26753 labelAlign : 'left',
26760 getAutoCreate : function()
26762 var managerWidget = {
26764 cls : 'roo-document-manager',
26768 cls : 'roo-document-manager-selector',
26773 cls : 'roo-document-manager-uploader',
26777 cls : 'roo-document-manager-upload-btn',
26778 html : '<i class="fa fa-plus"></i>'
26789 cls : 'column col-md-12',
26794 if(this.fieldLabel.length){
26799 cls : 'column col-md-12',
26800 html : this.fieldLabel
26804 cls : 'column col-md-12',
26809 if(this.labelAlign == 'left'){
26813 cls : 'column col-md-' + this.labelWidth,
26814 html : this.fieldLabel
26818 cls : 'column col-md-' + (12 - this.labelWidth),
26828 cls : 'row clearfix',
26836 initEvents : function()
26838 this.managerEl = this.el.select('.roo-document-manager', true).first();
26839 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26841 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
26842 this.selectorEl.hide();
26845 this.selectorEl.attr('multiple', 'multiple');
26848 this.selectorEl.on('change', this.onFileSelected, this);
26850 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
26851 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26853 this.uploader.on('click', this.onUploaderClick, this);
26855 this.renderProgressDialog();
26859 window.addEventListener("resize", function() { _this.refresh(); } );
26861 this.fireEvent('initial', this);
26864 renderProgressDialog : function()
26868 this.progressDialog = new Roo.bootstrap.Modal({
26869 cls : 'roo-document-manager-progress-dialog',
26870 allow_close : false,
26880 btnclick : function() {
26881 _this.uploadCancel();
26887 this.progressDialog.render(Roo.get(document.body));
26889 this.progress = new Roo.bootstrap.Progress({
26890 cls : 'roo-document-manager-progress',
26895 this.progress.render(this.progressDialog.getChildContainer());
26897 this.progressBar = new Roo.bootstrap.ProgressBar({
26898 cls : 'roo-document-manager-progress-bar',
26901 aria_valuemax : 12,
26905 this.progressBar.render(this.progress.getChildContainer());
26908 onUploaderClick : function(e)
26910 e.preventDefault();
26912 if(this.fireEvent('beforeselectfile', this) != false){
26913 this.selectorEl.dom.click();
26918 onFileSelected : function(e)
26920 e.preventDefault();
26922 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26926 Roo.each(this.selectorEl.dom.files, function(file){
26927 if(this.fireEvent('inspect', this, file) != false){
26928 this.files.push(file);
26938 this.selectorEl.dom.value = '';
26940 if(!this.files.length){
26944 if(this.boxes > 0 && this.files.length > this.boxes){
26945 this.files = this.files.slice(0, this.boxes);
26948 this.uploader.show();
26950 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26951 this.uploader.hide();
26960 Roo.each(this.files, function(file){
26962 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
26963 var f = this.renderPreview(file);
26968 if(file.type.indexOf('image') != -1){
26969 this.delegates.push(
26971 _this.process(file);
26972 }).createDelegate(this)
26980 _this.process(file);
26981 }).createDelegate(this)
26986 this.files = files;
26988 this.delegates = this.delegates.concat(docs);
26990 if(!this.delegates.length){
26995 this.progressBar.aria_valuemax = this.delegates.length;
27002 arrange : function()
27004 if(!this.delegates.length){
27005 this.progressDialog.hide();
27010 var delegate = this.delegates.shift();
27012 this.progressDialog.show();
27014 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27016 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27021 refresh : function()
27023 this.uploader.show();
27025 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27026 this.uploader.hide();
27029 Roo.isTouch ? this.closable(false) : this.closable(true);
27031 this.fireEvent('refresh', this);
27034 onRemove : function(e, el, o)
27036 e.preventDefault();
27038 this.fireEvent('remove', this, o);
27042 remove : function(o)
27046 Roo.each(this.files, function(file){
27047 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27056 this.files = files;
27063 Roo.each(this.files, function(file){
27068 file.target.remove();
27077 onClick : function(e, el, o)
27079 e.preventDefault();
27081 this.fireEvent('click', this, o);
27085 closable : function(closable)
27087 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27089 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27101 xhrOnLoad : function(xhr)
27103 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27107 if (xhr.readyState !== 4) {
27109 this.fireEvent('exception', this, xhr);
27113 var response = Roo.decode(xhr.responseText);
27115 if(!response.success){
27117 this.fireEvent('exception', this, xhr);
27121 var file = this.renderPreview(response.data);
27123 this.files.push(file);
27129 xhrOnError : function(xhr)
27131 Roo.log('xhr on error');
27133 var response = Roo.decode(xhr.responseText);
27140 process : function(file)
27142 if(this.fireEvent('process', this, file) !== false){
27143 if(this.editable && file.type.indexOf('image') != -1){
27144 this.fireEvent('edit', this, file);
27148 this.uploadStart(file, false);
27155 uploadStart : function(file, crop)
27157 this.xhr = new XMLHttpRequest();
27159 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27164 file.xhr = this.xhr;
27166 this.managerEl.createChild({
27168 cls : 'roo-document-manager-loading',
27172 tooltip : file.name,
27173 cls : 'roo-document-manager-thumb',
27174 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27180 this.xhr.open(this.method, this.url, true);
27183 "Accept": "application/json",
27184 "Cache-Control": "no-cache",
27185 "X-Requested-With": "XMLHttpRequest"
27188 for (var headerName in headers) {
27189 var headerValue = headers[headerName];
27191 this.xhr.setRequestHeader(headerName, headerValue);
27197 this.xhr.onload = function()
27199 _this.xhrOnLoad(_this.xhr);
27202 this.xhr.onerror = function()
27204 _this.xhrOnError(_this.xhr);
27207 var formData = new FormData();
27209 formData.append('returnHTML', 'NO');
27212 formData.append('crop', crop);
27215 formData.append(this.paramName, file, file.name);
27217 if(this.fireEvent('prepare', this, formData) != false){
27218 this.xhr.send(formData);
27222 uploadCancel : function()
27229 this.delegates = [];
27231 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27238 renderPreview : function(file)
27240 if(typeof(file.target) != 'undefined' && file.target){
27244 var previewEl = this.managerEl.createChild({
27246 cls : 'roo-document-manager-preview',
27250 tooltip : file.filename,
27251 cls : 'roo-document-manager-thumb',
27252 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27257 html : '<i class="fa fa-times-circle"></i>'
27262 var close = previewEl.select('button.close', true).first();
27264 close.on('click', this.onRemove, this, file);
27266 file.target = previewEl;
27268 var image = previewEl.select('img', true).first();
27272 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27274 image.on('click', this.onClick, this, file);
27280 onPreviewLoad : function(file, image)
27282 if(typeof(file.target) == 'undefined' || !file.target){
27286 var width = image.dom.naturalWidth || image.dom.width;
27287 var height = image.dom.naturalHeight || image.dom.height;
27289 if(width > height){
27290 file.target.addClass('wide');
27294 file.target.addClass('tall');
27299 uploadFromSource : function(file, crop)
27301 this.xhr = new XMLHttpRequest();
27303 this.managerEl.createChild({
27305 cls : 'roo-document-manager-loading',
27309 tooltip : file.name,
27310 cls : 'roo-document-manager-thumb',
27311 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27317 this.xhr.open(this.method, this.url, true);
27320 "Accept": "application/json",
27321 "Cache-Control": "no-cache",
27322 "X-Requested-With": "XMLHttpRequest"
27325 for (var headerName in headers) {
27326 var headerValue = headers[headerName];
27328 this.xhr.setRequestHeader(headerName, headerValue);
27334 this.xhr.onload = function()
27336 _this.xhrOnLoad(_this.xhr);
27339 this.xhr.onerror = function()
27341 _this.xhrOnError(_this.xhr);
27344 var formData = new FormData();
27346 formData.append('returnHTML', 'NO');
27348 formData.append('crop', crop);
27350 if(typeof(file.filename) != 'undefined'){
27351 formData.append('filename', file.filename);
27354 if(typeof(file.mimetype) != 'undefined'){
27355 formData.append('mimetype', file.mimetype);
27358 if(this.fireEvent('prepare', this, formData) != false){
27359 this.xhr.send(formData);
27369 * @class Roo.bootstrap.DocumentViewer
27370 * @extends Roo.bootstrap.Component
27371 * Bootstrap DocumentViewer class
27374 * Create a new DocumentViewer
27375 * @param {Object} config The config object
27378 Roo.bootstrap.DocumentViewer = function(config){
27379 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
27384 * Fire after initEvent
27385 * @param {Roo.bootstrap.DocumentViewer} this
27391 * @param {Roo.bootstrap.DocumentViewer} this
27396 * Fire after trash button
27397 * @param {Roo.bootstrap.DocumentViewer} this
27404 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
27406 getAutoCreate : function()
27410 cls : 'roo-document-viewer',
27414 cls : 'roo-document-viewer-body',
27418 cls : 'roo-document-viewer-thumb',
27422 cls : 'roo-document-viewer-image'
27430 cls : 'roo-document-viewer-footer',
27433 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
27441 cls : 'btn btn-default roo-document-viewer-trash',
27442 html : '<i class="fa fa-trash"></i>'
27455 initEvents : function()
27458 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
27459 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27461 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
27462 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27464 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
27465 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27467 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
27468 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27470 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
27471 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27473 this.bodyEl.on('click', this.onClick, this);
27475 this.trashBtn.on('click', this.onTrash, this);
27479 initial : function()
27481 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
27484 this.fireEvent('initial', this);
27488 onClick : function(e)
27490 e.preventDefault();
27492 this.fireEvent('click', this);
27495 onTrash : function(e)
27497 e.preventDefault();
27499 this.fireEvent('trash', this);
27511 * @class Roo.bootstrap.NavProgressBar
27512 * @extends Roo.bootstrap.Component
27513 * Bootstrap NavProgressBar class
27516 * Create a new nav progress bar
27517 * @param {Object} config The config object
27520 Roo.bootstrap.NavProgressBar = function(config){
27521 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
27523 this.bullets = this.bullets || [];
27525 // Roo.bootstrap.NavProgressBar.register(this);
27529 * Fires when the active item changes
27530 * @param {Roo.bootstrap.NavProgressBar} this
27531 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
27532 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
27539 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
27544 getAutoCreate : function()
27546 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
27550 cls : 'roo-navigation-bar-group',
27554 cls : 'roo-navigation-top-bar'
27558 cls : 'roo-navigation-bullets-bar',
27562 cls : 'roo-navigation-bar'
27569 cls : 'roo-navigation-bottom-bar'
27579 initEvents: function()
27584 onRender : function(ct, position)
27586 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
27588 if(this.bullets.length){
27589 Roo.each(this.bullets, function(b){
27598 addItem : function(cfg)
27600 var item = new Roo.bootstrap.NavProgressItem(cfg);
27602 item.parentId = this.id;
27603 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
27606 var top = new Roo.bootstrap.Element({
27608 cls : 'roo-navigation-bar-text'
27611 var bottom = new Roo.bootstrap.Element({
27613 cls : 'roo-navigation-bar-text'
27616 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
27617 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
27619 var topText = new Roo.bootstrap.Element({
27621 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
27624 var bottomText = new Roo.bootstrap.Element({
27626 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
27629 topText.onRender(top.el, null);
27630 bottomText.onRender(bottom.el, null);
27633 item.bottomEl = bottom;
27636 this.barItems.push(item);
27641 getActive : function()
27643 var active = false;
27645 Roo.each(this.barItems, function(v){
27647 if (!v.isActive()) {
27659 setActiveItem : function(item)
27663 Roo.each(this.barItems, function(v){
27664 if (v.rid == item.rid) {
27668 if (v.isActive()) {
27669 v.setActive(false);
27674 item.setActive(true);
27676 this.fireEvent('changed', this, item, prev);
27679 getBarItem: function(rid)
27683 Roo.each(this.barItems, function(e) {
27684 if (e.rid != rid) {
27695 indexOfItem : function(item)
27699 Roo.each(this.barItems, function(v, i){
27701 if (v.rid != item.rid) {
27712 setActiveNext : function()
27714 var i = this.indexOfItem(this.getActive());
27716 if (i > this.barItems.length) {
27720 this.setActiveItem(this.barItems[i+1]);
27723 setActivePrev : function()
27725 var i = this.indexOfItem(this.getActive());
27731 this.setActiveItem(this.barItems[i-1]);
27734 format : function()
27736 if(!this.barItems.length){
27740 var width = 100 / this.barItems.length;
27742 Roo.each(this.barItems, function(i){
27743 i.el.setStyle('width', width + '%');
27744 i.topEl.el.setStyle('width', width + '%');
27745 i.bottomEl.el.setStyle('width', width + '%');
27754 * Nav Progress Item
27759 * @class Roo.bootstrap.NavProgressItem
27760 * @extends Roo.bootstrap.Component
27761 * Bootstrap NavProgressItem class
27762 * @cfg {String} rid the reference id
27763 * @cfg {Boolean} active (true|false) Is item active default false
27764 * @cfg {Boolean} disabled (true|false) Is item active default false
27765 * @cfg {String} html
27766 * @cfg {String} position (top|bottom) text position default bottom
27767 * @cfg {String} icon show icon instead of number
27770 * Create a new NavProgressItem
27771 * @param {Object} config The config object
27773 Roo.bootstrap.NavProgressItem = function(config){
27774 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
27779 * The raw click event for the entire grid.
27780 * @param {Roo.bootstrap.NavProgressItem} this
27781 * @param {Roo.EventObject} e
27788 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
27794 position : 'bottom',
27797 getAutoCreate : function()
27799 var iconCls = 'roo-navigation-bar-item-icon';
27801 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
27805 cls: 'roo-navigation-bar-item',
27815 cfg.cls += ' active';
27818 cfg.cls += ' disabled';
27824 disable : function()
27826 this.setDisabled(true);
27829 enable : function()
27831 this.setDisabled(false);
27834 initEvents: function()
27836 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
27838 this.iconEl.on('click', this.onClick, this);
27841 onClick : function(e)
27843 e.preventDefault();
27849 if(this.fireEvent('click', this, e) === false){
27853 this.parent().setActiveItem(this);
27856 isActive: function ()
27858 return this.active;
27861 setActive : function(state)
27863 if(this.active == state){
27867 this.active = state;
27870 this.el.addClass('active');
27874 this.el.removeClass('active');
27879 setDisabled : function(state)
27881 if(this.disabled == state){
27885 this.disabled = state;
27888 this.el.addClass('disabled');
27892 this.el.removeClass('disabled');
27895 tooltipEl : function()
27897 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
27910 * @class Roo.bootstrap.FieldLabel
27911 * @extends Roo.bootstrap.Component
27912 * Bootstrap FieldLabel class
27913 * @cfg {String} html contents of the element
27914 * @cfg {String} tag tag of the element default label
27915 * @cfg {String} cls class of the element
27916 * @cfg {String} target label target
27917 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
27918 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
27919 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
27920 * @cfg {String} iconTooltip default "This field is required"
27923 * Create a new FieldLabel
27924 * @param {Object} config The config object
27927 Roo.bootstrap.FieldLabel = function(config){
27928 Roo.bootstrap.Element.superclass.constructor.call(this, config);
27933 * Fires after the field has been marked as invalid.
27934 * @param {Roo.form.FieldLabel} this
27935 * @param {String} msg The validation message
27940 * Fires after the field has been validated with no errors.
27941 * @param {Roo.form.FieldLabel} this
27947 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
27954 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
27955 validClass : 'text-success fa fa-lg fa-check',
27956 iconTooltip : 'This field is required',
27958 getAutoCreate : function(){
27962 cls : 'roo-bootstrap-field-label ' + this.cls,
27968 tooltip : this.iconTooltip
27980 initEvents: function()
27982 Roo.bootstrap.Element.superclass.initEvents.call(this);
27984 this.iconEl = this.el.select('i', true).first();
27986 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
27988 Roo.bootstrap.FieldLabel.register(this);
27992 * Mark this field as valid
27994 markValid : function()
27996 this.iconEl.show();
27998 this.iconEl.removeClass(this.invalidClass);
28000 this.iconEl.addClass(this.validClass);
28002 this.fireEvent('valid', this);
28006 * Mark this field as invalid
28007 * @param {String} msg The validation message
28009 markInvalid : function(msg)
28011 this.iconEl.show();
28013 this.iconEl.removeClass(this.validClass);
28015 this.iconEl.addClass(this.invalidClass);
28017 this.fireEvent('invalid', this, msg);
28023 Roo.apply(Roo.bootstrap.FieldLabel, {
28028 * register a FieldLabel Group
28029 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28031 register : function(label)
28033 if(this.groups.hasOwnProperty(label.target)){
28037 this.groups[label.target] = label;
28041 * fetch a FieldLabel Group based on the target
28042 * @param {string} target
28043 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28045 get: function(target) {
28046 if (typeof(this.groups[target]) == 'undefined') {
28050 return this.groups[target] ;
28059 * page DateSplitField.
28065 * @class Roo.bootstrap.DateSplitField
28066 * @extends Roo.bootstrap.Component
28067 * Bootstrap DateSplitField class
28068 * @cfg {string} fieldLabel - the label associated
28069 * @cfg {Number} labelWidth set the width of label (0-12)
28070 * @cfg {String} labelAlign (top|left)
28071 * @cfg {Boolean} dayAllowBlank (true|false) default false
28072 * @cfg {Boolean} monthAllowBlank (true|false) default false
28073 * @cfg {Boolean} yearAllowBlank (true|false) default false
28074 * @cfg {string} dayPlaceholder
28075 * @cfg {string} monthPlaceholder
28076 * @cfg {string} yearPlaceholder
28077 * @cfg {string} dayFormat default 'd'
28078 * @cfg {string} monthFormat default 'm'
28079 * @cfg {string} yearFormat default 'Y'
28083 * Create a new DateSplitField
28084 * @param {Object} config The config object
28087 Roo.bootstrap.DateSplitField = function(config){
28088 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28094 * getting the data of years
28095 * @param {Roo.bootstrap.DateSplitField} this
28096 * @param {Object} years
28101 * getting the data of days
28102 * @param {Roo.bootstrap.DateSplitField} this
28103 * @param {Object} days
28108 * Fires after the field has been marked as invalid.
28109 * @param {Roo.form.Field} this
28110 * @param {String} msg The validation message
28115 * Fires after the field has been validated with no errors.
28116 * @param {Roo.form.Field} this
28122 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28125 labelAlign : 'top',
28127 dayAllowBlank : false,
28128 monthAllowBlank : false,
28129 yearAllowBlank : false,
28130 dayPlaceholder : '',
28131 monthPlaceholder : '',
28132 yearPlaceholder : '',
28136 isFormField : true,
28138 getAutoCreate : function()
28142 cls : 'row roo-date-split-field-group',
28147 cls : 'form-hidden-field roo-date-split-field-group-value',
28153 if(this.fieldLabel){
28156 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28160 html : this.fieldLabel
28166 Roo.each(['day', 'month', 'year'], function(t){
28169 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28176 inputEl: function ()
28178 return this.el.select('.roo-date-split-field-group-value', true).first();
28181 onRender : function(ct, position)
28185 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28187 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28189 this.dayField = new Roo.bootstrap.ComboBox({
28190 allowBlank : this.dayAllowBlank,
28191 alwaysQuery : true,
28192 displayField : 'value',
28195 forceSelection : true,
28197 placeholder : this.dayPlaceholder,
28198 selectOnFocus : true,
28199 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28200 triggerAction : 'all',
28202 valueField : 'value',
28203 store : new Roo.data.SimpleStore({
28204 data : (function() {
28206 _this.fireEvent('days', _this, days);
28209 fields : [ 'value' ]
28212 select : function (_self, record, index)
28214 _this.setValue(_this.getValue());
28219 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28221 this.monthField = new Roo.bootstrap.MonthField({
28222 after : '<i class=\"fa fa-calendar\"></i>',
28223 allowBlank : this.monthAllowBlank,
28224 placeholder : this.monthPlaceholder,
28227 render : function (_self)
28229 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28230 e.preventDefault();
28234 select : function (_self, oldvalue, newvalue)
28236 _this.setValue(_this.getValue());
28241 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28243 this.yearField = new Roo.bootstrap.ComboBox({
28244 allowBlank : this.yearAllowBlank,
28245 alwaysQuery : true,
28246 displayField : 'value',
28249 forceSelection : true,
28251 placeholder : this.yearPlaceholder,
28252 selectOnFocus : true,
28253 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28254 triggerAction : 'all',
28256 valueField : 'value',
28257 store : new Roo.data.SimpleStore({
28258 data : (function() {
28260 _this.fireEvent('years', _this, years);
28263 fields : [ 'value' ]
28266 select : function (_self, record, index)
28268 _this.setValue(_this.getValue());
28273 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28276 setValue : function(v, format)
28278 this.inputEl.dom.value = v;
28280 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28282 var d = Date.parseDate(v, f);
28289 this.setDay(d.format(this.dayFormat));
28290 this.setMonth(d.format(this.monthFormat));
28291 this.setYear(d.format(this.yearFormat));
28298 setDay : function(v)
28300 this.dayField.setValue(v);
28301 this.inputEl.dom.value = this.getValue();
28306 setMonth : function(v)
28308 this.monthField.setValue(v, true);
28309 this.inputEl.dom.value = this.getValue();
28314 setYear : function(v)
28316 this.yearField.setValue(v);
28317 this.inputEl.dom.value = this.getValue();
28322 getDay : function()
28324 return this.dayField.getValue();
28327 getMonth : function()
28329 return this.monthField.getValue();
28332 getYear : function()
28334 return this.yearField.getValue();
28337 getValue : function()
28339 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
28341 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
28351 this.inputEl.dom.value = '';
28356 validate : function()
28358 var d = this.dayField.validate();
28359 var m = this.monthField.validate();
28360 var y = this.yearField.validate();
28365 (!this.dayAllowBlank && !d) ||
28366 (!this.monthAllowBlank && !m) ||
28367 (!this.yearAllowBlank && !y)
28372 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
28381 this.markInvalid();
28386 markValid : function()
28389 var label = this.el.select('label', true).first();
28390 var icon = this.el.select('i.fa-star', true).first();
28396 this.fireEvent('valid', this);
28400 * Mark this field as invalid
28401 * @param {String} msg The validation message
28403 markInvalid : function(msg)
28406 var label = this.el.select('label', true).first();
28407 var icon = this.el.select('i.fa-star', true).first();
28409 if(label && !icon){
28410 this.el.select('.roo-date-split-field-label', true).createChild({
28412 cls : 'text-danger fa fa-lg fa-star',
28413 tooltip : 'This field is required',
28414 style : 'margin-right:5px;'
28418 this.fireEvent('invalid', this, msg);
28421 clearInvalid : function()
28423 var label = this.el.select('label', true).first();
28424 var icon = this.el.select('i.fa-star', true).first();
28430 this.fireEvent('valid', this);
28433 getName: function()
28443 * http://masonry.desandro.com
28445 * The idea is to render all the bricks based on vertical width...
28447 * The original code extends 'outlayer' - we might need to use that....
28453 * @class Roo.bootstrap.LayoutMasonry
28454 * @extends Roo.bootstrap.Component
28455 * Bootstrap Layout Masonry class
28458 * Create a new Element
28459 * @param {Object} config The config object
28462 Roo.bootstrap.LayoutMasonry = function(config){
28463 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
28469 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
28472 * @cfg {Boolean} isLayoutInstant = no animation?
28474 isLayoutInstant : false, // needed?
28477 * @cfg {Number} boxWidth width of the columns
28482 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
28487 * @cfg {Number} padWidth padding below box..
28492 * @cfg {Number} gutter gutter width..
28497 * @cfg {Number} maxCols maximum number of columns
28503 * @cfg {Boolean} isAutoInitial defalut true
28505 isAutoInitial : true,
28510 * @cfg {Boolean} isHorizontal defalut false
28512 isHorizontal : false,
28514 currentSize : null,
28520 bricks: null, //CompositeElement
28524 _isLayoutInited : false,
28526 // isAlternative : false, // only use for vertical layout...
28529 * @cfg {Number} alternativePadWidth padding below box..
28531 alternativePadWidth : 50,
28533 getAutoCreate : function(){
28537 cls: 'blog-masonary-wrapper ' + this.cls,
28539 cls : 'mas-boxes masonary'
28546 getChildContainer: function( )
28548 if (this.boxesEl) {
28549 return this.boxesEl;
28552 this.boxesEl = this.el.select('.mas-boxes').first();
28554 return this.boxesEl;
28558 initEvents : function()
28562 if(this.isAutoInitial){
28563 Roo.log('hook children rendered');
28564 this.on('childrenrendered', function() {
28565 Roo.log('children rendered');
28571 initial : function()
28573 this.currentSize = this.el.getBox(true);
28575 Roo.EventManager.onWindowResize(this.resize, this);
28577 if(!this.isAutoInitial){
28585 //this.layout.defer(500,this);
28589 resize : function()
28593 var cs = this.el.getBox(true);
28595 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
28596 Roo.log("no change in with or X");
28600 this.currentSize = cs;
28606 layout : function()
28608 this._resetLayout();
28610 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
28612 this.layoutItems( isInstant );
28614 this._isLayoutInited = true;
28618 _resetLayout : function()
28620 if(this.isHorizontal){
28621 this.horizontalMeasureColumns();
28625 this.verticalMeasureColumns();
28629 verticalMeasureColumns : function()
28631 this.getContainerWidth();
28633 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28634 // this.colWidth = Math.floor(this.containerWidth * 0.8);
28638 var boxWidth = this.boxWidth + this.padWidth;
28640 if(this.containerWidth < this.boxWidth){
28641 boxWidth = this.containerWidth
28644 var containerWidth = this.containerWidth;
28646 var cols = Math.floor(containerWidth / boxWidth);
28648 this.cols = Math.max( cols, 1 );
28650 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
28652 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
28654 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
28656 this.colWidth = boxWidth + avail - this.padWidth;
28658 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
28659 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
28662 horizontalMeasureColumns : function()
28664 this.getContainerWidth();
28666 var boxWidth = this.boxWidth;
28668 if(this.containerWidth < boxWidth){
28669 boxWidth = this.containerWidth;
28672 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
28674 this.el.setHeight(boxWidth);
28678 getContainerWidth : function()
28680 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
28683 layoutItems : function( isInstant )
28685 var items = Roo.apply([], this.bricks);
28687 if(this.isHorizontal){
28688 this._horizontalLayoutItems( items , isInstant );
28692 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28693 // this._verticalAlternativeLayoutItems( items , isInstant );
28697 this._verticalLayoutItems( items , isInstant );
28701 _verticalLayoutItems : function ( items , isInstant)
28703 if ( !items || !items.length ) {
28708 ['xs', 'xs', 'xs', 'tall'],
28709 ['xs', 'xs', 'tall'],
28710 ['xs', 'xs', 'sm'],
28711 ['xs', 'xs', 'xs'],
28717 ['sm', 'xs', 'xs'],
28721 ['tall', 'xs', 'xs', 'xs'],
28722 ['tall', 'xs', 'xs'],
28734 Roo.each(items, function(item, k){
28736 switch (item.size) {
28737 // these layouts take up a full box,
28748 boxes.push([item]);
28771 var filterPattern = function(box, length)
28779 var pattern = box.slice(0, length);
28783 Roo.each(pattern, function(i){
28784 format.push(i.size);
28787 Roo.each(standard, function(s){
28789 if(String(s) != String(format)){
28798 if(!match && length == 1){
28803 filterPattern(box, length - 1);
28807 queue.push(pattern);
28809 box = box.slice(length, box.length);
28811 filterPattern(box, 4);
28817 Roo.each(boxes, function(box, k){
28823 if(box.length == 1){
28828 filterPattern(box, 4);
28832 this._processVerticalLayoutQueue( queue, isInstant );
28836 // _verticalAlternativeLayoutItems : function( items , isInstant )
28838 // if ( !items || !items.length ) {
28842 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
28846 _horizontalLayoutItems : function ( items , isInstant)
28848 if ( !items || !items.length || items.length < 3) {
28854 var eItems = items.slice(0, 3);
28856 items = items.slice(3, items.length);
28859 ['xs', 'xs', 'xs', 'wide'],
28860 ['xs', 'xs', 'wide'],
28861 ['xs', 'xs', 'sm'],
28862 ['xs', 'xs', 'xs'],
28868 ['sm', 'xs', 'xs'],
28872 ['wide', 'xs', 'xs', 'xs'],
28873 ['wide', 'xs', 'xs'],
28886 Roo.each(items, function(item, k){
28888 switch (item.size) {
28899 boxes.push([item]);
28923 var filterPattern = function(box, length)
28931 var pattern = box.slice(0, length);
28935 Roo.each(pattern, function(i){
28936 format.push(i.size);
28939 Roo.each(standard, function(s){
28941 if(String(s) != String(format)){
28950 if(!match && length == 1){
28955 filterPattern(box, length - 1);
28959 queue.push(pattern);
28961 box = box.slice(length, box.length);
28963 filterPattern(box, 4);
28969 Roo.each(boxes, function(box, k){
28975 if(box.length == 1){
28980 filterPattern(box, 4);
28987 var pos = this.el.getBox(true);
28991 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
28993 var hit_end = false;
28995 Roo.each(queue, function(box){
28999 Roo.each(box, function(b){
29001 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29011 Roo.each(box, function(b){
29013 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29016 mx = Math.max(mx, b.x);
29020 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29024 Roo.each(box, function(b){
29026 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29040 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29043 /** Sets position of item in DOM
29044 * @param {Element} item
29045 * @param {Number} x - horizontal position
29046 * @param {Number} y - vertical position
29047 * @param {Boolean} isInstant - disables transitions
29049 _processVerticalLayoutQueue : function( queue, isInstant )
29051 var pos = this.el.getBox(true);
29056 for (var i = 0; i < this.cols; i++){
29060 Roo.each(queue, function(box, k){
29062 var col = k % this.cols;
29064 Roo.each(box, function(b,kk){
29066 b.el.position('absolute');
29068 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29069 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29071 if(b.size == 'md-left' || b.size == 'md-right'){
29072 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29073 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29076 b.el.setWidth(width);
29077 b.el.setHeight(height);
29079 b.el.select('iframe',true).setSize(width,height);
29083 for (var i = 0; i < this.cols; i++){
29085 if(maxY[i] < maxY[col]){
29090 col = Math.min(col, i);
29094 x = pos.x + col * (this.colWidth + this.padWidth);
29098 var positions = [];
29100 switch (box.length){
29102 positions = this.getVerticalOneBoxColPositions(x, y, box);
29105 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29108 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29111 positions = this.getVerticalFourBoxColPositions(x, y, box);
29117 Roo.each(box, function(b,kk){
29119 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29121 var sz = b.el.getSize();
29123 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29131 for (var i = 0; i < this.cols; i++){
29132 mY = Math.max(mY, maxY[i]);
29135 this.el.setHeight(mY - pos.y);
29139 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29141 // var pos = this.el.getBox(true);
29144 // var maxX = pos.right;
29146 // var maxHeight = 0;
29148 // Roo.each(items, function(item, k){
29152 // item.el.position('absolute');
29154 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29156 // item.el.setWidth(width);
29158 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29160 // item.el.setHeight(height);
29163 // item.el.setXY([x, y], isInstant ? false : true);
29165 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29168 // y = y + height + this.alternativePadWidth;
29170 // maxHeight = maxHeight + height + this.alternativePadWidth;
29174 // this.el.setHeight(maxHeight);
29178 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29180 var pos = this.el.getBox(true);
29185 var maxX = pos.right;
29187 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29189 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29191 Roo.each(queue, function(box, k){
29193 Roo.each(box, function(b, kk){
29195 b.el.position('absolute');
29197 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29198 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29200 if(b.size == 'md-left' || b.size == 'md-right'){
29201 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29202 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29205 b.el.setWidth(width);
29206 b.el.setHeight(height);
29214 var positions = [];
29216 switch (box.length){
29218 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29221 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29224 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29227 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29233 Roo.each(box, function(b,kk){
29235 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29237 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29245 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29247 Roo.each(eItems, function(b,k){
29249 b.size = (k == 0) ? 'sm' : 'xs';
29250 b.x = (k == 0) ? 2 : 1;
29251 b.y = (k == 0) ? 2 : 1;
29253 b.el.position('absolute');
29255 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29257 b.el.setWidth(width);
29259 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29261 b.el.setHeight(height);
29265 var positions = [];
29268 x : maxX - this.unitWidth * 2 - this.gutter,
29273 x : maxX - this.unitWidth,
29274 y : minY + (this.unitWidth + this.gutter) * 2
29278 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29282 Roo.each(eItems, function(b,k){
29284 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29290 getVerticalOneBoxColPositions : function(x, y, box)
29294 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29296 if(box[0].size == 'md-left'){
29300 if(box[0].size == 'md-right'){
29305 x : x + (this.unitWidth + this.gutter) * rand,
29312 getVerticalTwoBoxColPositions : function(x, y, box)
29316 if(box[0].size == 'xs'){
29320 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
29324 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
29338 x : x + (this.unitWidth + this.gutter) * 2,
29339 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
29346 getVerticalThreeBoxColPositions : function(x, y, box)
29350 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29358 x : x + (this.unitWidth + this.gutter) * 1,
29363 x : x + (this.unitWidth + this.gutter) * 2,
29371 if(box[0].size == 'xs' && box[1].size == 'xs'){
29380 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
29384 x : x + (this.unitWidth + this.gutter) * 1,
29398 x : x + (this.unitWidth + this.gutter) * 2,
29403 x : x + (this.unitWidth + this.gutter) * 2,
29404 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
29411 getVerticalFourBoxColPositions : function(x, y, box)
29415 if(box[0].size == 'xs'){
29424 y : y + (this.unitHeight + this.gutter) * 1
29429 y : y + (this.unitHeight + this.gutter) * 2
29433 x : x + (this.unitWidth + this.gutter) * 1,
29447 x : x + (this.unitWidth + this.gutter) * 2,
29452 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
29453 y : y + (this.unitHeight + this.gutter) * 1
29457 x : x + (this.unitWidth + this.gutter) * 2,
29458 y : y + (this.unitWidth + this.gutter) * 2
29465 getHorizontalOneBoxColPositions : function(maxX, minY, box)
29469 if(box[0].size == 'md-left'){
29471 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29478 if(box[0].size == 'md-right'){
29480 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29481 y : minY + (this.unitWidth + this.gutter) * 1
29487 var rand = Math.floor(Math.random() * (4 - box[0].y));
29490 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29491 y : minY + (this.unitWidth + this.gutter) * rand
29498 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
29502 if(box[0].size == 'xs'){
29505 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29510 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29511 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
29519 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29524 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29525 y : minY + (this.unitWidth + this.gutter) * 2
29532 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
29536 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29539 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29544 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29545 y : minY + (this.unitWidth + this.gutter) * 1
29549 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29550 y : minY + (this.unitWidth + this.gutter) * 2
29557 if(box[0].size == 'xs' && box[1].size == 'xs'){
29560 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29565 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29570 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29571 y : minY + (this.unitWidth + this.gutter) * 1
29579 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29584 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29585 y : minY + (this.unitWidth + this.gutter) * 2
29589 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29590 y : minY + (this.unitWidth + this.gutter) * 2
29597 getHorizontalFourBoxColPositions : function(maxX, minY, box)
29601 if(box[0].size == 'xs'){
29604 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29609 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29614 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),
29619 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
29620 y : minY + (this.unitWidth + this.gutter) * 1
29628 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29633 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29634 y : minY + (this.unitWidth + this.gutter) * 2
29638 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29639 y : minY + (this.unitWidth + this.gutter) * 2
29643 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),
29644 y : minY + (this.unitWidth + this.gutter) * 2
29658 * http://masonry.desandro.com
29660 * The idea is to render all the bricks based on vertical width...
29662 * The original code extends 'outlayer' - we might need to use that....
29668 * @class Roo.bootstrap.LayoutMasonryAuto
29669 * @extends Roo.bootstrap.Component
29670 * Bootstrap Layout Masonry class
29673 * Create a new Element
29674 * @param {Object} config The config object
29677 Roo.bootstrap.LayoutMasonryAuto = function(config){
29678 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
29681 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
29684 * @cfg {Boolean} isFitWidth - resize the width..
29686 isFitWidth : false, // options..
29688 * @cfg {Boolean} isOriginLeft = left align?
29690 isOriginLeft : true,
29692 * @cfg {Boolean} isOriginTop = top align?
29694 isOriginTop : false,
29696 * @cfg {Boolean} isLayoutInstant = no animation?
29698 isLayoutInstant : false, // needed?
29700 * @cfg {Boolean} isResizingContainer = not sure if this is used..
29702 isResizingContainer : true,
29704 * @cfg {Number} columnWidth width of the columns
29710 * @cfg {Number} maxCols maximum number of columns
29715 * @cfg {Number} padHeight padding below box..
29721 * @cfg {Boolean} isAutoInitial defalut true
29724 isAutoInitial : true,
29730 initialColumnWidth : 0,
29731 currentSize : null,
29733 colYs : null, // array.
29740 bricks: null, //CompositeElement
29741 cols : 0, // array?
29742 // element : null, // wrapped now this.el
29743 _isLayoutInited : null,
29746 getAutoCreate : function(){
29750 cls: 'blog-masonary-wrapper ' + this.cls,
29752 cls : 'mas-boxes masonary'
29759 getChildContainer: function( )
29761 if (this.boxesEl) {
29762 return this.boxesEl;
29765 this.boxesEl = this.el.select('.mas-boxes').first();
29767 return this.boxesEl;
29771 initEvents : function()
29775 if(this.isAutoInitial){
29776 Roo.log('hook children rendered');
29777 this.on('childrenrendered', function() {
29778 Roo.log('children rendered');
29785 initial : function()
29787 this.reloadItems();
29789 this.currentSize = this.el.getBox(true);
29791 /// was window resize... - let's see if this works..
29792 Roo.EventManager.onWindowResize(this.resize, this);
29794 if(!this.isAutoInitial){
29799 this.layout.defer(500,this);
29802 reloadItems: function()
29804 this.bricks = this.el.select('.masonry-brick', true);
29806 this.bricks.each(function(b) {
29807 //Roo.log(b.getSize());
29808 if (!b.attr('originalwidth')) {
29809 b.attr('originalwidth', b.getSize().width);
29814 Roo.log(this.bricks.elements.length);
29817 resize : function()
29820 var cs = this.el.getBox(true);
29822 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29823 Roo.log("no change in with or X");
29826 this.currentSize = cs;
29830 layout : function()
29833 this._resetLayout();
29834 //this._manageStamps();
29836 // don't animate first layout
29837 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29838 this.layoutItems( isInstant );
29840 // flag for initalized
29841 this._isLayoutInited = true;
29844 layoutItems : function( isInstant )
29846 //var items = this._getItemsForLayout( this.items );
29847 // original code supports filtering layout items.. we just ignore it..
29849 this._layoutItems( this.bricks , isInstant );
29851 this._postLayout();
29853 _layoutItems : function ( items , isInstant)
29855 //this.fireEvent( 'layout', this, items );
29858 if ( !items || !items.elements.length ) {
29859 // no items, emit event with empty array
29864 items.each(function(item) {
29865 Roo.log("layout item");
29867 // get x/y object from method
29868 var position = this._getItemLayoutPosition( item );
29870 position.item = item;
29871 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
29872 queue.push( position );
29875 this._processLayoutQueue( queue );
29877 /** Sets position of item in DOM
29878 * @param {Element} item
29879 * @param {Number} x - horizontal position
29880 * @param {Number} y - vertical position
29881 * @param {Boolean} isInstant - disables transitions
29883 _processLayoutQueue : function( queue )
29885 for ( var i=0, len = queue.length; i < len; i++ ) {
29886 var obj = queue[i];
29887 obj.item.position('absolute');
29888 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
29894 * Any logic you want to do after each layout,
29895 * i.e. size the container
29897 _postLayout : function()
29899 this.resizeContainer();
29902 resizeContainer : function()
29904 if ( !this.isResizingContainer ) {
29907 var size = this._getContainerSize();
29909 this.el.setSize(size.width,size.height);
29910 this.boxesEl.setSize(size.width,size.height);
29916 _resetLayout : function()
29918 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
29919 this.colWidth = this.el.getWidth();
29920 //this.gutter = this.el.getWidth();
29922 this.measureColumns();
29928 this.colYs.push( 0 );
29934 measureColumns : function()
29936 this.getContainerWidth();
29937 // if columnWidth is 0, default to outerWidth of first item
29938 if ( !this.columnWidth ) {
29939 var firstItem = this.bricks.first();
29940 Roo.log(firstItem);
29941 this.columnWidth = this.containerWidth;
29942 if (firstItem && firstItem.attr('originalwidth') ) {
29943 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
29945 // columnWidth fall back to item of first element
29946 Roo.log("set column width?");
29947 this.initialColumnWidth = this.columnWidth ;
29949 // if first elem has no width, default to size of container
29954 if (this.initialColumnWidth) {
29955 this.columnWidth = this.initialColumnWidth;
29960 // column width is fixed at the top - however if container width get's smaller we should
29963 // this bit calcs how man columns..
29965 var columnWidth = this.columnWidth += this.gutter;
29967 // calculate columns
29968 var containerWidth = this.containerWidth + this.gutter;
29970 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
29971 // fix rounding errors, typically with gutters
29972 var excess = columnWidth - containerWidth % columnWidth;
29975 // if overshoot is less than a pixel, round up, otherwise floor it
29976 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
29977 cols = Math[ mathMethod ]( cols );
29978 this.cols = Math.max( cols, 1 );
29979 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29981 // padding positioning..
29982 var totalColWidth = this.cols * this.columnWidth;
29983 var padavail = this.containerWidth - totalColWidth;
29984 // so for 2 columns - we need 3 'pads'
29986 var padNeeded = (1+this.cols) * this.padWidth;
29988 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
29990 this.columnWidth += padExtra
29991 //this.padWidth = Math.floor(padavail / ( this.cols));
29993 // adjust colum width so that padding is fixed??
29995 // we have 3 columns ... total = width * 3
29996 // we have X left over... that should be used by
29998 //if (this.expandC) {
30006 getContainerWidth : function()
30008 /* // container is parent if fit width
30009 var container = this.isFitWidth ? this.element.parentNode : this.element;
30010 // check that this.size and size are there
30011 // IE8 triggers resize on body size change, so they might not be
30013 var size = getSize( container ); //FIXME
30014 this.containerWidth = size && size.innerWidth; //FIXME
30017 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30021 _getItemLayoutPosition : function( item ) // what is item?
30023 // we resize the item to our columnWidth..
30025 item.setWidth(this.columnWidth);
30026 item.autoBoxAdjust = false;
30028 var sz = item.getSize();
30030 // how many columns does this brick span
30031 var remainder = this.containerWidth % this.columnWidth;
30033 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30034 // round if off by 1 pixel, otherwise use ceil
30035 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30036 colSpan = Math.min( colSpan, this.cols );
30038 // normally this should be '1' as we dont' currently allow multi width columns..
30040 var colGroup = this._getColGroup( colSpan );
30041 // get the minimum Y value from the columns
30042 var minimumY = Math.min.apply( Math, colGroup );
30043 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30045 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30047 // position the brick
30049 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30050 y: this.currentSize.y + minimumY + this.padHeight
30054 // apply setHeight to necessary columns
30055 var setHeight = minimumY + sz.height + this.padHeight;
30056 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30058 var setSpan = this.cols + 1 - colGroup.length;
30059 for ( var i = 0; i < setSpan; i++ ) {
30060 this.colYs[ shortColIndex + i ] = setHeight ;
30067 * @param {Number} colSpan - number of columns the element spans
30068 * @returns {Array} colGroup
30070 _getColGroup : function( colSpan )
30072 if ( colSpan < 2 ) {
30073 // if brick spans only one column, use all the column Ys
30078 // how many different places could this brick fit horizontally
30079 var groupCount = this.cols + 1 - colSpan;
30080 // for each group potential horizontal position
30081 for ( var i = 0; i < groupCount; i++ ) {
30082 // make an array of colY values for that one group
30083 var groupColYs = this.colYs.slice( i, i + colSpan );
30084 // and get the max value of the array
30085 colGroup[i] = Math.max.apply( Math, groupColYs );
30090 _manageStamp : function( stamp )
30092 var stampSize = stamp.getSize();
30093 var offset = stamp.getBox();
30094 // get the columns that this stamp affects
30095 var firstX = this.isOriginLeft ? offset.x : offset.right;
30096 var lastX = firstX + stampSize.width;
30097 var firstCol = Math.floor( firstX / this.columnWidth );
30098 firstCol = Math.max( 0, firstCol );
30100 var lastCol = Math.floor( lastX / this.columnWidth );
30101 // lastCol should not go over if multiple of columnWidth #425
30102 lastCol -= lastX % this.columnWidth ? 0 : 1;
30103 lastCol = Math.min( this.cols - 1, lastCol );
30105 // set colYs to bottom of the stamp
30106 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30109 for ( var i = firstCol; i <= lastCol; i++ ) {
30110 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30115 _getContainerSize : function()
30117 this.maxY = Math.max.apply( Math, this.colYs );
30122 if ( this.isFitWidth ) {
30123 size.width = this._getContainerFitWidth();
30129 _getContainerFitWidth : function()
30131 var unusedCols = 0;
30132 // count unused columns
30135 if ( this.colYs[i] !== 0 ) {
30140 // fit container to columns that have been used
30141 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30144 needsResizeLayout : function()
30146 var previousWidth = this.containerWidth;
30147 this.getContainerWidth();
30148 return previousWidth !== this.containerWidth;
30163 * @class Roo.bootstrap.MasonryBrick
30164 * @extends Roo.bootstrap.Component
30165 * Bootstrap MasonryBrick class
30168 * Create a new MasonryBrick
30169 * @param {Object} config The config object
30172 Roo.bootstrap.MasonryBrick = function(config){
30173 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30179 * When a MasonryBrick is clcik
30180 * @param {Roo.bootstrap.MasonryBrick} this
30181 * @param {Roo.EventObject} e
30187 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30190 * @cfg {String} title
30194 * @cfg {String} html
30198 * @cfg {String} bgimage
30202 * @cfg {String} videourl
30206 * @cfg {String} cls
30210 * @cfg {String} href
30214 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30219 * @cfg {String} (center|bottom) placetitle
30223 getAutoCreate : function()
30225 var cls = 'masonry-brick';
30227 if(this.href.length){
30228 cls += ' masonry-brick-link';
30231 if(this.bgimage.length){
30232 cls += ' masonry-brick-image';
30236 cls += ' masonry-' + this.size + '-brick';
30239 if(this.placetitle.length){
30241 switch (this.placetitle) {
30243 cls += ' masonry-center-title';
30246 cls += ' masonry-bottom-title';
30253 if(!this.html.length && !this.bgimage.length){
30254 cls += ' masonry-center-title';
30257 if(!this.html.length && this.bgimage.length){
30258 cls += ' masonry-bottom-title';
30263 cls += ' ' + this.cls;
30267 tag: (this.href.length) ? 'a' : 'div',
30272 cls: 'masonry-brick-paragraph',
30278 if(this.href.length){
30279 cfg.href = this.href;
30282 var cn = cfg.cn[0].cn;
30284 if(this.title.length){
30287 cls: 'masonry-brick-title',
30292 if(this.html.length){
30295 cls: 'masonry-brick-text',
30299 if (!this.title.length && !this.html.length) {
30300 cfg.cn[0].cls += ' hide';
30303 if(this.bgimage.length){
30306 cls: 'masonry-brick-image-view',
30310 if(this.videourl.length){
30311 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
30312 // youtube support only?
30315 cls: 'masonry-brick-image-view',
30318 allowfullscreen : true
30327 initEvents: function()
30329 switch (this.size) {
30331 // this.intSize = 1;
30336 // this.intSize = 2;
30343 // this.intSize = 3;
30348 // this.intSize = 3;
30353 // this.intSize = 3;
30358 // this.intSize = 3;
30370 this.el.on('touchstart', this.onTouchStart, this);
30371 this.el.on('touchmove', this.onTouchMove, this);
30372 this.el.on('touchend', this.onTouchEnd, this);
30373 this.el.on('contextmenu', this.onContextMenu, this);
30375 this.el.on('mouseenter' ,this.enter, this);
30376 this.el.on('mouseleave', this.leave, this);
30379 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
30380 this.parent().bricks.push(this);
30385 onClick: function(e, el)
30393 var time = this.endTimer - this.startTimer;
30401 e.preventDefault();
30404 enter: function(e, el)
30406 e.preventDefault();
30408 if(this.bgimage.length && this.html.length){
30409 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30413 leave: function(e, el)
30415 e.preventDefault();
30417 if(this.bgimage.length && this.html.length){
30418 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30422 onTouchStart: function(e, el)
30424 // e.preventDefault();
30426 if(!this.bgimage.length || !this.html.length){
30430 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30432 this.timer = new Date().getTime();
30434 this.touchmoved = false;
30437 onTouchMove: function(e, el)
30439 this.touchmoved = true;
30441 onContextMenu : function(e,el)
30443 e.preventDefault();
30444 e.stopPropagation();
30449 onTouchEnd: function(e, el)
30451 // e.preventDefault();
30453 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
30460 if(!this.bgimage.length || !this.html.length){
30462 if(this.href.length){
30463 window.location.href = this.href;
30469 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30471 window.location.href = this.href;
30486 * @class Roo.bootstrap.Brick
30487 * @extends Roo.bootstrap.Component
30488 * Bootstrap Brick class
30491 * Create a new Brick
30492 * @param {Object} config The config object
30495 Roo.bootstrap.Brick = function(config){
30496 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
30502 * When a Brick is click
30503 * @param {Roo.bootstrap.Brick} this
30504 * @param {Roo.EventObject} e
30510 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
30513 * @cfg {String} title
30517 * @cfg {String} html
30521 * @cfg {String} bgimage
30525 * @cfg {String} cls
30529 * @cfg {String} href
30533 * @cfg {String} video
30537 * @cfg {Boolean} square
30541 getAutoCreate : function()
30543 var cls = 'roo-brick';
30545 if(this.href.length){
30546 cls += ' roo-brick-link';
30549 if(this.bgimage.length){
30550 cls += ' roo-brick-image';
30553 if(!this.html.length && !this.bgimage.length){
30554 cls += ' roo-brick-center-title';
30557 if(!this.html.length && this.bgimage.length){
30558 cls += ' roo-brick-bottom-title';
30562 cls += ' ' + this.cls;
30566 tag: (this.href.length) ? 'a' : 'div',
30571 cls: 'roo-brick-paragraph',
30577 if(this.href.length){
30578 cfg.href = this.href;
30581 var cn = cfg.cn[0].cn;
30583 if(this.title.length){
30586 cls: 'roo-brick-title',
30591 if(this.html.length){
30594 cls: 'roo-brick-text',
30601 if(this.bgimage.length){
30604 cls: 'roo-brick-image-view',
30612 initEvents: function()
30614 if(this.title.length || this.html.length){
30615 this.el.on('mouseenter' ,this.enter, this);
30616 this.el.on('mouseleave', this.leave, this);
30620 Roo.EventManager.onWindowResize(this.resize, this);
30625 resize : function()
30627 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
30629 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
30630 // paragraph.setHeight(paragraph.getWidth());
30632 if(this.bgimage.length){
30633 var image = this.el.select('.roo-brick-image-view', true).first();
30634 image.setWidth(paragraph.getWidth());
30635 image.setHeight(paragraph.getWidth());
30640 enter: function(e, el)
30642 e.preventDefault();
30644 if(this.bgimage.length){
30645 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
30646 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
30650 leave: function(e, el)
30652 e.preventDefault();
30654 if(this.bgimage.length){
30655 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
30656 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
30666 * Ext JS Library 1.1.1
30667 * Copyright(c) 2006-2007, Ext JS, LLC.
30669 * Originally Released Under LGPL - original licence link has changed is not relivant.
30672 * <script type="text/javascript">
30677 * @class Roo.bootstrap.SplitBar
30678 * @extends Roo.util.Observable
30679 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
30683 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
30684 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
30685 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
30686 split.minSize = 100;
30687 split.maxSize = 600;
30688 split.animate = true;
30689 split.on('moved', splitterMoved);
30692 * Create a new SplitBar
30693 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
30694 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
30695 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30696 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
30697 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
30698 position of the SplitBar).
30700 Roo.bootstrap.SplitBar = function(cfg){
30705 // dragElement : elm
30706 // resizingElement: el,
30708 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
30709 // placement : Roo.bootstrap.SplitBar.LEFT ,
30710 // existingProxy ???
30713 this.el = Roo.get(cfg.dragElement, true);
30714 this.el.dom.unselectable = "on";
30716 this.resizingEl = Roo.get(cfg.resizingElement, true);
30720 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30721 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
30724 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
30727 * The minimum size of the resizing element. (Defaults to 0)
30733 * The maximum size of the resizing element. (Defaults to 2000)
30736 this.maxSize = 2000;
30739 * Whether to animate the transition to the new size
30742 this.animate = false;
30745 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
30748 this.useShim = false;
30753 if(!cfg.existingProxy){
30755 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
30757 this.proxy = Roo.get(cfg.existingProxy).dom;
30760 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
30763 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
30766 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
30769 this.dragSpecs = {};
30772 * @private The adapter to use to positon and resize elements
30774 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30775 this.adapter.init(this);
30777 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30779 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
30780 this.el.addClass("roo-splitbar-h");
30783 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
30784 this.el.addClass("roo-splitbar-v");
30790 * Fires when the splitter is moved (alias for {@link #event-moved})
30791 * @param {Roo.bootstrap.SplitBar} this
30792 * @param {Number} newSize the new width or height
30797 * Fires when the splitter is moved
30798 * @param {Roo.bootstrap.SplitBar} this
30799 * @param {Number} newSize the new width or height
30803 * @event beforeresize
30804 * Fires before the splitter is dragged
30805 * @param {Roo.bootstrap.SplitBar} this
30807 "beforeresize" : true,
30809 "beforeapply" : true
30812 Roo.util.Observable.call(this);
30815 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
30816 onStartProxyDrag : function(x, y){
30817 this.fireEvent("beforeresize", this);
30819 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
30821 o.enableDisplayMode("block");
30822 // all splitbars share the same overlay
30823 Roo.bootstrap.SplitBar.prototype.overlay = o;
30825 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30826 this.overlay.show();
30827 Roo.get(this.proxy).setDisplayed("block");
30828 var size = this.adapter.getElementSize(this);
30829 this.activeMinSize = this.getMinimumSize();;
30830 this.activeMaxSize = this.getMaximumSize();;
30831 var c1 = size - this.activeMinSize;
30832 var c2 = Math.max(this.activeMaxSize - size, 0);
30833 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30834 this.dd.resetConstraints();
30835 this.dd.setXConstraint(
30836 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
30837 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
30839 this.dd.setYConstraint(0, 0);
30841 this.dd.resetConstraints();
30842 this.dd.setXConstraint(0, 0);
30843 this.dd.setYConstraint(
30844 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
30845 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
30848 this.dragSpecs.startSize = size;
30849 this.dragSpecs.startPoint = [x, y];
30850 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
30854 * @private Called after the drag operation by the DDProxy
30856 onEndProxyDrag : function(e){
30857 Roo.get(this.proxy).setDisplayed(false);
30858 var endPoint = Roo.lib.Event.getXY(e);
30860 this.overlay.hide();
30863 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30864 newSize = this.dragSpecs.startSize +
30865 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
30866 endPoint[0] - this.dragSpecs.startPoint[0] :
30867 this.dragSpecs.startPoint[0] - endPoint[0]
30870 newSize = this.dragSpecs.startSize +
30871 (this.placement == Roo.bootstrap.SplitBar.TOP ?
30872 endPoint[1] - this.dragSpecs.startPoint[1] :
30873 this.dragSpecs.startPoint[1] - endPoint[1]
30876 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
30877 if(newSize != this.dragSpecs.startSize){
30878 if(this.fireEvent('beforeapply', this, newSize) !== false){
30879 this.adapter.setElementSize(this, newSize);
30880 this.fireEvent("moved", this, newSize);
30881 this.fireEvent("resize", this, newSize);
30887 * Get the adapter this SplitBar uses
30888 * @return The adapter object
30890 getAdapter : function(){
30891 return this.adapter;
30895 * Set the adapter this SplitBar uses
30896 * @param {Object} adapter A SplitBar adapter object
30898 setAdapter : function(adapter){
30899 this.adapter = adapter;
30900 this.adapter.init(this);
30904 * Gets the minimum size for the resizing element
30905 * @return {Number} The minimum size
30907 getMinimumSize : function(){
30908 return this.minSize;
30912 * Sets the minimum size for the resizing element
30913 * @param {Number} minSize The minimum size
30915 setMinimumSize : function(minSize){
30916 this.minSize = minSize;
30920 * Gets the maximum size for the resizing element
30921 * @return {Number} The maximum size
30923 getMaximumSize : function(){
30924 return this.maxSize;
30928 * Sets the maximum size for the resizing element
30929 * @param {Number} maxSize The maximum size
30931 setMaximumSize : function(maxSize){
30932 this.maxSize = maxSize;
30936 * Sets the initialize size for the resizing element
30937 * @param {Number} size The initial size
30939 setCurrentSize : function(size){
30940 var oldAnimate = this.animate;
30941 this.animate = false;
30942 this.adapter.setElementSize(this, size);
30943 this.animate = oldAnimate;
30947 * Destroy this splitbar.
30948 * @param {Boolean} removeEl True to remove the element
30950 destroy : function(removeEl){
30952 this.shim.remove();
30955 this.proxy.parentNode.removeChild(this.proxy);
30963 * @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.
30965 Roo.bootstrap.SplitBar.createProxy = function(dir){
30966 var proxy = new Roo.Element(document.createElement("div"));
30967 proxy.unselectable();
30968 var cls = 'roo-splitbar-proxy';
30969 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
30970 document.body.appendChild(proxy.dom);
30975 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
30976 * Default Adapter. It assumes the splitter and resizing element are not positioned
30977 * elements and only gets/sets the width of the element. Generally used for table based layouts.
30979 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
30982 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
30983 // do nothing for now
30984 init : function(s){
30988 * Called before drag operations to get the current size of the resizing element.
30989 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30991 getElementSize : function(s){
30992 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30993 return s.resizingEl.getWidth();
30995 return s.resizingEl.getHeight();
31000 * Called after drag operations to set the size of the resizing element.
31001 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31002 * @param {Number} newSize The new size to set
31003 * @param {Function} onComplete A function to be invoked when resizing is complete
31005 setElementSize : function(s, newSize, onComplete){
31006 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31008 s.resizingEl.setWidth(newSize);
31010 onComplete(s, newSize);
31013 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
31018 s.resizingEl.setHeight(newSize);
31020 onComplete(s, newSize);
31023 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
31030 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
31031 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
31032 * Adapter that moves the splitter element to align with the resized sizing element.
31033 * Used with an absolute positioned SplitBar.
31034 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
31035 * document.body, make sure you assign an id to the body element.
31037 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
31038 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31039 this.container = Roo.get(container);
31042 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
31043 init : function(s){
31044 this.basic.init(s);
31047 getElementSize : function(s){
31048 return this.basic.getElementSize(s);
31051 setElementSize : function(s, newSize, onComplete){
31052 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
31055 moveSplitter : function(s){
31056 var yes = Roo.bootstrap.SplitBar;
31057 switch(s.placement){
31059 s.el.setX(s.resizingEl.getRight());
31062 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
31065 s.el.setY(s.resizingEl.getBottom());
31068 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
31075 * Orientation constant - Create a vertical SplitBar
31079 Roo.bootstrap.SplitBar.VERTICAL = 1;
31082 * Orientation constant - Create a horizontal SplitBar
31086 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
31089 * Placement constant - The resizing element is to the left of the splitter element
31093 Roo.bootstrap.SplitBar.LEFT = 1;
31096 * Placement constant - The resizing element is to the right of the splitter element
31100 Roo.bootstrap.SplitBar.RIGHT = 2;
31103 * Placement constant - The resizing element is positioned above the splitter element
31107 Roo.bootstrap.SplitBar.TOP = 3;
31110 * Placement constant - The resizing element is positioned under splitter element
31114 Roo.bootstrap.SplitBar.BOTTOM = 4;
31115 Roo.namespace("Roo.bootstrap.layout");/*
31117 * Ext JS Library 1.1.1
31118 * Copyright(c) 2006-2007, Ext JS, LLC.
31120 * Originally Released Under LGPL - original licence link has changed is not relivant.
31123 * <script type="text/javascript">
31127 * @class Roo.bootstrap.layout.Manager
31128 * @extends Roo.bootstrap.Component
31129 * Base class for layout managers.
31131 Roo.bootstrap.layout.Manager = function(config)
31133 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
31139 /** false to disable window resize monitoring @type Boolean */
31140 this.monitorWindowResize = true;
31145 * Fires when a layout is performed.
31146 * @param {Roo.LayoutManager} this
31150 * @event regionresized
31151 * Fires when the user resizes a region.
31152 * @param {Roo.LayoutRegion} region The resized region
31153 * @param {Number} newSize The new size (width for east/west, height for north/south)
31155 "regionresized" : true,
31157 * @event regioncollapsed
31158 * Fires when a region is collapsed.
31159 * @param {Roo.LayoutRegion} region The collapsed region
31161 "regioncollapsed" : true,
31163 * @event regionexpanded
31164 * Fires when a region is expanded.
31165 * @param {Roo.LayoutRegion} region The expanded region
31167 "regionexpanded" : true
31169 this.updating = false;
31172 this.el = Roo.get(config.el);
31178 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31183 monitorWindowResize : true,
31189 onRender : function(ct, position)
31192 this.el = Roo.get(ct);
31198 initEvents: function()
31202 // ie scrollbar fix
31203 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31204 document.body.scroll = "no";
31205 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31206 this.el.position('relative');
31208 this.id = this.el.id;
31209 this.el.addClass("roo-layout-container");
31210 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31211 if(this.el.dom != document.body ) {
31212 this.el.on('resize', this.layout,this);
31213 this.el.on('show', this.layout,this);
31219 * Returns true if this layout is currently being updated
31220 * @return {Boolean}
31222 isUpdating : function(){
31223 return this.updating;
31227 * Suspend the LayoutManager from doing auto-layouts while
31228 * making multiple add or remove calls
31230 beginUpdate : function(){
31231 this.updating = true;
31235 * Restore auto-layouts and optionally disable the manager from performing a layout
31236 * @param {Boolean} noLayout true to disable a layout update
31238 endUpdate : function(noLayout){
31239 this.updating = false;
31245 layout: function(){
31249 onRegionResized : function(region, newSize){
31250 this.fireEvent("regionresized", region, newSize);
31254 onRegionCollapsed : function(region){
31255 this.fireEvent("regioncollapsed", region);
31258 onRegionExpanded : function(region){
31259 this.fireEvent("regionexpanded", region);
31263 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31264 * performs box-model adjustments.
31265 * @return {Object} The size as an object {width: (the width), height: (the height)}
31267 getViewSize : function()
31270 if(this.el.dom != document.body){
31271 size = this.el.getSize();
31273 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31275 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31276 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31281 * Returns the Element this layout is bound to.
31282 * @return {Roo.Element}
31284 getEl : function(){
31289 * Returns the specified region.
31290 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31291 * @return {Roo.LayoutRegion}
31293 getRegion : function(target){
31294 return this.regions[target.toLowerCase()];
31297 onWindowResize : function(){
31298 if(this.monitorWindowResize){
31304 * Ext JS Library 1.1.1
31305 * Copyright(c) 2006-2007, Ext JS, LLC.
31307 * Originally Released Under LGPL - original licence link has changed is not relivant.
31310 * <script type="text/javascript">
31313 * @class Roo.bootstrap.layout.Border
31314 * @extends Roo.bootstrap.layout.Manager
31315 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
31316 * please see: examples/bootstrap/nested.html<br><br>
31318 <b>The container the layout is rendered into can be either the body element or any other element.
31319 If it is not the body element, the container needs to either be an absolute positioned element,
31320 or you will need to add "position:relative" to the css of the container. You will also need to specify
31321 the container size if it is not the body element.</b>
31324 * Create a new Border
31325 * @param {Object} config Configuration options
31327 Roo.bootstrap.layout.Border = function(config){
31328 config = config || {};
31329 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
31333 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
31334 if(config[region]){
31335 config[region].region = region;
31336 this.addRegion(config[region]);
31342 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
31344 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
31346 * Creates and adds a new region if it doesn't already exist.
31347 * @param {String} target The target region key (north, south, east, west or center).
31348 * @param {Object} config The regions config object
31349 * @return {BorderLayoutRegion} The new region
31351 addRegion : function(config)
31353 if(!this.regions[config.region]){
31354 var r = this.factory(config);
31355 this.bindRegion(r);
31357 return this.regions[config.region];
31361 bindRegion : function(r){
31362 this.regions[r.config.region] = r;
31364 r.on("visibilitychange", this.layout, this);
31365 r.on("paneladded", this.layout, this);
31366 r.on("panelremoved", this.layout, this);
31367 r.on("invalidated", this.layout, this);
31368 r.on("resized", this.onRegionResized, this);
31369 r.on("collapsed", this.onRegionCollapsed, this);
31370 r.on("expanded", this.onRegionExpanded, this);
31374 * Performs a layout update.
31376 layout : function()
31378 if(this.updating) {
31381 var size = this.getViewSize();
31382 var w = size.width;
31383 var h = size.height;
31388 //var x = 0, y = 0;
31390 var rs = this.regions;
31391 var north = rs["north"];
31392 var south = rs["south"];
31393 var west = rs["west"];
31394 var east = rs["east"];
31395 var center = rs["center"];
31396 //if(this.hideOnLayout){ // not supported anymore
31397 //c.el.setStyle("display", "none");
31399 if(north && north.isVisible()){
31400 var b = north.getBox();
31401 var m = north.getMargins();
31402 b.width = w - (m.left+m.right);
31405 centerY = b.height + b.y + m.bottom;
31406 centerH -= centerY;
31407 north.updateBox(this.safeBox(b));
31409 if(south && south.isVisible()){
31410 var b = south.getBox();
31411 var m = south.getMargins();
31412 b.width = w - (m.left+m.right);
31414 var totalHeight = (b.height + m.top + m.bottom);
31415 b.y = h - totalHeight + m.top;
31416 centerH -= totalHeight;
31417 south.updateBox(this.safeBox(b));
31419 if(west && west.isVisible()){
31420 var b = west.getBox();
31421 var m = west.getMargins();
31422 b.height = centerH - (m.top+m.bottom);
31424 b.y = centerY + m.top;
31425 var totalWidth = (b.width + m.left + m.right);
31426 centerX += totalWidth;
31427 centerW -= totalWidth;
31428 west.updateBox(this.safeBox(b));
31430 if(east && east.isVisible()){
31431 var b = east.getBox();
31432 var m = east.getMargins();
31433 b.height = centerH - (m.top+m.bottom);
31434 var totalWidth = (b.width + m.left + m.right);
31435 b.x = w - totalWidth + m.left;
31436 b.y = centerY + m.top;
31437 centerW -= totalWidth;
31438 east.updateBox(this.safeBox(b));
31441 var m = center.getMargins();
31443 x: centerX + m.left,
31444 y: centerY + m.top,
31445 width: centerW - (m.left+m.right),
31446 height: centerH - (m.top+m.bottom)
31448 //if(this.hideOnLayout){
31449 //center.el.setStyle("display", "block");
31451 center.updateBox(this.safeBox(centerBox));
31454 this.fireEvent("layout", this);
31458 safeBox : function(box){
31459 box.width = Math.max(0, box.width);
31460 box.height = Math.max(0, box.height);
31465 * Adds a ContentPanel (or subclass) to this layout.
31466 * @param {String} target The target region key (north, south, east, west or center).
31467 * @param {Roo.ContentPanel} panel The panel to add
31468 * @return {Roo.ContentPanel} The added panel
31470 add : function(target, panel){
31472 target = target.toLowerCase();
31473 return this.regions[target].add(panel);
31477 * Remove a ContentPanel (or subclass) to this layout.
31478 * @param {String} target The target region key (north, south, east, west or center).
31479 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
31480 * @return {Roo.ContentPanel} The removed panel
31482 remove : function(target, panel){
31483 target = target.toLowerCase();
31484 return this.regions[target].remove(panel);
31488 * Searches all regions for a panel with the specified id
31489 * @param {String} panelId
31490 * @return {Roo.ContentPanel} The panel or null if it wasn't found
31492 findPanel : function(panelId){
31493 var rs = this.regions;
31494 for(var target in rs){
31495 if(typeof rs[target] != "function"){
31496 var p = rs[target].getPanel(panelId);
31506 * Searches all regions for a panel with the specified id and activates (shows) it.
31507 * @param {String/ContentPanel} panelId The panels id or the panel itself
31508 * @return {Roo.ContentPanel} The shown panel or null
31510 showPanel : function(panelId) {
31511 var rs = this.regions;
31512 for(var target in rs){
31513 var r = rs[target];
31514 if(typeof r != "function"){
31515 if(r.hasPanel(panelId)){
31516 return r.showPanel(panelId);
31524 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
31525 * @param {Roo.state.Provider} provider (optional) An alternate state provider
31528 restoreState : function(provider){
31530 provider = Roo.state.Manager;
31532 var sm = new Roo.LayoutStateManager();
31533 sm.init(this, provider);
31539 * Adds a xtype elements to the layout.
31543 xtype : 'ContentPanel',
31550 xtype : 'NestedLayoutPanel',
31556 items : [ ... list of content panels or nested layout panels.. ]
31560 * @param {Object} cfg Xtype definition of item to add.
31562 addxtype : function(cfg)
31564 // basically accepts a pannel...
31565 // can accept a layout region..!?!?
31566 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
31569 // theory? children can only be panels??
31571 //if (!cfg.xtype.match(/Panel$/)) {
31576 if (typeof(cfg.region) == 'undefined') {
31577 Roo.log("Failed to add Panel, region was not set");
31581 var region = cfg.region;
31587 xitems = cfg.items;
31594 case 'Content': // ContentPanel (el, cfg)
31595 case 'Scroll': // ContentPanel (el, cfg)
31597 cfg.autoCreate = true;
31598 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31600 // var el = this.el.createChild();
31601 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
31604 this.add(region, ret);
31608 case 'TreePanel': // our new panel!
31609 cfg.el = this.el.createChild();
31610 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31611 this.add(region, ret);
31616 // create a new Layout (which is a Border Layout...
31618 var clayout = cfg.layout;
31619 clayout.el = this.el.createChild();
31620 clayout.items = clayout.items || [];
31624 // replace this exitems with the clayout ones..
31625 xitems = clayout.items;
31627 // force background off if it's in center...
31628 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
31629 cfg.background = false;
31631 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
31634 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31635 //console.log('adding nested layout panel ' + cfg.toSource());
31636 this.add(region, ret);
31637 nb = {}; /// find first...
31642 // needs grid and region
31644 //var el = this.getRegion(region).el.createChild();
31646 *var el = this.el.createChild();
31647 // create the grid first...
31648 cfg.grid.container = el;
31649 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
31652 if (region == 'center' && this.active ) {
31653 cfg.background = false;
31656 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31658 this.add(region, ret);
31660 if (cfg.background) {
31661 // render grid on panel activation (if panel background)
31662 ret.on('activate', function(gp) {
31663 if (!gp.grid.rendered) {
31664 // gp.grid.render(el);
31668 // cfg.grid.render(el);
31674 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
31675 // it was the old xcomponent building that caused this before.
31676 // espeically if border is the top element in the tree.
31686 if (typeof(Roo[cfg.xtype]) != 'undefined') {
31688 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31689 this.add(region, ret);
31693 throw "Can not add '" + cfg.xtype + "' to Border";
31699 this.beginUpdate();
31703 Roo.each(xitems, function(i) {
31704 region = nb && i.region ? i.region : false;
31706 var add = ret.addxtype(i);
31709 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
31710 if (!i.background) {
31711 abn[region] = nb[region] ;
31718 // make the last non-background panel active..
31719 //if (nb) { Roo.log(abn); }
31722 for(var r in abn) {
31723 region = this.getRegion(r);
31725 // tried using nb[r], but it does not work..
31727 region.showPanel(abn[r]);
31738 factory : function(cfg)
31741 var validRegions = Roo.bootstrap.layout.Border.regions;
31743 var target = cfg.region;
31746 var r = Roo.bootstrap.layout;
31750 return new r.North(cfg);
31752 return new r.South(cfg);
31754 return new r.East(cfg);
31756 return new r.West(cfg);
31758 return new r.Center(cfg);
31760 throw 'Layout region "'+target+'" not supported.';
31767 * Ext JS Library 1.1.1
31768 * Copyright(c) 2006-2007, Ext JS, LLC.
31770 * Originally Released Under LGPL - original licence link has changed is not relivant.
31773 * <script type="text/javascript">
31777 * @class Roo.bootstrap.layout.Basic
31778 * @extends Roo.util.Observable
31779 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
31780 * and does not have a titlebar, tabs or any other features. All it does is size and position
31781 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
31782 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31783 * @cfg {string} region the region that it inhabits..
31784 * @cfg {bool} skipConfig skip config?
31788 Roo.bootstrap.layout.Basic = function(config){
31790 this.mgr = config.mgr;
31792 this.position = config.region;
31794 var skipConfig = config.skipConfig;
31798 * @scope Roo.BasicLayoutRegion
31802 * @event beforeremove
31803 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
31804 * @param {Roo.LayoutRegion} this
31805 * @param {Roo.ContentPanel} panel The panel
31806 * @param {Object} e The cancel event object
31808 "beforeremove" : true,
31810 * @event invalidated
31811 * Fires when the layout for this region is changed.
31812 * @param {Roo.LayoutRegion} this
31814 "invalidated" : true,
31816 * @event visibilitychange
31817 * Fires when this region is shown or hidden
31818 * @param {Roo.LayoutRegion} this
31819 * @param {Boolean} visibility true or false
31821 "visibilitychange" : true,
31823 * @event paneladded
31824 * Fires when a panel is added.
31825 * @param {Roo.LayoutRegion} this
31826 * @param {Roo.ContentPanel} panel The panel
31828 "paneladded" : true,
31830 * @event panelremoved
31831 * Fires when a panel is removed.
31832 * @param {Roo.LayoutRegion} this
31833 * @param {Roo.ContentPanel} panel The panel
31835 "panelremoved" : true,
31837 * @event beforecollapse
31838 * Fires when this region before collapse.
31839 * @param {Roo.LayoutRegion} this
31841 "beforecollapse" : true,
31844 * Fires when this region is collapsed.
31845 * @param {Roo.LayoutRegion} this
31847 "collapsed" : true,
31850 * Fires when this region is expanded.
31851 * @param {Roo.LayoutRegion} this
31856 * Fires when this region is slid into view.
31857 * @param {Roo.LayoutRegion} this
31859 "slideshow" : true,
31862 * Fires when this region slides out of view.
31863 * @param {Roo.LayoutRegion} this
31865 "slidehide" : true,
31867 * @event panelactivated
31868 * Fires when a panel is activated.
31869 * @param {Roo.LayoutRegion} this
31870 * @param {Roo.ContentPanel} panel The activated panel
31872 "panelactivated" : true,
31875 * Fires when the user resizes this region.
31876 * @param {Roo.LayoutRegion} this
31877 * @param {Number} newSize The new size (width for east/west, height for north/south)
31881 /** A collection of panels in this region. @type Roo.util.MixedCollection */
31882 this.panels = new Roo.util.MixedCollection();
31883 this.panels.getKey = this.getPanelId.createDelegate(this);
31885 this.activePanel = null;
31886 // ensure listeners are added...
31888 if (config.listeners || config.events) {
31889 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
31890 listeners : config.listeners || {},
31891 events : config.events || {}
31895 if(skipConfig !== true){
31896 this.applyConfig(config);
31900 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
31902 getPanelId : function(p){
31906 applyConfig : function(config){
31907 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
31908 this.config = config;
31913 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
31914 * the width, for horizontal (north, south) the height.
31915 * @param {Number} newSize The new width or height
31917 resizeTo : function(newSize){
31918 var el = this.el ? this.el :
31919 (this.activePanel ? this.activePanel.getEl() : null);
31921 switch(this.position){
31924 el.setWidth(newSize);
31925 this.fireEvent("resized", this, newSize);
31929 el.setHeight(newSize);
31930 this.fireEvent("resized", this, newSize);
31936 getBox : function(){
31937 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
31940 getMargins : function(){
31941 return this.margins;
31944 updateBox : function(box){
31946 var el = this.activePanel.getEl();
31947 el.dom.style.left = box.x + "px";
31948 el.dom.style.top = box.y + "px";
31949 this.activePanel.setSize(box.width, box.height);
31953 * Returns the container element for this region.
31954 * @return {Roo.Element}
31956 getEl : function(){
31957 return this.activePanel;
31961 * Returns true if this region is currently visible.
31962 * @return {Boolean}
31964 isVisible : function(){
31965 return this.activePanel ? true : false;
31968 setActivePanel : function(panel){
31969 panel = this.getPanel(panel);
31970 if(this.activePanel && this.activePanel != panel){
31971 this.activePanel.setActiveState(false);
31972 this.activePanel.getEl().setLeftTop(-10000,-10000);
31974 this.activePanel = panel;
31975 panel.setActiveState(true);
31977 panel.setSize(this.box.width, this.box.height);
31979 this.fireEvent("panelactivated", this, panel);
31980 this.fireEvent("invalidated");
31984 * Show the specified panel.
31985 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
31986 * @return {Roo.ContentPanel} The shown panel or null
31988 showPanel : function(panel){
31989 panel = this.getPanel(panel);
31991 this.setActivePanel(panel);
31997 * Get the active panel for this region.
31998 * @return {Roo.ContentPanel} The active panel or null
32000 getActivePanel : function(){
32001 return this.activePanel;
32005 * Add the passed ContentPanel(s)
32006 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32007 * @return {Roo.ContentPanel} The panel added (if only one was added)
32009 add : function(panel){
32010 if(arguments.length > 1){
32011 for(var i = 0, len = arguments.length; i < len; i++) {
32012 this.add(arguments[i]);
32016 if(this.hasPanel(panel)){
32017 this.showPanel(panel);
32020 var el = panel.getEl();
32021 if(el.dom.parentNode != this.mgr.el.dom){
32022 this.mgr.el.dom.appendChild(el.dom);
32024 if(panel.setRegion){
32025 panel.setRegion(this);
32027 this.panels.add(panel);
32028 el.setStyle("position", "absolute");
32029 if(!panel.background){
32030 this.setActivePanel(panel);
32031 if(this.config.initialSize && this.panels.getCount()==1){
32032 this.resizeTo(this.config.initialSize);
32035 this.fireEvent("paneladded", this, panel);
32040 * Returns true if the panel is in this region.
32041 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32042 * @return {Boolean}
32044 hasPanel : function(panel){
32045 if(typeof panel == "object"){ // must be panel obj
32046 panel = panel.getId();
32048 return this.getPanel(panel) ? true : false;
32052 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32053 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32054 * @param {Boolean} preservePanel Overrides the config preservePanel option
32055 * @return {Roo.ContentPanel} The panel that was removed
32057 remove : function(panel, preservePanel){
32058 panel = this.getPanel(panel);
32063 this.fireEvent("beforeremove", this, panel, e);
32064 if(e.cancel === true){
32067 var panelId = panel.getId();
32068 this.panels.removeKey(panelId);
32073 * Returns the panel specified or null if it's not in this region.
32074 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32075 * @return {Roo.ContentPanel}
32077 getPanel : function(id){
32078 if(typeof id == "object"){ // must be panel obj
32081 return this.panels.get(id);
32085 * Returns this regions position (north/south/east/west/center).
32088 getPosition: function(){
32089 return this.position;
32093 * Ext JS Library 1.1.1
32094 * Copyright(c) 2006-2007, Ext JS, LLC.
32096 * Originally Released Under LGPL - original licence link has changed is not relivant.
32099 * <script type="text/javascript">
32103 * @class Roo.bootstrap.layout.Region
32104 * @extends Roo.bootstrap.layout.Basic
32105 * This class represents a region in a layout manager.
32107 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
32108 * @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})
32109 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
32110 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
32111 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
32112 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
32113 * @cfg {String} title The title for the region (overrides panel titles)
32114 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
32115 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
32116 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
32117 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
32118 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
32119 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
32120 * the space available, similar to FireFox 1.5 tabs (defaults to false)
32121 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
32122 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
32123 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
32125 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
32126 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
32127 * @cfg {Boolean} disableTabTips True to disable tab tooltips
32128 * @cfg {Number} width For East/West panels
32129 * @cfg {Number} height For North/South panels
32130 * @cfg {Boolean} split To show the splitter
32131 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
32133 * @cfg {string} cls Extra CSS classes to add to region
32135 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32136 * @cfg {string} region the region that it inhabits..
32139 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
32140 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
32142 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
32143 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
32144 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
32146 Roo.bootstrap.layout.Region = function(config)
32148 this.applyConfig(config);
32150 var mgr = config.mgr;
32151 var pos = config.region;
32152 config.skipConfig = true;
32153 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
32156 this.onRender(mgr.el);
32159 this.visible = true;
32160 this.collapsed = false;
32163 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32165 position: '', // set by wrapper (eg. north/south etc..)
32167 createBody : function(){
32168 /** This region's body element
32169 * @type Roo.Element */
32170 this.bodyEl = this.el.createChild({
32172 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32176 onRender: function(ctr, pos)
32178 var dh = Roo.DomHelper;
32179 /** This region's container element
32180 * @type Roo.Element */
32181 this.el = dh.append(ctr.dom, {
32183 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
32185 /** This region's title element
32186 * @type Roo.Element */
32188 this.titleEl = dh.append(this.el.dom,
32191 unselectable: "on",
32192 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32194 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32195 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32198 this.titleEl.enableDisplayMode();
32199 /** This region's title text element
32200 * @type HTMLElement */
32201 this.titleTextEl = this.titleEl.dom.firstChild;
32202 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32204 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32205 this.closeBtn.enableDisplayMode();
32206 this.closeBtn.on("click", this.closeClicked, this);
32207 this.closeBtn.hide();
32209 this.createBody(this.config);
32210 if(this.config.hideWhenEmpty){
32212 this.on("paneladded", this.validateVisibility, this);
32213 this.on("panelremoved", this.validateVisibility, this);
32215 if(this.autoScroll){
32216 this.bodyEl.setStyle("overflow", "auto");
32218 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
32220 //if(c.titlebar !== false){
32221 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
32222 this.titleEl.hide();
32224 this.titleEl.show();
32225 if(this.config.title){
32226 this.titleTextEl.innerHTML = this.config.title;
32230 if(this.config.collapsed){
32231 this.collapse(true);
32233 if(this.config.hidden){
32238 applyConfig : function(c)
32241 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32242 var dh = Roo.DomHelper;
32243 if(c.titlebar !== false){
32244 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32245 this.collapseBtn.on("click", this.collapse, this);
32246 this.collapseBtn.enableDisplayMode();
32248 if(c.showPin === true || this.showPin){
32249 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32250 this.stickBtn.enableDisplayMode();
32251 this.stickBtn.on("click", this.expand, this);
32252 this.stickBtn.hide();
32257 /** This region's collapsed element
32258 * @type Roo.Element */
32261 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32262 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32265 if(c.floatable !== false){
32266 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32267 this.collapsedEl.on("click", this.collapseClick, this);
32270 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32271 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32272 id: "message", unselectable: "on", style:{"float":"left"}});
32273 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32275 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32276 this.expandBtn.on("click", this.expand, this);
32280 if(this.collapseBtn){
32281 this.collapseBtn.setVisible(c.collapsible == true);
32284 this.cmargins = c.cmargins || this.cmargins ||
32285 (this.position == "west" || this.position == "east" ?
32286 {top: 0, left: 2, right:2, bottom: 0} :
32287 {top: 2, left: 0, right:0, bottom: 2});
32289 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32292 this.bottomTabs = c.tabPosition != "top";
32294 this.autoScroll = c.autoScroll || false;
32299 this.duration = c.duration || .30;
32300 this.slideDuration = c.slideDuration || .45;
32305 * Returns true if this region is currently visible.
32306 * @return {Boolean}
32308 isVisible : function(){
32309 return this.visible;
32313 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
32314 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
32316 //setCollapsedTitle : function(title){
32317 // title = title || " ";
32318 // if(this.collapsedTitleTextEl){
32319 // this.collapsedTitleTextEl.innerHTML = title;
32323 getBox : function(){
32325 // if(!this.collapsed){
32326 b = this.el.getBox(false, true);
32328 // b = this.collapsedEl.getBox(false, true);
32333 getMargins : function(){
32334 return this.margins;
32335 //return this.collapsed ? this.cmargins : this.margins;
32338 highlight : function(){
32339 this.el.addClass("x-layout-panel-dragover");
32342 unhighlight : function(){
32343 this.el.removeClass("x-layout-panel-dragover");
32346 updateBox : function(box)
32349 if(!this.collapsed){
32350 this.el.dom.style.left = box.x + "px";
32351 this.el.dom.style.top = box.y + "px";
32352 this.updateBody(box.width, box.height);
32354 this.collapsedEl.dom.style.left = box.x + "px";
32355 this.collapsedEl.dom.style.top = box.y + "px";
32356 this.collapsedEl.setSize(box.width, box.height);
32359 this.tabs.autoSizeTabs();
32363 updateBody : function(w, h)
32366 this.el.setWidth(w);
32367 w -= this.el.getBorderWidth("rl");
32368 if(this.config.adjustments){
32369 w += this.config.adjustments[0];
32373 this.el.setHeight(h);
32374 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
32375 h -= this.el.getBorderWidth("tb");
32376 if(this.config.adjustments){
32377 h += this.config.adjustments[1];
32379 this.bodyEl.setHeight(h);
32381 h = this.tabs.syncHeight(h);
32384 if(this.panelSize){
32385 w = w !== null ? w : this.panelSize.width;
32386 h = h !== null ? h : this.panelSize.height;
32388 if(this.activePanel){
32389 var el = this.activePanel.getEl();
32390 w = w !== null ? w : el.getWidth();
32391 h = h !== null ? h : el.getHeight();
32392 this.panelSize = {width: w, height: h};
32393 this.activePanel.setSize(w, h);
32395 if(Roo.isIE && this.tabs){
32396 this.tabs.el.repaint();
32401 * Returns the container element for this region.
32402 * @return {Roo.Element}
32404 getEl : function(){
32409 * Hides this region.
32412 //if(!this.collapsed){
32413 this.el.dom.style.left = "-2000px";
32416 // this.collapsedEl.dom.style.left = "-2000px";
32417 // this.collapsedEl.hide();
32419 this.visible = false;
32420 this.fireEvent("visibilitychange", this, false);
32424 * Shows this region if it was previously hidden.
32427 //if(!this.collapsed){
32430 // this.collapsedEl.show();
32432 this.visible = true;
32433 this.fireEvent("visibilitychange", this, true);
32436 closeClicked : function(){
32437 if(this.activePanel){
32438 this.remove(this.activePanel);
32442 collapseClick : function(e){
32444 e.stopPropagation();
32447 e.stopPropagation();
32453 * Collapses this region.
32454 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
32457 collapse : function(skipAnim, skipCheck = false){
32458 if(this.collapsed) {
32462 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
32464 this.collapsed = true;
32466 this.split.el.hide();
32468 if(this.config.animate && skipAnim !== true){
32469 this.fireEvent("invalidated", this);
32470 this.animateCollapse();
32472 this.el.setLocation(-20000,-20000);
32474 this.collapsedEl.show();
32475 this.fireEvent("collapsed", this);
32476 this.fireEvent("invalidated", this);
32482 animateCollapse : function(){
32487 * Expands this region if it was previously collapsed.
32488 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
32489 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
32492 expand : function(e, skipAnim){
32494 e.stopPropagation();
32496 if(!this.collapsed || this.el.hasActiveFx()) {
32500 this.afterSlideIn();
32503 this.collapsed = false;
32504 if(this.config.animate && skipAnim !== true){
32505 this.animateExpand();
32509 this.split.el.show();
32511 this.collapsedEl.setLocation(-2000,-2000);
32512 this.collapsedEl.hide();
32513 this.fireEvent("invalidated", this);
32514 this.fireEvent("expanded", this);
32518 animateExpand : function(){
32522 initTabs : function()
32524 this.bodyEl.setStyle("overflow", "hidden");
32525 var ts = new Roo.bootstrap.panel.Tabs({
32526 el: this.bodyEl.dom,
32527 tabPosition: this.bottomTabs ? 'bottom' : 'top',
32528 disableTooltips: this.config.disableTabTips,
32529 toolbar : this.config.toolbar
32532 if(this.config.hideTabs){
32533 ts.stripWrap.setDisplayed(false);
32536 ts.resizeTabs = this.config.resizeTabs === true;
32537 ts.minTabWidth = this.config.minTabWidth || 40;
32538 ts.maxTabWidth = this.config.maxTabWidth || 250;
32539 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
32540 ts.monitorResize = false;
32541 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32542 ts.bodyEl.addClass('roo-layout-tabs-body');
32543 this.panels.each(this.initPanelAsTab, this);
32546 initPanelAsTab : function(panel){
32547 var ti = this.tabs.addTab(
32549 panel.getTitle(), null,
32550 this.config.closeOnTab && panel.isClosable()
32552 if(panel.tabTip !== undefined){
32553 ti.setTooltip(panel.tabTip);
32555 ti.on("activate", function(){
32556 this.setActivePanel(panel);
32559 if(this.config.closeOnTab){
32560 ti.on("beforeclose", function(t, e){
32562 this.remove(panel);
32568 updatePanelTitle : function(panel, title)
32570 if(this.activePanel == panel){
32571 this.updateTitle(title);
32574 var ti = this.tabs.getTab(panel.getEl().id);
32576 if(panel.tabTip !== undefined){
32577 ti.setTooltip(panel.tabTip);
32582 updateTitle : function(title){
32583 if(this.titleTextEl && !this.config.title){
32584 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
32588 setActivePanel : function(panel)
32590 panel = this.getPanel(panel);
32591 if(this.activePanel && this.activePanel != panel){
32592 this.activePanel.setActiveState(false);
32594 this.activePanel = panel;
32595 panel.setActiveState(true);
32596 if(this.panelSize){
32597 panel.setSize(this.panelSize.width, this.panelSize.height);
32600 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
32602 this.updateTitle(panel.getTitle());
32604 this.fireEvent("invalidated", this);
32606 this.fireEvent("panelactivated", this, panel);
32610 * Shows the specified panel.
32611 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
32612 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
32614 showPanel : function(panel)
32616 panel = this.getPanel(panel);
32619 var tab = this.tabs.getTab(panel.getEl().id);
32620 if(tab.isHidden()){
32621 this.tabs.unhideTab(tab.id);
32625 this.setActivePanel(panel);
32632 * Get the active panel for this region.
32633 * @return {Roo.ContentPanel} The active panel or null
32635 getActivePanel : function(){
32636 return this.activePanel;
32639 validateVisibility : function(){
32640 if(this.panels.getCount() < 1){
32641 this.updateTitle(" ");
32642 this.closeBtn.hide();
32645 if(!this.isVisible()){
32652 * Adds the passed ContentPanel(s) to this region.
32653 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32654 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
32656 add : function(panel){
32657 if(arguments.length > 1){
32658 for(var i = 0, len = arguments.length; i < len; i++) {
32659 this.add(arguments[i]);
32663 if(this.hasPanel(panel)){
32664 this.showPanel(panel);
32667 panel.setRegion(this);
32668 this.panels.add(panel);
32669 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
32670 this.bodyEl.dom.appendChild(panel.getEl().dom);
32671 if(panel.background !== true){
32672 this.setActivePanel(panel);
32674 this.fireEvent("paneladded", this, panel);
32680 this.initPanelAsTab(panel);
32684 if(panel.background !== true){
32685 this.tabs.activate(panel.getEl().id);
32687 this.fireEvent("paneladded", this, panel);
32692 * Hides the tab for the specified panel.
32693 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32695 hidePanel : function(panel){
32696 if(this.tabs && (panel = this.getPanel(panel))){
32697 this.tabs.hideTab(panel.getEl().id);
32702 * Unhides the tab for a previously hidden panel.
32703 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32705 unhidePanel : function(panel){
32706 if(this.tabs && (panel = this.getPanel(panel))){
32707 this.tabs.unhideTab(panel.getEl().id);
32711 clearPanels : function(){
32712 while(this.panels.getCount() > 0){
32713 this.remove(this.panels.first());
32718 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32719 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32720 * @param {Boolean} preservePanel Overrides the config preservePanel option
32721 * @return {Roo.ContentPanel} The panel that was removed
32723 remove : function(panel, preservePanel)
32725 panel = this.getPanel(panel);
32730 this.fireEvent("beforeremove", this, panel, e);
32731 if(e.cancel === true){
32734 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
32735 var panelId = panel.getId();
32736 this.panels.removeKey(panelId);
32738 document.body.appendChild(panel.getEl().dom);
32741 this.tabs.removeTab(panel.getEl().id);
32742 }else if (!preservePanel){
32743 this.bodyEl.dom.removeChild(panel.getEl().dom);
32745 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
32746 var p = this.panels.first();
32747 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
32748 tempEl.appendChild(p.getEl().dom);
32749 this.bodyEl.update("");
32750 this.bodyEl.dom.appendChild(p.getEl().dom);
32752 this.updateTitle(p.getTitle());
32754 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32755 this.setActivePanel(p);
32757 panel.setRegion(null);
32758 if(this.activePanel == panel){
32759 this.activePanel = null;
32761 if(this.config.autoDestroy !== false && preservePanel !== true){
32762 try{panel.destroy();}catch(e){}
32764 this.fireEvent("panelremoved", this, panel);
32769 * Returns the TabPanel component used by this region
32770 * @return {Roo.TabPanel}
32772 getTabs : function(){
32776 createTool : function(parentEl, className){
32777 var btn = Roo.DomHelper.append(parentEl, {
32779 cls: "x-layout-tools-button",
32782 cls: "roo-layout-tools-button-inner " + className,
32786 btn.addClassOnOver("roo-layout-tools-button-over");
32791 * Ext JS Library 1.1.1
32792 * Copyright(c) 2006-2007, Ext JS, LLC.
32794 * Originally Released Under LGPL - original licence link has changed is not relivant.
32797 * <script type="text/javascript">
32803 * @class Roo.SplitLayoutRegion
32804 * @extends Roo.LayoutRegion
32805 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
32807 Roo.bootstrap.layout.Split = function(config){
32808 this.cursor = config.cursor;
32809 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
32812 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
32814 splitTip : "Drag to resize.",
32815 collapsibleSplitTip : "Drag to resize. Double click to hide.",
32816 useSplitTips : false,
32818 applyConfig : function(config){
32819 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
32822 onRender : function(ctr,pos) {
32824 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
32825 if(!this.config.split){
32830 var splitEl = Roo.DomHelper.append(ctr.dom, {
32832 id: this.el.id + "-split",
32833 cls: "roo-layout-split roo-layout-split-"+this.position,
32836 /** The SplitBar for this region
32837 * @type Roo.SplitBar */
32838 // does not exist yet...
32839 Roo.log([this.position, this.orientation]);
32841 this.split = new Roo.bootstrap.SplitBar({
32842 dragElement : splitEl,
32843 resizingElement: this.el,
32844 orientation : this.orientation
32847 this.split.on("moved", this.onSplitMove, this);
32848 this.split.useShim = this.config.useShim === true;
32849 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
32850 if(this.useSplitTips){
32851 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
32853 //if(config.collapsible){
32854 // this.split.el.on("dblclick", this.collapse, this);
32857 if(typeof this.config.minSize != "undefined"){
32858 this.split.minSize = this.config.minSize;
32860 if(typeof this.config.maxSize != "undefined"){
32861 this.split.maxSize = this.config.maxSize;
32863 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
32864 this.hideSplitter();
32869 getHMaxSize : function(){
32870 var cmax = this.config.maxSize || 10000;
32871 var center = this.mgr.getRegion("center");
32872 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
32875 getVMaxSize : function(){
32876 var cmax = this.config.maxSize || 10000;
32877 var center = this.mgr.getRegion("center");
32878 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
32881 onSplitMove : function(split, newSize){
32882 this.fireEvent("resized", this, newSize);
32886 * Returns the {@link Roo.SplitBar} for this region.
32887 * @return {Roo.SplitBar}
32889 getSplitBar : function(){
32894 this.hideSplitter();
32895 Roo.bootstrap.layout.Split.superclass.hide.call(this);
32898 hideSplitter : function(){
32900 this.split.el.setLocation(-2000,-2000);
32901 this.split.el.hide();
32907 this.split.el.show();
32909 Roo.bootstrap.layout.Split.superclass.show.call(this);
32912 beforeSlide: function(){
32913 if(Roo.isGecko){// firefox overflow auto bug workaround
32914 this.bodyEl.clip();
32916 this.tabs.bodyEl.clip();
32918 if(this.activePanel){
32919 this.activePanel.getEl().clip();
32921 if(this.activePanel.beforeSlide){
32922 this.activePanel.beforeSlide();
32928 afterSlide : function(){
32929 if(Roo.isGecko){// firefox overflow auto bug workaround
32930 this.bodyEl.unclip();
32932 this.tabs.bodyEl.unclip();
32934 if(this.activePanel){
32935 this.activePanel.getEl().unclip();
32936 if(this.activePanel.afterSlide){
32937 this.activePanel.afterSlide();
32943 initAutoHide : function(){
32944 if(this.autoHide !== false){
32945 if(!this.autoHideHd){
32946 var st = new Roo.util.DelayedTask(this.slideIn, this);
32947 this.autoHideHd = {
32948 "mouseout": function(e){
32949 if(!e.within(this.el, true)){
32953 "mouseover" : function(e){
32959 this.el.on(this.autoHideHd);
32963 clearAutoHide : function(){
32964 if(this.autoHide !== false){
32965 this.el.un("mouseout", this.autoHideHd.mouseout);
32966 this.el.un("mouseover", this.autoHideHd.mouseover);
32970 clearMonitor : function(){
32971 Roo.get(document).un("click", this.slideInIf, this);
32974 // these names are backwards but not changed for compat
32975 slideOut : function(){
32976 if(this.isSlid || this.el.hasActiveFx()){
32979 this.isSlid = true;
32980 if(this.collapseBtn){
32981 this.collapseBtn.hide();
32983 this.closeBtnState = this.closeBtn.getStyle('display');
32984 this.closeBtn.hide();
32986 this.stickBtn.show();
32989 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
32990 this.beforeSlide();
32991 this.el.setStyle("z-index", 10001);
32992 this.el.slideIn(this.getSlideAnchor(), {
32993 callback: function(){
32995 this.initAutoHide();
32996 Roo.get(document).on("click", this.slideInIf, this);
32997 this.fireEvent("slideshow", this);
33004 afterSlideIn : function(){
33005 this.clearAutoHide();
33006 this.isSlid = false;
33007 this.clearMonitor();
33008 this.el.setStyle("z-index", "");
33009 if(this.collapseBtn){
33010 this.collapseBtn.show();
33012 this.closeBtn.setStyle('display', this.closeBtnState);
33014 this.stickBtn.hide();
33016 this.fireEvent("slidehide", this);
33019 slideIn : function(cb){
33020 if(!this.isSlid || this.el.hasActiveFx()){
33024 this.isSlid = false;
33025 this.beforeSlide();
33026 this.el.slideOut(this.getSlideAnchor(), {
33027 callback: function(){
33028 this.el.setLeftTop(-10000, -10000);
33030 this.afterSlideIn();
33038 slideInIf : function(e){
33039 if(!e.within(this.el)){
33044 animateCollapse : function(){
33045 this.beforeSlide();
33046 this.el.setStyle("z-index", 20000);
33047 var anchor = this.getSlideAnchor();
33048 this.el.slideOut(anchor, {
33049 callback : function(){
33050 this.el.setStyle("z-index", "");
33051 this.collapsedEl.slideIn(anchor, {duration:.3});
33053 this.el.setLocation(-10000,-10000);
33055 this.fireEvent("collapsed", this);
33062 animateExpand : function(){
33063 this.beforeSlide();
33064 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
33065 this.el.setStyle("z-index", 20000);
33066 this.collapsedEl.hide({
33069 this.el.slideIn(this.getSlideAnchor(), {
33070 callback : function(){
33071 this.el.setStyle("z-index", "");
33074 this.split.el.show();
33076 this.fireEvent("invalidated", this);
33077 this.fireEvent("expanded", this);
33105 getAnchor : function(){
33106 return this.anchors[this.position];
33109 getCollapseAnchor : function(){
33110 return this.canchors[this.position];
33113 getSlideAnchor : function(){
33114 return this.sanchors[this.position];
33117 getAlignAdj : function(){
33118 var cm = this.cmargins;
33119 switch(this.position){
33135 getExpandAdj : function(){
33136 var c = this.collapsedEl, cm = this.cmargins;
33137 switch(this.position){
33139 return [-(cm.right+c.getWidth()+cm.left), 0];
33142 return [cm.right+c.getWidth()+cm.left, 0];
33145 return [0, -(cm.top+cm.bottom+c.getHeight())];
33148 return [0, cm.top+cm.bottom+c.getHeight()];
33154 * Ext JS Library 1.1.1
33155 * Copyright(c) 2006-2007, Ext JS, LLC.
33157 * Originally Released Under LGPL - original licence link has changed is not relivant.
33160 * <script type="text/javascript">
33163 * These classes are private internal classes
33165 Roo.bootstrap.layout.Center = function(config){
33166 config.region = "center";
33167 Roo.bootstrap.layout.Region.call(this, config);
33168 this.visible = true;
33169 this.minWidth = config.minWidth || 20;
33170 this.minHeight = config.minHeight || 20;
33173 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
33175 // center panel can't be hidden
33179 // center panel can't be hidden
33182 getMinWidth: function(){
33183 return this.minWidth;
33186 getMinHeight: function(){
33187 return this.minHeight;
33200 Roo.bootstrap.layout.North = function(config)
33202 config.region = 'north';
33203 config.cursor = 'n-resize';
33205 Roo.bootstrap.layout.Split.call(this, config);
33209 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33210 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33211 this.split.el.addClass("roo-layout-split-v");
33213 var size = config.initialSize || config.height;
33214 if(typeof size != "undefined"){
33215 this.el.setHeight(size);
33218 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
33220 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33224 getBox : function(){
33225 if(this.collapsed){
33226 return this.collapsedEl.getBox();
33228 var box = this.el.getBox();
33230 box.height += this.split.el.getHeight();
33235 updateBox : function(box){
33236 if(this.split && !this.collapsed){
33237 box.height -= this.split.el.getHeight();
33238 this.split.el.setLeft(box.x);
33239 this.split.el.setTop(box.y+box.height);
33240 this.split.el.setWidth(box.width);
33242 if(this.collapsed){
33243 this.updateBody(box.width, null);
33245 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33253 Roo.bootstrap.layout.South = function(config){
33254 config.region = 'south';
33255 config.cursor = 's-resize';
33256 Roo.bootstrap.layout.Split.call(this, config);
33258 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33259 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33260 this.split.el.addClass("roo-layout-split-v");
33262 var size = config.initialSize || config.height;
33263 if(typeof size != "undefined"){
33264 this.el.setHeight(size);
33268 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33269 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33270 getBox : function(){
33271 if(this.collapsed){
33272 return this.collapsedEl.getBox();
33274 var box = this.el.getBox();
33276 var sh = this.split.el.getHeight();
33283 updateBox : function(box){
33284 if(this.split && !this.collapsed){
33285 var sh = this.split.el.getHeight();
33288 this.split.el.setLeft(box.x);
33289 this.split.el.setTop(box.y-sh);
33290 this.split.el.setWidth(box.width);
33292 if(this.collapsed){
33293 this.updateBody(box.width, null);
33295 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33299 Roo.bootstrap.layout.East = function(config){
33300 config.region = "east";
33301 config.cursor = "e-resize";
33302 Roo.bootstrap.layout.Split.call(this, config);
33304 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
33305 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33306 this.split.el.addClass("roo-layout-split-h");
33308 var size = config.initialSize || config.width;
33309 if(typeof size != "undefined"){
33310 this.el.setWidth(size);
33313 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
33314 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33315 getBox : function(){
33316 if(this.collapsed){
33317 return this.collapsedEl.getBox();
33319 var box = this.el.getBox();
33321 var sw = this.split.el.getWidth();
33328 updateBox : function(box){
33329 if(this.split && !this.collapsed){
33330 var sw = this.split.el.getWidth();
33332 this.split.el.setLeft(box.x);
33333 this.split.el.setTop(box.y);
33334 this.split.el.setHeight(box.height);
33337 if(this.collapsed){
33338 this.updateBody(null, box.height);
33340 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33344 Roo.bootstrap.layout.West = function(config){
33345 config.region = "west";
33346 config.cursor = "w-resize";
33348 Roo.bootstrap.layout.Split.call(this, config);
33350 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
33351 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33352 this.split.el.addClass("roo-layout-split-h");
33356 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
33357 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33359 onRender: function(ctr, pos)
33361 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
33362 var size = this.config.initialSize || this.config.width;
33363 if(typeof size != "undefined"){
33364 this.el.setWidth(size);
33368 getBox : function(){
33369 if(this.collapsed){
33370 return this.collapsedEl.getBox();
33372 var box = this.el.getBox();
33374 box.width += this.split.el.getWidth();
33379 updateBox : function(box){
33380 if(this.split && !this.collapsed){
33381 var sw = this.split.el.getWidth();
33383 this.split.el.setLeft(box.x+box.width);
33384 this.split.el.setTop(box.y);
33385 this.split.el.setHeight(box.height);
33387 if(this.collapsed){
33388 this.updateBody(null, box.height);
33390 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33393 Roo.namespace("Roo.bootstrap.panel");/*
33395 * Ext JS Library 1.1.1
33396 * Copyright(c) 2006-2007, Ext JS, LLC.
33398 * Originally Released Under LGPL - original licence link has changed is not relivant.
33401 * <script type="text/javascript">
33404 * @class Roo.ContentPanel
33405 * @extends Roo.util.Observable
33406 * A basic ContentPanel element.
33407 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
33408 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
33409 * @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
33410 * @cfg {Boolean} closable True if the panel can be closed/removed
33411 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
33412 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
33413 * @cfg {Toolbar} toolbar A toolbar for this panel
33414 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
33415 * @cfg {String} title The title for this panel
33416 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
33417 * @cfg {String} url Calls {@link #setUrl} with this value
33418 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
33419 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
33420 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
33421 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
33424 * Create a new ContentPanel.
33425 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
33426 * @param {String/Object} config A string to set only the title or a config object
33427 * @param {String} content (optional) Set the HTML content for this panel
33428 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
33430 Roo.bootstrap.panel.Content = function( config){
33432 var el = config.el;
33433 var content = config.content;
33435 if(config.autoCreate){ // xtype is available if this is called from factory
33438 this.el = Roo.get(el);
33439 if(!this.el && config && config.autoCreate){
33440 if(typeof config.autoCreate == "object"){
33441 if(!config.autoCreate.id){
33442 config.autoCreate.id = config.id||el;
33444 this.el = Roo.DomHelper.append(document.body,
33445 config.autoCreate, true);
33447 var elcfg = { tag: "div",
33448 cls: "roo-layout-inactive-content",
33452 elcfg.html = config.html;
33456 this.el = Roo.DomHelper.append(document.body, elcfg , true);
33459 this.closable = false;
33460 this.loaded = false;
33461 this.active = false;
33464 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
33466 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
33468 this.wrapEl = this.el.wrap();
33470 if (config.toolbar.items) {
33471 ti = config.toolbar.items ;
33472 delete config.toolbar.items ;
33476 this.toolbar.render(this.wrapEl, 'before');
33477 for(var i =0;i < ti.length;i++) {
33478 // Roo.log(['add child', items[i]]);
33479 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
33481 this.toolbar.items = nitems;
33482 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
33483 delete config.toolbar;
33487 // xtype created footer. - not sure if will work as we normally have to render first..
33488 if (this.footer && !this.footer.el && this.footer.xtype) {
33489 if (!this.wrapEl) {
33490 this.wrapEl = this.el.wrap();
33493 this.footer.container = this.wrapEl.createChild();
33495 this.footer = Roo.factory(this.footer, Roo);
33500 if(typeof config == "string"){
33501 this.title = config;
33503 Roo.apply(this, config);
33507 this.resizeEl = Roo.get(this.resizeEl, true);
33509 this.resizeEl = this.el;
33511 // handle view.xtype
33519 * Fires when this panel is activated.
33520 * @param {Roo.ContentPanel} this
33524 * @event deactivate
33525 * Fires when this panel is activated.
33526 * @param {Roo.ContentPanel} this
33528 "deactivate" : true,
33532 * Fires when this panel is resized if fitToFrame is true.
33533 * @param {Roo.ContentPanel} this
33534 * @param {Number} width The width after any component adjustments
33535 * @param {Number} height The height after any component adjustments
33541 * Fires when this tab is created
33542 * @param {Roo.ContentPanel} this
33553 if(this.autoScroll){
33554 this.resizeEl.setStyle("overflow", "auto");
33556 // fix randome scrolling
33557 //this.el.on('scroll', function() {
33558 // Roo.log('fix random scolling');
33559 // this.scrollTo('top',0);
33562 content = content || this.content;
33564 this.setContent(content);
33566 if(config && config.url){
33567 this.setUrl(this.url, this.params, this.loadOnce);
33572 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
33574 if (this.view && typeof(this.view.xtype) != 'undefined') {
33575 this.view.el = this.el.appendChild(document.createElement("div"));
33576 this.view = Roo.factory(this.view);
33577 this.view.render && this.view.render(false, '');
33581 this.fireEvent('render', this);
33584 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
33586 setRegion : function(region){
33587 this.region = region;
33589 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
33591 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
33596 * Returns the toolbar for this Panel if one was configured.
33597 * @return {Roo.Toolbar}
33599 getToolbar : function(){
33600 return this.toolbar;
33603 setActiveState : function(active){
33604 this.active = active;
33606 this.fireEvent("deactivate", this);
33608 this.fireEvent("activate", this);
33612 * Updates this panel's element
33613 * @param {String} content The new content
33614 * @param {Boolean} loadScripts (optional) true to look for and process scripts
33616 setContent : function(content, loadScripts){
33617 this.el.update(content, loadScripts);
33620 ignoreResize : function(w, h){
33621 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
33624 this.lastSize = {width: w, height: h};
33629 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
33630 * @return {Roo.UpdateManager} The UpdateManager
33632 getUpdateManager : function(){
33633 return this.el.getUpdateManager();
33636 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
33637 * @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:
33640 url: "your-url.php",
33641 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
33642 callback: yourFunction,
33643 scope: yourObject, //(optional scope)
33646 text: "Loading...",
33651 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
33652 * 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.
33653 * @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}
33654 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
33655 * @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.
33656 * @return {Roo.ContentPanel} this
33659 var um = this.el.getUpdateManager();
33660 um.update.apply(um, arguments);
33666 * 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.
33667 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
33668 * @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)
33669 * @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)
33670 * @return {Roo.UpdateManager} The UpdateManager
33672 setUrl : function(url, params, loadOnce){
33673 if(this.refreshDelegate){
33674 this.removeListener("activate", this.refreshDelegate);
33676 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
33677 this.on("activate", this.refreshDelegate);
33678 return this.el.getUpdateManager();
33681 _handleRefresh : function(url, params, loadOnce){
33682 if(!loadOnce || !this.loaded){
33683 var updater = this.el.getUpdateManager();
33684 updater.update(url, params, this._setLoaded.createDelegate(this));
33688 _setLoaded : function(){
33689 this.loaded = true;
33693 * Returns this panel's id
33696 getId : function(){
33701 * Returns this panel's element - used by regiosn to add.
33702 * @return {Roo.Element}
33704 getEl : function(){
33705 return this.wrapEl || this.el;
33710 adjustForComponents : function(width, height)
33712 //Roo.log('adjustForComponents ');
33713 if(this.resizeEl != this.el){
33714 width -= this.el.getFrameWidth('lr');
33715 height -= this.el.getFrameWidth('tb');
33718 var te = this.toolbar.getEl();
33719 height -= te.getHeight();
33720 te.setWidth(width);
33723 var te = this.footer.getEl();
33724 Roo.log("footer:" + te.getHeight());
33726 height -= te.getHeight();
33727 te.setWidth(width);
33731 if(this.adjustments){
33732 width += this.adjustments[0];
33733 height += this.adjustments[1];
33735 return {"width": width, "height": height};
33738 setSize : function(width, height){
33739 if(this.fitToFrame && !this.ignoreResize(width, height)){
33740 if(this.fitContainer && this.resizeEl != this.el){
33741 this.el.setSize(width, height);
33743 var size = this.adjustForComponents(width, height);
33744 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
33745 this.fireEvent('resize', this, size.width, size.height);
33750 * Returns this panel's title
33753 getTitle : function(){
33758 * Set this panel's title
33759 * @param {String} title
33761 setTitle : function(title){
33762 this.title = title;
33764 this.region.updatePanelTitle(this, title);
33769 * Returns true is this panel was configured to be closable
33770 * @return {Boolean}
33772 isClosable : function(){
33773 return this.closable;
33776 beforeSlide : function(){
33778 this.resizeEl.clip();
33781 afterSlide : function(){
33783 this.resizeEl.unclip();
33787 * Force a content refresh from the URL specified in the {@link #setUrl} method.
33788 * Will fail silently if the {@link #setUrl} method has not been called.
33789 * This does not activate the panel, just updates its content.
33791 refresh : function(){
33792 if(this.refreshDelegate){
33793 this.loaded = false;
33794 this.refreshDelegate();
33799 * Destroys this panel
33801 destroy : function(){
33802 this.el.removeAllListeners();
33803 var tempEl = document.createElement("span");
33804 tempEl.appendChild(this.el.dom);
33805 tempEl.innerHTML = "";
33811 * form - if the content panel contains a form - this is a reference to it.
33812 * @type {Roo.form.Form}
33816 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
33817 * This contains a reference to it.
33823 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
33833 * @param {Object} cfg Xtype definition of item to add.
33837 getChildContainer: function () {
33838 return this.getEl();
33843 var ret = new Roo.factory(cfg);
33848 if (cfg.xtype.match(/^Form$/)) {
33851 //if (this.footer) {
33852 // el = this.footer.container.insertSibling(false, 'before');
33854 el = this.el.createChild();
33857 this.form = new Roo.form.Form(cfg);
33860 if ( this.form.allItems.length) {
33861 this.form.render(el.dom);
33865 // should only have one of theses..
33866 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
33867 // views.. should not be just added - used named prop 'view''
33869 cfg.el = this.el.appendChild(document.createElement("div"));
33872 var ret = new Roo.factory(cfg);
33874 ret.render && ret.render(false, ''); // render blank..
33884 * @class Roo.bootstrap.panel.Grid
33885 * @extends Roo.bootstrap.panel.Content
33887 * Create a new GridPanel.
33888 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
33889 * @param {Object} config A the config object
33895 Roo.bootstrap.panel.Grid = function(config)
33899 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
33900 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
33902 config.el = this.wrapper;
33903 //this.el = this.wrapper;
33905 if (config.container) {
33906 // ctor'ed from a Border/panel.grid
33909 this.wrapper.setStyle("overflow", "hidden");
33910 this.wrapper.addClass('roo-grid-container');
33915 if(config.toolbar){
33916 var tool_el = this.wrapper.createChild();
33917 this.toolbar = Roo.factory(config.toolbar);
33919 if (config.toolbar.items) {
33920 ti = config.toolbar.items ;
33921 delete config.toolbar.items ;
33925 this.toolbar.render(tool_el);
33926 for(var i =0;i < ti.length;i++) {
33927 // Roo.log(['add child', items[i]]);
33928 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
33930 this.toolbar.items = nitems;
33932 delete config.toolbar;
33935 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
33936 config.grid.scrollBody = true;;
33937 config.grid.monitorWindowResize = false; // turn off autosizing
33938 config.grid.autoHeight = false;
33939 config.grid.autoWidth = false;
33941 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
33943 if (config.background) {
33944 // render grid on panel activation (if panel background)
33945 this.on('activate', function(gp) {
33946 if (!gp.grid.rendered) {
33947 gp.grid.render(el);
33948 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
33954 this.grid.render(this.wrapper);
33955 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
33958 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
33959 // ??? needed ??? config.el = this.wrapper;
33964 // xtype created footer. - not sure if will work as we normally have to render first..
33965 if (this.footer && !this.footer.el && this.footer.xtype) {
33967 var ctr = this.grid.getView().getFooterPanel(true);
33968 this.footer.dataSource = this.grid.dataSource;
33969 this.footer = Roo.factory(this.footer, Roo);
33970 this.footer.render(ctr);
33980 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
33981 getId : function(){
33982 return this.grid.id;
33986 * Returns the grid for this panel
33987 * @return {Roo.bootstrap.Table}
33989 getGrid : function(){
33993 setSize : function(width, height){
33994 if(!this.ignoreResize(width, height)){
33995 var grid = this.grid;
33996 var size = this.adjustForComponents(width, height);
33997 var gridel = grid.getGridEl();
33998 gridel.setSize(size.width, size.height);
34000 var thd = grid.getGridEl().select('thead',true).first();
34001 var tbd = grid.getGridEl().select('tbody', true).first();
34003 tbd.setSize(width, height - thd.getHeight());
34012 beforeSlide : function(){
34013 this.grid.getView().scroller.clip();
34016 afterSlide : function(){
34017 this.grid.getView().scroller.unclip();
34020 destroy : function(){
34021 this.grid.destroy();
34023 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
34028 * @class Roo.bootstrap.panel.Nest
34029 * @extends Roo.bootstrap.panel.Content
34031 * Create a new Panel, that can contain a layout.Border.
34034 * @param {Roo.BorderLayout} layout The layout for this panel
34035 * @param {String/Object} config A string to set only the title or a config object
34037 Roo.bootstrap.panel.Nest = function(config)
34039 // construct with only one argument..
34040 /* FIXME - implement nicer consturctors
34041 if (layout.layout) {
34043 layout = config.layout;
34044 delete config.layout;
34046 if (layout.xtype && !layout.getEl) {
34047 // then layout needs constructing..
34048 layout = Roo.factory(layout, Roo);
34052 config.el = config.layout.getEl();
34054 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
34056 config.layout.monitorWindowResize = false; // turn off autosizing
34057 this.layout = config.layout;
34058 this.layout.getEl().addClass("roo-layout-nested-layout");
34065 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
34067 setSize : function(width, height){
34068 if(!this.ignoreResize(width, height)){
34069 var size = this.adjustForComponents(width, height);
34070 var el = this.layout.getEl();
34071 el.setSize(size.width, size.height);
34072 var touch = el.dom.offsetWidth;
34073 this.layout.layout();
34074 // ie requires a double layout on the first pass
34075 if(Roo.isIE && !this.initialized){
34076 this.initialized = true;
34077 this.layout.layout();
34082 // activate all subpanels if not currently active..
34084 setActiveState : function(active){
34085 this.active = active;
34087 this.fireEvent("deactivate", this);
34091 this.fireEvent("activate", this);
34092 // not sure if this should happen before or after..
34093 if (!this.layout) {
34094 return; // should not happen..
34097 for (var r in this.layout.regions) {
34098 reg = this.layout.getRegion(r);
34099 if (reg.getActivePanel()) {
34100 //reg.showPanel(reg.getActivePanel()); // force it to activate..
34101 reg.setActivePanel(reg.getActivePanel());
34104 if (!reg.panels.length) {
34107 reg.showPanel(reg.getPanel(0));
34116 * Returns the nested BorderLayout for this panel
34117 * @return {Roo.BorderLayout}
34119 getLayout : function(){
34120 return this.layout;
34124 * Adds a xtype elements to the layout of the nested panel
34128 xtype : 'ContentPanel',
34135 xtype : 'NestedLayoutPanel',
34141 items : [ ... list of content panels or nested layout panels.. ]
34145 * @param {Object} cfg Xtype definition of item to add.
34147 addxtype : function(cfg) {
34148 return this.layout.addxtype(cfg);
34153 * Ext JS Library 1.1.1
34154 * Copyright(c) 2006-2007, Ext JS, LLC.
34156 * Originally Released Under LGPL - original licence link has changed is not relivant.
34159 * <script type="text/javascript">
34162 * @class Roo.TabPanel
34163 * @extends Roo.util.Observable
34164 * A lightweight tab container.
34168 // basic tabs 1, built from existing content
34169 var tabs = new Roo.TabPanel("tabs1");
34170 tabs.addTab("script", "View Script");
34171 tabs.addTab("markup", "View Markup");
34172 tabs.activate("script");
34174 // more advanced tabs, built from javascript
34175 var jtabs = new Roo.TabPanel("jtabs");
34176 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
34178 // set up the UpdateManager
34179 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
34180 var updater = tab2.getUpdateManager();
34181 updater.setDefaultUrl("ajax1.htm");
34182 tab2.on('activate', updater.refresh, updater, true);
34184 // Use setUrl for Ajax loading
34185 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
34186 tab3.setUrl("ajax2.htm", null, true);
34189 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
34192 jtabs.activate("jtabs-1");
34195 * Create a new TabPanel.
34196 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
34197 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
34199 Roo.bootstrap.panel.Tabs = function(config){
34201 * The container element for this TabPanel.
34202 * @type Roo.Element
34204 this.el = Roo.get(config.el);
34207 if(typeof config == "boolean"){
34208 this.tabPosition = config ? "bottom" : "top";
34210 Roo.apply(this, config);
34214 if(this.tabPosition == "bottom"){
34215 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34216 this.el.addClass("roo-tabs-bottom");
34218 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
34219 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
34220 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
34222 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
34224 if(this.tabPosition != "bottom"){
34225 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
34226 * @type Roo.Element
34228 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34229 this.el.addClass("roo-tabs-top");
34233 this.bodyEl.setStyle("position", "relative");
34235 this.active = null;
34236 this.activateDelegate = this.activate.createDelegate(this);
34241 * Fires when the active tab changes
34242 * @param {Roo.TabPanel} this
34243 * @param {Roo.TabPanelItem} activePanel The new active tab
34247 * @event beforetabchange
34248 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
34249 * @param {Roo.TabPanel} this
34250 * @param {Object} e Set cancel to true on this object to cancel the tab change
34251 * @param {Roo.TabPanelItem} tab The tab being changed to
34253 "beforetabchange" : true
34256 Roo.EventManager.onWindowResize(this.onResize, this);
34257 this.cpad = this.el.getPadding("lr");
34258 this.hiddenCount = 0;
34261 // toolbar on the tabbar support...
34262 if (this.toolbar) {
34263 alert("no toolbar support yet");
34264 this.toolbar = false;
34266 var tcfg = this.toolbar;
34267 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
34268 this.toolbar = new Roo.Toolbar(tcfg);
34269 if (Roo.isSafari) {
34270 var tbl = tcfg.container.child('table', true);
34271 tbl.setAttribute('width', '100%');
34279 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
34282 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
34284 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
34286 tabPosition : "top",
34288 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
34290 currentTabWidth : 0,
34292 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
34296 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
34300 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
34302 preferredTabWidth : 175,
34304 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
34306 resizeTabs : false,
34308 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
34310 monitorResize : true,
34312 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
34317 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
34318 * @param {String} id The id of the div to use <b>or create</b>
34319 * @param {String} text The text for the tab
34320 * @param {String} content (optional) Content to put in the TabPanelItem body
34321 * @param {Boolean} closable (optional) True to create a close icon on the tab
34322 * @return {Roo.TabPanelItem} The created TabPanelItem
34324 addTab : function(id, text, content, closable)
34326 var item = new Roo.bootstrap.panel.TabItem({
34330 closable : closable
34332 this.addTabItem(item);
34334 item.setContent(content);
34340 * Returns the {@link Roo.TabPanelItem} with the specified id/index
34341 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
34342 * @return {Roo.TabPanelItem}
34344 getTab : function(id){
34345 return this.items[id];
34349 * Hides the {@link Roo.TabPanelItem} with the specified id/index
34350 * @param {String/Number} id The id or index of the TabPanelItem to hide.
34352 hideTab : function(id){
34353 var t = this.items[id];
34356 this.hiddenCount++;
34357 this.autoSizeTabs();
34362 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
34363 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
34365 unhideTab : function(id){
34366 var t = this.items[id];
34368 t.setHidden(false);
34369 this.hiddenCount--;
34370 this.autoSizeTabs();
34375 * Adds an existing {@link Roo.TabPanelItem}.
34376 * @param {Roo.TabPanelItem} item The TabPanelItem to add
34378 addTabItem : function(item){
34379 this.items[item.id] = item;
34380 this.items.push(item);
34381 // if(this.resizeTabs){
34382 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
34383 // this.autoSizeTabs();
34385 // item.autoSize();
34390 * Removes a {@link Roo.TabPanelItem}.
34391 * @param {String/Number} id The id or index of the TabPanelItem to remove.
34393 removeTab : function(id){
34394 var items = this.items;
34395 var tab = items[id];
34396 if(!tab) { return; }
34397 var index = items.indexOf(tab);
34398 if(this.active == tab && items.length > 1){
34399 var newTab = this.getNextAvailable(index);
34404 this.stripEl.dom.removeChild(tab.pnode.dom);
34405 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
34406 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
34408 items.splice(index, 1);
34409 delete this.items[tab.id];
34410 tab.fireEvent("close", tab);
34411 tab.purgeListeners();
34412 this.autoSizeTabs();
34415 getNextAvailable : function(start){
34416 var items = this.items;
34418 // look for a next tab that will slide over to
34419 // replace the one being removed
34420 while(index < items.length){
34421 var item = items[++index];
34422 if(item && !item.isHidden()){
34426 // if one isn't found select the previous tab (on the left)
34429 var item = items[--index];
34430 if(item && !item.isHidden()){
34438 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
34439 * @param {String/Number} id The id or index of the TabPanelItem to disable.
34441 disableTab : function(id){
34442 var tab = this.items[id];
34443 if(tab && this.active != tab){
34449 * Enables a {@link Roo.TabPanelItem} that is disabled.
34450 * @param {String/Number} id The id or index of the TabPanelItem to enable.
34452 enableTab : function(id){
34453 var tab = this.items[id];
34458 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
34459 * @param {String/Number} id The id or index of the TabPanelItem to activate.
34460 * @return {Roo.TabPanelItem} The TabPanelItem.
34462 activate : function(id){
34463 var tab = this.items[id];
34467 if(tab == this.active || tab.disabled){
34471 this.fireEvent("beforetabchange", this, e, tab);
34472 if(e.cancel !== true && !tab.disabled){
34474 this.active.hide();
34476 this.active = this.items[id];
34477 this.active.show();
34478 this.fireEvent("tabchange", this, this.active);
34484 * Gets the active {@link Roo.TabPanelItem}.
34485 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
34487 getActiveTab : function(){
34488 return this.active;
34492 * Updates the tab body element to fit the height of the container element
34493 * for overflow scrolling
34494 * @param {Number} targetHeight (optional) Override the starting height from the elements height
34496 syncHeight : function(targetHeight){
34497 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34498 var bm = this.bodyEl.getMargins();
34499 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
34500 this.bodyEl.setHeight(newHeight);
34504 onResize : function(){
34505 if(this.monitorResize){
34506 this.autoSizeTabs();
34511 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
34513 beginUpdate : function(){
34514 this.updating = true;
34518 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
34520 endUpdate : function(){
34521 this.updating = false;
34522 this.autoSizeTabs();
34526 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
34528 autoSizeTabs : function(){
34529 var count = this.items.length;
34530 var vcount = count - this.hiddenCount;
34531 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
34534 var w = Math.max(this.el.getWidth() - this.cpad, 10);
34535 var availWidth = Math.floor(w / vcount);
34536 var b = this.stripBody;
34537 if(b.getWidth() > w){
34538 var tabs = this.items;
34539 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
34540 if(availWidth < this.minTabWidth){
34541 /*if(!this.sleft){ // incomplete scrolling code
34542 this.createScrollButtons();
34545 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
34548 if(this.currentTabWidth < this.preferredTabWidth){
34549 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
34555 * Returns the number of tabs in this TabPanel.
34558 getCount : function(){
34559 return this.items.length;
34563 * Resizes all the tabs to the passed width
34564 * @param {Number} The new width
34566 setTabWidth : function(width){
34567 this.currentTabWidth = width;
34568 for(var i = 0, len = this.items.length; i < len; i++) {
34569 if(!this.items[i].isHidden()) {
34570 this.items[i].setWidth(width);
34576 * Destroys this TabPanel
34577 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
34579 destroy : function(removeEl){
34580 Roo.EventManager.removeResizeListener(this.onResize, this);
34581 for(var i = 0, len = this.items.length; i < len; i++){
34582 this.items[i].purgeListeners();
34584 if(removeEl === true){
34585 this.el.update("");
34590 createStrip : function(container)
34592 var strip = document.createElement("nav");
34593 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
34594 container.appendChild(strip);
34598 createStripList : function(strip)
34600 // div wrapper for retard IE
34601 // returns the "tr" element.
34602 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
34603 //'<div class="x-tabs-strip-wrap">'+
34604 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
34605 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
34606 return strip.firstChild; //.firstChild.firstChild.firstChild;
34608 createBody : function(container)
34610 var body = document.createElement("div");
34611 Roo.id(body, "tab-body");
34612 //Roo.fly(body).addClass("x-tabs-body");
34613 Roo.fly(body).addClass("tab-content");
34614 container.appendChild(body);
34617 createItemBody :function(bodyEl, id){
34618 var body = Roo.getDom(id);
34620 body = document.createElement("div");
34623 //Roo.fly(body).addClass("x-tabs-item-body");
34624 Roo.fly(body).addClass("tab-pane");
34625 bodyEl.insertBefore(body, bodyEl.firstChild);
34629 createStripElements : function(stripEl, text, closable)
34631 var td = document.createElement("li"); // was td..
34632 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
34633 //stripEl.appendChild(td);
34635 td.className = "x-tabs-closable";
34636 if(!this.closeTpl){
34637 this.closeTpl = new Roo.Template(
34638 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34639 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
34640 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
34643 var el = this.closeTpl.overwrite(td, {"text": text});
34644 var close = el.getElementsByTagName("div")[0];
34645 var inner = el.getElementsByTagName("em")[0];
34646 return {"el": el, "close": close, "inner": inner};
34649 // not sure what this is..
34651 //this.tabTpl = new Roo.Template(
34652 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34653 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
34655 this.tabTpl = new Roo.Template(
34657 '<span unselectable="on"' +
34658 (this.disableTooltips ? '' : ' title="{text}"') +
34659 ' >{text}</span></span></a>'
34663 var el = this.tabTpl.overwrite(td, {"text": text});
34664 var inner = el.getElementsByTagName("span")[0];
34665 return {"el": el, "inner": inner};
34673 * @class Roo.TabPanelItem
34674 * @extends Roo.util.Observable
34675 * Represents an individual item (tab plus body) in a TabPanel.
34676 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
34677 * @param {String} id The id of this TabPanelItem
34678 * @param {String} text The text for the tab of this TabPanelItem
34679 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
34681 Roo.bootstrap.panel.TabItem = function(config){
34683 * The {@link Roo.TabPanel} this TabPanelItem belongs to
34684 * @type Roo.TabPanel
34686 this.tabPanel = config.panel;
34688 * The id for this TabPanelItem
34691 this.id = config.id;
34693 this.disabled = false;
34695 this.text = config.text;
34697 this.loaded = false;
34698 this.closable = config.closable;
34701 * The body element for this TabPanelItem.
34702 * @type Roo.Element
34704 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
34705 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
34706 this.bodyEl.setStyle("display", "block");
34707 this.bodyEl.setStyle("zoom", "1");
34708 //this.hideAction();
34710 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
34712 this.el = Roo.get(els.el);
34713 this.inner = Roo.get(els.inner, true);
34714 this.textEl = Roo.get(this.el.dom.firstChild, true);
34715 this.pnode = Roo.get(els.el.parentNode, true);
34716 this.el.on("mousedown", this.onTabMouseDown, this);
34717 this.el.on("click", this.onTabClick, this);
34719 if(config.closable){
34720 var c = Roo.get(els.close, true);
34721 c.dom.title = this.closeText;
34722 c.addClassOnOver("close-over");
34723 c.on("click", this.closeClick, this);
34729 * Fires when this tab becomes the active tab.
34730 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34731 * @param {Roo.TabPanelItem} this
34735 * @event beforeclose
34736 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
34737 * @param {Roo.TabPanelItem} this
34738 * @param {Object} e Set cancel to true on this object to cancel the close.
34740 "beforeclose": true,
34743 * Fires when this tab is closed.
34744 * @param {Roo.TabPanelItem} this
34748 * @event deactivate
34749 * Fires when this tab is no longer the active tab.
34750 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34751 * @param {Roo.TabPanelItem} this
34753 "deactivate" : true
34755 this.hidden = false;
34757 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
34760 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
34762 purgeListeners : function(){
34763 Roo.util.Observable.prototype.purgeListeners.call(this);
34764 this.el.removeAllListeners();
34767 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
34770 this.pnode.addClass("active");
34773 this.tabPanel.stripWrap.repaint();
34775 this.fireEvent("activate", this.tabPanel, this);
34779 * Returns true if this tab is the active tab.
34780 * @return {Boolean}
34782 isActive : function(){
34783 return this.tabPanel.getActiveTab() == this;
34787 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
34790 this.pnode.removeClass("active");
34792 this.fireEvent("deactivate", this.tabPanel, this);
34795 hideAction : function(){
34796 this.bodyEl.hide();
34797 this.bodyEl.setStyle("position", "absolute");
34798 this.bodyEl.setLeft("-20000px");
34799 this.bodyEl.setTop("-20000px");
34802 showAction : function(){
34803 this.bodyEl.setStyle("position", "relative");
34804 this.bodyEl.setTop("");
34805 this.bodyEl.setLeft("");
34806 this.bodyEl.show();
34810 * Set the tooltip for the tab.
34811 * @param {String} tooltip The tab's tooltip
34813 setTooltip : function(text){
34814 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
34815 this.textEl.dom.qtip = text;
34816 this.textEl.dom.removeAttribute('title');
34818 this.textEl.dom.title = text;
34822 onTabClick : function(e){
34823 e.preventDefault();
34824 this.tabPanel.activate(this.id);
34827 onTabMouseDown : function(e){
34828 e.preventDefault();
34829 this.tabPanel.activate(this.id);
34832 getWidth : function(){
34833 return this.inner.getWidth();
34836 setWidth : function(width){
34837 var iwidth = width - this.pnode.getPadding("lr");
34838 this.inner.setWidth(iwidth);
34839 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
34840 this.pnode.setWidth(width);
34844 * Show or hide the tab
34845 * @param {Boolean} hidden True to hide or false to show.
34847 setHidden : function(hidden){
34848 this.hidden = hidden;
34849 this.pnode.setStyle("display", hidden ? "none" : "");
34853 * Returns true if this tab is "hidden"
34854 * @return {Boolean}
34856 isHidden : function(){
34857 return this.hidden;
34861 * Returns the text for this tab
34864 getText : function(){
34868 autoSize : function(){
34869 //this.el.beginMeasure();
34870 this.textEl.setWidth(1);
34872 * #2804 [new] Tabs in Roojs
34873 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
34875 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
34876 //this.el.endMeasure();
34880 * Sets the text for the tab (Note: this also sets the tooltip text)
34881 * @param {String} text The tab's text and tooltip
34883 setText : function(text){
34885 this.textEl.update(text);
34886 this.setTooltip(text);
34887 //if(!this.tabPanel.resizeTabs){
34888 // this.autoSize();
34892 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
34894 activate : function(){
34895 this.tabPanel.activate(this.id);
34899 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
34901 disable : function(){
34902 if(this.tabPanel.active != this){
34903 this.disabled = true;
34904 this.pnode.addClass("disabled");
34909 * Enables this TabPanelItem if it was previously disabled.
34911 enable : function(){
34912 this.disabled = false;
34913 this.pnode.removeClass("disabled");
34917 * Sets the content for this TabPanelItem.
34918 * @param {String} content The content
34919 * @param {Boolean} loadScripts true to look for and load scripts
34921 setContent : function(content, loadScripts){
34922 this.bodyEl.update(content, loadScripts);
34926 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
34927 * @return {Roo.UpdateManager} The UpdateManager
34929 getUpdateManager : function(){
34930 return this.bodyEl.getUpdateManager();
34934 * Set a URL to be used to load the content for this TabPanelItem.
34935 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
34936 * @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)
34937 * @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)
34938 * @return {Roo.UpdateManager} The UpdateManager
34940 setUrl : function(url, params, loadOnce){
34941 if(this.refreshDelegate){
34942 this.un('activate', this.refreshDelegate);
34944 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34945 this.on("activate", this.refreshDelegate);
34946 return this.bodyEl.getUpdateManager();
34950 _handleRefresh : function(url, params, loadOnce){
34951 if(!loadOnce || !this.loaded){
34952 var updater = this.bodyEl.getUpdateManager();
34953 updater.update(url, params, this._setLoaded.createDelegate(this));
34958 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
34959 * Will fail silently if the setUrl method has not been called.
34960 * This does not activate the panel, just updates its content.
34962 refresh : function(){
34963 if(this.refreshDelegate){
34964 this.loaded = false;
34965 this.refreshDelegate();
34970 _setLoaded : function(){
34971 this.loaded = true;
34975 closeClick : function(e){
34978 this.fireEvent("beforeclose", this, o);
34979 if(o.cancel !== true){
34980 this.tabPanel.removeTab(this.id);
34984 * The text displayed in the tooltip for the close icon.
34987 closeText : "Close this tab"