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);
1518 * Sets the url of the image - used to update it
1519 * @param {String} url the url of the image
1522 setSrc : function(url)
1525 this.el.select('img', true).first().dom.src = url;
1541 * @class Roo.bootstrap.Link
1542 * @extends Roo.bootstrap.Component
1543 * Bootstrap Link Class
1544 * @cfg {String} alt image alternative text
1545 * @cfg {String} href a tag href
1546 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1547 * @cfg {String} html the content of the link.
1548 * @cfg {String} anchor name for the anchor link
1549 * @cfg {String} fa - favicon
1551 * @cfg {Boolean} preventDefault (true | false) default false
1555 * Create a new Input
1556 * @param {Object} config The config object
1559 Roo.bootstrap.Link = function(config){
1560 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1566 * The img click event for the img.
1567 * @param {Roo.EventObject} e
1573 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1577 preventDefault: false,
1583 getAutoCreate : function()
1585 var html = this.html || '';
1587 if (this.fa !== false) {
1588 html = '<i class="fa fa-' + this.fa + '"></i>';
1593 // anchor's do not require html/href...
1594 if (this.anchor === false) {
1596 cfg.href = this.href || '#';
1598 cfg.name = this.anchor;
1599 if (this.html !== false || this.fa !== false) {
1602 if (this.href !== false) {
1603 cfg.href = this.href;
1607 if(this.alt !== false){
1612 if(this.target !== false) {
1613 cfg.target = this.target;
1619 initEvents: function() {
1621 if(!this.href || this.preventDefault){
1622 this.el.on('click', this.onClick, this);
1626 onClick : function(e)
1628 if(this.preventDefault){
1631 //Roo.log('img onclick');
1632 this.fireEvent('click', this, e);
1645 * @class Roo.bootstrap.Header
1646 * @extends Roo.bootstrap.Component
1647 * Bootstrap Header class
1648 * @cfg {String} html content of header
1649 * @cfg {Number} level (1|2|3|4|5|6) default 1
1652 * Create a new Header
1653 * @param {Object} config The config object
1657 Roo.bootstrap.Header = function(config){
1658 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1661 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1669 getAutoCreate : function(){
1674 tag: 'h' + (1 *this.level),
1675 html: this.html || ''
1687 * Ext JS Library 1.1.1
1688 * Copyright(c) 2006-2007, Ext JS, LLC.
1690 * Originally Released Under LGPL - original licence link has changed is not relivant.
1693 * <script type="text/javascript">
1697 * @class Roo.bootstrap.MenuMgr
1698 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1701 Roo.bootstrap.MenuMgr = function(){
1702 var menus, active, groups = {}, attached = false, lastShow = new Date();
1704 // private - called when first menu is created
1707 active = new Roo.util.MixedCollection();
1708 Roo.get(document).addKeyListener(27, function(){
1709 if(active.length > 0){
1717 if(active && active.length > 0){
1718 var c = active.clone();
1728 if(active.length < 1){
1729 Roo.get(document).un("mouseup", onMouseDown);
1737 var last = active.last();
1738 lastShow = new Date();
1741 Roo.get(document).on("mouseup", onMouseDown);
1746 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1747 m.parentMenu.activeChild = m;
1748 }else if(last && last.isVisible()){
1749 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1754 function onBeforeHide(m){
1756 m.activeChild.hide();
1758 if(m.autoHideTimer){
1759 clearTimeout(m.autoHideTimer);
1760 delete m.autoHideTimer;
1765 function onBeforeShow(m){
1766 var pm = m.parentMenu;
1767 if(!pm && !m.allowOtherMenus){
1769 }else if(pm && pm.activeChild && active != m){
1770 pm.activeChild.hide();
1774 // private this should really trigger on mouseup..
1775 function onMouseDown(e){
1776 Roo.log("on Mouse Up");
1778 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1779 Roo.log("MenuManager hideAll");
1788 function onBeforeCheck(mi, state){
1790 var g = groups[mi.group];
1791 for(var i = 0, l = g.length; i < l; i++){
1793 g[i].setChecked(false);
1802 * Hides all menus that are currently visible
1804 hideAll : function(){
1809 register : function(menu){
1813 menus[menu.id] = menu;
1814 menu.on("beforehide", onBeforeHide);
1815 menu.on("hide", onHide);
1816 menu.on("beforeshow", onBeforeShow);
1817 menu.on("show", onShow);
1819 if(g && menu.events["checkchange"]){
1823 groups[g].push(menu);
1824 menu.on("checkchange", onCheck);
1829 * Returns a {@link Roo.menu.Menu} object
1830 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1831 * be used to generate and return a new Menu instance.
1833 get : function(menu){
1834 if(typeof menu == "string"){ // menu id
1836 }else if(menu.events){ // menu instance
1839 /*else if(typeof menu.length == 'number'){ // array of menu items?
1840 return new Roo.bootstrap.Menu({items:menu});
1841 }else{ // otherwise, must be a config
1842 return new Roo.bootstrap.Menu(menu);
1849 unregister : function(menu){
1850 delete menus[menu.id];
1851 menu.un("beforehide", onBeforeHide);
1852 menu.un("hide", onHide);
1853 menu.un("beforeshow", onBeforeShow);
1854 menu.un("show", onShow);
1856 if(g && menu.events["checkchange"]){
1857 groups[g].remove(menu);
1858 menu.un("checkchange", onCheck);
1863 registerCheckable : function(menuItem){
1864 var g = menuItem.group;
1869 groups[g].push(menuItem);
1870 menuItem.on("beforecheckchange", onBeforeCheck);
1875 unregisterCheckable : function(menuItem){
1876 var g = menuItem.group;
1878 groups[g].remove(menuItem);
1879 menuItem.un("beforecheckchange", onBeforeCheck);
1891 * @class Roo.bootstrap.Menu
1892 * @extends Roo.bootstrap.Component
1893 * Bootstrap Menu class - container for MenuItems
1894 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1895 * @cfg {bool} hidden if the menu should be hidden when rendered.
1896 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1897 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1901 * @param {Object} config The config object
1905 Roo.bootstrap.Menu = function(config){
1906 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1907 if (this.registerMenu && this.type != 'treeview') {
1908 Roo.bootstrap.MenuMgr.register(this);
1913 * Fires before this menu is displayed
1914 * @param {Roo.menu.Menu} this
1919 * Fires before this menu is hidden
1920 * @param {Roo.menu.Menu} this
1925 * Fires after this menu is displayed
1926 * @param {Roo.menu.Menu} this
1931 * Fires after this menu is hidden
1932 * @param {Roo.menu.Menu} this
1937 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1938 * @param {Roo.menu.Menu} this
1939 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1940 * @param {Roo.EventObject} e
1945 * Fires when the mouse is hovering over this menu
1946 * @param {Roo.menu.Menu} this
1947 * @param {Roo.EventObject} e
1948 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1953 * Fires when the mouse exits this menu
1954 * @param {Roo.menu.Menu} this
1955 * @param {Roo.EventObject} e
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1961 * Fires when a menu item contained in this menu is clicked
1962 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1963 * @param {Roo.EventObject} e
1967 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1970 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1974 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1977 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1979 registerMenu : true,
1981 menuItems :false, // stores the menu items..
1991 getChildContainer : function() {
1995 getAutoCreate : function(){
1997 //if (['right'].indexOf(this.align)!==-1) {
1998 // cfg.cn[1].cls += ' pull-right'
2004 cls : 'dropdown-menu' ,
2005 style : 'z-index:1000'
2009 if (this.type === 'submenu') {
2010 cfg.cls = 'submenu active';
2012 if (this.type === 'treeview') {
2013 cfg.cls = 'treeview-menu';
2018 initEvents : function() {
2020 // Roo.log("ADD event");
2021 // Roo.log(this.triggerEl.dom);
2023 this.triggerEl.on('click', this.onTriggerClick, this);
2025 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2027 this.triggerEl.addClass('dropdown-toggle');
2030 this.el.on('touchstart' , this.onTouch, this);
2032 this.el.on('click' , this.onClick, this);
2034 this.el.on("mouseover", this.onMouseOver, this);
2035 this.el.on("mouseout", this.onMouseOut, this);
2039 findTargetItem : function(e)
2041 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2045 //Roo.log(t); Roo.log(t.id);
2047 //Roo.log(this.menuitems);
2048 return this.menuitems.get(t.id);
2050 //return this.items.get(t.menuItemId);
2056 onTouch : function(e)
2058 Roo.log("menu.onTouch");
2059 //e.stopEvent(); this make the user popdown broken
2063 onClick : function(e)
2065 Roo.log("menu.onClick");
2067 var t = this.findTargetItem(e);
2068 if(!t || t.isContainer){
2073 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2074 if(t == this.activeItem && t.shouldDeactivate(e)){
2075 this.activeItem.deactivate();
2076 delete this.activeItem;
2080 this.setActiveItem(t, true);
2088 Roo.log('pass click event');
2092 this.fireEvent("click", this, t, e);
2096 (function() { _this.hide(); }).defer(500);
2099 onMouseOver : function(e){
2100 var t = this.findTargetItem(e);
2103 // if(t.canActivate && !t.disabled){
2104 // this.setActiveItem(t, true);
2108 this.fireEvent("mouseover", this, e, t);
2110 isVisible : function(){
2111 return !this.hidden;
2113 onMouseOut : function(e){
2114 var t = this.findTargetItem(e);
2117 // if(t == this.activeItem && t.shouldDeactivate(e)){
2118 // this.activeItem.deactivate();
2119 // delete this.activeItem;
2122 this.fireEvent("mouseout", this, e, t);
2127 * Displays this menu relative to another element
2128 * @param {String/HTMLElement/Roo.Element} element The element to align to
2129 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2130 * the element (defaults to this.defaultAlign)
2131 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2133 show : function(el, pos, parentMenu){
2134 this.parentMenu = parentMenu;
2138 this.fireEvent("beforeshow", this);
2139 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2142 * Displays this menu at a specific xy position
2143 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2144 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2146 showAt : function(xy, parentMenu, /* private: */_e){
2147 this.parentMenu = parentMenu;
2152 this.fireEvent("beforeshow", this);
2153 //xy = this.el.adjustForConstraints(xy);
2157 this.hideMenuItems();
2158 this.hidden = false;
2159 this.triggerEl.addClass('open');
2161 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2162 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2165 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2170 this.fireEvent("show", this);
2176 this.doFocus.defer(50, this);
2180 doFocus : function(){
2182 this.focusEl.focus();
2187 * Hides this menu and optionally all parent menus
2188 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2190 hide : function(deep)
2193 this.hideMenuItems();
2194 if(this.el && this.isVisible()){
2195 this.fireEvent("beforehide", this);
2196 if(this.activeItem){
2197 this.activeItem.deactivate();
2198 this.activeItem = null;
2200 this.triggerEl.removeClass('open');;
2202 this.fireEvent("hide", this);
2204 if(deep === true && this.parentMenu){
2205 this.parentMenu.hide(true);
2209 onTriggerClick : function(e)
2211 Roo.log('trigger click');
2213 var target = e.getTarget();
2215 Roo.log(target.nodeName.toLowerCase());
2217 if(target.nodeName.toLowerCase() === 'i'){
2223 onTriggerPress : function(e)
2225 Roo.log('trigger press');
2226 //Roo.log(e.getTarget());
2227 // Roo.log(this.triggerEl.dom);
2229 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2230 var pel = Roo.get(e.getTarget());
2231 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2232 Roo.log('is treeview or dropdown?');
2236 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2240 if (this.isVisible()) {
2245 this.show(this.triggerEl, false, false);
2248 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2255 hideMenuItems : function()
2257 Roo.log("hide Menu Items");
2261 //$(backdrop).remove()
2262 this.el.select('.open',true).each(function(aa) {
2264 aa.removeClass('open');
2265 //var parent = getParent($(this))
2266 //var relatedTarget = { relatedTarget: this }
2268 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2269 //if (e.isDefaultPrevented()) return
2270 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2273 addxtypeChild : function (tree, cntr) {
2274 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2276 this.menuitems.add(comp);
2297 * @class Roo.bootstrap.MenuItem
2298 * @extends Roo.bootstrap.Component
2299 * Bootstrap MenuItem class
2300 * @cfg {String} html the menu label
2301 * @cfg {String} href the link
2302 * @cfg {Boolean} preventDefault do not trigger A href on clicks.
2303 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2304 * @cfg {Boolean} active used on sidebars to highlight active itesm
2305 * @cfg {String} fa favicon to show on left of menu item.
2306 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2310 * Create a new MenuItem
2311 * @param {Object} config The config object
2315 Roo.bootstrap.MenuItem = function(config){
2316 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2321 * The raw click event for the entire grid.
2322 * @param {Roo.bootstrap.MenuItem} this
2323 * @param {Roo.EventObject} e
2329 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2333 preventDefault: true,
2334 isContainer : false,
2338 getAutoCreate : function(){
2340 if(this.isContainer){
2343 cls: 'dropdown-menu-item'
2357 if (this.fa !== false) {
2360 cls : 'fa fa-' + this.fa
2369 cls: 'dropdown-menu-item',
2372 if (this.parent().type == 'treeview') {
2373 cfg.cls = 'treeview-menu';
2376 cfg.cls += ' active';
2381 anc.href = this.href || cfg.cn[0].href ;
2382 ctag.html = this.html || cfg.cn[0].html ;
2386 initEvents: function()
2388 if (this.parent().type == 'treeview') {
2389 this.el.select('a').on('click', this.onClick, this);
2392 this.menu.parentType = this.xtype;
2393 this.menu.triggerEl = this.el;
2394 this.menu = this.addxtype(Roo.apply({}, this.menu));
2398 onClick : function(e)
2400 Roo.log('item on click ');
2401 //if(this.preventDefault){
2402 // e.preventDefault();
2404 //this.parent().hideMenuItems();
2406 this.fireEvent('click', this, e);
2425 * @class Roo.bootstrap.MenuSeparator
2426 * @extends Roo.bootstrap.Component
2427 * Bootstrap MenuSeparator class
2430 * Create a new MenuItem
2431 * @param {Object} config The config object
2435 Roo.bootstrap.MenuSeparator = function(config){
2436 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2439 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2441 getAutoCreate : function(){
2460 * @class Roo.bootstrap.Modal
2461 * @extends Roo.bootstrap.Component
2462 * Bootstrap Modal class
2463 * @cfg {String} title Title of dialog
2464 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2465 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2466 * @cfg {Boolean} specificTitle default false
2467 * @cfg {Array} buttons Array of buttons or standard button set..
2468 * @cfg {String} buttonPosition (left|right|center) default right
2469 * @cfg {Boolean} animate default true
2470 * @cfg {Boolean} allow_close default true
2471 * @cfg {Boolean} fitwindow default false
2472 * @cfg {String} size (sm|lg) default empty
2476 * Create a new Modal Dialog
2477 * @param {Object} config The config object
2480 Roo.bootstrap.Modal = function(config){
2481 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2486 * The raw btnclick event for the button
2487 * @param {Roo.EventObject} e
2491 this.buttons = this.buttons || [];
2494 this.tmpl = Roo.factory(this.tmpl);
2499 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2501 title : 'test dialog',
2511 specificTitle: false,
2513 buttonPosition: 'right',
2532 onRender : function(ct, position)
2534 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2537 var cfg = Roo.apply({}, this.getAutoCreate());
2540 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2542 //if (!cfg.name.length) {
2546 cfg.cls += ' ' + this.cls;
2549 cfg.style = this.style;
2551 this.el = Roo.get(document.body).createChild(cfg, position);
2553 //var type = this.el.dom.type;
2556 if(this.tabIndex !== undefined){
2557 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2560 this.dialogEl = this.el.select('.modal-dialog',true).first();
2561 this.bodyEl = this.el.select('.modal-body',true).first();
2562 this.closeEl = this.el.select('.modal-header .close', true).first();
2563 this.footerEl = this.el.select('.modal-footer',true).first();
2564 this.titleEl = this.el.select('.modal-title',true).first();
2568 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2569 this.maskEl.enableDisplayMode("block");
2571 //this.el.addClass("x-dlg-modal");
2573 if (this.buttons.length) {
2574 Roo.each(this.buttons, function(bb) {
2575 var b = Roo.apply({}, bb);
2576 b.xns = b.xns || Roo.bootstrap;
2577 b.xtype = b.xtype || 'Button';
2578 if (typeof(b.listeners) == 'undefined') {
2579 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2582 var btn = Roo.factory(b);
2584 btn.render(this.el.select('.modal-footer div').first());
2588 // render the children.
2591 if(typeof(this.items) != 'undefined'){
2592 var items = this.items;
2595 for(var i =0;i < items.length;i++) {
2596 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2600 this.items = nitems;
2602 // where are these used - they used to be body/close/footer
2606 //this.el.addClass([this.fieldClass, this.cls]);
2610 getAutoCreate : function(){
2615 html : this.html || ''
2620 cls : 'modal-title',
2624 if(this.specificTitle){
2630 if (this.allow_close) {
2642 if(this.size.length){
2643 size = 'modal-' + this.size;
2648 style : 'display: none',
2651 cls: "modal-dialog " + size,
2654 cls : "modal-content",
2657 cls : 'modal-header',
2662 cls : 'modal-footer',
2666 cls: 'btn-' + this.buttonPosition
2683 modal.cls += ' fade';
2689 getChildContainer : function() {
2694 getButtonContainer : function() {
2695 return this.el.select('.modal-footer div',true).first();
2698 initEvents : function()
2700 if (this.allow_close) {
2701 this.closeEl.on('click', this.hide, this);
2703 Roo.EventManager.onWindowResize(this.resize, this, true);
2710 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2711 if (this.fitwindow) {
2712 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2713 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2718 setSize : function(w,h)
2728 if (!this.rendered) {
2732 this.el.setStyle('display', 'block');
2734 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2737 this.el.addClass('in');
2740 this.el.addClass('in');
2744 // not sure how we can show data in here..
2746 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2749 Roo.get(document.body).addClass("x-body-masked");
2750 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2752 this.el.setStyle('zIndex', '10001');
2754 this.fireEvent('show', this);
2759 this.items.forEach( function(e) {
2760 e.layout ? e.layout() : false;
2769 Roo.get(document.body).removeClass("x-body-masked");
2770 this.el.removeClass('in');
2771 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2773 if(this.animate){ // why
2775 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2777 this.el.setStyle('display', 'none');
2780 this.fireEvent('hide', this);
2783 addButton : function(str, cb)
2787 var b = Roo.apply({}, { html : str } );
2788 b.xns = b.xns || Roo.bootstrap;
2789 b.xtype = b.xtype || 'Button';
2790 if (typeof(b.listeners) == 'undefined') {
2791 b.listeners = { click : cb.createDelegate(this) };
2794 var btn = Roo.factory(b);
2796 btn.render(this.el.select('.modal-footer div').first());
2802 setDefaultButton : function(btn)
2804 //this.el.select('.modal-footer').()
2808 resizeTo: function(w,h)
2812 this.dialogEl.setWidth(w);
2813 if (this.diff === false) {
2814 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2817 this.bodyEl.setHeight(h-this.diff);
2821 setContentSize : function(w, h)
2825 onButtonClick: function(btn,e)
2828 this.fireEvent('btnclick', btn.name, e);
2831 * Set the title of the Dialog
2832 * @param {String} str new Title
2834 setTitle: function(str) {
2835 this.titleEl.dom.innerHTML = str;
2838 * Set the body of the Dialog
2839 * @param {String} str new Title
2841 setBody: function(str) {
2842 this.bodyEl.dom.innerHTML = str;
2845 * Set the body of the Dialog using the template
2846 * @param {Obj} data - apply this data to the template and replace the body contents.
2848 applyBody: function(obj)
2851 Roo.log("Error - using apply Body without a template");
2854 this.tmpl.overwrite(this.bodyEl, obj);
2860 Roo.apply(Roo.bootstrap.Modal, {
2862 * Button config that displays a single OK button
2871 * Button config that displays Yes and No buttons
2887 * Button config that displays OK and Cancel buttons
2902 * Button config that displays Yes, No and Cancel buttons
2925 * messagebox - can be used as a replace
2929 * @class Roo.MessageBox
2930 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2934 Roo.Msg.alert('Status', 'Changes saved successfully.');
2936 // Prompt for user data:
2937 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2939 // process text value...
2943 // Show a dialog using config options:
2945 title:'Save Changes?',
2946 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2947 buttons: Roo.Msg.YESNOCANCEL,
2954 Roo.bootstrap.MessageBox = function(){
2955 var dlg, opt, mask, waitTimer;
2956 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2957 var buttons, activeTextEl, bwidth;
2961 var handleButton = function(button){
2963 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2967 var handleHide = function(){
2969 dlg.el.removeClass(opt.cls);
2972 // Roo.TaskMgr.stop(waitTimer);
2973 // waitTimer = null;
2978 var updateButtons = function(b){
2981 buttons["ok"].hide();
2982 buttons["cancel"].hide();
2983 buttons["yes"].hide();
2984 buttons["no"].hide();
2985 //dlg.footer.dom.style.display = 'none';
2988 dlg.footerEl.dom.style.display = '';
2989 for(var k in buttons){
2990 if(typeof buttons[k] != "function"){
2993 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2994 width += buttons[k].el.getWidth()+15;
3004 var handleEsc = function(d, k, e){
3005 if(opt && opt.closable !== false){
3015 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3016 * @return {Roo.BasicDialog} The BasicDialog element
3018 getDialog : function(){
3020 dlg = new Roo.bootstrap.Modal( {
3023 //constraintoviewport:false,
3025 //collapsible : false,
3030 //buttonAlign:"center",
3031 closeClick : function(){
3032 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3035 handleButton("cancel");
3040 dlg.on("hide", handleHide);
3042 //dlg.addKeyListener(27, handleEsc);
3044 this.buttons = buttons;
3045 var bt = this.buttonText;
3046 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3047 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3048 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3049 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3051 bodyEl = dlg.bodyEl.createChild({
3053 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3054 '<textarea class="roo-mb-textarea"></textarea>' +
3055 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3057 msgEl = bodyEl.dom.firstChild;
3058 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3059 textboxEl.enableDisplayMode();
3060 textboxEl.addKeyListener([10,13], function(){
3061 if(dlg.isVisible() && opt && opt.buttons){
3064 }else if(opt.buttons.yes){
3065 handleButton("yes");
3069 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3070 textareaEl.enableDisplayMode();
3071 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3072 progressEl.enableDisplayMode();
3073 var pf = progressEl.dom.firstChild;
3075 pp = Roo.get(pf.firstChild);
3076 pp.setHeight(pf.offsetHeight);
3084 * Updates the message box body text
3085 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3086 * the XHTML-compliant non-breaking space character '&#160;')
3087 * @return {Roo.MessageBox} This message box
3089 updateText : function(text){
3090 if(!dlg.isVisible() && !opt.width){
3091 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3093 msgEl.innerHTML = text || ' ';
3095 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3096 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3098 Math.min(opt.width || cw , this.maxWidth),
3099 Math.max(opt.minWidth || this.minWidth, bwidth)
3102 activeTextEl.setWidth(w);
3104 if(dlg.isVisible()){
3105 dlg.fixedcenter = false;
3107 // to big, make it scroll. = But as usual stupid IE does not support
3110 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3111 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3112 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3114 bodyEl.dom.style.height = '';
3115 bodyEl.dom.style.overflowY = '';
3118 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3120 bodyEl.dom.style.overflowX = '';
3123 dlg.setContentSize(w, bodyEl.getHeight());
3124 if(dlg.isVisible()){
3125 dlg.fixedcenter = true;
3131 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3132 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3133 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3134 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3135 * @return {Roo.MessageBox} This message box
3137 updateProgress : function(value, text){
3139 this.updateText(text);
3141 if (pp) { // weird bug on my firefox - for some reason this is not defined
3142 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3148 * Returns true if the message box is currently displayed
3149 * @return {Boolean} True if the message box is visible, else false
3151 isVisible : function(){
3152 return dlg && dlg.isVisible();
3156 * Hides the message box if it is displayed
3159 if(this.isVisible()){
3165 * Displays a new message box, or reinitializes an existing message box, based on the config options
3166 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3167 * The following config object properties are supported:
3169 Property Type Description
3170 ---------- --------------- ------------------------------------------------------------------------------------
3171 animEl String/Element An id or Element from which the message box should animate as it opens and
3172 closes (defaults to undefined)
3173 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3174 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3175 closable Boolean False to hide the top-right close button (defaults to true). Note that
3176 progress and wait dialogs will ignore this property and always hide the
3177 close button as they can only be closed programmatically.
3178 cls String A custom CSS class to apply to the message box element
3179 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3180 displayed (defaults to 75)
3181 fn Function A callback function to execute after closing the dialog. The arguments to the
3182 function will be btn (the name of the button that was clicked, if applicable,
3183 e.g. "ok"), and text (the value of the active text field, if applicable).
3184 Progress and wait dialogs will ignore this option since they do not respond to
3185 user actions and can only be closed programmatically, so any required function
3186 should be called by the same code after it closes the dialog.
3187 icon String A CSS class that provides a background image to be used as an icon for
3188 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3189 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3190 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3191 modal Boolean False to allow user interaction with the page while the message box is
3192 displayed (defaults to true)
3193 msg String A string that will replace the existing message box body text (defaults
3194 to the XHTML-compliant non-breaking space character ' ')
3195 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3196 progress Boolean True to display a progress bar (defaults to false)
3197 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3198 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3199 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3200 title String The title text
3201 value String The string value to set into the active textbox element if displayed
3202 wait Boolean True to display a progress bar (defaults to false)
3203 width Number The width of the dialog in pixels
3210 msg: 'Please enter your address:',
3212 buttons: Roo.MessageBox.OKCANCEL,
3215 animEl: 'addAddressBtn'
3218 * @param {Object} config Configuration options
3219 * @return {Roo.MessageBox} This message box
3221 show : function(options)
3224 // this causes nightmares if you show one dialog after another
3225 // especially on callbacks..
3227 if(this.isVisible()){
3230 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3231 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3232 Roo.log("New Dialog Message:" + options.msg )
3233 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3234 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3237 var d = this.getDialog();
3239 d.setTitle(opt.title || " ");
3240 d.closeEl.setDisplayed(opt.closable !== false);
3241 activeTextEl = textboxEl;
3242 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3247 textareaEl.setHeight(typeof opt.multiline == "number" ?
3248 opt.multiline : this.defaultTextHeight);
3249 activeTextEl = textareaEl;
3258 progressEl.setDisplayed(opt.progress === true);
3259 this.updateProgress(0);
3260 activeTextEl.dom.value = opt.value || "";
3262 dlg.setDefaultButton(activeTextEl);
3264 var bs = opt.buttons;
3268 }else if(bs && bs.yes){
3269 db = buttons["yes"];
3271 dlg.setDefaultButton(db);
3273 bwidth = updateButtons(opt.buttons);
3274 this.updateText(opt.msg);
3276 d.el.addClass(opt.cls);
3278 d.proxyDrag = opt.proxyDrag === true;
3279 d.modal = opt.modal !== false;
3280 d.mask = opt.modal !== false ? mask : false;
3282 // force it to the end of the z-index stack so it gets a cursor in FF
3283 document.body.appendChild(dlg.el.dom);
3284 d.animateTarget = null;
3285 d.show(options.animEl);
3291 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3292 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3293 * and closing the message box when the process is complete.
3294 * @param {String} title The title bar text
3295 * @param {String} msg The message box body text
3296 * @return {Roo.MessageBox} This message box
3298 progress : function(title, msg){
3305 minWidth: this.minProgressWidth,
3312 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3313 * If a callback function is passed it will be called after the user clicks the button, and the
3314 * id of the button that was clicked will be passed as the only parameter to the callback
3315 * (could also be the top-right close button).
3316 * @param {String} title The title bar text
3317 * @param {String} msg The message box body text
3318 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3319 * @param {Object} scope (optional) The scope of the callback function
3320 * @return {Roo.MessageBox} This message box
3322 alert : function(title, msg, fn, scope){
3335 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3336 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3337 * You are responsible for closing the message box when the process is complete.
3338 * @param {String} msg The message box body text
3339 * @param {String} title (optional) The title bar text
3340 * @return {Roo.MessageBox} This message box
3342 wait : function(msg, title){
3353 waitTimer = Roo.TaskMgr.start({
3355 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3363 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3364 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3365 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
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 * @return {Roo.MessageBox} This message box
3372 confirm : function(title, msg, fn, scope){
3376 buttons: this.YESNO,
3385 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3386 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3387 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3388 * (could also be the top-right close button) and the text that was entered will be passed as the two
3389 * parameters to the callback.
3390 * @param {String} title The title bar text
3391 * @param {String} msg The message box body text
3392 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3393 * @param {Object} scope (optional) The scope of the callback function
3394 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3395 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3396 * @return {Roo.MessageBox} This message box
3398 prompt : function(title, msg, fn, scope, multiline){
3402 buttons: this.OKCANCEL,
3407 multiline: multiline,
3414 * Button config that displays a single OK button
3419 * Button config that displays Yes and No buttons
3422 YESNO : {yes:true, no:true},
3424 * Button config that displays OK and Cancel buttons
3427 OKCANCEL : {ok:true, cancel:true},
3429 * Button config that displays Yes, No and Cancel buttons
3432 YESNOCANCEL : {yes:true, no:true, cancel:true},
3435 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3438 defaultTextHeight : 75,
3440 * The maximum width in pixels of the message box (defaults to 600)
3445 * The minimum width in pixels of the message box (defaults to 100)
3450 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3451 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3454 minProgressWidth : 250,
3456 * An object containing the default button text strings that can be overriden for localized language support.
3457 * Supported properties are: ok, cancel, yes and no.
3458 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3471 * Shorthand for {@link Roo.MessageBox}
3473 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3474 Roo.Msg = Roo.Msg || Roo.MessageBox;
3483 * @class Roo.bootstrap.Navbar
3484 * @extends Roo.bootstrap.Component
3485 * Bootstrap Navbar class
3488 * Create a new Navbar
3489 * @param {Object} config The config object
3493 Roo.bootstrap.Navbar = function(config){
3494 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3498 * @event beforetoggle
3499 * Fire before toggle the menu
3500 * @param {Roo.EventObject} e
3502 "beforetoggle" : true
3506 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3515 getAutoCreate : function(){
3518 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3522 initEvents :function ()
3524 //Roo.log(this.el.select('.navbar-toggle',true));
3525 this.el.select('.navbar-toggle',true).on('click', function() {
3526 if(this.fireEvent('beforetoggle', this) !== false){
3527 this.el.select('.navbar-collapse',true).toggleClass('in');
3537 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3539 var size = this.el.getSize();
3540 this.maskEl.setSize(size.width, size.height);
3541 this.maskEl.enableDisplayMode("block");
3550 getChildContainer : function()
3552 if (this.el.select('.collapse').getCount()) {
3553 return this.el.select('.collapse',true).first();
3586 * @class Roo.bootstrap.NavSimplebar
3587 * @extends Roo.bootstrap.Navbar
3588 * Bootstrap Sidebar class
3590 * @cfg {Boolean} inverse is inverted color
3592 * @cfg {String} type (nav | pills | tabs)
3593 * @cfg {Boolean} arrangement stacked | justified
3594 * @cfg {String} align (left | right) alignment
3596 * @cfg {Boolean} main (true|false) main nav bar? default false
3597 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3599 * @cfg {String} tag (header|footer|nav|div) default is nav
3605 * Create a new Sidebar
3606 * @param {Object} config The config object
3610 Roo.bootstrap.NavSimplebar = function(config){
3611 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3614 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3630 getAutoCreate : function(){
3634 tag : this.tag || 'div',
3647 this.type = this.type || 'nav';
3648 if (['tabs','pills'].indexOf(this.type)!==-1) {
3649 cfg.cn[0].cls += ' nav-' + this.type
3653 if (this.type!=='nav') {
3654 Roo.log('nav type must be nav/tabs/pills')
3656 cfg.cn[0].cls += ' navbar-nav'
3662 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3663 cfg.cn[0].cls += ' nav-' + this.arrangement;
3667 if (this.align === 'right') {
3668 cfg.cn[0].cls += ' navbar-right';
3672 cfg.cls += ' navbar-inverse';
3699 * @class Roo.bootstrap.NavHeaderbar
3700 * @extends Roo.bootstrap.NavSimplebar
3701 * Bootstrap Sidebar class
3703 * @cfg {String} brand what is brand
3704 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3705 * @cfg {String} brand_href href of the brand
3706 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3707 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3708 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3709 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3712 * Create a new Sidebar
3713 * @param {Object} config The config object
3717 Roo.bootstrap.NavHeaderbar = function(config){
3718 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3722 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3729 desktopCenter : false,
3732 getAutoCreate : function(){
3735 tag: this.nav || 'nav',
3742 if (this.desktopCenter) {
3743 cn.push({cls : 'container', cn : []});
3750 cls: 'navbar-header',
3755 cls: 'navbar-toggle',
3756 'data-toggle': 'collapse',
3761 html: 'Toggle navigation'
3783 cls: 'collapse navbar-collapse',
3787 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3789 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3790 cfg.cls += ' navbar-' + this.position;
3792 // tag can override this..
3794 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3797 if (this.brand !== '') {
3800 href: this.brand_href ? this.brand_href : '#',
3801 cls: 'navbar-brand',
3809 cfg.cls += ' main-nav';
3817 getHeaderChildContainer : function()
3819 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3820 return this.el.select('.navbar-header',true).first();
3823 return this.getChildContainer();
3827 initEvents : function()
3829 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3831 if (this.autohide) {
3836 Roo.get(document).on('scroll',function(e) {
3837 var ns = Roo.get(document).getScroll().top;
3838 var os = prevScroll;
3842 ft.removeClass('slideDown');
3843 ft.addClass('slideUp');
3846 ft.removeClass('slideUp');
3847 ft.addClass('slideDown');
3868 * @class Roo.bootstrap.NavSidebar
3869 * @extends Roo.bootstrap.Navbar
3870 * Bootstrap Sidebar class
3873 * Create a new Sidebar
3874 * @param {Object} config The config object
3878 Roo.bootstrap.NavSidebar = function(config){
3879 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3882 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3884 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3886 getAutoCreate : function(){
3891 cls: 'sidebar sidebar-nav'
3913 * @class Roo.bootstrap.NavGroup
3914 * @extends Roo.bootstrap.Component
3915 * Bootstrap NavGroup class
3916 * @cfg {String} align (left|right)
3917 * @cfg {Boolean} inverse
3918 * @cfg {String} type (nav|pills|tab) default nav
3919 * @cfg {String} navId - reference Id for navbar.
3923 * Create a new nav group
3924 * @param {Object} config The config object
3927 Roo.bootstrap.NavGroup = function(config){
3928 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3931 Roo.bootstrap.NavGroup.register(this);
3935 * Fires when the active item changes
3936 * @param {Roo.bootstrap.NavGroup} this
3937 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3938 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3945 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3956 getAutoCreate : function()
3958 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3965 if (['tabs','pills'].indexOf(this.type)!==-1) {
3966 cfg.cls += ' nav-' + this.type
3968 if (this.type!=='nav') {
3969 Roo.log('nav type must be nav/tabs/pills')
3971 cfg.cls += ' navbar-nav'
3974 if (this.parent().sidebar) {
3977 cls: 'dashboard-menu sidebar-menu'
3983 if (this.form === true) {
3989 if (this.align === 'right') {
3990 cfg.cls += ' navbar-right';
3992 cfg.cls += ' navbar-left';
3996 if (this.align === 'right') {
3997 cfg.cls += ' navbar-right';
4001 cfg.cls += ' navbar-inverse';
4009 * sets the active Navigation item
4010 * @param {Roo.bootstrap.NavItem} the new current navitem
4012 setActiveItem : function(item)
4015 Roo.each(this.navItems, function(v){
4020 v.setActive(false, true);
4027 item.setActive(true, true);
4028 this.fireEvent('changed', this, item, prev);
4033 * gets the active Navigation item
4034 * @return {Roo.bootstrap.NavItem} the current navitem
4036 getActive : function()
4040 Roo.each(this.navItems, function(v){
4051 indexOfNav : function()
4055 Roo.each(this.navItems, function(v,i){
4066 * adds a Navigation item
4067 * @param {Roo.bootstrap.NavItem} the navitem to add
4069 addItem : function(cfg)
4071 var cn = new Roo.bootstrap.NavItem(cfg);
4073 cn.parentId = this.id;
4074 cn.onRender(this.el, null);
4078 * register a Navigation item
4079 * @param {Roo.bootstrap.NavItem} the navitem to add
4081 register : function(item)
4083 this.navItems.push( item);
4084 item.navId = this.navId;
4089 * clear all the Navigation item
4092 clearAll : function()
4095 this.el.dom.innerHTML = '';
4098 getNavItem: function(tabId)
4101 Roo.each(this.navItems, function(e) {
4102 if (e.tabId == tabId) {
4112 setActiveNext : function()
4114 var i = this.indexOfNav(this.getActive());
4115 if (i > this.navItems.length) {
4118 this.setActiveItem(this.navItems[i+1]);
4120 setActivePrev : function()
4122 var i = this.indexOfNav(this.getActive());
4126 this.setActiveItem(this.navItems[i-1]);
4128 clearWasActive : function(except) {
4129 Roo.each(this.navItems, function(e) {
4130 if (e.tabId != except.tabId && e.was_active) {
4131 e.was_active = false;
4138 getWasActive : function ()
4141 Roo.each(this.navItems, function(e) {
4156 Roo.apply(Roo.bootstrap.NavGroup, {
4160 * register a Navigation Group
4161 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4163 register : function(navgrp)
4165 this.groups[navgrp.navId] = navgrp;
4169 * fetch a Navigation Group based on the navigation ID
4170 * @param {string} the navgroup to add
4171 * @returns {Roo.bootstrap.NavGroup} the navgroup
4173 get: function(navId) {
4174 if (typeof(this.groups[navId]) == 'undefined') {
4176 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4178 return this.groups[navId] ;
4193 * @class Roo.bootstrap.NavItem
4194 * @extends Roo.bootstrap.Component
4195 * Bootstrap Navbar.NavItem class
4196 * @cfg {String} href link to
4197 * @cfg {String} html content of button
4198 * @cfg {String} badge text inside badge
4199 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4200 * @cfg {String} glyphicon name of glyphicon
4201 * @cfg {String} icon name of font awesome icon
4202 * @cfg {Boolean} active Is item active
4203 * @cfg {Boolean} disabled Is item disabled
4205 * @cfg {Boolean} preventDefault (true | false) default false
4206 * @cfg {String} tabId the tab that this item activates.
4207 * @cfg {String} tagtype (a|span) render as a href or span?
4208 * @cfg {Boolean} animateRef (true|false) link to element default false
4211 * Create a new Navbar Item
4212 * @param {Object} config The config object
4214 Roo.bootstrap.NavItem = function(config){
4215 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4220 * The raw click event for the entire grid.
4221 * @param {Roo.EventObject} e
4226 * Fires when the active item active state changes
4227 * @param {Roo.bootstrap.NavItem} this
4228 * @param {boolean} state the new state
4234 * Fires when scroll to element
4235 * @param {Roo.bootstrap.NavItem} this
4236 * @param {Object} options
4237 * @param {Roo.EventObject} e
4245 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4253 preventDefault : false,
4260 getAutoCreate : function(){
4269 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4271 if (this.disabled) {
4272 cfg.cls += ' disabled';
4275 if (this.href || this.html || this.glyphicon || this.icon) {
4279 href : this.href || "#",
4280 html: this.html || ''
4285 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4288 if(this.glyphicon) {
4289 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4294 cfg.cn[0].html += " <span class='caret'></span>";
4298 if (this.badge !== '') {
4300 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4308 initEvents: function()
4310 if (typeof (this.menu) != 'undefined') {
4311 this.menu.parentType = this.xtype;
4312 this.menu.triggerEl = this.el;
4313 this.menu = this.addxtype(Roo.apply({}, this.menu));
4316 this.el.select('a',true).on('click', this.onClick, this);
4318 if(this.tagtype == 'span'){
4319 this.el.select('span',true).on('click', this.onClick, this);
4322 // at this point parent should be available..
4323 this.parent().register(this);
4326 onClick : function(e)
4328 if (e.getTarget('.dropdown-menu-item')) {
4329 // did you click on a menu itemm.... - then don't trigger onclick..
4334 this.preventDefault ||
4337 Roo.log("NavItem - prevent Default?");
4341 if (this.disabled) {
4345 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4346 if (tg && tg.transition) {
4347 Roo.log("waiting for the transitionend");
4353 //Roo.log("fire event clicked");
4354 if(this.fireEvent('click', this, e) === false){
4358 if(this.tagtype == 'span'){
4362 //Roo.log(this.href);
4363 var ael = this.el.select('a',true).first();
4366 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4367 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4368 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4369 return; // ignore... - it's a 'hash' to another page.
4371 Roo.log("NavItem - prevent Default?");
4373 this.scrollToElement(e);
4377 var p = this.parent();
4379 if (['tabs','pills'].indexOf(p.type)!==-1) {
4380 if (typeof(p.setActiveItem) !== 'undefined') {
4381 p.setActiveItem(this);
4385 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4386 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4387 // remove the collapsed menu expand...
4388 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4392 isActive: function () {
4395 setActive : function(state, fire, is_was_active)
4397 if (this.active && !state && this.navId) {
4398 this.was_active = true;
4399 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4401 nv.clearWasActive(this);
4405 this.active = state;
4408 this.el.removeClass('active');
4409 } else if (!this.el.hasClass('active')) {
4410 this.el.addClass('active');
4413 this.fireEvent('changed', this, state);
4416 // show a panel if it's registered and related..
4418 if (!this.navId || !this.tabId || !state || is_was_active) {
4422 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4426 var pan = tg.getPanelByName(this.tabId);
4430 // if we can not flip to new panel - go back to old nav highlight..
4431 if (false == tg.showPanel(pan)) {
4432 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4434 var onav = nv.getWasActive();
4436 onav.setActive(true, false, true);
4445 // this should not be here...
4446 setDisabled : function(state)
4448 this.disabled = state;
4450 this.el.removeClass('disabled');
4451 } else if (!this.el.hasClass('disabled')) {
4452 this.el.addClass('disabled');
4458 * Fetch the element to display the tooltip on.
4459 * @return {Roo.Element} defaults to this.el
4461 tooltipEl : function()
4463 return this.el.select('' + this.tagtype + '', true).first();
4466 scrollToElement : function(e)
4468 var c = document.body;
4471 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4473 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4474 c = document.documentElement;
4477 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4483 var o = target.calcOffsetsTo(c);
4490 this.fireEvent('scrollto', this, options, e);
4492 Roo.get(c).scrollTo('top', options.value, true);
4505 * <span> icon </span>
4506 * <span> text </span>
4507 * <span>badge </span>
4511 * @class Roo.bootstrap.NavSidebarItem
4512 * @extends Roo.bootstrap.NavItem
4513 * Bootstrap Navbar.NavSidebarItem class
4514 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4515 * {bool} open is the menu open
4517 * Create a new Navbar Button
4518 * @param {Object} config The config object
4520 Roo.bootstrap.NavSidebarItem = function(config){
4521 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4526 * The raw click event for the entire grid.
4527 * @param {Roo.EventObject} e
4532 * Fires when the active item active state changes
4533 * @param {Roo.bootstrap.NavSidebarItem} this
4534 * @param {boolean} state the new state
4542 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4544 badgeWeight : 'default',
4548 getAutoCreate : function(){
4553 href : this.href || '#',
4565 html : this.html || ''
4570 cfg.cls += ' active';
4573 if (this.disabled) {
4574 cfg.cls += ' disabled';
4577 cfg.cls += ' open x-open';
4580 if (this.glyphicon || this.icon) {
4581 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4582 a.cn.push({ tag : 'i', cls : c }) ;
4587 if (this.badge !== '') {
4589 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4593 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4594 a.cls += 'dropdown-toggle treeview' ;
4602 initEvents : function()
4604 if (typeof (this.menu) != 'undefined') {
4605 this.menu.parentType = this.xtype;
4606 this.menu.triggerEl = this.el;
4607 this.menu = this.addxtype(Roo.apply({}, this.menu));
4610 this.el.on('click', this.onClick, this);
4613 if(this.badge !== ''){
4615 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4620 onClick : function(e)
4627 if(this.preventDefault){
4631 this.fireEvent('click', this);
4634 disable : function()
4636 this.setDisabled(true);
4641 this.setDisabled(false);
4644 setDisabled : function(state)
4646 if(this.disabled == state){
4650 this.disabled = state;
4653 this.el.addClass('disabled');
4657 this.el.removeClass('disabled');
4662 setActive : function(state)
4664 if(this.active == state){
4668 this.active = state;
4671 this.el.addClass('active');
4675 this.el.removeClass('active');
4680 isActive: function ()
4685 setBadge : function(str)
4691 this.badgeEl.dom.innerHTML = str;
4708 * @class Roo.bootstrap.Row
4709 * @extends Roo.bootstrap.Component
4710 * Bootstrap Row class (contains columns...)
4714 * @param {Object} config The config object
4717 Roo.bootstrap.Row = function(config){
4718 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4721 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4723 getAutoCreate : function(){
4742 * @class Roo.bootstrap.Element
4743 * @extends Roo.bootstrap.Component
4744 * Bootstrap Element class
4745 * @cfg {String} html contents of the element
4746 * @cfg {String} tag tag of the element
4747 * @cfg {String} cls class of the element
4748 * @cfg {Boolean} preventDefault (true|false) default false
4749 * @cfg {Boolean} clickable (true|false) default false
4752 * Create a new Element
4753 * @param {Object} config The config object
4756 Roo.bootstrap.Element = function(config){
4757 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4763 * When a element is chick
4764 * @param {Roo.bootstrap.Element} this
4765 * @param {Roo.EventObject} e
4771 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4776 preventDefault: false,
4779 getAutoCreate : function(){
4790 initEvents: function()
4792 Roo.bootstrap.Element.superclass.initEvents.call(this);
4795 this.el.on('click', this.onClick, this);
4800 onClick : function(e)
4802 if(this.preventDefault){
4806 this.fireEvent('click', this, e);
4809 getValue : function()
4811 return this.el.dom.innerHTML;
4814 setValue : function(value)
4816 this.el.dom.innerHTML = value;
4831 * @class Roo.bootstrap.Pagination
4832 * @extends Roo.bootstrap.Component
4833 * Bootstrap Pagination class
4834 * @cfg {String} size xs | sm | md | lg
4835 * @cfg {Boolean} inverse false | true
4838 * Create a new Pagination
4839 * @param {Object} config The config object
4842 Roo.bootstrap.Pagination = function(config){
4843 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4846 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4852 getAutoCreate : function(){
4858 cfg.cls += ' inverse';
4864 cfg.cls += " " + this.cls;
4882 * @class Roo.bootstrap.PaginationItem
4883 * @extends Roo.bootstrap.Component
4884 * Bootstrap PaginationItem class
4885 * @cfg {String} html text
4886 * @cfg {String} href the link
4887 * @cfg {Boolean} preventDefault (true | false) default true
4888 * @cfg {Boolean} active (true | false) default false
4889 * @cfg {Boolean} disabled default false
4893 * Create a new PaginationItem
4894 * @param {Object} config The config object
4898 Roo.bootstrap.PaginationItem = function(config){
4899 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4904 * The raw click event for the entire grid.
4905 * @param {Roo.EventObject} e
4911 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4915 preventDefault: true,
4920 getAutoCreate : function(){
4926 href : this.href ? this.href : '#',
4927 html : this.html ? this.html : ''
4937 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4941 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4947 initEvents: function() {
4949 this.el.on('click', this.onClick, this);
4952 onClick : function(e)
4954 Roo.log('PaginationItem on click ');
4955 if(this.preventDefault){
4963 this.fireEvent('click', this, e);
4979 * @class Roo.bootstrap.Slider
4980 * @extends Roo.bootstrap.Component
4981 * Bootstrap Slider class
4984 * Create a new Slider
4985 * @param {Object} config The config object
4988 Roo.bootstrap.Slider = function(config){
4989 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4992 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4994 getAutoCreate : function(){
4998 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5002 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5014 * Ext JS Library 1.1.1
5015 * Copyright(c) 2006-2007, Ext JS, LLC.
5017 * Originally Released Under LGPL - original licence link has changed is not relivant.
5020 * <script type="text/javascript">
5025 * @class Roo.grid.ColumnModel
5026 * @extends Roo.util.Observable
5027 * This is the default implementation of a ColumnModel used by the Grid. It defines
5028 * the columns in the grid.
5031 var colModel = new Roo.grid.ColumnModel([
5032 {header: "Ticker", width: 60, sortable: true, locked: true},
5033 {header: "Company Name", width: 150, sortable: true},
5034 {header: "Market Cap.", width: 100, sortable: true},
5035 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5036 {header: "Employees", width: 100, sortable: true, resizable: false}
5041 * The config options listed for this class are options which may appear in each
5042 * individual column definition.
5043 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5045 * @param {Object} config An Array of column config objects. See this class's
5046 * config objects for details.
5048 Roo.grid.ColumnModel = function(config){
5050 * The config passed into the constructor
5052 this.config = config;
5055 // if no id, create one
5056 // if the column does not have a dataIndex mapping,
5057 // map it to the order it is in the config
5058 for(var i = 0, len = config.length; i < len; i++){
5060 if(typeof c.dataIndex == "undefined"){
5063 if(typeof c.renderer == "string"){
5064 c.renderer = Roo.util.Format[c.renderer];
5066 if(typeof c.id == "undefined"){
5069 if(c.editor && c.editor.xtype){
5070 c.editor = Roo.factory(c.editor, Roo.grid);
5072 if(c.editor && c.editor.isFormField){
5073 c.editor = new Roo.grid.GridEditor(c.editor);
5075 this.lookup[c.id] = c;
5079 * The width of columns which have no width specified (defaults to 100)
5082 this.defaultWidth = 100;
5085 * Default sortable of columns which have no sortable specified (defaults to false)
5088 this.defaultSortable = false;
5092 * @event widthchange
5093 * Fires when the width of a column changes.
5094 * @param {ColumnModel} this
5095 * @param {Number} columnIndex The column index
5096 * @param {Number} newWidth The new width
5098 "widthchange": true,
5100 * @event headerchange
5101 * Fires when the text of a header changes.
5102 * @param {ColumnModel} this
5103 * @param {Number} columnIndex The column index
5104 * @param {Number} newText The new header text
5106 "headerchange": true,
5108 * @event hiddenchange
5109 * Fires when a column is hidden or "unhidden".
5110 * @param {ColumnModel} this
5111 * @param {Number} columnIndex The column index
5112 * @param {Boolean} hidden true if hidden, false otherwise
5114 "hiddenchange": true,
5116 * @event columnmoved
5117 * Fires when a column is moved.
5118 * @param {ColumnModel} this
5119 * @param {Number} oldIndex
5120 * @param {Number} newIndex
5122 "columnmoved" : true,
5124 * @event columlockchange
5125 * Fires when a column's locked state is changed
5126 * @param {ColumnModel} this
5127 * @param {Number} colIndex
5128 * @param {Boolean} locked true if locked
5130 "columnlockchange" : true
5132 Roo.grid.ColumnModel.superclass.constructor.call(this);
5134 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5136 * @cfg {String} header The header text to display in the Grid view.
5139 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5140 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5141 * specified, the column's index is used as an index into the Record's data Array.
5144 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5145 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5148 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5149 * Defaults to the value of the {@link #defaultSortable} property.
5150 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5153 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5156 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5159 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5162 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5165 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5166 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5167 * default renderer uses the raw data value. If an object is returned (bootstrap only)
5168 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5171 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5174 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5177 * @cfg {String} cursor (Optional)
5180 * @cfg {String} tooltip (Optional)
5183 * @cfg {Number} xs (Optional)
5186 * @cfg {Number} sm (Optional)
5189 * @cfg {Number} md (Optional)
5192 * @cfg {Number} lg (Optional)
5195 * Returns the id of the column at the specified index.
5196 * @param {Number} index The column index
5197 * @return {String} the id
5199 getColumnId : function(index){
5200 return this.config[index].id;
5204 * Returns the column for a specified id.
5205 * @param {String} id The column id
5206 * @return {Object} the column
5208 getColumnById : function(id){
5209 return this.lookup[id];
5214 * Returns the column for a specified dataIndex.
5215 * @param {String} dataIndex The column dataIndex
5216 * @return {Object|Boolean} the column or false if not found
5218 getColumnByDataIndex: function(dataIndex){
5219 var index = this.findColumnIndex(dataIndex);
5220 return index > -1 ? this.config[index] : false;
5224 * Returns the index for a specified column id.
5225 * @param {String} id The column id
5226 * @return {Number} the index, or -1 if not found
5228 getIndexById : function(id){
5229 for(var i = 0, len = this.config.length; i < len; i++){
5230 if(this.config[i].id == id){
5238 * Returns the index for a specified column dataIndex.
5239 * @param {String} dataIndex The column dataIndex
5240 * @return {Number} the index, or -1 if not found
5243 findColumnIndex : function(dataIndex){
5244 for(var i = 0, len = this.config.length; i < len; i++){
5245 if(this.config[i].dataIndex == dataIndex){
5253 moveColumn : function(oldIndex, newIndex){
5254 var c = this.config[oldIndex];
5255 this.config.splice(oldIndex, 1);
5256 this.config.splice(newIndex, 0, c);
5257 this.dataMap = null;
5258 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5261 isLocked : function(colIndex){
5262 return this.config[colIndex].locked === true;
5265 setLocked : function(colIndex, value, suppressEvent){
5266 if(this.isLocked(colIndex) == value){
5269 this.config[colIndex].locked = value;
5271 this.fireEvent("columnlockchange", this, colIndex, value);
5275 getTotalLockedWidth : function(){
5277 for(var i = 0; i < this.config.length; i++){
5278 if(this.isLocked(i) && !this.isHidden(i)){
5279 this.totalWidth += this.getColumnWidth(i);
5285 getLockedCount : function(){
5286 for(var i = 0, len = this.config.length; i < len; i++){
5287 if(!this.isLocked(i)){
5292 return this.config.length;
5296 * Returns the number of columns.
5299 getColumnCount : function(visibleOnly){
5300 if(visibleOnly === true){
5302 for(var i = 0, len = this.config.length; i < len; i++){
5303 if(!this.isHidden(i)){
5309 return this.config.length;
5313 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5314 * @param {Function} fn
5315 * @param {Object} scope (optional)
5316 * @return {Array} result
5318 getColumnsBy : function(fn, scope){
5320 for(var i = 0, len = this.config.length; i < len; i++){
5321 var c = this.config[i];
5322 if(fn.call(scope||this, c, i) === true){
5330 * Returns true if the specified column is sortable.
5331 * @param {Number} col The column index
5334 isSortable : function(col){
5335 if(typeof this.config[col].sortable == "undefined"){
5336 return this.defaultSortable;
5338 return this.config[col].sortable;
5342 * Returns the rendering (formatting) function defined for the column.
5343 * @param {Number} col The column index.
5344 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5346 getRenderer : function(col){
5347 if(!this.config[col].renderer){
5348 return Roo.grid.ColumnModel.defaultRenderer;
5350 return this.config[col].renderer;
5354 * Sets the rendering (formatting) function for a column.
5355 * @param {Number} col The column index
5356 * @param {Function} fn The function to use to process the cell's raw data
5357 * to return HTML markup for the grid view. The render function is called with
5358 * the following parameters:<ul>
5359 * <li>Data value.</li>
5360 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5361 * <li>css A CSS style string to apply to the table cell.</li>
5362 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5363 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5364 * <li>Row index</li>
5365 * <li>Column index</li>
5366 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5368 setRenderer : function(col, fn){
5369 this.config[col].renderer = fn;
5373 * Returns the width for the specified column.
5374 * @param {Number} col The column index
5377 getColumnWidth : function(col){
5378 return this.config[col].width * 1 || this.defaultWidth;
5382 * Sets the width for a column.
5383 * @param {Number} col The column index
5384 * @param {Number} width The new width
5386 setColumnWidth : function(col, width, suppressEvent){
5387 this.config[col].width = width;
5388 this.totalWidth = null;
5390 this.fireEvent("widthchange", this, col, width);
5395 * Returns the total width of all columns.
5396 * @param {Boolean} includeHidden True to include hidden column widths
5399 getTotalWidth : function(includeHidden){
5400 if(!this.totalWidth){
5401 this.totalWidth = 0;
5402 for(var i = 0, len = this.config.length; i < len; i++){
5403 if(includeHidden || !this.isHidden(i)){
5404 this.totalWidth += this.getColumnWidth(i);
5408 return this.totalWidth;
5412 * Returns the header for the specified column.
5413 * @param {Number} col The column index
5416 getColumnHeader : function(col){
5417 return this.config[col].header;
5421 * Sets the header for a column.
5422 * @param {Number} col The column index
5423 * @param {String} header The new header
5425 setColumnHeader : function(col, header){
5426 this.config[col].header = header;
5427 this.fireEvent("headerchange", this, col, header);
5431 * Returns the tooltip for the specified column.
5432 * @param {Number} col The column index
5435 getColumnTooltip : function(col){
5436 return this.config[col].tooltip;
5439 * Sets the tooltip for a column.
5440 * @param {Number} col The column index
5441 * @param {String} tooltip The new tooltip
5443 setColumnTooltip : function(col, tooltip){
5444 this.config[col].tooltip = tooltip;
5448 * Returns the dataIndex for the specified column.
5449 * @param {Number} col The column index
5452 getDataIndex : function(col){
5453 return this.config[col].dataIndex;
5457 * Sets the dataIndex for a column.
5458 * @param {Number} col The column index
5459 * @param {Number} dataIndex The new dataIndex
5461 setDataIndex : function(col, dataIndex){
5462 this.config[col].dataIndex = dataIndex;
5468 * Returns true if the cell is editable.
5469 * @param {Number} colIndex The column index
5470 * @param {Number} rowIndex The row index - this is nto actually used..?
5473 isCellEditable : function(colIndex, rowIndex){
5474 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5478 * Returns the editor defined for the cell/column.
5479 * return false or null to disable editing.
5480 * @param {Number} colIndex The column index
5481 * @param {Number} rowIndex The row index
5484 getCellEditor : function(colIndex, rowIndex){
5485 return this.config[colIndex].editor;
5489 * Sets if a column is editable.
5490 * @param {Number} col The column index
5491 * @param {Boolean} editable True if the column is editable
5493 setEditable : function(col, editable){
5494 this.config[col].editable = editable;
5499 * Returns true if the column is hidden.
5500 * @param {Number} colIndex The column index
5503 isHidden : function(colIndex){
5504 return this.config[colIndex].hidden;
5509 * Returns true if the column width cannot be changed
5511 isFixed : function(colIndex){
5512 return this.config[colIndex].fixed;
5516 * Returns true if the column can be resized
5519 isResizable : function(colIndex){
5520 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5523 * Sets if a column is hidden.
5524 * @param {Number} colIndex The column index
5525 * @param {Boolean} hidden True if the column is hidden
5527 setHidden : function(colIndex, hidden){
5528 this.config[colIndex].hidden = hidden;
5529 this.totalWidth = null;
5530 this.fireEvent("hiddenchange", this, colIndex, hidden);
5534 * Sets the editor for a column.
5535 * @param {Number} col The column index
5536 * @param {Object} editor The editor object
5538 setEditor : function(col, editor){
5539 this.config[col].editor = editor;
5543 Roo.grid.ColumnModel.defaultRenderer = function(value){
5544 if(typeof value == "string" && value.length < 1){
5550 // Alias for backwards compatibility
5551 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5554 * Ext JS Library 1.1.1
5555 * Copyright(c) 2006-2007, Ext JS, LLC.
5557 * Originally Released Under LGPL - original licence link has changed is not relivant.
5560 * <script type="text/javascript">
5564 * @class Roo.LoadMask
5565 * A simple utility class for generically masking elements while loading data. If the element being masked has
5566 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5567 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5568 * element's UpdateManager load indicator and will be destroyed after the initial load.
5570 * Create a new LoadMask
5571 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5572 * @param {Object} config The config object
5574 Roo.LoadMask = function(el, config){
5575 this.el = Roo.get(el);
5576 Roo.apply(this, config);
5578 this.store.on('beforeload', this.onBeforeLoad, this);
5579 this.store.on('load', this.onLoad, this);
5580 this.store.on('loadexception', this.onLoadException, this);
5581 this.removeMask = false;
5583 var um = this.el.getUpdateManager();
5584 um.showLoadIndicator = false; // disable the default indicator
5585 um.on('beforeupdate', this.onBeforeLoad, this);
5586 um.on('update', this.onLoad, this);
5587 um.on('failure', this.onLoad, this);
5588 this.removeMask = true;
5592 Roo.LoadMask.prototype = {
5594 * @cfg {Boolean} removeMask
5595 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5596 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5600 * The text to display in a centered loading message box (defaults to 'Loading...')
5604 * @cfg {String} msgCls
5605 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5607 msgCls : 'x-mask-loading',
5610 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5616 * Disables the mask to prevent it from being displayed
5618 disable : function(){
5619 this.disabled = true;
5623 * Enables the mask so that it can be displayed
5625 enable : function(){
5626 this.disabled = false;
5629 onLoadException : function()
5633 if (typeof(arguments[3]) != 'undefined') {
5634 Roo.MessageBox.alert("Error loading",arguments[3]);
5638 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5639 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5648 this.el.unmask(this.removeMask);
5653 this.el.unmask(this.removeMask);
5657 onBeforeLoad : function(){
5659 this.el.mask(this.msg, this.msgCls);
5664 destroy : function(){
5666 this.store.un('beforeload', this.onBeforeLoad, this);
5667 this.store.un('load', this.onLoad, this);
5668 this.store.un('loadexception', this.onLoadException, this);
5670 var um = this.el.getUpdateManager();
5671 um.un('beforeupdate', this.onBeforeLoad, this);
5672 um.un('update', this.onLoad, this);
5673 um.un('failure', this.onLoad, this);
5684 * @class Roo.bootstrap.Table
5685 * @extends Roo.bootstrap.Component
5686 * Bootstrap Table class
5687 * @cfg {String} cls table class
5688 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5689 * @cfg {String} bgcolor Specifies the background color for a table
5690 * @cfg {Number} border Specifies whether the table cells should have borders or not
5691 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5692 * @cfg {Number} cellspacing Specifies the space between cells
5693 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5694 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5695 * @cfg {String} sortable Specifies that the table should be sortable
5696 * @cfg {String} summary Specifies a summary of the content of a table
5697 * @cfg {Number} width Specifies the width of a table
5698 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5700 * @cfg {boolean} striped Should the rows be alternative striped
5701 * @cfg {boolean} bordered Add borders to the table
5702 * @cfg {boolean} hover Add hover highlighting
5703 * @cfg {boolean} condensed Format condensed
5704 * @cfg {boolean} responsive Format condensed
5705 * @cfg {Boolean} loadMask (true|false) default false
5706 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5707 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5708 * @cfg {Boolean} rowSelection (true|false) default false
5709 * @cfg {Boolean} cellSelection (true|false) default false
5710 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5711 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5715 * Create a new Table
5716 * @param {Object} config The config object
5719 Roo.bootstrap.Table = function(config){
5720 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5725 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5726 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5727 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5728 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5730 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5732 this.sm.grid = this;
5733 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5734 this.sm = this.selModel;
5735 this.sm.xmodule = this.xmodule || false;
5738 if (this.cm && typeof(this.cm.config) == 'undefined') {
5739 this.colModel = new Roo.grid.ColumnModel(this.cm);
5740 this.cm = this.colModel;
5741 this.cm.xmodule = this.xmodule || false;
5744 this.store= Roo.factory(this.store, Roo.data);
5745 this.ds = this.store;
5746 this.ds.xmodule = this.xmodule || false;
5749 if (this.footer && this.store) {
5750 this.footer.dataSource = this.ds;
5751 this.footer = Roo.factory(this.footer);
5758 * Fires when a cell is clicked
5759 * @param {Roo.bootstrap.Table} this
5760 * @param {Roo.Element} el
5761 * @param {Number} rowIndex
5762 * @param {Number} columnIndex
5763 * @param {Roo.EventObject} e
5767 * @event celldblclick
5768 * Fires when a cell is double clicked
5769 * @param {Roo.bootstrap.Table} this
5770 * @param {Roo.Element} el
5771 * @param {Number} rowIndex
5772 * @param {Number} columnIndex
5773 * @param {Roo.EventObject} e
5775 "celldblclick" : true,
5778 * Fires when a row is clicked
5779 * @param {Roo.bootstrap.Table} this
5780 * @param {Roo.Element} el
5781 * @param {Number} rowIndex
5782 * @param {Roo.EventObject} e
5786 * @event rowdblclick
5787 * Fires when a row is double clicked
5788 * @param {Roo.bootstrap.Table} this
5789 * @param {Roo.Element} el
5790 * @param {Number} rowIndex
5791 * @param {Roo.EventObject} e
5793 "rowdblclick" : true,
5796 * Fires when a mouseover occur
5797 * @param {Roo.bootstrap.Table} this
5798 * @param {Roo.Element} el
5799 * @param {Number} rowIndex
5800 * @param {Number} columnIndex
5801 * @param {Roo.EventObject} e
5806 * Fires when a mouseout occur
5807 * @param {Roo.bootstrap.Table} this
5808 * @param {Roo.Element} el
5809 * @param {Number} rowIndex
5810 * @param {Number} columnIndex
5811 * @param {Roo.EventObject} e
5816 * Fires when a row is rendered, so you can change add a style to it.
5817 * @param {Roo.bootstrap.Table} this
5818 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5822 * @event rowsrendered
5823 * Fires when all the rows have been rendered
5824 * @param {Roo.bootstrap.Table} this
5826 'rowsrendered' : true,
5828 * @event contextmenu
5829 * The raw contextmenu event for the entire grid.
5830 * @param {Roo.EventObject} e
5832 "contextmenu" : true,
5834 * @event rowcontextmenu
5835 * Fires when a row is right clicked
5836 * @param {Roo.bootstrap.Table} this
5837 * @param {Number} rowIndex
5838 * @param {Roo.EventObject} e
5840 "rowcontextmenu" : true,
5842 * @event cellcontextmenu
5843 * Fires when a cell is right clicked
5844 * @param {Roo.bootstrap.Table} this
5845 * @param {Number} rowIndex
5846 * @param {Number} cellIndex
5847 * @param {Roo.EventObject} e
5849 "cellcontextmenu" : true,
5851 * @event headercontextmenu
5852 * Fires when a header is right clicked
5853 * @param {Roo.bootstrap.Table} this
5854 * @param {Number} columnIndex
5855 * @param {Roo.EventObject} e
5857 "headercontextmenu" : true
5861 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5887 rowSelection : false,
5888 cellSelection : false,
5891 // Roo.Element - the tbody
5893 // Roo.Element - thead element
5896 container: false, // used by gridpanel...
5898 getAutoCreate : function()
5900 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5907 if (this.scrollBody) {
5908 cfg.cls += ' table-body-fixed';
5911 cfg.cls += ' table-striped';
5915 cfg.cls += ' table-hover';
5917 if (this.bordered) {
5918 cfg.cls += ' table-bordered';
5920 if (this.condensed) {
5921 cfg.cls += ' table-condensed';
5923 if (this.responsive) {
5924 cfg.cls += ' table-responsive';
5928 cfg.cls+= ' ' +this.cls;
5931 // this lot should be simplifed...
5934 cfg.align=this.align;
5937 cfg.bgcolor=this.bgcolor;
5940 cfg.border=this.border;
5942 if (this.cellpadding) {
5943 cfg.cellpadding=this.cellpadding;
5945 if (this.cellspacing) {
5946 cfg.cellspacing=this.cellspacing;
5949 cfg.frame=this.frame;
5952 cfg.rules=this.rules;
5954 if (this.sortable) {
5955 cfg.sortable=this.sortable;
5958 cfg.summary=this.summary;
5961 cfg.width=this.width;
5964 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5967 if(this.store || this.cm){
5968 if(this.headerShow){
5969 cfg.cn.push(this.renderHeader());
5972 cfg.cn.push(this.renderBody());
5974 if(this.footerShow){
5975 cfg.cn.push(this.renderFooter());
5977 // where does this come from?
5978 //cfg.cls+= ' TableGrid';
5981 return { cn : [ cfg ] };
5984 initEvents : function()
5986 if(!this.store || !this.cm){
5989 if (this.selModel) {
5990 this.selModel.initEvents();
5994 //Roo.log('initEvents with ds!!!!');
5996 this.mainBody = this.el.select('tbody', true).first();
5997 this.mainHead = this.el.select('thead', true).first();
6004 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6005 e.on('click', _this.sort, _this);
6008 this.el.on("click", this.onClick, this);
6009 this.el.on("dblclick", this.onDblClick, this);
6011 // why is this done????? = it breaks dialogs??
6012 //this.parent().el.setStyle('position', 'relative');
6016 this.footer.parentId = this.id;
6017 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6020 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6022 this.store.on('load', this.onLoad, this);
6023 this.store.on('beforeload', this.onBeforeLoad, this);
6024 this.store.on('update', this.onUpdate, this);
6025 this.store.on('add', this.onAdd, this);
6026 this.store.on("clear", this.clear, this);
6028 this.el.on("contextmenu", this.onContextMenu, this);
6030 this.mainBody.on('scroll', this.onBodyScroll, this);
6035 onContextMenu : function(e, t)
6037 this.processEvent("contextmenu", e);
6040 processEvent : function(name, e)
6042 if (name != 'touchstart' ) {
6043 this.fireEvent(name, e);
6046 var t = e.getTarget();
6048 var cell = Roo.get(t);
6054 if(cell.findParent('tfoot', false, true)){
6058 if(cell.findParent('thead', false, true)){
6060 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6061 cell = Roo.get(t).findParent('th', false, true);
6063 Roo.log("failed to find th in thead?");
6064 Roo.log(e.getTarget());
6069 var cellIndex = cell.dom.cellIndex;
6071 var ename = name == 'touchstart' ? 'click' : name;
6072 this.fireEvent("header" + ename, this, cellIndex, e);
6077 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6078 cell = Roo.get(t).findParent('td', false, true);
6080 Roo.log("failed to find th in tbody?");
6081 Roo.log(e.getTarget());
6086 var row = cell.findParent('tr', false, true);
6087 var cellIndex = cell.dom.cellIndex;
6088 var rowIndex = row.dom.rowIndex - 1;
6092 this.fireEvent("row" + name, this, rowIndex, e);
6096 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6102 onMouseover : function(e, el)
6104 var cell = Roo.get(el);
6110 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6111 cell = cell.findParent('td', false, true);
6114 var row = cell.findParent('tr', false, true);
6115 var cellIndex = cell.dom.cellIndex;
6116 var rowIndex = row.dom.rowIndex - 1; // start from 0
6118 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6122 onMouseout : function(e, el)
6124 var cell = Roo.get(el);
6130 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6131 cell = cell.findParent('td', false, true);
6134 var row = cell.findParent('tr', false, true);
6135 var cellIndex = cell.dom.cellIndex;
6136 var rowIndex = row.dom.rowIndex - 1; // start from 0
6138 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6142 onClick : function(e, el)
6144 var cell = Roo.get(el);
6146 if(!cell || (!this.cellSelection && !this.rowSelection)){
6150 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6151 cell = cell.findParent('td', false, true);
6154 if(!cell || typeof(cell) == 'undefined'){
6158 var row = cell.findParent('tr', false, true);
6160 if(!row || typeof(row) == 'undefined'){
6164 var cellIndex = cell.dom.cellIndex;
6165 var rowIndex = this.getRowIndex(row);
6167 // why??? - should these not be based on SelectionModel?
6168 if(this.cellSelection){
6169 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6172 if(this.rowSelection){
6173 this.fireEvent('rowclick', this, row, rowIndex, e);
6179 onDblClick : function(e,el)
6181 var cell = Roo.get(el);
6183 if(!cell || (!this.cellSelection && !this.rowSelection)){
6187 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6188 cell = cell.findParent('td', false, true);
6191 if(!cell || typeof(cell) == 'undefined'){
6195 var row = cell.findParent('tr', false, true);
6197 if(!row || typeof(row) == 'undefined'){
6201 var cellIndex = cell.dom.cellIndex;
6202 var rowIndex = this.getRowIndex(row);
6204 if(this.cellSelection){
6205 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6208 if(this.rowSelection){
6209 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6213 sort : function(e,el)
6215 var col = Roo.get(el);
6217 if(!col.hasClass('sortable')){
6221 var sort = col.attr('sort');
6224 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6228 this.store.sortInfo = {field : sort, direction : dir};
6231 Roo.log("calling footer first");
6232 this.footer.onClick('first');
6235 this.store.load({ params : { start : 0 } });
6239 renderHeader : function()
6247 this.totalWidth = 0;
6249 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6251 var config = cm.config[i];
6256 html: cm.getColumnHeader(i)
6261 if(typeof(config.sortable) != 'undefined' && config.sortable){
6263 c.html = '<i class="glyphicon"></i>' + c.html;
6266 if(typeof(config.lgHeader) != 'undefined'){
6267 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6270 if(typeof(config.mdHeader) != 'undefined'){
6271 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6274 if(typeof(config.smHeader) != 'undefined'){
6275 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6278 if(typeof(config.xsHeader) != 'undefined'){
6279 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6286 if(typeof(config.tooltip) != 'undefined'){
6287 c.tooltip = config.tooltip;
6290 if(typeof(config.colspan) != 'undefined'){
6291 c.colspan = config.colspan;
6294 if(typeof(config.hidden) != 'undefined' && config.hidden){
6295 c.style += ' display:none;';
6298 if(typeof(config.dataIndex) != 'undefined'){
6299 c.sort = config.dataIndex;
6304 if(typeof(config.align) != 'undefined' && config.align.length){
6305 c.style += ' text-align:' + config.align + ';';
6308 if(typeof(config.width) != 'undefined'){
6309 c.style += ' width:' + config.width + 'px;';
6310 this.totalWidth += config.width;
6312 this.totalWidth += 100; // assume minimum of 100 per column?
6315 if(typeof(config.cls) != 'undefined'){
6316 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6319 ['xs','sm','md','lg'].map(function(size){
6321 if(typeof(config[size]) == 'undefined'){
6325 if (!config[size]) { // 0 = hidden
6326 c.cls += ' hidden-' + size;
6330 c.cls += ' col-' + size + '-' + config[size];
6340 renderBody : function()
6350 colspan : this.cm.getColumnCount()
6360 renderFooter : function()
6370 colspan : this.cm.getColumnCount()
6384 // Roo.log('ds onload');
6389 var ds = this.store;
6391 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6392 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6393 if (_this.store.sortInfo) {
6395 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6396 e.select('i', true).addClass(['glyphicon-arrow-up']);
6399 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6400 e.select('i', true).addClass(['glyphicon-arrow-down']);
6405 var tbody = this.mainBody;
6407 if(ds.getCount() > 0){
6408 ds.data.each(function(d,rowIndex){
6409 var row = this.renderRow(cm, ds, rowIndex);
6411 tbody.createChild(row);
6415 if(row.cellObjects.length){
6416 Roo.each(row.cellObjects, function(r){
6417 _this.renderCellObject(r);
6424 Roo.each(this.el.select('tbody td', true).elements, function(e){
6425 e.on('mouseover', _this.onMouseover, _this);
6428 Roo.each(this.el.select('tbody td', true).elements, function(e){
6429 e.on('mouseout', _this.onMouseout, _this);
6431 this.fireEvent('rowsrendered', this);
6432 //if(this.loadMask){
6433 // this.maskEl.hide();
6440 onUpdate : function(ds,record)
6442 this.refreshRow(record);
6446 onRemove : function(ds, record, index, isUpdate){
6447 if(isUpdate !== true){
6448 this.fireEvent("beforerowremoved", this, index, record);
6450 var bt = this.mainBody.dom;
6452 var rows = this.el.select('tbody > tr', true).elements;
6454 if(typeof(rows[index]) != 'undefined'){
6455 bt.removeChild(rows[index].dom);
6458 // if(bt.rows[index]){
6459 // bt.removeChild(bt.rows[index]);
6462 if(isUpdate !== true){
6463 //this.stripeRows(index);
6464 //this.syncRowHeights(index, index);
6466 this.fireEvent("rowremoved", this, index, record);
6470 onAdd : function(ds, records, rowIndex)
6472 //Roo.log('on Add called');
6473 // - note this does not handle multiple adding very well..
6474 var bt = this.mainBody.dom;
6475 for (var i =0 ; i < records.length;i++) {
6476 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6477 //Roo.log(records[i]);
6478 //Roo.log(this.store.getAt(rowIndex+i));
6479 this.insertRow(this.store, rowIndex + i, false);
6486 refreshRow : function(record){
6487 var ds = this.store, index;
6488 if(typeof record == 'number'){
6490 record = ds.getAt(index);
6492 index = ds.indexOf(record);
6494 this.insertRow(ds, index, true);
6496 this.onRemove(ds, record, index+1, true);
6498 //this.syncRowHeights(index, index);
6500 this.fireEvent("rowupdated", this, index, record);
6503 insertRow : function(dm, rowIndex, isUpdate){
6506 this.fireEvent("beforerowsinserted", this, rowIndex);
6508 //var s = this.getScrollState();
6509 var row = this.renderRow(this.cm, this.store, rowIndex);
6510 // insert before rowIndex..
6511 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6515 if(row.cellObjects.length){
6516 Roo.each(row.cellObjects, function(r){
6517 _this.renderCellObject(r);
6522 this.fireEvent("rowsinserted", this, rowIndex);
6523 //this.syncRowHeights(firstRow, lastRow);
6524 //this.stripeRows(firstRow);
6531 getRowDom : function(rowIndex)
6533 var rows = this.el.select('tbody > tr', true).elements;
6535 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6538 // returns the object tree for a tr..
6541 renderRow : function(cm, ds, rowIndex)
6544 var d = ds.getAt(rowIndex);
6551 var cellObjects = [];
6553 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6554 var config = cm.config[i];
6556 var renderer = cm.getRenderer(i);
6560 if(typeof(renderer) !== 'undefined'){
6561 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6563 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6564 // and are rendered into the cells after the row is rendered - using the id for the element.
6566 if(typeof(value) === 'object'){
6576 rowIndex : rowIndex,
6581 this.fireEvent('rowclass', this, rowcfg);
6585 cls : rowcfg.rowClass,
6587 html: (typeof(value) === 'object') ? '' : value
6594 if(typeof(config.colspan) != 'undefined'){
6595 td.colspan = config.colspan;
6598 if(typeof(config.hidden) != 'undefined' && config.hidden){
6599 td.style += ' display:none;';
6602 if(typeof(config.align) != 'undefined' && config.align.length){
6603 td.style += ' text-align:' + config.align + ';';
6606 if(typeof(config.width) != 'undefined'){
6607 td.style += ' width:' + config.width + 'px;';
6610 if(typeof(config.cursor) != 'undefined'){
6611 td.style += ' cursor:' + config.cursor + ';';
6614 if(typeof(config.cls) != 'undefined'){
6615 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6618 ['xs','sm','md','lg'].map(function(size){
6620 if(typeof(config[size]) == 'undefined'){
6624 if (!config[size]) { // 0 = hidden
6625 td.cls += ' hidden-' + size;
6629 td.cls += ' col-' + size + '-' + config[size];
6637 row.cellObjects = cellObjects;
6645 onBeforeLoad : function()
6647 //Roo.log('ds onBeforeLoad');
6651 //if(this.loadMask){
6652 // this.maskEl.show();
6660 this.el.select('tbody', true).first().dom.innerHTML = '';
6663 * Show or hide a row.
6664 * @param {Number} rowIndex to show or hide
6665 * @param {Boolean} state hide
6667 setRowVisibility : function(rowIndex, state)
6669 var bt = this.mainBody.dom;
6671 var rows = this.el.select('tbody > tr', true).elements;
6673 if(typeof(rows[rowIndex]) == 'undefined'){
6676 rows[rowIndex].dom.style.display = state ? '' : 'none';
6680 getSelectionModel : function(){
6682 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6684 return this.selModel;
6687 * Render the Roo.bootstrap object from renderder
6689 renderCellObject : function(r)
6693 var t = r.cfg.render(r.container);
6696 Roo.each(r.cfg.cn, function(c){
6698 container: t.getChildContainer(),
6701 _this.renderCellObject(child);
6706 getRowIndex : function(row)
6710 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6721 * Returns the grid's underlying element = used by panel.Grid
6722 * @return {Element} The element
6724 getGridEl : function(){
6728 * Forces a resize - used by panel.Grid
6729 * @return {Element} The element
6731 autoSize : function()
6733 //var ctr = Roo.get(this.container.dom.parentElement);
6734 var ctr = Roo.get(this.el.dom);
6736 var thd = this.getGridEl().select('thead',true).first();
6737 var tbd = this.getGridEl().select('tbody', true).first();
6738 var tfd = this.getGridEl().select('tfoot', true).first();
6740 var cw = ctr.getWidth();
6744 tbd.setSize(ctr.getWidth(),
6745 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6747 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6750 cw = Math.max(cw, this.totalWidth);
6751 this.getGridEl().select('tr',true).setWidth(cw);
6752 // resize 'expandable coloumn?
6754 return; // we doe not have a view in this design..
6757 onBodyScroll: function()
6760 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6761 this.mainHead.setStyle({
6762 'position' : 'relative',
6763 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6780 * @class Roo.bootstrap.TableCell
6781 * @extends Roo.bootstrap.Component
6782 * Bootstrap TableCell class
6783 * @cfg {String} html cell contain text
6784 * @cfg {String} cls cell class
6785 * @cfg {String} tag cell tag (td|th) default td
6786 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6787 * @cfg {String} align Aligns the content in a cell
6788 * @cfg {String} axis Categorizes cells
6789 * @cfg {String} bgcolor Specifies the background color of a cell
6790 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6791 * @cfg {Number} colspan Specifies the number of columns a cell should span
6792 * @cfg {String} headers Specifies one or more header cells a cell is related to
6793 * @cfg {Number} height Sets the height of a cell
6794 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6795 * @cfg {Number} rowspan Sets the number of rows a cell should span
6796 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6797 * @cfg {String} valign Vertical aligns the content in a cell
6798 * @cfg {Number} width Specifies the width of a cell
6801 * Create a new TableCell
6802 * @param {Object} config The config object
6805 Roo.bootstrap.TableCell = function(config){
6806 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6809 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6829 getAutoCreate : function(){
6830 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6850 cfg.align=this.align
6856 cfg.bgcolor=this.bgcolor
6859 cfg.charoff=this.charoff
6862 cfg.colspan=this.colspan
6865 cfg.headers=this.headers
6868 cfg.height=this.height
6871 cfg.nowrap=this.nowrap
6874 cfg.rowspan=this.rowspan
6877 cfg.scope=this.scope
6880 cfg.valign=this.valign
6883 cfg.width=this.width
6902 * @class Roo.bootstrap.TableRow
6903 * @extends Roo.bootstrap.Component
6904 * Bootstrap TableRow class
6905 * @cfg {String} cls row class
6906 * @cfg {String} align Aligns the content in a table row
6907 * @cfg {String} bgcolor Specifies a background color for a table row
6908 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6909 * @cfg {String} valign Vertical aligns the content in a table row
6912 * Create a new TableRow
6913 * @param {Object} config The config object
6916 Roo.bootstrap.TableRow = function(config){
6917 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6920 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6928 getAutoCreate : function(){
6929 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6939 cfg.align = this.align;
6942 cfg.bgcolor = this.bgcolor;
6945 cfg.charoff = this.charoff;
6948 cfg.valign = this.valign;
6966 * @class Roo.bootstrap.TableBody
6967 * @extends Roo.bootstrap.Component
6968 * Bootstrap TableBody class
6969 * @cfg {String} cls element class
6970 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6971 * @cfg {String} align Aligns the content inside the element
6972 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6973 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6976 * Create a new TableBody
6977 * @param {Object} config The config object
6980 Roo.bootstrap.TableBody = function(config){
6981 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6984 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6992 getAutoCreate : function(){
6993 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7007 cfg.align = this.align;
7010 cfg.charoff = this.charoff;
7013 cfg.valign = this.valign;
7020 // initEvents : function()
7027 // this.store = Roo.factory(this.store, Roo.data);
7028 // this.store.on('load', this.onLoad, this);
7030 // this.store.load();
7034 // onLoad: function ()
7036 // this.fireEvent('load', this);
7046 * Ext JS Library 1.1.1
7047 * Copyright(c) 2006-2007, Ext JS, LLC.
7049 * Originally Released Under LGPL - original licence link has changed is not relivant.
7052 * <script type="text/javascript">
7055 // as we use this in bootstrap.
7056 Roo.namespace('Roo.form');
7058 * @class Roo.form.Action
7059 * Internal Class used to handle form actions
7061 * @param {Roo.form.BasicForm} el The form element or its id
7062 * @param {Object} config Configuration options
7067 // define the action interface
7068 Roo.form.Action = function(form, options){
7070 this.options = options || {};
7073 * Client Validation Failed
7076 Roo.form.Action.CLIENT_INVALID = 'client';
7078 * Server Validation Failed
7081 Roo.form.Action.SERVER_INVALID = 'server';
7083 * Connect to Server Failed
7086 Roo.form.Action.CONNECT_FAILURE = 'connect';
7088 * Reading Data from Server Failed
7091 Roo.form.Action.LOAD_FAILURE = 'load';
7093 Roo.form.Action.prototype = {
7095 failureType : undefined,
7096 response : undefined,
7100 run : function(options){
7105 success : function(response){
7110 handleResponse : function(response){
7114 // default connection failure
7115 failure : function(response){
7117 this.response = response;
7118 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7119 this.form.afterAction(this, false);
7122 processResponse : function(response){
7123 this.response = response;
7124 if(!response.responseText){
7127 this.result = this.handleResponse(response);
7131 // utility functions used internally
7132 getUrl : function(appendParams){
7133 var url = this.options.url || this.form.url || this.form.el.dom.action;
7135 var p = this.getParams();
7137 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7143 getMethod : function(){
7144 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7147 getParams : function(){
7148 var bp = this.form.baseParams;
7149 var p = this.options.params;
7151 if(typeof p == "object"){
7152 p = Roo.urlEncode(Roo.applyIf(p, bp));
7153 }else if(typeof p == 'string' && bp){
7154 p += '&' + Roo.urlEncode(bp);
7157 p = Roo.urlEncode(bp);
7162 createCallback : function(){
7164 success: this.success,
7165 failure: this.failure,
7167 timeout: (this.form.timeout*1000),
7168 upload: this.form.fileUpload ? this.success : undefined
7173 Roo.form.Action.Submit = function(form, options){
7174 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7177 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7180 haveProgress : false,
7181 uploadComplete : false,
7183 // uploadProgress indicator.
7184 uploadProgress : function()
7186 if (!this.form.progressUrl) {
7190 if (!this.haveProgress) {
7191 Roo.MessageBox.progress("Uploading", "Uploading");
7193 if (this.uploadComplete) {
7194 Roo.MessageBox.hide();
7198 this.haveProgress = true;
7200 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7202 var c = new Roo.data.Connection();
7204 url : this.form.progressUrl,
7209 success : function(req){
7210 //console.log(data);
7214 rdata = Roo.decode(req.responseText)
7216 Roo.log("Invalid data from server..");
7220 if (!rdata || !rdata.success) {
7222 Roo.MessageBox.alert(Roo.encode(rdata));
7225 var data = rdata.data;
7227 if (this.uploadComplete) {
7228 Roo.MessageBox.hide();
7233 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7234 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7237 this.uploadProgress.defer(2000,this);
7240 failure: function(data) {
7241 Roo.log('progress url failed ');
7252 // run get Values on the form, so it syncs any secondary forms.
7253 this.form.getValues();
7255 var o = this.options;
7256 var method = this.getMethod();
7257 var isPost = method == 'POST';
7258 if(o.clientValidation === false || this.form.isValid()){
7260 if (this.form.progressUrl) {
7261 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7262 (new Date() * 1) + '' + Math.random());
7267 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7268 form:this.form.el.dom,
7269 url:this.getUrl(!isPost),
7271 params:isPost ? this.getParams() : null,
7272 isUpload: this.form.fileUpload
7275 this.uploadProgress();
7277 }else if (o.clientValidation !== false){ // client validation failed
7278 this.failureType = Roo.form.Action.CLIENT_INVALID;
7279 this.form.afterAction(this, false);
7283 success : function(response)
7285 this.uploadComplete= true;
7286 if (this.haveProgress) {
7287 Roo.MessageBox.hide();
7291 var result = this.processResponse(response);
7292 if(result === true || result.success){
7293 this.form.afterAction(this, true);
7297 this.form.markInvalid(result.errors);
7298 this.failureType = Roo.form.Action.SERVER_INVALID;
7300 this.form.afterAction(this, false);
7302 failure : function(response)
7304 this.uploadComplete= true;
7305 if (this.haveProgress) {
7306 Roo.MessageBox.hide();
7309 this.response = response;
7310 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7311 this.form.afterAction(this, false);
7314 handleResponse : function(response){
7315 if(this.form.errorReader){
7316 var rs = this.form.errorReader.read(response);
7319 for(var i = 0, len = rs.records.length; i < len; i++) {
7320 var r = rs.records[i];
7324 if(errors.length < 1){
7328 success : rs.success,
7334 ret = Roo.decode(response.responseText);
7338 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7348 Roo.form.Action.Load = function(form, options){
7349 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7350 this.reader = this.form.reader;
7353 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7358 Roo.Ajax.request(Roo.apply(
7359 this.createCallback(), {
7360 method:this.getMethod(),
7361 url:this.getUrl(false),
7362 params:this.getParams()
7366 success : function(response){
7368 var result = this.processResponse(response);
7369 if(result === true || !result.success || !result.data){
7370 this.failureType = Roo.form.Action.LOAD_FAILURE;
7371 this.form.afterAction(this, false);
7374 this.form.clearInvalid();
7375 this.form.setValues(result.data);
7376 this.form.afterAction(this, true);
7379 handleResponse : function(response){
7380 if(this.form.reader){
7381 var rs = this.form.reader.read(response);
7382 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7384 success : rs.success,
7388 return Roo.decode(response.responseText);
7392 Roo.form.Action.ACTION_TYPES = {
7393 'load' : Roo.form.Action.Load,
7394 'submit' : Roo.form.Action.Submit
7403 * @class Roo.bootstrap.Form
7404 * @extends Roo.bootstrap.Component
7405 * Bootstrap Form class
7406 * @cfg {String} method GET | POST (default POST)
7407 * @cfg {String} labelAlign top | left (default top)
7408 * @cfg {String} align left | right - for navbars
7409 * @cfg {Boolean} loadMask load mask when submit (default true)
7414 * @param {Object} config The config object
7418 Roo.bootstrap.Form = function(config){
7419 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7422 * @event clientvalidation
7423 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7424 * @param {Form} this
7425 * @param {Boolean} valid true if the form has passed client-side validation
7427 clientvalidation: true,
7429 * @event beforeaction
7430 * Fires before any action is performed. Return false to cancel the action.
7431 * @param {Form} this
7432 * @param {Action} action The action to be performed
7436 * @event actionfailed
7437 * Fires when an action fails.
7438 * @param {Form} this
7439 * @param {Action} action The action that failed
7441 actionfailed : true,
7443 * @event actioncomplete
7444 * Fires when an action is completed.
7445 * @param {Form} this
7446 * @param {Action} action The action that completed
7448 actioncomplete : true
7453 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7456 * @cfg {String} method
7457 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7462 * The URL to use for form actions if one isn't supplied in the action options.
7465 * @cfg {Boolean} fileUpload
7466 * Set to true if this form is a file upload.
7470 * @cfg {Object} baseParams
7471 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7475 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7479 * @cfg {Sting} align (left|right) for navbar forms
7484 activeAction : null,
7487 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7488 * element by passing it or its id or mask the form itself by passing in true.
7491 waitMsgTarget : false,
7495 getAutoCreate : function(){
7499 method : this.method || 'POST',
7500 id : this.id || Roo.id(),
7503 if (this.parent().xtype.match(/^Nav/)) {
7504 cfg.cls = 'navbar-form navbar-' + this.align;
7508 if (this.labelAlign == 'left' ) {
7509 cfg.cls += ' form-horizontal';
7515 initEvents : function()
7517 this.el.on('submit', this.onSubmit, this);
7518 // this was added as random key presses on the form where triggering form submit.
7519 this.el.on('keypress', function(e) {
7520 if (e.getCharCode() != 13) {
7523 // we might need to allow it for textareas.. and some other items.
7524 // check e.getTarget().
7526 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7530 Roo.log("keypress blocked");
7538 onSubmit : function(e){
7543 * Returns true if client-side validation on the form is successful.
7546 isValid : function(){
7547 var items = this.getItems();
7549 items.each(function(f){
7558 * Returns true if any fields in this form have changed since their original load.
7561 isDirty : function(){
7563 var items = this.getItems();
7564 items.each(function(f){
7574 * Performs a predefined action (submit or load) or custom actions you define on this form.
7575 * @param {String} actionName The name of the action type
7576 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7577 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7578 * accept other config options):
7580 Property Type Description
7581 ---------------- --------------- ----------------------------------------------------------------------------------
7582 url String The url for the action (defaults to the form's url)
7583 method String The form method to use (defaults to the form's method, or POST if not defined)
7584 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7585 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7586 validate the form on the client (defaults to false)
7588 * @return {BasicForm} this
7590 doAction : function(action, options){
7591 if(typeof action == 'string'){
7592 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7594 if(this.fireEvent('beforeaction', this, action) !== false){
7595 this.beforeAction(action);
7596 action.run.defer(100, action);
7602 beforeAction : function(action){
7603 var o = action.options;
7606 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7608 // not really supported yet.. ??
7610 //if(this.waitMsgTarget === true){
7611 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7612 //}else if(this.waitMsgTarget){
7613 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7614 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7616 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7622 afterAction : function(action, success){
7623 this.activeAction = null;
7624 var o = action.options;
7626 //if(this.waitMsgTarget === true){
7628 //}else if(this.waitMsgTarget){
7629 // this.waitMsgTarget.unmask();
7631 // Roo.MessageBox.updateProgress(1);
7632 // Roo.MessageBox.hide();
7639 Roo.callback(o.success, o.scope, [this, action]);
7640 this.fireEvent('actioncomplete', this, action);
7644 // failure condition..
7645 // we have a scenario where updates need confirming.
7646 // eg. if a locking scenario exists..
7647 // we look for { errors : { needs_confirm : true }} in the response.
7649 (typeof(action.result) != 'undefined') &&
7650 (typeof(action.result.errors) != 'undefined') &&
7651 (typeof(action.result.errors.needs_confirm) != 'undefined')
7654 Roo.log("not supported yet");
7657 Roo.MessageBox.confirm(
7658 "Change requires confirmation",
7659 action.result.errorMsg,
7664 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7674 Roo.callback(o.failure, o.scope, [this, action]);
7675 // show an error message if no failed handler is set..
7676 if (!this.hasListener('actionfailed')) {
7677 Roo.log("need to add dialog support");
7679 Roo.MessageBox.alert("Error",
7680 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7681 action.result.errorMsg :
7682 "Saving Failed, please check your entries or try again"
7687 this.fireEvent('actionfailed', this, action);
7692 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7693 * @param {String} id The value to search for
7696 findField : function(id){
7697 var items = this.getItems();
7698 var field = items.get(id);
7700 items.each(function(f){
7701 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7708 return field || null;
7711 * Mark fields in this form invalid in bulk.
7712 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7713 * @return {BasicForm} this
7715 markInvalid : function(errors){
7716 if(errors instanceof Array){
7717 for(var i = 0, len = errors.length; i < len; i++){
7718 var fieldError = errors[i];
7719 var f = this.findField(fieldError.id);
7721 f.markInvalid(fieldError.msg);
7727 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7728 field.markInvalid(errors[id]);
7732 //Roo.each(this.childForms || [], function (f) {
7733 // f.markInvalid(errors);
7740 * Set values for fields in this form in bulk.
7741 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7742 * @return {BasicForm} this
7744 setValues : function(values){
7745 if(values instanceof Array){ // array of objects
7746 for(var i = 0, len = values.length; i < len; i++){
7748 var f = this.findField(v.id);
7750 f.setValue(v.value);
7751 if(this.trackResetOnLoad){
7752 f.originalValue = f.getValue();
7756 }else{ // object hash
7759 if(typeof values[id] != 'function' && (field = this.findField(id))){
7761 if (field.setFromData &&
7763 field.displayField &&
7764 // combos' with local stores can
7765 // be queried via setValue()
7766 // to set their value..
7767 (field.store && !field.store.isLocal)
7771 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7772 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7773 field.setFromData(sd);
7776 field.setValue(values[id]);
7780 if(this.trackResetOnLoad){
7781 field.originalValue = field.getValue();
7787 //Roo.each(this.childForms || [], function (f) {
7788 // f.setValues(values);
7795 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7796 * they are returned as an array.
7797 * @param {Boolean} asString
7800 getValues : function(asString){
7801 //if (this.childForms) {
7802 // copy values from the child forms
7803 // Roo.each(this.childForms, function (f) {
7804 // this.setValues(f.getValues());
7810 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7811 if(asString === true){
7814 return Roo.urlDecode(fs);
7818 * Returns the fields in this form as an object with key/value pairs.
7819 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7822 getFieldValues : function(with_hidden)
7824 var items = this.getItems();
7826 items.each(function(f){
7830 var v = f.getValue();
7831 if (f.inputType =='radio') {
7832 if (typeof(ret[f.getName()]) == 'undefined') {
7833 ret[f.getName()] = ''; // empty..
7836 if (!f.el.dom.checked) {
7844 // not sure if this supported any more..
7845 if ((typeof(v) == 'object') && f.getRawValue) {
7846 v = f.getRawValue() ; // dates..
7848 // combo boxes where name != hiddenName...
7849 if (f.name != f.getName()) {
7850 ret[f.name] = f.getRawValue();
7852 ret[f.getName()] = v;
7859 * Clears all invalid messages in this form.
7860 * @return {BasicForm} this
7862 clearInvalid : function(){
7863 var items = this.getItems();
7865 items.each(function(f){
7876 * @return {BasicForm} this
7879 var items = this.getItems();
7880 items.each(function(f){
7884 Roo.each(this.childForms || [], function (f) {
7891 getItems : function()
7893 var r=new Roo.util.MixedCollection(false, function(o){
7894 return o.id || (o.id = Roo.id());
7896 var iter = function(el) {
7903 Roo.each(el.items,function(e) {
7923 * Ext JS Library 1.1.1
7924 * Copyright(c) 2006-2007, Ext JS, LLC.
7926 * Originally Released Under LGPL - original licence link has changed is not relivant.
7929 * <script type="text/javascript">
7932 * @class Roo.form.VTypes
7933 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7936 Roo.form.VTypes = function(){
7937 // closure these in so they are only created once.
7938 var alpha = /^[a-zA-Z_]+$/;
7939 var alphanum = /^[a-zA-Z0-9_]+$/;
7940 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7941 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7943 // All these messages and functions are configurable
7946 * The function used to validate email addresses
7947 * @param {String} value The email address
7949 'email' : function(v){
7950 return email.test(v);
7953 * The error text to display when the email validation function returns false
7956 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7958 * The keystroke filter mask to be applied on email input
7961 'emailMask' : /[a-z0-9_\.\-@]/i,
7964 * The function used to validate URLs
7965 * @param {String} value The URL
7967 'url' : function(v){
7971 * The error text to display when the url validation function returns false
7974 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7977 * The function used to validate alpha values
7978 * @param {String} value The value
7980 'alpha' : function(v){
7981 return alpha.test(v);
7984 * The error text to display when the alpha validation function returns false
7987 'alphaText' : 'This field should only contain letters and _',
7989 * The keystroke filter mask to be applied on alpha input
7992 'alphaMask' : /[a-z_]/i,
7995 * The function used to validate alphanumeric values
7996 * @param {String} value The value
7998 'alphanum' : function(v){
7999 return alphanum.test(v);
8002 * The error text to display when the alphanumeric validation function returns false
8005 'alphanumText' : 'This field should only contain letters, numbers and _',
8007 * The keystroke filter mask to be applied on alphanumeric input
8010 'alphanumMask' : /[a-z0-9_]/i
8020 * @class Roo.bootstrap.Input
8021 * @extends Roo.bootstrap.Component
8022 * Bootstrap Input class
8023 * @cfg {Boolean} disabled is it disabled
8024 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8025 * @cfg {String} name name of the input
8026 * @cfg {string} fieldLabel - the label associated
8027 * @cfg {string} placeholder - placeholder to put in text.
8028 * @cfg {string} before - input group add on before
8029 * @cfg {string} after - input group add on after
8030 * @cfg {string} size - (lg|sm) or leave empty..
8031 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8032 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8033 * @cfg {Number} md colspan out of 12 for computer-sized screens
8034 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8035 * @cfg {string} value default value of the input
8036 * @cfg {Number} labelWidth set the width of label (0-12)
8037 * @cfg {String} labelAlign (top|left)
8038 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8039 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8040 * @cfg {String} indicatorpos (left|right) default left
8042 * @cfg {String} align (left|center|right) Default left
8043 * @cfg {Boolean} forceFeedback (true|false) Default false
8049 * Create a new Input
8050 * @param {Object} config The config object
8053 Roo.bootstrap.Input = function(config){
8054 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8059 * Fires when this field receives input focus.
8060 * @param {Roo.form.Field} this
8065 * Fires when this field loses input focus.
8066 * @param {Roo.form.Field} this
8071 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8072 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8073 * @param {Roo.form.Field} this
8074 * @param {Roo.EventObject} e The event object
8079 * Fires just before the field blurs if the field value has changed.
8080 * @param {Roo.form.Field} this
8081 * @param {Mixed} newValue The new value
8082 * @param {Mixed} oldValue The original value
8087 * Fires after the field has been marked as invalid.
8088 * @param {Roo.form.Field} this
8089 * @param {String} msg The validation message
8094 * Fires after the field has been validated with no errors.
8095 * @param {Roo.form.Field} this
8100 * Fires after the key up
8101 * @param {Roo.form.Field} this
8102 * @param {Roo.EventObject} e The event Object
8108 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8110 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8111 automatic validation (defaults to "keyup").
8113 validationEvent : "keyup",
8115 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8117 validateOnBlur : true,
8119 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8121 validationDelay : 250,
8123 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8125 focusClass : "x-form-focus", // not needed???
8129 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8131 invalidClass : "has-warning",
8134 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8136 validClass : "has-success",
8139 * @cfg {Boolean} hasFeedback (true|false) default true
8144 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8146 invalidFeedbackClass : "glyphicon-warning-sign",
8149 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8151 validFeedbackClass : "glyphicon-ok",
8154 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8156 selectOnFocus : false,
8159 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8163 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8168 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8170 disableKeyFilter : false,
8173 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8177 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8181 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8183 blankText : "This field is required",
8186 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8190 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8192 maxLength : Number.MAX_VALUE,
8194 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8196 minLengthText : "The minimum length for this field is {0}",
8198 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8200 maxLengthText : "The maximum length for this field is {0}",
8204 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8205 * If available, this function will be called only after the basic validators all return true, and will be passed the
8206 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8210 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8211 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8212 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8216 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8220 autocomplete: false,
8239 formatedValue : false,
8240 forceFeedback : false,
8242 indicatorpos : 'left',
8244 parentLabelAlign : function()
8247 while (parent.parent()) {
8248 parent = parent.parent();
8249 if (typeof(parent.labelAlign) !='undefined') {
8250 return parent.labelAlign;
8257 getAutoCreate : function()
8259 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8265 if(this.inputType != 'hidden'){
8266 cfg.cls = 'form-group' //input-group
8272 type : this.inputType,
8274 cls : 'form-control',
8275 placeholder : this.placeholder || '',
8276 autocomplete : this.autocomplete || 'new-password'
8280 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8283 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8284 input.maxLength = this.maxLength;
8287 if (this.disabled) {
8288 input.disabled=true;
8291 if (this.readOnly) {
8292 input.readonly=true;
8296 input.name = this.name;
8300 input.cls += ' input-' + this.size;
8304 ['xs','sm','md','lg'].map(function(size){
8305 if (settings[size]) {
8306 cfg.cls += ' col-' + size + '-' + settings[size];
8310 var inputblock = input;
8314 cls: 'glyphicon form-control-feedback'
8317 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8320 cls : 'has-feedback',
8328 if (this.before || this.after) {
8331 cls : 'input-group',
8335 if (this.before && typeof(this.before) == 'string') {
8337 inputblock.cn.push({
8339 cls : 'roo-input-before input-group-addon',
8343 if (this.before && typeof(this.before) == 'object') {
8344 this.before = Roo.factory(this.before);
8346 inputblock.cn.push({
8348 cls : 'roo-input-before input-group-' +
8349 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8353 inputblock.cn.push(input);
8355 if (this.after && typeof(this.after) == 'string') {
8356 inputblock.cn.push({
8358 cls : 'roo-input-after input-group-addon',
8362 if (this.after && typeof(this.after) == 'object') {
8363 this.after = Roo.factory(this.after);
8365 inputblock.cn.push({
8367 cls : 'roo-input-after input-group-' +
8368 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8372 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8373 inputblock.cls += ' has-feedback';
8374 inputblock.cn.push(feedback);
8378 if (align ==='left' && this.fieldLabel.length) {
8383 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8384 tooltip : 'This field is required'
8389 cls : 'control-label col-sm-' + this.labelWidth,
8390 html : this.fieldLabel
8394 cls : "col-sm-" + (12 - this.labelWidth),
8402 if(this.indicatorpos == 'right'){
8407 cls : 'control-label col-sm-' + this.labelWidth,
8408 html : this.fieldLabel
8413 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8414 tooltip : 'This field is required'
8417 cls : "col-sm-" + (12 - this.labelWidth),
8426 } else if ( this.fieldLabel.length) {
8431 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8432 tooltip : 'This field is required'
8436 //cls : 'input-group-addon',
8437 html : this.fieldLabel
8445 if(this.indicatorpos == 'right'){
8450 //cls : 'input-group-addon',
8451 html : this.fieldLabel
8456 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8457 tooltip : 'This field is required'
8477 if (this.parentType === 'Navbar' && this.parent().bar) {
8478 cfg.cls += ' navbar-form';
8481 if (this.parentType === 'NavGroup') {
8482 cfg.cls += ' navbar-form';
8490 * return the real input element.
8492 inputEl: function ()
8494 return this.el.select('input.form-control',true).first();
8497 tooltipEl : function()
8499 return this.inputEl();
8502 indicatorEl : function()
8504 var indicator = this.el.select('i.roo-required-indicator',true).first();
8514 setDisabled : function(v)
8516 var i = this.inputEl().dom;
8518 i.removeAttribute('disabled');
8522 i.setAttribute('disabled','true');
8524 initEvents : function()
8527 this.inputEl().on("keydown" , this.fireKey, this);
8528 this.inputEl().on("focus", this.onFocus, this);
8529 this.inputEl().on("blur", this.onBlur, this);
8531 this.inputEl().relayEvent('keyup', this);
8533 this.indicator = this.indicatorEl();
8536 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8537 this.indicator.hide();
8540 // reference to original value for reset
8541 this.originalValue = this.getValue();
8542 //Roo.form.TextField.superclass.initEvents.call(this);
8543 if(this.validationEvent == 'keyup'){
8544 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8545 this.inputEl().on('keyup', this.filterValidation, this);
8547 else if(this.validationEvent !== false){
8548 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8551 if(this.selectOnFocus){
8552 this.on("focus", this.preFocus, this);
8555 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8556 this.inputEl().on("keypress", this.filterKeys, this);
8558 this.inputEl().relayEvent('keypress', this);
8561 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8562 this.el.on("click", this.autoSize, this);
8565 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8566 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8569 if (typeof(this.before) == 'object') {
8570 this.before.render(this.el.select('.roo-input-before',true).first());
8572 if (typeof(this.after) == 'object') {
8573 this.after.render(this.el.select('.roo-input-after',true).first());
8578 filterValidation : function(e){
8579 if(!e.isNavKeyPress()){
8580 this.validationTask.delay(this.validationDelay);
8584 * Validates the field value
8585 * @return {Boolean} True if the value is valid, else false
8587 validate : function(){
8588 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8589 if(this.disabled || this.validateValue(this.getRawValue())){
8600 * Validates a value according to the field's validation rules and marks the field as invalid
8601 * if the validation fails
8602 * @param {Mixed} value The value to validate
8603 * @return {Boolean} True if the value is valid, else false
8605 validateValue : function(value){
8606 if(value.length < 1) { // if it's blank
8607 if(this.allowBlank){
8613 if(value.length < this.minLength){
8616 if(value.length > this.maxLength){
8620 var vt = Roo.form.VTypes;
8621 if(!vt[this.vtype](value, this)){
8625 if(typeof this.validator == "function"){
8626 var msg = this.validator(value);
8632 if(this.regex && !this.regex.test(value)){
8642 fireKey : function(e){
8643 //Roo.log('field ' + e.getKey());
8644 if(e.isNavKeyPress()){
8645 this.fireEvent("specialkey", this, e);
8648 focus : function (selectText){
8650 this.inputEl().focus();
8651 if(selectText === true){
8652 this.inputEl().dom.select();
8658 onFocus : function(){
8659 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8660 // this.el.addClass(this.focusClass);
8663 this.hasFocus = true;
8664 this.startValue = this.getValue();
8665 this.fireEvent("focus", this);
8669 beforeBlur : Roo.emptyFn,
8673 onBlur : function(){
8675 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8676 //this.el.removeClass(this.focusClass);
8678 this.hasFocus = false;
8679 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8682 var v = this.getValue();
8683 if(String(v) !== String(this.startValue)){
8684 this.fireEvent('change', this, v, this.startValue);
8686 this.fireEvent("blur", this);
8690 * Resets the current field value to the originally loaded value and clears any validation messages
8693 this.setValue(this.originalValue);
8697 * Returns the name of the field
8698 * @return {Mixed} name The name field
8700 getName: function(){
8704 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8705 * @return {Mixed} value The field value
8707 getValue : function(){
8709 var v = this.inputEl().getValue();
8714 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8715 * @return {Mixed} value The field value
8717 getRawValue : function(){
8718 var v = this.inputEl().getValue();
8724 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8725 * @param {Mixed} value The value to set
8727 setRawValue : function(v){
8728 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8731 selectText : function(start, end){
8732 var v = this.getRawValue();
8734 start = start === undefined ? 0 : start;
8735 end = end === undefined ? v.length : end;
8736 var d = this.inputEl().dom;
8737 if(d.setSelectionRange){
8738 d.setSelectionRange(start, end);
8739 }else if(d.createTextRange){
8740 var range = d.createTextRange();
8741 range.moveStart("character", start);
8742 range.moveEnd("character", v.length-end);
8749 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8750 * @param {Mixed} value The value to set
8752 setValue : function(v){
8755 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8761 processValue : function(value){
8762 if(this.stripCharsRe){
8763 var newValue = value.replace(this.stripCharsRe, '');
8764 if(newValue !== value){
8765 this.setRawValue(newValue);
8772 preFocus : function(){
8774 if(this.selectOnFocus){
8775 this.inputEl().dom.select();
8778 filterKeys : function(e){
8780 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8783 var c = e.getCharCode(), cc = String.fromCharCode(c);
8784 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8787 if(!this.maskRe.test(cc)){
8792 * Clear any invalid styles/messages for this field
8794 clearInvalid : function(){
8796 if(!this.el || this.preventMark){ // not rendered
8801 this.indicator.hide();
8804 this.el.removeClass(this.invalidClass);
8806 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8808 var feedback = this.el.select('.form-control-feedback', true).first();
8811 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8816 this.fireEvent('valid', this);
8820 * Mark this field as valid
8822 markValid : function()
8824 if(!this.el || this.preventMark){ // not rendered
8828 this.el.removeClass([this.invalidClass, this.validClass]);
8830 var feedback = this.el.select('.form-control-feedback', true).first();
8833 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8836 if(this.disabled || this.allowBlank){
8841 this.indicator.hide();
8844 this.el.addClass(this.validClass);
8846 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8848 var feedback = this.el.select('.form-control-feedback', true).first();
8851 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8852 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8857 this.fireEvent('valid', this);
8861 * Mark this field as invalid
8862 * @param {String} msg The validation message
8864 markInvalid : function(msg)
8866 if(!this.el || this.preventMark){ // not rendered
8870 this.el.removeClass([this.invalidClass, this.validClass]);
8872 var feedback = this.el.select('.form-control-feedback', true).first();
8875 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8878 if(this.disabled || this.allowBlank){
8883 this.indicator.show();
8886 this.el.addClass(this.invalidClass);
8888 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8890 var feedback = this.el.select('.form-control-feedback', true).first();
8893 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8895 if(this.getValue().length || this.forceFeedback){
8896 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8903 this.fireEvent('invalid', this, msg);
8906 SafariOnKeyDown : function(event)
8908 // this is a workaround for a password hang bug on chrome/ webkit.
8910 var isSelectAll = false;
8912 if(this.inputEl().dom.selectionEnd > 0){
8913 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8915 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8916 event.preventDefault();
8921 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8923 event.preventDefault();
8924 // this is very hacky as keydown always get's upper case.
8926 var cc = String.fromCharCode(event.getCharCode());
8927 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8931 adjustWidth : function(tag, w){
8932 tag = tag.toLowerCase();
8933 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8934 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8938 if(tag == 'textarea'){
8941 }else if(Roo.isOpera){
8945 if(tag == 'textarea'){
8964 * @class Roo.bootstrap.TextArea
8965 * @extends Roo.bootstrap.Input
8966 * Bootstrap TextArea class
8967 * @cfg {Number} cols Specifies the visible width of a text area
8968 * @cfg {Number} rows Specifies the visible number of lines in a text area
8969 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8970 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8971 * @cfg {string} html text
8974 * Create a new TextArea
8975 * @param {Object} config The config object
8978 Roo.bootstrap.TextArea = function(config){
8979 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8983 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8993 getAutoCreate : function(){
8995 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9006 value : this.value || '',
9007 html: this.html || '',
9008 cls : 'form-control',
9009 placeholder : this.placeholder || ''
9013 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9014 input.maxLength = this.maxLength;
9018 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9022 input.cols = this.cols;
9025 if (this.readOnly) {
9026 input.readonly = true;
9030 input.name = this.name;
9034 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9038 ['xs','sm','md','lg'].map(function(size){
9039 if (settings[size]) {
9040 cfg.cls += ' col-' + size + '-' + settings[size];
9044 var inputblock = input;
9046 if(this.hasFeedback && !this.allowBlank){
9050 cls: 'glyphicon form-control-feedback'
9054 cls : 'has-feedback',
9063 if (this.before || this.after) {
9066 cls : 'input-group',
9070 inputblock.cn.push({
9072 cls : 'input-group-addon',
9077 inputblock.cn.push(input);
9079 if(this.hasFeedback && !this.allowBlank){
9080 inputblock.cls += ' has-feedback';
9081 inputblock.cn.push(feedback);
9085 inputblock.cn.push({
9087 cls : 'input-group-addon',
9094 if (align ==='left' && this.fieldLabel.length) {
9095 // Roo.log("left and has label");
9101 cls : 'control-label col-sm-' + this.labelWidth,
9102 html : this.fieldLabel
9106 cls : "col-sm-" + (12 - this.labelWidth),
9113 } else if ( this.fieldLabel.length) {
9114 // Roo.log(" label");
9119 //cls : 'input-group-addon',
9120 html : this.fieldLabel
9130 // Roo.log(" no label && no align");
9140 if (this.disabled) {
9141 input.disabled=true;
9148 * return the real textarea element.
9150 inputEl: function ()
9152 return this.el.select('textarea.form-control',true).first();
9156 * Clear any invalid styles/messages for this field
9158 clearInvalid : function()
9161 if(!this.el || this.preventMark){ // not rendered
9165 var label = this.el.select('label', true).first();
9166 var icon = this.el.select('i.fa-star', true).first();
9172 this.el.removeClass(this.invalidClass);
9174 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9176 var feedback = this.el.select('.form-control-feedback', true).first();
9179 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9184 this.fireEvent('valid', this);
9188 * Mark this field as valid
9190 markValid : function()
9192 if(!this.el || this.preventMark){ // not rendered
9196 this.el.removeClass([this.invalidClass, this.validClass]);
9198 var feedback = this.el.select('.form-control-feedback', true).first();
9201 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9204 if(this.disabled || this.allowBlank){
9208 var label = this.el.select('label', true).first();
9209 var icon = this.el.select('i.fa-star', true).first();
9215 this.el.addClass(this.validClass);
9217 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9219 var feedback = this.el.select('.form-control-feedback', true).first();
9222 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9223 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9228 this.fireEvent('valid', this);
9232 * Mark this field as invalid
9233 * @param {String} msg The validation message
9235 markInvalid : function(msg)
9237 if(!this.el || this.preventMark){ // not rendered
9241 this.el.removeClass([this.invalidClass, this.validClass]);
9243 var feedback = this.el.select('.form-control-feedback', true).first();
9246 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9249 if(this.disabled || this.allowBlank){
9253 var label = this.el.select('label', true).first();
9254 var icon = this.el.select('i.fa-star', true).first();
9256 if(!this.getValue().length && label && !icon){
9257 this.el.createChild({
9259 cls : 'text-danger fa fa-lg fa-star',
9260 tooltip : 'This field is required',
9261 style : 'margin-right:5px;'
9265 this.el.addClass(this.invalidClass);
9267 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9269 var feedback = this.el.select('.form-control-feedback', true).first();
9272 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9274 if(this.getValue().length || this.forceFeedback){
9275 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9282 this.fireEvent('invalid', this, msg);
9290 * trigger field - base class for combo..
9295 * @class Roo.bootstrap.TriggerField
9296 * @extends Roo.bootstrap.Input
9297 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9298 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9299 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9300 * for which you can provide a custom implementation. For example:
9302 var trigger = new Roo.bootstrap.TriggerField();
9303 trigger.onTriggerClick = myTriggerFn;
9304 trigger.applyTo('my-field');
9307 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9308 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9309 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9310 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9311 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9314 * Create a new TriggerField.
9315 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9316 * to the base TextField)
9318 Roo.bootstrap.TriggerField = function(config){
9319 this.mimicing = false;
9320 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9323 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9325 * @cfg {String} triggerClass A CSS class to apply to the trigger
9328 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9333 * @cfg {Boolean} removable (true|false) special filter default false
9337 /** @cfg {Boolean} grow @hide */
9338 /** @cfg {Number} growMin @hide */
9339 /** @cfg {Number} growMax @hide */
9345 autoSize: Roo.emptyFn,
9352 actionMode : 'wrap',
9357 getAutoCreate : function(){
9359 var align = this.labelAlign || this.parentLabelAlign();
9364 cls: 'form-group' //input-group
9371 type : this.inputType,
9372 cls : 'form-control',
9373 autocomplete: 'new-password',
9374 placeholder : this.placeholder || ''
9378 input.name = this.name;
9381 input.cls += ' input-' + this.size;
9384 if (this.disabled) {
9385 input.disabled=true;
9388 var inputblock = input;
9390 if(this.hasFeedback && !this.allowBlank){
9394 cls: 'glyphicon form-control-feedback'
9397 if(this.removable && !this.editable && !this.tickable){
9399 cls : 'has-feedback',
9405 cls : 'roo-combo-removable-btn close'
9412 cls : 'has-feedback',
9421 if(this.removable && !this.editable && !this.tickable){
9423 cls : 'roo-removable',
9429 cls : 'roo-combo-removable-btn close'
9436 if (this.before || this.after) {
9439 cls : 'input-group',
9443 inputblock.cn.push({
9445 cls : 'input-group-addon',
9450 inputblock.cn.push(input);
9452 if(this.hasFeedback && !this.allowBlank){
9453 inputblock.cls += ' has-feedback';
9454 inputblock.cn.push(feedback);
9458 inputblock.cn.push({
9460 cls : 'input-group-addon',
9473 cls: 'form-hidden-field'
9487 cls: 'form-hidden-field'
9491 cls: 'roo-select2-choices',
9495 cls: 'roo-select2-search-field',
9508 cls: 'roo-select2-container input-group',
9513 // cls: 'typeahead typeahead-long dropdown-menu',
9514 // style: 'display:none'
9519 if(!this.multiple && this.showToggleBtn){
9525 if (this.caret != false) {
9528 cls: 'fa fa-' + this.caret
9535 cls : 'input-group-addon btn dropdown-toggle',
9540 cls: 'combobox-clear',
9554 combobox.cls += ' roo-select2-container-multi';
9557 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
9559 // Roo.log("left and has label");
9563 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9564 tooltip : 'This field is required'
9569 cls : 'control-label col-sm-' + this.labelWidth,
9570 html : this.fieldLabel
9574 cls : "col-sm-" + (12 - this.labelWidth),
9582 if(this.indicatorpos == 'right'){
9587 cls : 'control-label col-sm-' + this.labelWidth,
9588 html : this.fieldLabel
9593 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9594 tooltip : 'This field is required'
9597 cls : "col-sm-" + (12 - this.labelWidth),
9606 } else if ( this.fieldLabel.length) {
9607 // Roo.log(" label");
9611 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9612 tooltip : 'This field is required'
9616 //cls : 'input-group-addon',
9617 html : this.fieldLabel
9625 if(this.indicatorpos == 'right'){
9630 //cls : 'input-group-addon',
9631 html : this.fieldLabel
9636 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9637 tooltip : 'This field is required'
9648 // Roo.log(" no label && no align");
9655 ['xs','sm','md','lg'].map(function(size){
9656 if (settings[size]) {
9657 cfg.cls += ' col-' + size + '-' + settings[size];
9668 onResize : function(w, h){
9669 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9670 // if(typeof w == 'number'){
9671 // var x = w - this.trigger.getWidth();
9672 // this.inputEl().setWidth(this.adjustWidth('input', x));
9673 // this.trigger.setStyle('left', x+'px');
9678 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9681 getResizeEl : function(){
9682 return this.inputEl();
9686 getPositionEl : function(){
9687 return this.inputEl();
9691 alignErrorIcon : function(){
9692 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9696 initEvents : function(){
9700 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9701 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9702 if(!this.multiple && this.showToggleBtn){
9703 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9704 if(this.hideTrigger){
9705 this.trigger.setDisplayed(false);
9707 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9711 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9714 if(this.removable && !this.editable && !this.tickable){
9715 var close = this.closeTriggerEl();
9718 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9719 close.on('click', this.removeBtnClick, this, close);
9723 //this.trigger.addClassOnOver('x-form-trigger-over');
9724 //this.trigger.addClassOnClick('x-form-trigger-click');
9727 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9731 closeTriggerEl : function()
9733 var close = this.el.select('.roo-combo-removable-btn', true).first();
9734 return close ? close : false;
9737 removeBtnClick : function(e, h, el)
9741 if(this.fireEvent("remove", this) !== false){
9743 this.fireEvent("afterremove", this)
9747 createList : function()
9749 this.list = Roo.get(document.body).createChild({
9751 cls: 'typeahead typeahead-long dropdown-menu',
9752 style: 'display:none'
9755 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9760 initTrigger : function(){
9765 onDestroy : function(){
9767 this.trigger.removeAllListeners();
9768 // this.trigger.remove();
9771 // this.wrap.remove();
9773 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9777 onFocus : function(){
9778 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9781 this.wrap.addClass('x-trigger-wrap-focus');
9782 this.mimicing = true;
9783 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9784 if(this.monitorTab){
9785 this.el.on("keydown", this.checkTab, this);
9792 checkTab : function(e){
9793 if(e.getKey() == e.TAB){
9799 onBlur : function(){
9804 mimicBlur : function(e, t){
9806 if(!this.wrap.contains(t) && this.validateBlur()){
9813 triggerBlur : function(){
9814 this.mimicing = false;
9815 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9816 if(this.monitorTab){
9817 this.el.un("keydown", this.checkTab, this);
9819 //this.wrap.removeClass('x-trigger-wrap-focus');
9820 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9824 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9825 validateBlur : function(e, t){
9830 onDisable : function(){
9831 this.inputEl().dom.disabled = true;
9832 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9834 // this.wrap.addClass('x-item-disabled');
9839 onEnable : function(){
9840 this.inputEl().dom.disabled = false;
9841 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9843 // this.el.removeClass('x-item-disabled');
9848 onShow : function(){
9849 var ae = this.getActionEl();
9852 ae.dom.style.display = '';
9853 ae.dom.style.visibility = 'visible';
9859 onHide : function(){
9860 var ae = this.getActionEl();
9861 ae.dom.style.display = 'none';
9865 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9866 * by an implementing function.
9868 * @param {EventObject} e
9870 onTriggerClick : Roo.emptyFn
9874 * Ext JS Library 1.1.1
9875 * Copyright(c) 2006-2007, Ext JS, LLC.
9877 * Originally Released Under LGPL - original licence link has changed is not relivant.
9880 * <script type="text/javascript">
9885 * @class Roo.data.SortTypes
9887 * Defines the default sorting (casting?) comparison functions used when sorting data.
9889 Roo.data.SortTypes = {
9891 * Default sort that does nothing
9892 * @param {Mixed} s The value being converted
9893 * @return {Mixed} The comparison value
9900 * The regular expression used to strip tags
9904 stripTagsRE : /<\/?[^>]+>/gi,
9907 * Strips all HTML tags to sort on text only
9908 * @param {Mixed} s The value being converted
9909 * @return {String} The comparison value
9911 asText : function(s){
9912 return String(s).replace(this.stripTagsRE, "");
9916 * Strips all HTML tags to sort on text only - Case insensitive
9917 * @param {Mixed} s The value being converted
9918 * @return {String} The comparison value
9920 asUCText : function(s){
9921 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9925 * Case insensitive string
9926 * @param {Mixed} s The value being converted
9927 * @return {String} The comparison value
9929 asUCString : function(s) {
9930 return String(s).toUpperCase();
9935 * @param {Mixed} s The value being converted
9936 * @return {Number} The comparison value
9938 asDate : function(s) {
9942 if(s instanceof Date){
9945 return Date.parse(String(s));
9950 * @param {Mixed} s The value being converted
9951 * @return {Float} The comparison value
9953 asFloat : function(s) {
9954 var val = parseFloat(String(s).replace(/,/g, ""));
9963 * @param {Mixed} s The value being converted
9964 * @return {Number} The comparison value
9966 asInt : function(s) {
9967 var val = parseInt(String(s).replace(/,/g, ""));
9975 * Ext JS Library 1.1.1
9976 * Copyright(c) 2006-2007, Ext JS, LLC.
9978 * Originally Released Under LGPL - original licence link has changed is not relivant.
9981 * <script type="text/javascript">
9985 * @class Roo.data.Record
9986 * Instances of this class encapsulate both record <em>definition</em> information, and record
9987 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9988 * to access Records cached in an {@link Roo.data.Store} object.<br>
9990 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9991 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9994 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9996 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9997 * {@link #create}. The parameters are the same.
9998 * @param {Array} data An associative Array of data values keyed by the field name.
9999 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10000 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10001 * not specified an integer id is generated.
10003 Roo.data.Record = function(data, id){
10004 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10009 * Generate a constructor for a specific record layout.
10010 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10011 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10012 * Each field definition object may contain the following properties: <ul>
10013 * <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,
10014 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10015 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10016 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10017 * is being used, then this is a string containing the javascript expression to reference the data relative to
10018 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10019 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10020 * this may be omitted.</p></li>
10021 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10022 * <ul><li>auto (Default, implies no conversion)</li>
10027 * <li>date</li></ul></p></li>
10028 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10029 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10030 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10031 * by the Reader into an object that will be stored in the Record. It is passed the
10032 * following parameters:<ul>
10033 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10035 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10037 * <br>usage:<br><pre><code>
10038 var TopicRecord = Roo.data.Record.create(
10039 {name: 'title', mapping: 'topic_title'},
10040 {name: 'author', mapping: 'username'},
10041 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10042 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10043 {name: 'lastPoster', mapping: 'user2'},
10044 {name: 'excerpt', mapping: 'post_text'}
10047 var myNewRecord = new TopicRecord({
10048 title: 'Do my job please',
10051 lastPost: new Date(),
10052 lastPoster: 'Animal',
10053 excerpt: 'No way dude!'
10055 myStore.add(myNewRecord);
10060 Roo.data.Record.create = function(o){
10061 var f = function(){
10062 f.superclass.constructor.apply(this, arguments);
10064 Roo.extend(f, Roo.data.Record);
10065 var p = f.prototype;
10066 p.fields = new Roo.util.MixedCollection(false, function(field){
10069 for(var i = 0, len = o.length; i < len; i++){
10070 p.fields.add(new Roo.data.Field(o[i]));
10072 f.getField = function(name){
10073 return p.fields.get(name);
10078 Roo.data.Record.AUTO_ID = 1000;
10079 Roo.data.Record.EDIT = 'edit';
10080 Roo.data.Record.REJECT = 'reject';
10081 Roo.data.Record.COMMIT = 'commit';
10083 Roo.data.Record.prototype = {
10085 * Readonly flag - true if this record has been modified.
10094 join : function(store){
10095 this.store = store;
10099 * Set the named field to the specified value.
10100 * @param {String} name The name of the field to set.
10101 * @param {Object} value The value to set the field to.
10103 set : function(name, value){
10104 if(this.data[name] == value){
10108 if(!this.modified){
10109 this.modified = {};
10111 if(typeof this.modified[name] == 'undefined'){
10112 this.modified[name] = this.data[name];
10114 this.data[name] = value;
10115 if(!this.editing && this.store){
10116 this.store.afterEdit(this);
10121 * Get the value of the named field.
10122 * @param {String} name The name of the field to get the value of.
10123 * @return {Object} The value of the field.
10125 get : function(name){
10126 return this.data[name];
10130 beginEdit : function(){
10131 this.editing = true;
10132 this.modified = {};
10136 cancelEdit : function(){
10137 this.editing = false;
10138 delete this.modified;
10142 endEdit : function(){
10143 this.editing = false;
10144 if(this.dirty && this.store){
10145 this.store.afterEdit(this);
10150 * Usually called by the {@link Roo.data.Store} which owns the Record.
10151 * Rejects all changes made to the Record since either creation, or the last commit operation.
10152 * Modified fields are reverted to their original values.
10154 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10155 * of reject operations.
10157 reject : function(){
10158 var m = this.modified;
10160 if(typeof m[n] != "function"){
10161 this.data[n] = m[n];
10164 this.dirty = false;
10165 delete this.modified;
10166 this.editing = false;
10168 this.store.afterReject(this);
10173 * Usually called by the {@link Roo.data.Store} which owns the Record.
10174 * Commits all changes made to the Record since either creation, or the last commit operation.
10176 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10177 * of commit operations.
10179 commit : function(){
10180 this.dirty = false;
10181 delete this.modified;
10182 this.editing = false;
10184 this.store.afterCommit(this);
10189 hasError : function(){
10190 return this.error != null;
10194 clearError : function(){
10199 * Creates a copy of this record.
10200 * @param {String} id (optional) A new record id if you don't want to use this record's id
10203 copy : function(newId) {
10204 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10208 * Ext JS Library 1.1.1
10209 * Copyright(c) 2006-2007, Ext JS, LLC.
10211 * Originally Released Under LGPL - original licence link has changed is not relivant.
10214 * <script type="text/javascript">
10220 * @class Roo.data.Store
10221 * @extends Roo.util.Observable
10222 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10223 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10225 * 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
10226 * has no knowledge of the format of the data returned by the Proxy.<br>
10228 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10229 * instances from the data object. These records are cached and made available through accessor functions.
10231 * Creates a new Store.
10232 * @param {Object} config A config object containing the objects needed for the Store to access data,
10233 * and read the data into Records.
10235 Roo.data.Store = function(config){
10236 this.data = new Roo.util.MixedCollection(false);
10237 this.data.getKey = function(o){
10240 this.baseParams = {};
10242 this.paramNames = {
10247 "multisort" : "_multisort"
10250 if(config && config.data){
10251 this.inlineData = config.data;
10252 delete config.data;
10255 Roo.apply(this, config);
10257 if(this.reader){ // reader passed
10258 this.reader = Roo.factory(this.reader, Roo.data);
10259 this.reader.xmodule = this.xmodule || false;
10260 if(!this.recordType){
10261 this.recordType = this.reader.recordType;
10263 if(this.reader.onMetaChange){
10264 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10268 if(this.recordType){
10269 this.fields = this.recordType.prototype.fields;
10271 this.modified = [];
10275 * @event datachanged
10276 * Fires when the data cache has changed, and a widget which is using this Store
10277 * as a Record cache should refresh its view.
10278 * @param {Store} this
10280 datachanged : true,
10282 * @event metachange
10283 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10284 * @param {Store} this
10285 * @param {Object} meta The JSON metadata
10290 * Fires when Records have been added to the Store
10291 * @param {Store} this
10292 * @param {Roo.data.Record[]} records The array of Records added
10293 * @param {Number} index The index at which the record(s) were added
10298 * Fires when a Record has been removed from the Store
10299 * @param {Store} this
10300 * @param {Roo.data.Record} record The Record that was removed
10301 * @param {Number} index The index at which the record was removed
10306 * Fires when a Record has been updated
10307 * @param {Store} this
10308 * @param {Roo.data.Record} record The Record that was updated
10309 * @param {String} operation The update operation being performed. Value may be one of:
10311 Roo.data.Record.EDIT
10312 Roo.data.Record.REJECT
10313 Roo.data.Record.COMMIT
10319 * Fires when the data cache has been cleared.
10320 * @param {Store} this
10324 * @event beforeload
10325 * Fires before a request is made for a new data object. If the beforeload handler returns false
10326 * the load action will be canceled.
10327 * @param {Store} this
10328 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10332 * @event beforeloadadd
10333 * Fires after a new set of Records has been loaded.
10334 * @param {Store} this
10335 * @param {Roo.data.Record[]} records The Records that were loaded
10336 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10338 beforeloadadd : true,
10341 * Fires after a new set of Records has been loaded, before they are added to the store.
10342 * @param {Store} this
10343 * @param {Roo.data.Record[]} records The Records that were loaded
10344 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10345 * @params {Object} return from reader
10349 * @event loadexception
10350 * Fires if an exception occurs in the Proxy during loading.
10351 * Called with the signature of the Proxy's "loadexception" event.
10352 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10355 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10356 * @param {Object} load options
10357 * @param {Object} jsonData from your request (normally this contains the Exception)
10359 loadexception : true
10363 this.proxy = Roo.factory(this.proxy, Roo.data);
10364 this.proxy.xmodule = this.xmodule || false;
10365 this.relayEvents(this.proxy, ["loadexception"]);
10367 this.sortToggle = {};
10368 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10370 Roo.data.Store.superclass.constructor.call(this);
10372 if(this.inlineData){
10373 this.loadData(this.inlineData);
10374 delete this.inlineData;
10378 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10380 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10381 * without a remote query - used by combo/forms at present.
10385 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10388 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10391 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10392 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10395 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10396 * on any HTTP request
10399 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10402 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10406 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10407 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10409 remoteSort : false,
10412 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10413 * loaded or when a record is removed. (defaults to false).
10415 pruneModifiedRecords : false,
10418 lastOptions : null,
10421 * Add Records to the Store and fires the add event.
10422 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10424 add : function(records){
10425 records = [].concat(records);
10426 for(var i = 0, len = records.length; i < len; i++){
10427 records[i].join(this);
10429 var index = this.data.length;
10430 this.data.addAll(records);
10431 this.fireEvent("add", this, records, index);
10435 * Remove a Record from the Store and fires the remove event.
10436 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10438 remove : function(record){
10439 var index = this.data.indexOf(record);
10440 this.data.removeAt(index);
10441 if(this.pruneModifiedRecords){
10442 this.modified.remove(record);
10444 this.fireEvent("remove", this, record, index);
10448 * Remove all Records from the Store and fires the clear event.
10450 removeAll : function(){
10452 if(this.pruneModifiedRecords){
10453 this.modified = [];
10455 this.fireEvent("clear", this);
10459 * Inserts Records to the Store at the given index and fires the add event.
10460 * @param {Number} index The start index at which to insert the passed Records.
10461 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10463 insert : function(index, records){
10464 records = [].concat(records);
10465 for(var i = 0, len = records.length; i < len; i++){
10466 this.data.insert(index, records[i]);
10467 records[i].join(this);
10469 this.fireEvent("add", this, records, index);
10473 * Get the index within the cache of the passed Record.
10474 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10475 * @return {Number} The index of the passed Record. Returns -1 if not found.
10477 indexOf : function(record){
10478 return this.data.indexOf(record);
10482 * Get the index within the cache of the Record with the passed id.
10483 * @param {String} id The id of the Record to find.
10484 * @return {Number} The index of the Record. Returns -1 if not found.
10486 indexOfId : function(id){
10487 return this.data.indexOfKey(id);
10491 * Get the Record with the specified id.
10492 * @param {String} id The id of the Record to find.
10493 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10495 getById : function(id){
10496 return this.data.key(id);
10500 * Get the Record at the specified index.
10501 * @param {Number} index The index of the Record to find.
10502 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10504 getAt : function(index){
10505 return this.data.itemAt(index);
10509 * Returns a range of Records between specified indices.
10510 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10511 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10512 * @return {Roo.data.Record[]} An array of Records
10514 getRange : function(start, end){
10515 return this.data.getRange(start, end);
10519 storeOptions : function(o){
10520 o = Roo.apply({}, o);
10523 this.lastOptions = o;
10527 * Loads the Record cache from the configured Proxy using the configured Reader.
10529 * If using remote paging, then the first load call must specify the <em>start</em>
10530 * and <em>limit</em> properties in the options.params property to establish the initial
10531 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10533 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10534 * and this call will return before the new data has been loaded. Perform any post-processing
10535 * in a callback function, or in a "load" event handler.</strong>
10537 * @param {Object} options An object containing properties which control loading options:<ul>
10538 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10539 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10540 * passed the following arguments:<ul>
10541 * <li>r : Roo.data.Record[]</li>
10542 * <li>options: Options object from the load call</li>
10543 * <li>success: Boolean success indicator</li></ul></li>
10544 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10545 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10548 load : function(options){
10549 options = options || {};
10550 if(this.fireEvent("beforeload", this, options) !== false){
10551 this.storeOptions(options);
10552 var p = Roo.apply(options.params || {}, this.baseParams);
10553 // if meta was not loaded from remote source.. try requesting it.
10554 if (!this.reader.metaFromRemote) {
10555 p._requestMeta = 1;
10557 if(this.sortInfo && this.remoteSort){
10558 var pn = this.paramNames;
10559 p[pn["sort"]] = this.sortInfo.field;
10560 p[pn["dir"]] = this.sortInfo.direction;
10562 if (this.multiSort) {
10563 var pn = this.paramNames;
10564 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10567 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10572 * Reloads the Record cache from the configured Proxy using the configured Reader and
10573 * the options from the last load operation performed.
10574 * @param {Object} options (optional) An object containing properties which may override the options
10575 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10576 * the most recently used options are reused).
10578 reload : function(options){
10579 this.load(Roo.applyIf(options||{}, this.lastOptions));
10583 // Called as a callback by the Reader during a load operation.
10584 loadRecords : function(o, options, success){
10585 if(!o || success === false){
10586 if(success !== false){
10587 this.fireEvent("load", this, [], options, o);
10589 if(options.callback){
10590 options.callback.call(options.scope || this, [], options, false);
10594 // if data returned failure - throw an exception.
10595 if (o.success === false) {
10596 // show a message if no listener is registered.
10597 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10598 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10600 // loadmask wil be hooked into this..
10601 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10604 var r = o.records, t = o.totalRecords || r.length;
10606 this.fireEvent("beforeloadadd", this, r, options, o);
10608 if(!options || options.add !== true){
10609 if(this.pruneModifiedRecords){
10610 this.modified = [];
10612 for(var i = 0, len = r.length; i < len; i++){
10616 this.data = this.snapshot;
10617 delete this.snapshot;
10620 this.data.addAll(r);
10621 this.totalLength = t;
10623 this.fireEvent("datachanged", this);
10625 this.totalLength = Math.max(t, this.data.length+r.length);
10628 this.fireEvent("load", this, r, options, o);
10629 if(options.callback){
10630 options.callback.call(options.scope || this, r, options, true);
10636 * Loads data from a passed data block. A Reader which understands the format of the data
10637 * must have been configured in the constructor.
10638 * @param {Object} data The data block from which to read the Records. The format of the data expected
10639 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10640 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10642 loadData : function(o, append){
10643 var r = this.reader.readRecords(o);
10644 this.loadRecords(r, {add: append}, true);
10648 * Gets the number of cached records.
10650 * <em>If using paging, this may not be the total size of the dataset. If the data object
10651 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10652 * the data set size</em>
10654 getCount : function(){
10655 return this.data.length || 0;
10659 * Gets the total number of records in the dataset as returned by the server.
10661 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10662 * the dataset size</em>
10664 getTotalCount : function(){
10665 return this.totalLength || 0;
10669 * Returns the sort state of the Store as an object with two properties:
10671 field {String} The name of the field by which the Records are sorted
10672 direction {String} The sort order, "ASC" or "DESC"
10675 getSortState : function(){
10676 return this.sortInfo;
10680 applySort : function(){
10681 if(this.sortInfo && !this.remoteSort){
10682 var s = this.sortInfo, f = s.field;
10683 var st = this.fields.get(f).sortType;
10684 var fn = function(r1, r2){
10685 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10686 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10688 this.data.sort(s.direction, fn);
10689 if(this.snapshot && this.snapshot != this.data){
10690 this.snapshot.sort(s.direction, fn);
10696 * Sets the default sort column and order to be used by the next load operation.
10697 * @param {String} fieldName The name of the field to sort by.
10698 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10700 setDefaultSort : function(field, dir){
10701 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10705 * Sort the Records.
10706 * If remote sorting is used, the sort is performed on the server, and the cache is
10707 * reloaded. If local sorting is used, the cache is sorted internally.
10708 * @param {String} fieldName The name of the field to sort by.
10709 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10711 sort : function(fieldName, dir){
10712 var f = this.fields.get(fieldName);
10714 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10716 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10717 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10722 this.sortToggle[f.name] = dir;
10723 this.sortInfo = {field: f.name, direction: dir};
10724 if(!this.remoteSort){
10726 this.fireEvent("datachanged", this);
10728 this.load(this.lastOptions);
10733 * Calls the specified function for each of the Records in the cache.
10734 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10735 * Returning <em>false</em> aborts and exits the iteration.
10736 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10738 each : function(fn, scope){
10739 this.data.each(fn, scope);
10743 * Gets all records modified since the last commit. Modified records are persisted across load operations
10744 * (e.g., during paging).
10745 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10747 getModifiedRecords : function(){
10748 return this.modified;
10752 createFilterFn : function(property, value, anyMatch){
10753 if(!value.exec){ // not a regex
10754 value = String(value);
10755 if(value.length == 0){
10758 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10760 return function(r){
10761 return value.test(r.data[property]);
10766 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10767 * @param {String} property A field on your records
10768 * @param {Number} start The record index to start at (defaults to 0)
10769 * @param {Number} end The last record index to include (defaults to length - 1)
10770 * @return {Number} The sum
10772 sum : function(property, start, end){
10773 var rs = this.data.items, v = 0;
10774 start = start || 0;
10775 end = (end || end === 0) ? end : rs.length-1;
10777 for(var i = start; i <= end; i++){
10778 v += (rs[i].data[property] || 0);
10784 * Filter the records by a specified property.
10785 * @param {String} field A field on your records
10786 * @param {String/RegExp} value Either a string that the field
10787 * should start with or a RegExp to test against the field
10788 * @param {Boolean} anyMatch True to match any part not just the beginning
10790 filter : function(property, value, anyMatch){
10791 var fn = this.createFilterFn(property, value, anyMatch);
10792 return fn ? this.filterBy(fn) : this.clearFilter();
10796 * Filter by a function. The specified function will be called with each
10797 * record in this data source. If the function returns true the record is included,
10798 * otherwise it is filtered.
10799 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10800 * @param {Object} scope (optional) The scope of the function (defaults to this)
10802 filterBy : function(fn, scope){
10803 this.snapshot = this.snapshot || this.data;
10804 this.data = this.queryBy(fn, scope||this);
10805 this.fireEvent("datachanged", this);
10809 * Query the records by a specified property.
10810 * @param {String} field A field on your records
10811 * @param {String/RegExp} value Either a string that the field
10812 * should start with or a RegExp to test against the field
10813 * @param {Boolean} anyMatch True to match any part not just the beginning
10814 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10816 query : function(property, value, anyMatch){
10817 var fn = this.createFilterFn(property, value, anyMatch);
10818 return fn ? this.queryBy(fn) : this.data.clone();
10822 * Query by a function. The specified function will be called with each
10823 * record in this data source. If the function returns true the record is included
10825 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10826 * @param {Object} scope (optional) The scope of the function (defaults to this)
10827 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10829 queryBy : function(fn, scope){
10830 var data = this.snapshot || this.data;
10831 return data.filterBy(fn, scope||this);
10835 * Collects unique values for a particular dataIndex from this store.
10836 * @param {String} dataIndex The property to collect
10837 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10838 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10839 * @return {Array} An array of the unique values
10841 collect : function(dataIndex, allowNull, bypassFilter){
10842 var d = (bypassFilter === true && this.snapshot) ?
10843 this.snapshot.items : this.data.items;
10844 var v, sv, r = [], l = {};
10845 for(var i = 0, len = d.length; i < len; i++){
10846 v = d[i].data[dataIndex];
10848 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10857 * Revert to a view of the Record cache with no filtering applied.
10858 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10860 clearFilter : function(suppressEvent){
10861 if(this.snapshot && this.snapshot != this.data){
10862 this.data = this.snapshot;
10863 delete this.snapshot;
10864 if(suppressEvent !== true){
10865 this.fireEvent("datachanged", this);
10871 afterEdit : function(record){
10872 if(this.modified.indexOf(record) == -1){
10873 this.modified.push(record);
10875 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10879 afterReject : function(record){
10880 this.modified.remove(record);
10881 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10885 afterCommit : function(record){
10886 this.modified.remove(record);
10887 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10891 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10892 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10894 commitChanges : function(){
10895 var m = this.modified.slice(0);
10896 this.modified = [];
10897 for(var i = 0, len = m.length; i < len; i++){
10903 * Cancel outstanding changes on all changed records.
10905 rejectChanges : function(){
10906 var m = this.modified.slice(0);
10907 this.modified = [];
10908 for(var i = 0, len = m.length; i < len; i++){
10913 onMetaChange : function(meta, rtype, o){
10914 this.recordType = rtype;
10915 this.fields = rtype.prototype.fields;
10916 delete this.snapshot;
10917 this.sortInfo = meta.sortInfo || this.sortInfo;
10918 this.modified = [];
10919 this.fireEvent('metachange', this, this.reader.meta);
10922 moveIndex : function(data, type)
10924 var index = this.indexOf(data);
10926 var newIndex = index + type;
10930 this.insert(newIndex, data);
10935 * Ext JS Library 1.1.1
10936 * Copyright(c) 2006-2007, Ext JS, LLC.
10938 * Originally Released Under LGPL - original licence link has changed is not relivant.
10941 * <script type="text/javascript">
10945 * @class Roo.data.SimpleStore
10946 * @extends Roo.data.Store
10947 * Small helper class to make creating Stores from Array data easier.
10948 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10949 * @cfg {Array} fields An array of field definition objects, or field name strings.
10950 * @cfg {Array} data The multi-dimensional array of data
10952 * @param {Object} config
10954 Roo.data.SimpleStore = function(config){
10955 Roo.data.SimpleStore.superclass.constructor.call(this, {
10957 reader: new Roo.data.ArrayReader({
10960 Roo.data.Record.create(config.fields)
10962 proxy : new Roo.data.MemoryProxy(config.data)
10966 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10968 * Ext JS Library 1.1.1
10969 * Copyright(c) 2006-2007, Ext JS, LLC.
10971 * Originally Released Under LGPL - original licence link has changed is not relivant.
10974 * <script type="text/javascript">
10979 * @extends Roo.data.Store
10980 * @class Roo.data.JsonStore
10981 * Small helper class to make creating Stores for JSON data easier. <br/>
10983 var store = new Roo.data.JsonStore({
10984 url: 'get-images.php',
10986 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10989 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10990 * JsonReader and HttpProxy (unless inline data is provided).</b>
10991 * @cfg {Array} fields An array of field definition objects, or field name strings.
10993 * @param {Object} config
10995 Roo.data.JsonStore = function(c){
10996 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10997 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10998 reader: new Roo.data.JsonReader(c, c.fields)
11001 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11003 * Ext JS Library 1.1.1
11004 * Copyright(c) 2006-2007, Ext JS, LLC.
11006 * Originally Released Under LGPL - original licence link has changed is not relivant.
11009 * <script type="text/javascript">
11013 Roo.data.Field = function(config){
11014 if(typeof config == "string"){
11015 config = {name: config};
11017 Roo.apply(this, config);
11020 this.type = "auto";
11023 var st = Roo.data.SortTypes;
11024 // named sortTypes are supported, here we look them up
11025 if(typeof this.sortType == "string"){
11026 this.sortType = st[this.sortType];
11029 // set default sortType for strings and dates
11030 if(!this.sortType){
11033 this.sortType = st.asUCString;
11036 this.sortType = st.asDate;
11039 this.sortType = st.none;
11044 var stripRe = /[\$,%]/g;
11046 // prebuilt conversion function for this field, instead of
11047 // switching every time we're reading a value
11049 var cv, dateFormat = this.dateFormat;
11054 cv = function(v){ return v; };
11057 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11061 return v !== undefined && v !== null && v !== '' ?
11062 parseInt(String(v).replace(stripRe, ""), 10) : '';
11067 return v !== undefined && v !== null && v !== '' ?
11068 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11073 cv = function(v){ return v === true || v === "true" || v == 1; };
11080 if(v instanceof Date){
11084 if(dateFormat == "timestamp"){
11085 return new Date(v*1000);
11087 return Date.parseDate(v, dateFormat);
11089 var parsed = Date.parse(v);
11090 return parsed ? new Date(parsed) : null;
11099 Roo.data.Field.prototype = {
11107 * Ext JS Library 1.1.1
11108 * Copyright(c) 2006-2007, Ext JS, LLC.
11110 * Originally Released Under LGPL - original licence link has changed is not relivant.
11113 * <script type="text/javascript">
11116 // Base class for reading structured data from a data source. This class is intended to be
11117 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11120 * @class Roo.data.DataReader
11121 * Base class for reading structured data from a data source. This class is intended to be
11122 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11125 Roo.data.DataReader = function(meta, recordType){
11129 this.recordType = recordType instanceof Array ?
11130 Roo.data.Record.create(recordType) : recordType;
11133 Roo.data.DataReader.prototype = {
11135 * Create an empty record
11136 * @param {Object} data (optional) - overlay some values
11137 * @return {Roo.data.Record} record created.
11139 newRow : function(d) {
11141 this.recordType.prototype.fields.each(function(c) {
11143 case 'int' : da[c.name] = 0; break;
11144 case 'date' : da[c.name] = new Date(); break;
11145 case 'float' : da[c.name] = 0.0; break;
11146 case 'boolean' : da[c.name] = false; break;
11147 default : da[c.name] = ""; break;
11151 return new this.recordType(Roo.apply(da, d));
11156 * Ext JS Library 1.1.1
11157 * Copyright(c) 2006-2007, Ext JS, LLC.
11159 * Originally Released Under LGPL - original licence link has changed is not relivant.
11162 * <script type="text/javascript">
11166 * @class Roo.data.DataProxy
11167 * @extends Roo.data.Observable
11168 * This class is an abstract base class for implementations which provide retrieval of
11169 * unformatted data objects.<br>
11171 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11172 * (of the appropriate type which knows how to parse the data object) to provide a block of
11173 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11175 * Custom implementations must implement the load method as described in
11176 * {@link Roo.data.HttpProxy#load}.
11178 Roo.data.DataProxy = function(){
11181 * @event beforeload
11182 * Fires before a network request is made to retrieve a data object.
11183 * @param {Object} This DataProxy object.
11184 * @param {Object} params The params parameter to the load function.
11189 * Fires before the load method's callback is called.
11190 * @param {Object} This DataProxy object.
11191 * @param {Object} o The data object.
11192 * @param {Object} arg The callback argument object passed to the load function.
11196 * @event loadexception
11197 * Fires if an Exception occurs during data retrieval.
11198 * @param {Object} This DataProxy object.
11199 * @param {Object} o The data object.
11200 * @param {Object} arg The callback argument object passed to the load function.
11201 * @param {Object} e The Exception.
11203 loadexception : true
11205 Roo.data.DataProxy.superclass.constructor.call(this);
11208 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11211 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11215 * Ext JS Library 1.1.1
11216 * Copyright(c) 2006-2007, Ext JS, LLC.
11218 * Originally Released Under LGPL - original licence link has changed is not relivant.
11221 * <script type="text/javascript">
11224 * @class Roo.data.MemoryProxy
11225 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11226 * to the Reader when its load method is called.
11228 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11230 Roo.data.MemoryProxy = function(data){
11234 Roo.data.MemoryProxy.superclass.constructor.call(this);
11238 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11241 * Load data from the requested source (in this case an in-memory
11242 * data object passed to the constructor), read the data object into
11243 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11244 * process that block using the passed callback.
11245 * @param {Object} params This parameter is not used by the MemoryProxy class.
11246 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11247 * object into a block of Roo.data.Records.
11248 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11249 * The function must be passed <ul>
11250 * <li>The Record block object</li>
11251 * <li>The "arg" argument from the load function</li>
11252 * <li>A boolean success indicator</li>
11254 * @param {Object} scope The scope in which to call the callback
11255 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11257 load : function(params, reader, callback, scope, arg){
11258 params = params || {};
11261 result = reader.readRecords(this.data);
11263 this.fireEvent("loadexception", this, arg, null, e);
11264 callback.call(scope, null, arg, false);
11267 callback.call(scope, result, arg, true);
11271 update : function(params, records){
11276 * Ext JS Library 1.1.1
11277 * Copyright(c) 2006-2007, Ext JS, LLC.
11279 * Originally Released Under LGPL - original licence link has changed is not relivant.
11282 * <script type="text/javascript">
11285 * @class Roo.data.HttpProxy
11286 * @extends Roo.data.DataProxy
11287 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11288 * configured to reference a certain URL.<br><br>
11290 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11291 * from which the running page was served.<br><br>
11293 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11295 * Be aware that to enable the browser to parse an XML document, the server must set
11296 * the Content-Type header in the HTTP response to "text/xml".
11298 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11299 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11300 * will be used to make the request.
11302 Roo.data.HttpProxy = function(conn){
11303 Roo.data.HttpProxy.superclass.constructor.call(this);
11304 // is conn a conn config or a real conn?
11306 this.useAjax = !conn || !conn.events;
11310 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11311 // thse are take from connection...
11314 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11317 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11318 * extra parameters to each request made by this object. (defaults to undefined)
11321 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11322 * to each request made by this object. (defaults to undefined)
11325 * @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)
11328 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11331 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11337 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11341 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11342 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11343 * a finer-grained basis than the DataProxy events.
11345 getConnection : function(){
11346 return this.useAjax ? Roo.Ajax : this.conn;
11350 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11351 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11352 * process that block using the passed callback.
11353 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11354 * for the request to the remote server.
11355 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11356 * object into a block of Roo.data.Records.
11357 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11358 * The function must be passed <ul>
11359 * <li>The Record block object</li>
11360 * <li>The "arg" argument from the load function</li>
11361 * <li>A boolean success indicator</li>
11363 * @param {Object} scope The scope in which to call the callback
11364 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11366 load : function(params, reader, callback, scope, arg){
11367 if(this.fireEvent("beforeload", this, params) !== false){
11369 params : params || {},
11371 callback : callback,
11376 callback : this.loadResponse,
11380 Roo.applyIf(o, this.conn);
11381 if(this.activeRequest){
11382 Roo.Ajax.abort(this.activeRequest);
11384 this.activeRequest = Roo.Ajax.request(o);
11386 this.conn.request(o);
11389 callback.call(scope||this, null, arg, false);
11394 loadResponse : function(o, success, response){
11395 delete this.activeRequest;
11397 this.fireEvent("loadexception", this, o, response);
11398 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11403 result = o.reader.read(response);
11405 this.fireEvent("loadexception", this, o, response, e);
11406 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11410 this.fireEvent("load", this, o, o.request.arg);
11411 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11415 update : function(dataSet){
11420 updateResponse : function(dataSet){
11425 * Ext JS Library 1.1.1
11426 * Copyright(c) 2006-2007, Ext JS, LLC.
11428 * Originally Released Under LGPL - original licence link has changed is not relivant.
11431 * <script type="text/javascript">
11435 * @class Roo.data.ScriptTagProxy
11436 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11437 * other than the originating domain of the running page.<br><br>
11439 * <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
11440 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11442 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11443 * source code that is used as the source inside a <script> tag.<br><br>
11445 * In order for the browser to process the returned data, the server must wrap the data object
11446 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11447 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11448 * depending on whether the callback name was passed:
11451 boolean scriptTag = false;
11452 String cb = request.getParameter("callback");
11455 response.setContentType("text/javascript");
11457 response.setContentType("application/x-json");
11459 Writer out = response.getWriter();
11461 out.write(cb + "(");
11463 out.print(dataBlock.toJsonString());
11470 * @param {Object} config A configuration object.
11472 Roo.data.ScriptTagProxy = function(config){
11473 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11474 Roo.apply(this, config);
11475 this.head = document.getElementsByTagName("head")[0];
11478 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11480 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11482 * @cfg {String} url The URL from which to request the data object.
11485 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11489 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11490 * the server the name of the callback function set up by the load call to process the returned data object.
11491 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11492 * javascript output which calls this named function passing the data object as its only parameter.
11494 callbackParam : "callback",
11496 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11497 * name to the request.
11502 * Load data from the configured URL, read the data object into
11503 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11504 * process that block using the passed callback.
11505 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11506 * for the request to the remote server.
11507 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11508 * object into a block of Roo.data.Records.
11509 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11510 * The function must be passed <ul>
11511 * <li>The Record block object</li>
11512 * <li>The "arg" argument from the load function</li>
11513 * <li>A boolean success indicator</li>
11515 * @param {Object} scope The scope in which to call the callback
11516 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11518 load : function(params, reader, callback, scope, arg){
11519 if(this.fireEvent("beforeload", this, params) !== false){
11521 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11523 var url = this.url;
11524 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11526 url += "&_dc=" + (new Date().getTime());
11528 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11531 cb : "stcCallback"+transId,
11532 scriptId : "stcScript"+transId,
11536 callback : callback,
11542 window[trans.cb] = function(o){
11543 conn.handleResponse(o, trans);
11546 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11548 if(this.autoAbort !== false){
11552 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11554 var script = document.createElement("script");
11555 script.setAttribute("src", url);
11556 script.setAttribute("type", "text/javascript");
11557 script.setAttribute("id", trans.scriptId);
11558 this.head.appendChild(script);
11560 this.trans = trans;
11562 callback.call(scope||this, null, arg, false);
11567 isLoading : function(){
11568 return this.trans ? true : false;
11572 * Abort the current server request.
11574 abort : function(){
11575 if(this.isLoading()){
11576 this.destroyTrans(this.trans);
11581 destroyTrans : function(trans, isLoaded){
11582 this.head.removeChild(document.getElementById(trans.scriptId));
11583 clearTimeout(trans.timeoutId);
11585 window[trans.cb] = undefined;
11587 delete window[trans.cb];
11590 // if hasn't been loaded, wait for load to remove it to prevent script error
11591 window[trans.cb] = function(){
11592 window[trans.cb] = undefined;
11594 delete window[trans.cb];
11601 handleResponse : function(o, trans){
11602 this.trans = false;
11603 this.destroyTrans(trans, true);
11606 result = trans.reader.readRecords(o);
11608 this.fireEvent("loadexception", this, o, trans.arg, e);
11609 trans.callback.call(trans.scope||window, null, trans.arg, false);
11612 this.fireEvent("load", this, o, trans.arg);
11613 trans.callback.call(trans.scope||window, result, trans.arg, true);
11617 handleFailure : function(trans){
11618 this.trans = false;
11619 this.destroyTrans(trans, false);
11620 this.fireEvent("loadexception", this, null, trans.arg);
11621 trans.callback.call(trans.scope||window, null, trans.arg, false);
11625 * Ext JS Library 1.1.1
11626 * Copyright(c) 2006-2007, Ext JS, LLC.
11628 * Originally Released Under LGPL - original licence link has changed is not relivant.
11631 * <script type="text/javascript">
11635 * @class Roo.data.JsonReader
11636 * @extends Roo.data.DataReader
11637 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11638 * based on mappings in a provided Roo.data.Record constructor.
11640 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11641 * in the reply previously.
11646 var RecordDef = Roo.data.Record.create([
11647 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11648 {name: 'occupation'} // This field will use "occupation" as the mapping.
11650 var myReader = new Roo.data.JsonReader({
11651 totalProperty: "results", // The property which contains the total dataset size (optional)
11652 root: "rows", // The property which contains an Array of row objects
11653 id: "id" // The property within each row object that provides an ID for the record (optional)
11657 * This would consume a JSON file like this:
11659 { 'results': 2, 'rows': [
11660 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11661 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11664 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11665 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11666 * paged from the remote server.
11667 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11668 * @cfg {String} root name of the property which contains the Array of row objects.
11669 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11670 * @cfg {Array} fields Array of field definition objects
11672 * Create a new JsonReader
11673 * @param {Object} meta Metadata configuration options
11674 * @param {Object} recordType Either an Array of field definition objects,
11675 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11677 Roo.data.JsonReader = function(meta, recordType){
11680 // set some defaults:
11681 Roo.applyIf(meta, {
11682 totalProperty: 'total',
11683 successProperty : 'success',
11688 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11690 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11693 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11694 * Used by Store query builder to append _requestMeta to params.
11697 metaFromRemote : false,
11699 * This method is only used by a DataProxy which has retrieved data from a remote server.
11700 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11701 * @return {Object} data A data block which is used by an Roo.data.Store object as
11702 * a cache of Roo.data.Records.
11704 read : function(response){
11705 var json = response.responseText;
11707 var o = /* eval:var:o */ eval("("+json+")");
11709 throw {message: "JsonReader.read: Json object not found"};
11715 this.metaFromRemote = true;
11716 this.meta = o.metaData;
11717 this.recordType = Roo.data.Record.create(o.metaData.fields);
11718 this.onMetaChange(this.meta, this.recordType, o);
11720 return this.readRecords(o);
11723 // private function a store will implement
11724 onMetaChange : function(meta, recordType, o){
11731 simpleAccess: function(obj, subsc) {
11738 getJsonAccessor: function(){
11740 return function(expr) {
11742 return(re.test(expr))
11743 ? new Function("obj", "return obj." + expr)
11748 return Roo.emptyFn;
11753 * Create a data block containing Roo.data.Records from an XML document.
11754 * @param {Object} o An object which contains an Array of row objects in the property specified
11755 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11756 * which contains the total size of the dataset.
11757 * @return {Object} data A data block which is used by an Roo.data.Store object as
11758 * a cache of Roo.data.Records.
11760 readRecords : function(o){
11762 * After any data loads, the raw JSON data is available for further custom processing.
11766 var s = this.meta, Record = this.recordType,
11767 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11769 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11771 if(s.totalProperty) {
11772 this.getTotal = this.getJsonAccessor(s.totalProperty);
11774 if(s.successProperty) {
11775 this.getSuccess = this.getJsonAccessor(s.successProperty);
11777 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11779 var g = this.getJsonAccessor(s.id);
11780 this.getId = function(rec) {
11782 return (r === undefined || r === "") ? null : r;
11785 this.getId = function(){return null;};
11788 for(var jj = 0; jj < fl; jj++){
11790 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11791 this.ef[jj] = this.getJsonAccessor(map);
11795 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11796 if(s.totalProperty){
11797 var vt = parseInt(this.getTotal(o), 10);
11802 if(s.successProperty){
11803 var vs = this.getSuccess(o);
11804 if(vs === false || vs === 'false'){
11809 for(var i = 0; i < c; i++){
11812 var id = this.getId(n);
11813 for(var j = 0; j < fl; j++){
11815 var v = this.ef[j](n);
11817 Roo.log('missing convert for ' + f.name);
11821 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11823 var record = new Record(values, id);
11825 records[i] = record;
11831 totalRecords : totalRecords
11836 * Ext JS Library 1.1.1
11837 * Copyright(c) 2006-2007, Ext JS, LLC.
11839 * Originally Released Under LGPL - original licence link has changed is not relivant.
11842 * <script type="text/javascript">
11846 * @class Roo.data.ArrayReader
11847 * @extends Roo.data.DataReader
11848 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11849 * Each element of that Array represents a row of data fields. The
11850 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11851 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11855 var RecordDef = Roo.data.Record.create([
11856 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11857 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11859 var myReader = new Roo.data.ArrayReader({
11860 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11864 * This would consume an Array like this:
11866 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11868 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11870 * Create a new JsonReader
11871 * @param {Object} meta Metadata configuration options.
11872 * @param {Object} recordType Either an Array of field definition objects
11873 * as specified to {@link Roo.data.Record#create},
11874 * or an {@link Roo.data.Record} object
11875 * created using {@link Roo.data.Record#create}.
11877 Roo.data.ArrayReader = function(meta, recordType){
11878 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11881 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11883 * Create a data block containing Roo.data.Records from an XML document.
11884 * @param {Object} o An Array of row objects which represents the dataset.
11885 * @return {Object} data A data block which is used by an Roo.data.Store object as
11886 * a cache of Roo.data.Records.
11888 readRecords : function(o){
11889 var sid = this.meta ? this.meta.id : null;
11890 var recordType = this.recordType, fields = recordType.prototype.fields;
11893 for(var i = 0; i < root.length; i++){
11896 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11897 for(var j = 0, jlen = fields.length; j < jlen; j++){
11898 var f = fields.items[j];
11899 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11900 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11902 values[f.name] = v;
11904 var record = new recordType(values, id);
11906 records[records.length] = record;
11910 totalRecords : records.length
11919 * @class Roo.bootstrap.ComboBox
11920 * @extends Roo.bootstrap.TriggerField
11921 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11922 * @cfg {Boolean} append (true|false) default false
11923 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11924 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11925 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11926 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11927 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11928 * @cfg {Boolean} animate default true
11929 * @cfg {Boolean} emptyResultText only for touch device
11930 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11932 * Create a new ComboBox.
11933 * @param {Object} config Configuration options
11935 Roo.bootstrap.ComboBox = function(config){
11936 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11940 * Fires when the dropdown list is expanded
11941 * @param {Roo.bootstrap.ComboBox} combo This combo box
11946 * Fires when the dropdown list is collapsed
11947 * @param {Roo.bootstrap.ComboBox} combo This combo box
11951 * @event beforeselect
11952 * Fires before a list item is selected. Return false to cancel the selection.
11953 * @param {Roo.bootstrap.ComboBox} combo This combo box
11954 * @param {Roo.data.Record} record The data record returned from the underlying store
11955 * @param {Number} index The index of the selected item in the dropdown list
11957 'beforeselect' : true,
11960 * Fires when a list item is selected
11961 * @param {Roo.bootstrap.ComboBox} combo This combo box
11962 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11963 * @param {Number} index The index of the selected item in the dropdown list
11967 * @event beforequery
11968 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11969 * The event object passed has these properties:
11970 * @param {Roo.bootstrap.ComboBox} combo This combo box
11971 * @param {String} query The query
11972 * @param {Boolean} forceAll true to force "all" query
11973 * @param {Boolean} cancel true to cancel the query
11974 * @param {Object} e The query event object
11976 'beforequery': true,
11979 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11980 * @param {Roo.bootstrap.ComboBox} combo This combo box
11985 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11986 * @param {Roo.bootstrap.ComboBox} combo This combo box
11987 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11992 * Fires when the remove value from the combobox array
11993 * @param {Roo.bootstrap.ComboBox} combo This combo box
11997 * @event afterremove
11998 * Fires when the remove value from the combobox array
11999 * @param {Roo.bootstrap.ComboBox} combo This combo box
12001 'afterremove' : true,
12003 * @event specialfilter
12004 * Fires when specialfilter
12005 * @param {Roo.bootstrap.ComboBox} combo This combo box
12007 'specialfilter' : true,
12010 * Fires when tick the element
12011 * @param {Roo.bootstrap.ComboBox} combo This combo box
12015 * @event touchviewdisplay
12016 * Fires when touch view require special display (default is using displayField)
12017 * @param {Roo.bootstrap.ComboBox} combo This combo box
12018 * @param {Object} cfg set html .
12020 'touchviewdisplay' : true
12025 this.tickItems = [];
12027 this.selectedIndex = -1;
12028 if(this.mode == 'local'){
12029 if(config.queryDelay === undefined){
12030 this.queryDelay = 10;
12032 if(config.minChars === undefined){
12038 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12041 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12042 * rendering into an Roo.Editor, defaults to false)
12045 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12046 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12049 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12052 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12053 * the dropdown list (defaults to undefined, with no header element)
12057 * @cfg {String/Roo.Template} tpl The template to use to render the output
12061 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12063 listWidth: undefined,
12065 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12066 * mode = 'remote' or 'text' if mode = 'local')
12068 displayField: undefined,
12071 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12072 * mode = 'remote' or 'value' if mode = 'local').
12073 * Note: use of a valueField requires the user make a selection
12074 * in order for a value to be mapped.
12076 valueField: undefined,
12078 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12083 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12084 * field's data value (defaults to the underlying DOM element's name)
12086 hiddenName: undefined,
12088 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12092 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12094 selectedClass: 'active',
12097 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12101 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12102 * anchor positions (defaults to 'tl-bl')
12104 listAlign: 'tl-bl?',
12106 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12110 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12111 * query specified by the allQuery config option (defaults to 'query')
12113 triggerAction: 'query',
12115 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12116 * (defaults to 4, does not apply if editable = false)
12120 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12121 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12125 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12126 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12130 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12131 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12135 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12136 * when editable = true (defaults to false)
12138 selectOnFocus:false,
12140 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12142 queryParam: 'query',
12144 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12145 * when mode = 'remote' (defaults to 'Loading...')
12147 loadingText: 'Loading...',
12149 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12153 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12157 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12158 * traditional select (defaults to true)
12162 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12166 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12170 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12171 * listWidth has a higher value)
12175 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12176 * allow the user to set arbitrary text into the field (defaults to false)
12178 forceSelection:false,
12180 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12181 * if typeAhead = true (defaults to 250)
12183 typeAheadDelay : 250,
12185 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12186 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12188 valueNotFoundText : undefined,
12190 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12192 blockFocus : false,
12195 * @cfg {Boolean} disableClear Disable showing of clear button.
12197 disableClear : false,
12199 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12201 alwaysQuery : false,
12204 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12209 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12211 invalidClass : "has-warning",
12214 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12216 validClass : "has-success",
12219 * @cfg {Boolean} specialFilter (true|false) special filter default false
12221 specialFilter : false,
12224 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12226 mobileTouchView : true,
12229 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12231 useNativeIOS : false,
12233 ios_options : false,
12245 btnPosition : 'right',
12246 triggerList : true,
12247 showToggleBtn : true,
12249 emptyResultText: 'Empty',
12250 triggerText : 'Select',
12252 // element that contains real text value.. (when hidden is used..)
12254 getAutoCreate : function()
12259 * Render classic select for iso
12262 if(Roo.isIOS && this.useNativeIOS){
12263 cfg = this.getAutoCreateNativeIOS();
12271 if(Roo.isTouch && this.mobileTouchView){
12272 cfg = this.getAutoCreateTouchView();
12279 if(!this.tickable){
12280 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12285 * ComboBox with tickable selections
12288 var align = this.labelAlign || this.parentLabelAlign();
12291 cls : 'form-group roo-combobox-tickable' //input-group
12296 cls : 'tickable-buttons',
12301 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12302 html : this.triggerText
12308 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12315 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12322 buttons.cn.unshift({
12324 cls: 'roo-select2-search-field-input'
12330 Roo.each(buttons.cn, function(c){
12332 c.cls += ' btn-' + _this.size;
12335 if (_this.disabled) {
12346 cls: 'form-hidden-field'
12350 cls: 'roo-select2-choices',
12354 cls: 'roo-select2-search-field',
12366 cls: 'roo-select2-container input-group roo-select2-container-multi',
12371 // cls: 'typeahead typeahead-long dropdown-menu',
12372 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12377 if(this.hasFeedback && !this.allowBlank){
12381 cls: 'glyphicon form-control-feedback'
12384 combobox.cn.push(feedback);
12387 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
12389 // Roo.log("left and has label");
12393 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12394 tooltip : 'This field is required'
12399 cls : 'control-label col-sm-' + this.labelWidth,
12400 html : this.fieldLabel
12404 cls : "col-sm-" + (12 - this.labelWidth),
12412 if(this.indicatorpos == 'right'){
12418 cls : 'control-label col-sm-' + this.labelWidth,
12419 html : this.fieldLabel
12424 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12425 tooltip : 'This field is required'
12428 cls : "col-sm-" + (12 - this.labelWidth),
12439 } else if ( this.fieldLabel.length) {
12440 // Roo.log(" label");
12444 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12445 tooltip : 'This field is required'
12449 //cls : 'input-group-addon',
12450 html : this.fieldLabel
12458 if(this.indicatorpos == 'right'){
12463 //cls : 'input-group-addon',
12464 html : this.fieldLabel
12470 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12471 tooltip : 'This field is required'
12482 // Roo.log(" no label && no align");
12489 ['xs','sm','md','lg'].map(function(size){
12490 if (settings[size]) {
12491 cfg.cls += ' col-' + size + '-' + settings[size];
12499 _initEventsCalled : false,
12502 initEvents: function()
12504 if (this._initEventsCalled) { // as we call render... prevent looping...
12507 this._initEventsCalled = true;
12510 throw "can not find store for combo";
12513 this.store = Roo.factory(this.store, Roo.data);
12515 // if we are building from html. then this element is so complex, that we can not really
12516 // use the rendered HTML.
12517 // so we have to trash and replace the previous code.
12518 if (Roo.XComponent.build_from_html) {
12520 // remove this element....
12521 var e = this.el.dom, k=0;
12522 while (e ) { e = e.previousSibling; ++k;}
12527 this.rendered = false;
12529 this.render(this.parent().getChildContainer(true), k);
12535 if(Roo.isIOS && this.useNativeIOS){
12536 this.initIOSView();
12544 if(Roo.isTouch && this.mobileTouchView){
12545 this.initTouchView();
12550 this.initTickableEvents();
12554 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12556 if(this.hiddenName){
12558 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12560 this.hiddenField.dom.value =
12561 this.hiddenValue !== undefined ? this.hiddenValue :
12562 this.value !== undefined ? this.value : '';
12564 // prevent input submission
12565 this.el.dom.removeAttribute('name');
12566 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12571 // this.el.dom.setAttribute('autocomplete', 'off');
12574 var cls = 'x-combo-list';
12576 //this.list = new Roo.Layer({
12577 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12583 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12584 _this.list.setWidth(lw);
12587 this.list.on('mouseover', this.onViewOver, this);
12588 this.list.on('mousemove', this.onViewMove, this);
12590 this.list.on('scroll', this.onViewScroll, this);
12593 this.list.swallowEvent('mousewheel');
12594 this.assetHeight = 0;
12597 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12598 this.assetHeight += this.header.getHeight();
12601 this.innerList = this.list.createChild({cls:cls+'-inner'});
12602 this.innerList.on('mouseover', this.onViewOver, this);
12603 this.innerList.on('mousemove', this.onViewMove, this);
12604 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12606 if(this.allowBlank && !this.pageSize && !this.disableClear){
12607 this.footer = this.list.createChild({cls:cls+'-ft'});
12608 this.pageTb = new Roo.Toolbar(this.footer);
12612 this.footer = this.list.createChild({cls:cls+'-ft'});
12613 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12614 {pageSize: this.pageSize});
12618 if (this.pageTb && this.allowBlank && !this.disableClear) {
12620 this.pageTb.add(new Roo.Toolbar.Fill(), {
12621 cls: 'x-btn-icon x-btn-clear',
12623 handler: function()
12626 _this.clearValue();
12627 _this.onSelect(false, -1);
12632 this.assetHeight += this.footer.getHeight();
12637 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12640 this.view = new Roo.View(this.list, this.tpl, {
12641 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12643 //this.view.wrapEl.setDisplayed(false);
12644 this.view.on('click', this.onViewClick, this);
12648 this.store.on('beforeload', this.onBeforeLoad, this);
12649 this.store.on('load', this.onLoad, this);
12650 this.store.on('loadexception', this.onLoadException, this);
12652 if(this.resizable){
12653 this.resizer = new Roo.Resizable(this.list, {
12654 pinned:true, handles:'se'
12656 this.resizer.on('resize', function(r, w, h){
12657 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12658 this.listWidth = w;
12659 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12660 this.restrictHeight();
12662 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12665 if(!this.editable){
12666 this.editable = true;
12667 this.setEditable(false);
12672 if (typeof(this.events.add.listeners) != 'undefined') {
12674 this.addicon = this.wrap.createChild(
12675 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12677 this.addicon.on('click', function(e) {
12678 this.fireEvent('add', this);
12681 if (typeof(this.events.edit.listeners) != 'undefined') {
12683 this.editicon = this.wrap.createChild(
12684 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12685 if (this.addicon) {
12686 this.editicon.setStyle('margin-left', '40px');
12688 this.editicon.on('click', function(e) {
12690 // we fire even if inothing is selected..
12691 this.fireEvent('edit', this, this.lastData );
12697 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12698 "up" : function(e){
12699 this.inKeyMode = true;
12703 "down" : function(e){
12704 if(!this.isExpanded()){
12705 this.onTriggerClick();
12707 this.inKeyMode = true;
12712 "enter" : function(e){
12713 // this.onViewClick();
12717 if(this.fireEvent("specialkey", this, e)){
12718 this.onViewClick(false);
12724 "esc" : function(e){
12728 "tab" : function(e){
12731 if(this.fireEvent("specialkey", this, e)){
12732 this.onViewClick(false);
12740 doRelay : function(foo, bar, hname){
12741 if(hname == 'down' || this.scope.isExpanded()){
12742 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12751 this.queryDelay = Math.max(this.queryDelay || 10,
12752 this.mode == 'local' ? 10 : 250);
12755 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12757 if(this.typeAhead){
12758 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12760 if(this.editable !== false){
12761 this.inputEl().on("keyup", this.onKeyUp, this);
12763 if(this.forceSelection){
12764 this.inputEl().on('blur', this.doForce, this);
12768 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12769 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12773 initTickableEvents: function()
12777 if(this.hiddenName){
12779 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12781 this.hiddenField.dom.value =
12782 this.hiddenValue !== undefined ? this.hiddenValue :
12783 this.value !== undefined ? this.value : '';
12785 // prevent input submission
12786 this.el.dom.removeAttribute('name');
12787 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12792 // this.list = this.el.select('ul.dropdown-menu',true).first();
12794 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12795 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12796 if(this.triggerList){
12797 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12800 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12801 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12803 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12804 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12806 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12807 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12809 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12810 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12811 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12814 this.cancelBtn.hide();
12819 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12820 _this.list.setWidth(lw);
12823 this.list.on('mouseover', this.onViewOver, this);
12824 this.list.on('mousemove', this.onViewMove, this);
12826 this.list.on('scroll', this.onViewScroll, this);
12829 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>';
12832 this.view = new Roo.View(this.list, this.tpl, {
12833 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12836 //this.view.wrapEl.setDisplayed(false);
12837 this.view.on('click', this.onViewClick, this);
12841 this.store.on('beforeload', this.onBeforeLoad, this);
12842 this.store.on('load', this.onLoad, this);
12843 this.store.on('loadexception', this.onLoadException, this);
12846 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12847 "up" : function(e){
12848 this.inKeyMode = true;
12852 "down" : function(e){
12853 this.inKeyMode = true;
12857 "enter" : function(e){
12858 if(this.fireEvent("specialkey", this, e)){
12859 this.onViewClick(false);
12865 "esc" : function(e){
12866 this.onTickableFooterButtonClick(e, false, false);
12869 "tab" : function(e){
12870 this.fireEvent("specialkey", this, e);
12872 this.onTickableFooterButtonClick(e, false, false);
12879 doRelay : function(e, fn, key){
12880 if(this.scope.isExpanded()){
12881 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12890 this.queryDelay = Math.max(this.queryDelay || 10,
12891 this.mode == 'local' ? 10 : 250);
12894 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12896 if(this.typeAhead){
12897 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12900 if(this.editable !== false){
12901 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12906 onDestroy : function(){
12908 this.view.setStore(null);
12909 this.view.el.removeAllListeners();
12910 this.view.el.remove();
12911 this.view.purgeListeners();
12914 this.list.dom.innerHTML = '';
12918 this.store.un('beforeload', this.onBeforeLoad, this);
12919 this.store.un('load', this.onLoad, this);
12920 this.store.un('loadexception', this.onLoadException, this);
12922 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12926 fireKey : function(e){
12927 if(e.isNavKeyPress() && !this.list.isVisible()){
12928 this.fireEvent("specialkey", this, e);
12933 onResize: function(w, h){
12934 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12936 // if(typeof w != 'number'){
12937 // // we do not handle it!?!?
12940 // var tw = this.trigger.getWidth();
12941 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12942 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12944 // this.inputEl().setWidth( this.adjustWidth('input', x));
12946 // //this.trigger.setStyle('left', x+'px');
12948 // if(this.list && this.listWidth === undefined){
12949 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12950 // this.list.setWidth(lw);
12951 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12959 * Allow or prevent the user from directly editing the field text. If false is passed,
12960 * the user will only be able to select from the items defined in the dropdown list. This method
12961 * is the runtime equivalent of setting the 'editable' config option at config time.
12962 * @param {Boolean} value True to allow the user to directly edit the field text
12964 setEditable : function(value){
12965 if(value == this.editable){
12968 this.editable = value;
12970 this.inputEl().dom.setAttribute('readOnly', true);
12971 this.inputEl().on('mousedown', this.onTriggerClick, this);
12972 this.inputEl().addClass('x-combo-noedit');
12974 this.inputEl().dom.setAttribute('readOnly', false);
12975 this.inputEl().un('mousedown', this.onTriggerClick, this);
12976 this.inputEl().removeClass('x-combo-noedit');
12982 onBeforeLoad : function(combo,opts){
12983 if(!this.hasFocus){
12987 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12989 this.restrictHeight();
12990 this.selectedIndex = -1;
12994 onLoad : function(){
12996 this.hasQuery = false;
12998 if(!this.hasFocus){
13002 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13003 this.loading.hide();
13006 if(this.store.getCount() > 0){
13008 this.restrictHeight();
13009 if(this.lastQuery == this.allQuery){
13010 if(this.editable && !this.tickable){
13011 this.inputEl().dom.select();
13015 !this.selectByValue(this.value, true) &&
13018 !this.store.lastOptions ||
13019 typeof(this.store.lastOptions.add) == 'undefined' ||
13020 this.store.lastOptions.add != true
13023 this.select(0, true);
13026 if(this.autoFocus){
13029 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13030 this.taTask.delay(this.typeAheadDelay);
13034 this.onEmptyResults();
13040 onLoadException : function()
13042 this.hasQuery = false;
13044 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13045 this.loading.hide();
13048 if(this.tickable && this.editable){
13053 // only causes errors at present
13054 //Roo.log(this.store.reader.jsonData);
13055 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13057 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13063 onTypeAhead : function(){
13064 if(this.store.getCount() > 0){
13065 var r = this.store.getAt(0);
13066 var newValue = r.data[this.displayField];
13067 var len = newValue.length;
13068 var selStart = this.getRawValue().length;
13070 if(selStart != len){
13071 this.setRawValue(newValue);
13072 this.selectText(selStart, newValue.length);
13078 onSelect : function(record, index){
13080 if(this.fireEvent('beforeselect', this, record, index) !== false){
13082 this.setFromData(index > -1 ? record.data : false);
13085 this.fireEvent('select', this, record, index);
13090 * Returns the currently selected field value or empty string if no value is set.
13091 * @return {String} value The selected value
13093 getValue : function()
13095 if(Roo.isIOS && this.useNativeIOS){
13096 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13100 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13103 if(this.valueField){
13104 return typeof this.value != 'undefined' ? this.value : '';
13106 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13110 getRawValue : function()
13112 if(Roo.isIOS && this.useNativeIOS){
13113 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13116 var v = this.inputEl().getValue();
13122 * Clears any text/value currently set in the field
13124 clearValue : function(){
13126 if(this.hiddenField){
13127 this.hiddenField.dom.value = '';
13130 this.setRawValue('');
13131 this.lastSelectionText = '';
13132 this.lastData = false;
13134 var close = this.closeTriggerEl();
13145 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13146 * will be displayed in the field. If the value does not match the data value of an existing item,
13147 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13148 * Otherwise the field will be blank (although the value will still be set).
13149 * @param {String} value The value to match
13151 setValue : function(v)
13153 if(Roo.isIOS && this.useNativeIOS){
13154 this.setIOSValue(v);
13164 if(this.valueField){
13165 var r = this.findRecord(this.valueField, v);
13167 text = r.data[this.displayField];
13168 }else if(this.valueNotFoundText !== undefined){
13169 text = this.valueNotFoundText;
13172 this.lastSelectionText = text;
13173 if(this.hiddenField){
13174 this.hiddenField.dom.value = v;
13176 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13179 var close = this.closeTriggerEl();
13182 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13188 * @property {Object} the last set data for the element
13193 * Sets the value of the field based on a object which is related to the record format for the store.
13194 * @param {Object} value the value to set as. or false on reset?
13196 setFromData : function(o){
13203 var dv = ''; // display value
13204 var vv = ''; // value value..
13206 if (this.displayField) {
13207 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13209 // this is an error condition!!!
13210 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13213 if(this.valueField){
13214 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13217 var close = this.closeTriggerEl();
13220 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13223 if(this.hiddenField){
13224 this.hiddenField.dom.value = vv;
13226 this.lastSelectionText = dv;
13227 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13231 // no hidden field.. - we store the value in 'value', but still display
13232 // display field!!!!
13233 this.lastSelectionText = dv;
13234 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13241 reset : function(){
13242 // overridden so that last data is reset..
13249 this.setValue(this.originalValue);
13250 //this.clearInvalid();
13251 this.lastData = false;
13253 this.view.clearSelections();
13259 findRecord : function(prop, value){
13261 if(this.store.getCount() > 0){
13262 this.store.each(function(r){
13263 if(r.data[prop] == value){
13273 getName: function()
13275 // returns hidden if it's set..
13276 if (!this.rendered) {return ''};
13277 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13281 onViewMove : function(e, t){
13282 this.inKeyMode = false;
13286 onViewOver : function(e, t){
13287 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13290 var item = this.view.findItemFromChild(t);
13293 var index = this.view.indexOf(item);
13294 this.select(index, false);
13299 onViewClick : function(view, doFocus, el, e)
13301 var index = this.view.getSelectedIndexes()[0];
13303 var r = this.store.getAt(index);
13307 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13314 Roo.each(this.tickItems, function(v,k){
13316 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13318 _this.tickItems.splice(k, 1);
13320 if(typeof(e) == 'undefined' && view == false){
13321 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13333 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13334 this.tickItems.push(r.data);
13337 if(typeof(e) == 'undefined' && view == false){
13338 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13345 this.onSelect(r, index);
13347 if(doFocus !== false && !this.blockFocus){
13348 this.inputEl().focus();
13353 restrictHeight : function(){
13354 //this.innerList.dom.style.height = '';
13355 //var inner = this.innerList.dom;
13356 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13357 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13358 //this.list.beginUpdate();
13359 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13360 this.list.alignTo(this.inputEl(), this.listAlign);
13361 this.list.alignTo(this.inputEl(), this.listAlign);
13362 //this.list.endUpdate();
13366 onEmptyResults : function(){
13368 if(this.tickable && this.editable){
13369 this.restrictHeight();
13377 * Returns true if the dropdown list is expanded, else false.
13379 isExpanded : function(){
13380 return this.list.isVisible();
13384 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13385 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13386 * @param {String} value The data value of the item to select
13387 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13388 * selected item if it is not currently in view (defaults to true)
13389 * @return {Boolean} True if the value matched an item in the list, else false
13391 selectByValue : function(v, scrollIntoView){
13392 if(v !== undefined && v !== null){
13393 var r = this.findRecord(this.valueField || this.displayField, v);
13395 this.select(this.store.indexOf(r), scrollIntoView);
13403 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13404 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13405 * @param {Number} index The zero-based index of the list item to select
13406 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13407 * selected item if it is not currently in view (defaults to true)
13409 select : function(index, scrollIntoView){
13410 this.selectedIndex = index;
13411 this.view.select(index);
13412 if(scrollIntoView !== false){
13413 var el = this.view.getNode(index);
13415 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13418 this.list.scrollChildIntoView(el, false);
13424 selectNext : function(){
13425 var ct = this.store.getCount();
13427 if(this.selectedIndex == -1){
13429 }else if(this.selectedIndex < ct-1){
13430 this.select(this.selectedIndex+1);
13436 selectPrev : function(){
13437 var ct = this.store.getCount();
13439 if(this.selectedIndex == -1){
13441 }else if(this.selectedIndex != 0){
13442 this.select(this.selectedIndex-1);
13448 onKeyUp : function(e){
13449 if(this.editable !== false && !e.isSpecialKey()){
13450 this.lastKey = e.getKey();
13451 this.dqTask.delay(this.queryDelay);
13456 validateBlur : function(){
13457 return !this.list || !this.list.isVisible();
13461 initQuery : function(){
13463 var v = this.getRawValue();
13465 if(this.tickable && this.editable){
13466 v = this.tickableInputEl().getValue();
13473 doForce : function(){
13474 if(this.inputEl().dom.value.length > 0){
13475 this.inputEl().dom.value =
13476 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13482 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13483 * query allowing the query action to be canceled if needed.
13484 * @param {String} query The SQL query to execute
13485 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13486 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13487 * saved in the current store (defaults to false)
13489 doQuery : function(q, forceAll){
13491 if(q === undefined || q === null){
13496 forceAll: forceAll,
13500 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13505 forceAll = qe.forceAll;
13506 if(forceAll === true || (q.length >= this.minChars)){
13508 this.hasQuery = true;
13510 if(this.lastQuery != q || this.alwaysQuery){
13511 this.lastQuery = q;
13512 if(this.mode == 'local'){
13513 this.selectedIndex = -1;
13515 this.store.clearFilter();
13518 if(this.specialFilter){
13519 this.fireEvent('specialfilter', this);
13524 this.store.filter(this.displayField, q);
13527 this.store.fireEvent("datachanged", this.store);
13534 this.store.baseParams[this.queryParam] = q;
13536 var options = {params : this.getParams(q)};
13539 options.add = true;
13540 options.params.start = this.page * this.pageSize;
13543 this.store.load(options);
13546 * this code will make the page width larger, at the beginning, the list not align correctly,
13547 * we should expand the list on onLoad
13548 * so command out it
13553 this.selectedIndex = -1;
13558 this.loadNext = false;
13562 getParams : function(q){
13564 //p[this.queryParam] = q;
13568 p.limit = this.pageSize;
13574 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13576 collapse : function(){
13577 if(!this.isExpanded()){
13584 this.hasFocus = false;
13586 this.cancelBtn.hide();
13587 this.trigger.show();
13590 this.tickableInputEl().dom.value = '';
13591 this.tickableInputEl().blur();
13596 Roo.get(document).un('mousedown', this.collapseIf, this);
13597 Roo.get(document).un('mousewheel', this.collapseIf, this);
13598 if (!this.editable) {
13599 Roo.get(document).un('keydown', this.listKeyPress, this);
13601 this.fireEvent('collapse', this);
13607 collapseIf : function(e){
13608 var in_combo = e.within(this.el);
13609 var in_list = e.within(this.list);
13610 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13612 if (in_combo || in_list || is_list) {
13613 //e.stopPropagation();
13618 this.onTickableFooterButtonClick(e, false, false);
13626 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13628 expand : function(){
13630 if(this.isExpanded() || !this.hasFocus){
13634 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13635 this.list.setWidth(lw);
13642 this.restrictHeight();
13646 this.tickItems = Roo.apply([], this.item);
13649 this.cancelBtn.show();
13650 this.trigger.hide();
13653 this.tickableInputEl().focus();
13658 Roo.get(document).on('mousedown', this.collapseIf, this);
13659 Roo.get(document).on('mousewheel', this.collapseIf, this);
13660 if (!this.editable) {
13661 Roo.get(document).on('keydown', this.listKeyPress, this);
13664 this.fireEvent('expand', this);
13668 // Implements the default empty TriggerField.onTriggerClick function
13669 onTriggerClick : function(e)
13671 Roo.log('trigger click');
13673 if(this.disabled || !this.triggerList){
13678 this.loadNext = false;
13680 if(this.isExpanded()){
13682 if (!this.blockFocus) {
13683 this.inputEl().focus();
13687 this.hasFocus = true;
13688 if(this.triggerAction == 'all') {
13689 this.doQuery(this.allQuery, true);
13691 this.doQuery(this.getRawValue());
13693 if (!this.blockFocus) {
13694 this.inputEl().focus();
13699 onTickableTriggerClick : function(e)
13706 this.loadNext = false;
13707 this.hasFocus = true;
13709 if(this.triggerAction == 'all') {
13710 this.doQuery(this.allQuery, true);
13712 this.doQuery(this.getRawValue());
13716 onSearchFieldClick : function(e)
13718 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13719 this.onTickableFooterButtonClick(e, false, false);
13723 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13728 this.loadNext = false;
13729 this.hasFocus = true;
13731 if(this.triggerAction == 'all') {
13732 this.doQuery(this.allQuery, true);
13734 this.doQuery(this.getRawValue());
13738 listKeyPress : function(e)
13740 //Roo.log('listkeypress');
13741 // scroll to first matching element based on key pres..
13742 if (e.isSpecialKey()) {
13745 var k = String.fromCharCode(e.getKey()).toUpperCase();
13748 var csel = this.view.getSelectedNodes();
13749 var cselitem = false;
13751 var ix = this.view.indexOf(csel[0]);
13752 cselitem = this.store.getAt(ix);
13753 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13759 this.store.each(function(v) {
13761 // start at existing selection.
13762 if (cselitem.id == v.id) {
13768 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13769 match = this.store.indexOf(v);
13775 if (match === false) {
13776 return true; // no more action?
13779 this.view.select(match);
13780 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13781 sn.scrollIntoView(sn.dom.parentNode, false);
13784 onViewScroll : function(e, t){
13786 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){
13790 this.hasQuery = true;
13792 this.loading = this.list.select('.loading', true).first();
13794 if(this.loading === null){
13795 this.list.createChild({
13797 cls: 'loading roo-select2-more-results roo-select2-active',
13798 html: 'Loading more results...'
13801 this.loading = this.list.select('.loading', true).first();
13803 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13805 this.loading.hide();
13808 this.loading.show();
13813 this.loadNext = true;
13815 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13820 addItem : function(o)
13822 var dv = ''; // display value
13824 if (this.displayField) {
13825 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13827 // this is an error condition!!!
13828 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13835 var choice = this.choices.createChild({
13837 cls: 'roo-select2-search-choice',
13846 cls: 'roo-select2-search-choice-close',
13851 }, this.searchField);
13853 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13855 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13863 this.inputEl().dom.value = '';
13868 onRemoveItem : function(e, _self, o)
13870 e.preventDefault();
13872 this.lastItem = Roo.apply([], this.item);
13874 var index = this.item.indexOf(o.data) * 1;
13877 Roo.log('not this item?!');
13881 this.item.splice(index, 1);
13886 this.fireEvent('remove', this, e);
13892 syncValue : function()
13894 if(!this.item.length){
13901 Roo.each(this.item, function(i){
13902 if(_this.valueField){
13903 value.push(i[_this.valueField]);
13910 this.value = value.join(',');
13912 if(this.hiddenField){
13913 this.hiddenField.dom.value = this.value;
13916 this.store.fireEvent("datachanged", this.store);
13921 clearItem : function()
13923 if(!this.multiple){
13929 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13937 if(this.tickable && !Roo.isTouch){
13938 this.view.refresh();
13942 inputEl: function ()
13944 if(Roo.isIOS && this.useNativeIOS){
13945 return this.el.select('select.roo-ios-select', true).first();
13948 if(Roo.isTouch && this.mobileTouchView){
13949 return this.el.select('input.form-control',true).first();
13953 return this.searchField;
13956 return this.el.select('input.form-control',true).first();
13959 onTickableFooterButtonClick : function(e, btn, el)
13961 e.preventDefault();
13963 this.lastItem = Roo.apply([], this.item);
13965 if(btn && btn.name == 'cancel'){
13966 this.tickItems = Roo.apply([], this.item);
13975 Roo.each(this.tickItems, function(o){
13983 validate : function()
13985 var v = this.getRawValue();
13988 v = this.getValue();
13991 if(this.disabled || this.allowBlank || v.length){
13996 this.markInvalid();
14000 tickableInputEl : function()
14002 if(!this.tickable || !this.editable){
14003 return this.inputEl();
14006 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14010 getAutoCreateTouchView : function()
14015 cls: 'form-group' //input-group
14021 type : this.inputType,
14022 cls : 'form-control x-combo-noedit',
14023 autocomplete: 'new-password',
14024 placeholder : this.placeholder || '',
14029 input.name = this.name;
14033 input.cls += ' input-' + this.size;
14036 if (this.disabled) {
14037 input.disabled = true;
14048 inputblock.cls += ' input-group';
14050 inputblock.cn.unshift({
14052 cls : 'input-group-addon',
14057 if(this.removable && !this.multiple){
14058 inputblock.cls += ' roo-removable';
14060 inputblock.cn.push({
14063 cls : 'roo-combo-removable-btn close'
14067 if(this.hasFeedback && !this.allowBlank){
14069 inputblock.cls += ' has-feedback';
14071 inputblock.cn.push({
14073 cls: 'glyphicon form-control-feedback'
14080 inputblock.cls += (this.before) ? '' : ' input-group';
14082 inputblock.cn.push({
14084 cls : 'input-group-addon',
14095 cls: 'form-hidden-field'
14109 cls: 'form-hidden-field'
14113 cls: 'roo-select2-choices',
14117 cls: 'roo-select2-search-field',
14130 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14136 if(!this.multiple && this.showToggleBtn){
14143 if (this.caret != false) {
14146 cls: 'fa fa-' + this.caret
14153 cls : 'input-group-addon btn dropdown-toggle',
14158 cls: 'combobox-clear',
14172 combobox.cls += ' roo-select2-container-multi';
14175 var align = this.labelAlign || this.parentLabelAlign();
14179 if(this.fieldLabel.length && this.labelWidth){
14181 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
14182 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
14187 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14188 tooltip : 'This field is required'
14192 cls : 'control-label ' + lw,
14193 html : this.fieldLabel
14204 if(this.indicatorpos == 'right'){
14208 cls : 'control-label ' + lw,
14209 html : this.fieldLabel
14214 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14215 tooltip : 'This field is required'
14227 var settings = this;
14229 ['xs','sm','md','lg'].map(function(size){
14230 if (settings[size]) {
14231 cfg.cls += ' col-' + size + '-' + settings[size];
14238 initTouchView : function()
14240 this.renderTouchView();
14242 this.touchViewEl.on('scroll', function(){
14243 this.el.dom.scrollTop = 0;
14246 this.originalValue = this.getValue();
14248 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14250 this.inputEl().on("click", this.showTouchView, this);
14251 this.triggerEl.on("click", this.showTouchView, this);
14253 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14254 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14256 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14258 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14259 this.store.on('load', this.onTouchViewLoad, this);
14260 this.store.on('loadexception', this.onTouchViewLoadException, this);
14262 if(this.hiddenName){
14264 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14266 this.hiddenField.dom.value =
14267 this.hiddenValue !== undefined ? this.hiddenValue :
14268 this.value !== undefined ? this.value : '';
14270 this.el.dom.removeAttribute('name');
14271 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14275 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14276 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14279 if(this.removable && !this.multiple){
14280 var close = this.closeTriggerEl();
14282 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14283 close.on('click', this.removeBtnClick, this, close);
14287 * fix the bug in Safari iOS8
14289 this.inputEl().on("focus", function(e){
14290 document.activeElement.blur();
14298 renderTouchView : function()
14300 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14301 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14303 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14304 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14306 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14307 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14308 this.touchViewBodyEl.setStyle('overflow', 'auto');
14310 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14311 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14313 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14314 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14318 showTouchView : function()
14324 this.touchViewHeaderEl.hide();
14326 if(this.modalTitle.length){
14327 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14328 this.touchViewHeaderEl.show();
14331 this.touchViewEl.show();
14333 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14334 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14335 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14337 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14339 if(this.modalTitle.length){
14340 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14343 this.touchViewBodyEl.setHeight(bodyHeight);
14347 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14349 this.touchViewEl.addClass('in');
14352 this.doTouchViewQuery();
14356 hideTouchView : function()
14358 this.touchViewEl.removeClass('in');
14362 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14364 this.touchViewEl.setStyle('display', 'none');
14369 setTouchViewValue : function()
14376 Roo.each(this.tickItems, function(o){
14381 this.hideTouchView();
14384 doTouchViewQuery : function()
14393 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14397 if(!this.alwaysQuery || this.mode == 'local'){
14398 this.onTouchViewLoad();
14405 onTouchViewBeforeLoad : function(combo,opts)
14411 onTouchViewLoad : function()
14413 if(this.store.getCount() < 1){
14414 this.onTouchViewEmptyResults();
14418 this.clearTouchView();
14420 var rawValue = this.getRawValue();
14422 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14424 this.tickItems = [];
14426 this.store.data.each(function(d, rowIndex){
14427 var row = this.touchViewListGroup.createChild(template);
14429 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14430 row.addClass(d.data.cls);
14433 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14436 html : d.data[this.displayField]
14439 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14440 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14443 row.removeClass('selected');
14444 if(!this.multiple && this.valueField &&
14445 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14448 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14449 row.addClass('selected');
14452 if(this.multiple && this.valueField &&
14453 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14457 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14458 this.tickItems.push(d.data);
14461 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14465 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14467 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14469 if(this.modalTitle.length){
14470 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14473 var listHeight = this.touchViewListGroup.getHeight();
14477 if(firstChecked && listHeight > bodyHeight){
14478 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14483 onTouchViewLoadException : function()
14485 this.hideTouchView();
14488 onTouchViewEmptyResults : function()
14490 this.clearTouchView();
14492 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14494 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14498 clearTouchView : function()
14500 this.touchViewListGroup.dom.innerHTML = '';
14503 onTouchViewClick : function(e, el, o)
14505 e.preventDefault();
14508 var rowIndex = o.rowIndex;
14510 var r = this.store.getAt(rowIndex);
14512 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14514 if(!this.multiple){
14515 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14516 c.dom.removeAttribute('checked');
14519 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14521 this.setFromData(r.data);
14523 var close = this.closeTriggerEl();
14529 this.hideTouchView();
14531 this.fireEvent('select', this, r, rowIndex);
14536 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14537 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14538 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14542 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14543 this.addItem(r.data);
14544 this.tickItems.push(r.data);
14548 getAutoCreateNativeIOS : function()
14551 cls: 'form-group' //input-group,
14556 cls : 'roo-ios-select'
14560 combobox.name = this.name;
14563 if (this.disabled) {
14564 combobox.disabled = true;
14567 var settings = this;
14569 ['xs','sm','md','lg'].map(function(size){
14570 if (settings[size]) {
14571 cfg.cls += ' col-' + size + '-' + settings[size];
14581 initIOSView : function()
14583 this.store.on('load', this.onIOSViewLoad, this);
14588 onIOSViewLoad : function()
14590 if(this.store.getCount() < 1){
14594 this.clearIOSView();
14596 if(this.allowBlank) {
14598 var default_text = '-- SELECT --';
14600 var opt = this.inputEl().createChild({
14603 html : default_text
14607 o[this.valueField] = 0;
14608 o[this.displayField] = default_text;
14610 this.ios_options.push({
14617 this.store.data.each(function(d, rowIndex){
14621 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14622 html = d.data[this.displayField];
14627 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
14628 value = d.data[this.valueField];
14637 if(this.value == d.data[this.valueField]){
14638 option['selected'] = true;
14641 var opt = this.inputEl().createChild(option);
14643 this.ios_options.push({
14650 this.inputEl().on('change', function(){
14651 this.fireEvent('select', this);
14656 clearIOSView: function()
14658 this.inputEl().dom.innerHTML = '';
14660 this.ios_options = [];
14663 setIOSValue: function(v)
14667 if(!this.ios_options){
14671 Roo.each(this.ios_options, function(opts){
14673 opts.el.dom.removeAttribute('selected');
14675 if(opts.data[this.valueField] != v){
14679 opts.el.dom.setAttribute('selected', true);
14685 * @cfg {Boolean} grow
14689 * @cfg {Number} growMin
14693 * @cfg {Number} growMax
14702 Roo.apply(Roo.bootstrap.ComboBox, {
14706 cls: 'modal-header',
14728 cls: 'list-group-item',
14732 cls: 'roo-combobox-list-group-item-value'
14736 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14750 listItemCheckbox : {
14752 cls: 'list-group-item',
14756 cls: 'roo-combobox-list-group-item-value'
14760 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14776 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14781 cls: 'modal-footer',
14789 cls: 'col-xs-6 text-left',
14792 cls: 'btn btn-danger roo-touch-view-cancel',
14798 cls: 'col-xs-6 text-right',
14801 cls: 'btn btn-success roo-touch-view-ok',
14812 Roo.apply(Roo.bootstrap.ComboBox, {
14814 touchViewTemplate : {
14816 cls: 'modal fade roo-combobox-touch-view',
14820 cls: 'modal-dialog',
14821 style : 'position:fixed', // we have to fix position....
14825 cls: 'modal-content',
14827 Roo.bootstrap.ComboBox.header,
14828 Roo.bootstrap.ComboBox.body,
14829 Roo.bootstrap.ComboBox.footer
14838 * Ext JS Library 1.1.1
14839 * Copyright(c) 2006-2007, Ext JS, LLC.
14841 * Originally Released Under LGPL - original licence link has changed is not relivant.
14844 * <script type="text/javascript">
14849 * @extends Roo.util.Observable
14850 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14851 * This class also supports single and multi selection modes. <br>
14852 * Create a data model bound view:
14854 var store = new Roo.data.Store(...);
14856 var view = new Roo.View({
14858 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14860 singleSelect: true,
14861 selectedClass: "ydataview-selected",
14865 // listen for node click?
14866 view.on("click", function(vw, index, node, e){
14867 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14871 dataModel.load("foobar.xml");
14873 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14875 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14876 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14878 * Note: old style constructor is still suported (container, template, config)
14881 * Create a new View
14882 * @param {Object} config The config object
14885 Roo.View = function(config, depreciated_tpl, depreciated_config){
14887 this.parent = false;
14889 if (typeof(depreciated_tpl) == 'undefined') {
14890 // new way.. - universal constructor.
14891 Roo.apply(this, config);
14892 this.el = Roo.get(this.el);
14895 this.el = Roo.get(config);
14896 this.tpl = depreciated_tpl;
14897 Roo.apply(this, depreciated_config);
14899 this.wrapEl = this.el.wrap().wrap();
14900 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14903 if(typeof(this.tpl) == "string"){
14904 this.tpl = new Roo.Template(this.tpl);
14906 // support xtype ctors..
14907 this.tpl = new Roo.factory(this.tpl, Roo);
14911 this.tpl.compile();
14916 * @event beforeclick
14917 * Fires before a click is processed. Returns false to cancel the default action.
14918 * @param {Roo.View} this
14919 * @param {Number} index The index of the target node
14920 * @param {HTMLElement} node The target node
14921 * @param {Roo.EventObject} e The raw event object
14923 "beforeclick" : true,
14926 * Fires when a template node is clicked.
14927 * @param {Roo.View} this
14928 * @param {Number} index The index of the target node
14929 * @param {HTMLElement} node The target node
14930 * @param {Roo.EventObject} e The raw event object
14935 * Fires when a template node is double clicked.
14936 * @param {Roo.View} this
14937 * @param {Number} index The index of the target node
14938 * @param {HTMLElement} node The target node
14939 * @param {Roo.EventObject} e The raw event object
14943 * @event contextmenu
14944 * Fires when a template node is right clicked.
14945 * @param {Roo.View} this
14946 * @param {Number} index The index of the target node
14947 * @param {HTMLElement} node The target node
14948 * @param {Roo.EventObject} e The raw event object
14950 "contextmenu" : true,
14952 * @event selectionchange
14953 * Fires when the selected nodes change.
14954 * @param {Roo.View} this
14955 * @param {Array} selections Array of the selected nodes
14957 "selectionchange" : true,
14960 * @event beforeselect
14961 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14962 * @param {Roo.View} this
14963 * @param {HTMLElement} node The node to be selected
14964 * @param {Array} selections Array of currently selected nodes
14966 "beforeselect" : true,
14968 * @event preparedata
14969 * Fires on every row to render, to allow you to change the data.
14970 * @param {Roo.View} this
14971 * @param {Object} data to be rendered (change this)
14973 "preparedata" : true
14981 "click": this.onClick,
14982 "dblclick": this.onDblClick,
14983 "contextmenu": this.onContextMenu,
14987 this.selections = [];
14989 this.cmp = new Roo.CompositeElementLite([]);
14991 this.store = Roo.factory(this.store, Roo.data);
14992 this.setStore(this.store, true);
14995 if ( this.footer && this.footer.xtype) {
14997 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14999 this.footer.dataSource = this.store;
15000 this.footer.container = fctr;
15001 this.footer = Roo.factory(this.footer, Roo);
15002 fctr.insertFirst(this.el);
15004 // this is a bit insane - as the paging toolbar seems to detach the el..
15005 // dom.parentNode.parentNode.parentNode
15006 // they get detached?
15010 Roo.View.superclass.constructor.call(this);
15015 Roo.extend(Roo.View, Roo.util.Observable, {
15018 * @cfg {Roo.data.Store} store Data store to load data from.
15023 * @cfg {String|Roo.Element} el The container element.
15028 * @cfg {String|Roo.Template} tpl The template used by this View
15032 * @cfg {String} dataName the named area of the template to use as the data area
15033 * Works with domtemplates roo-name="name"
15037 * @cfg {String} selectedClass The css class to add to selected nodes
15039 selectedClass : "x-view-selected",
15041 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15046 * @cfg {String} text to display on mask (default Loading)
15050 * @cfg {Boolean} multiSelect Allow multiple selection
15052 multiSelect : false,
15054 * @cfg {Boolean} singleSelect Allow single selection
15056 singleSelect: false,
15059 * @cfg {Boolean} toggleSelect - selecting
15061 toggleSelect : false,
15064 * @cfg {Boolean} tickable - selecting
15069 * Returns the element this view is bound to.
15070 * @return {Roo.Element}
15072 getEl : function(){
15073 return this.wrapEl;
15079 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15081 refresh : function(){
15082 //Roo.log('refresh');
15085 // if we are using something like 'domtemplate', then
15086 // the what gets used is:
15087 // t.applySubtemplate(NAME, data, wrapping data..)
15088 // the outer template then get' applied with
15089 // the store 'extra data'
15090 // and the body get's added to the
15091 // roo-name="data" node?
15092 // <span class='roo-tpl-{name}'></span> ?????
15096 this.clearSelections();
15097 this.el.update("");
15099 var records = this.store.getRange();
15100 if(records.length < 1) {
15102 // is this valid?? = should it render a template??
15104 this.el.update(this.emptyText);
15108 if (this.dataName) {
15109 this.el.update(t.apply(this.store.meta)); //????
15110 el = this.el.child('.roo-tpl-' + this.dataName);
15113 for(var i = 0, len = records.length; i < len; i++){
15114 var data = this.prepareData(records[i].data, i, records[i]);
15115 this.fireEvent("preparedata", this, data, i, records[i]);
15117 var d = Roo.apply({}, data);
15120 Roo.apply(d, {'roo-id' : Roo.id()});
15124 Roo.each(this.parent.item, function(item){
15125 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15128 Roo.apply(d, {'roo-data-checked' : 'checked'});
15132 html[html.length] = Roo.util.Format.trim(
15134 t.applySubtemplate(this.dataName, d, this.store.meta) :
15141 el.update(html.join(""));
15142 this.nodes = el.dom.childNodes;
15143 this.updateIndexes(0);
15148 * Function to override to reformat the data that is sent to
15149 * the template for each node.
15150 * DEPRICATED - use the preparedata event handler.
15151 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15152 * a JSON object for an UpdateManager bound view).
15154 prepareData : function(data, index, record)
15156 this.fireEvent("preparedata", this, data, index, record);
15160 onUpdate : function(ds, record){
15161 // Roo.log('on update');
15162 this.clearSelections();
15163 var index = this.store.indexOf(record);
15164 var n = this.nodes[index];
15165 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15166 n.parentNode.removeChild(n);
15167 this.updateIndexes(index, index);
15173 onAdd : function(ds, records, index)
15175 //Roo.log(['on Add', ds, records, index] );
15176 this.clearSelections();
15177 if(this.nodes.length == 0){
15181 var n = this.nodes[index];
15182 for(var i = 0, len = records.length; i < len; i++){
15183 var d = this.prepareData(records[i].data, i, records[i]);
15185 this.tpl.insertBefore(n, d);
15188 this.tpl.append(this.el, d);
15191 this.updateIndexes(index);
15194 onRemove : function(ds, record, index){
15195 // Roo.log('onRemove');
15196 this.clearSelections();
15197 var el = this.dataName ?
15198 this.el.child('.roo-tpl-' + this.dataName) :
15201 el.dom.removeChild(this.nodes[index]);
15202 this.updateIndexes(index);
15206 * Refresh an individual node.
15207 * @param {Number} index
15209 refreshNode : function(index){
15210 this.onUpdate(this.store, this.store.getAt(index));
15213 updateIndexes : function(startIndex, endIndex){
15214 var ns = this.nodes;
15215 startIndex = startIndex || 0;
15216 endIndex = endIndex || ns.length - 1;
15217 for(var i = startIndex; i <= endIndex; i++){
15218 ns[i].nodeIndex = i;
15223 * Changes the data store this view uses and refresh the view.
15224 * @param {Store} store
15226 setStore : function(store, initial){
15227 if(!initial && this.store){
15228 this.store.un("datachanged", this.refresh);
15229 this.store.un("add", this.onAdd);
15230 this.store.un("remove", this.onRemove);
15231 this.store.un("update", this.onUpdate);
15232 this.store.un("clear", this.refresh);
15233 this.store.un("beforeload", this.onBeforeLoad);
15234 this.store.un("load", this.onLoad);
15235 this.store.un("loadexception", this.onLoad);
15239 store.on("datachanged", this.refresh, this);
15240 store.on("add", this.onAdd, this);
15241 store.on("remove", this.onRemove, this);
15242 store.on("update", this.onUpdate, this);
15243 store.on("clear", this.refresh, this);
15244 store.on("beforeload", this.onBeforeLoad, this);
15245 store.on("load", this.onLoad, this);
15246 store.on("loadexception", this.onLoad, this);
15254 * onbeforeLoad - masks the loading area.
15257 onBeforeLoad : function(store,opts)
15259 //Roo.log('onBeforeLoad');
15261 this.el.update("");
15263 this.el.mask(this.mask ? this.mask : "Loading" );
15265 onLoad : function ()
15272 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15273 * @param {HTMLElement} node
15274 * @return {HTMLElement} The template node
15276 findItemFromChild : function(node){
15277 var el = this.dataName ?
15278 this.el.child('.roo-tpl-' + this.dataName,true) :
15281 if(!node || node.parentNode == el){
15284 var p = node.parentNode;
15285 while(p && p != el){
15286 if(p.parentNode == el){
15295 onClick : function(e){
15296 var item = this.findItemFromChild(e.getTarget());
15298 var index = this.indexOf(item);
15299 if(this.onItemClick(item, index, e) !== false){
15300 this.fireEvent("click", this, index, item, e);
15303 this.clearSelections();
15308 onContextMenu : function(e){
15309 var item = this.findItemFromChild(e.getTarget());
15311 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15316 onDblClick : function(e){
15317 var item = this.findItemFromChild(e.getTarget());
15319 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15323 onItemClick : function(item, index, e)
15325 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15328 if (this.toggleSelect) {
15329 var m = this.isSelected(item) ? 'unselect' : 'select';
15332 _t[m](item, true, false);
15335 if(this.multiSelect || this.singleSelect){
15336 if(this.multiSelect && e.shiftKey && this.lastSelection){
15337 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15339 this.select(item, this.multiSelect && e.ctrlKey);
15340 this.lastSelection = item;
15343 if(!this.tickable){
15344 e.preventDefault();
15352 * Get the number of selected nodes.
15355 getSelectionCount : function(){
15356 return this.selections.length;
15360 * Get the currently selected nodes.
15361 * @return {Array} An array of HTMLElements
15363 getSelectedNodes : function(){
15364 return this.selections;
15368 * Get the indexes of the selected nodes.
15371 getSelectedIndexes : function(){
15372 var indexes = [], s = this.selections;
15373 for(var i = 0, len = s.length; i < len; i++){
15374 indexes.push(s[i].nodeIndex);
15380 * Clear all selections
15381 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15383 clearSelections : function(suppressEvent){
15384 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15385 this.cmp.elements = this.selections;
15386 this.cmp.removeClass(this.selectedClass);
15387 this.selections = [];
15388 if(!suppressEvent){
15389 this.fireEvent("selectionchange", this, this.selections);
15395 * Returns true if the passed node is selected
15396 * @param {HTMLElement/Number} node The node or node index
15397 * @return {Boolean}
15399 isSelected : function(node){
15400 var s = this.selections;
15404 node = this.getNode(node);
15405 return s.indexOf(node) !== -1;
15410 * @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
15411 * @param {Boolean} keepExisting (optional) true to keep existing selections
15412 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15414 select : function(nodeInfo, keepExisting, suppressEvent){
15415 if(nodeInfo instanceof Array){
15417 this.clearSelections(true);
15419 for(var i = 0, len = nodeInfo.length; i < len; i++){
15420 this.select(nodeInfo[i], true, true);
15424 var node = this.getNode(nodeInfo);
15425 if(!node || this.isSelected(node)){
15426 return; // already selected.
15429 this.clearSelections(true);
15432 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15433 Roo.fly(node).addClass(this.selectedClass);
15434 this.selections.push(node);
15435 if(!suppressEvent){
15436 this.fireEvent("selectionchange", this, this.selections);
15444 * @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
15445 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15446 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15448 unselect : function(nodeInfo, keepExisting, suppressEvent)
15450 if(nodeInfo instanceof Array){
15451 Roo.each(this.selections, function(s) {
15452 this.unselect(s, nodeInfo);
15456 var node = this.getNode(nodeInfo);
15457 if(!node || !this.isSelected(node)){
15458 //Roo.log("not selected");
15459 return; // not selected.
15463 Roo.each(this.selections, function(s) {
15465 Roo.fly(node).removeClass(this.selectedClass);
15472 this.selections= ns;
15473 this.fireEvent("selectionchange", this, this.selections);
15477 * Gets a template node.
15478 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15479 * @return {HTMLElement} The node or null if it wasn't found
15481 getNode : function(nodeInfo){
15482 if(typeof nodeInfo == "string"){
15483 return document.getElementById(nodeInfo);
15484 }else if(typeof nodeInfo == "number"){
15485 return this.nodes[nodeInfo];
15491 * Gets a range template nodes.
15492 * @param {Number} startIndex
15493 * @param {Number} endIndex
15494 * @return {Array} An array of nodes
15496 getNodes : function(start, end){
15497 var ns = this.nodes;
15498 start = start || 0;
15499 end = typeof end == "undefined" ? ns.length - 1 : end;
15502 for(var i = start; i <= end; i++){
15506 for(var i = start; i >= end; i--){
15514 * Finds the index of the passed node
15515 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15516 * @return {Number} The index of the node or -1
15518 indexOf : function(node){
15519 node = this.getNode(node);
15520 if(typeof node.nodeIndex == "number"){
15521 return node.nodeIndex;
15523 var ns = this.nodes;
15524 for(var i = 0, len = ns.length; i < len; i++){
15535 * based on jquery fullcalendar
15539 Roo.bootstrap = Roo.bootstrap || {};
15541 * @class Roo.bootstrap.Calendar
15542 * @extends Roo.bootstrap.Component
15543 * Bootstrap Calendar class
15544 * @cfg {Boolean} loadMask (true|false) default false
15545 * @cfg {Object} header generate the user specific header of the calendar, default false
15548 * Create a new Container
15549 * @param {Object} config The config object
15554 Roo.bootstrap.Calendar = function(config){
15555 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15559 * Fires when a date is selected
15560 * @param {DatePicker} this
15561 * @param {Date} date The selected date
15565 * @event monthchange
15566 * Fires when the displayed month changes
15567 * @param {DatePicker} this
15568 * @param {Date} date The selected month
15570 'monthchange': true,
15572 * @event evententer
15573 * Fires when mouse over an event
15574 * @param {Calendar} this
15575 * @param {event} Event
15577 'evententer': true,
15579 * @event eventleave
15580 * Fires when the mouse leaves an
15581 * @param {Calendar} this
15584 'eventleave': true,
15586 * @event eventclick
15587 * Fires when the mouse click an
15588 * @param {Calendar} this
15597 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15600 * @cfg {Number} startDay
15601 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15609 getAutoCreate : function(){
15612 var fc_button = function(name, corner, style, content ) {
15613 return Roo.apply({},{
15615 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15617 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15620 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15631 style : 'width:100%',
15638 cls : 'fc-header-left',
15640 fc_button('prev', 'left', 'arrow', '‹' ),
15641 fc_button('next', 'right', 'arrow', '›' ),
15642 { tag: 'span', cls: 'fc-header-space' },
15643 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15651 cls : 'fc-header-center',
15655 cls: 'fc-header-title',
15658 html : 'month / year'
15666 cls : 'fc-header-right',
15668 /* fc_button('month', 'left', '', 'month' ),
15669 fc_button('week', '', '', 'week' ),
15670 fc_button('day', 'right', '', 'day' )
15682 header = this.header;
15685 var cal_heads = function() {
15687 // fixme - handle this.
15689 for (var i =0; i < Date.dayNames.length; i++) {
15690 var d = Date.dayNames[i];
15693 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15694 html : d.substring(0,3)
15698 ret[0].cls += ' fc-first';
15699 ret[6].cls += ' fc-last';
15702 var cal_cell = function(n) {
15705 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15710 cls: 'fc-day-number',
15714 cls: 'fc-day-content',
15718 style: 'position: relative;' // height: 17px;
15730 var cal_rows = function() {
15733 for (var r = 0; r < 6; r++) {
15740 for (var i =0; i < Date.dayNames.length; i++) {
15741 var d = Date.dayNames[i];
15742 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15745 row.cn[0].cls+=' fc-first';
15746 row.cn[0].cn[0].style = 'min-height:90px';
15747 row.cn[6].cls+=' fc-last';
15751 ret[0].cls += ' fc-first';
15752 ret[4].cls += ' fc-prev-last';
15753 ret[5].cls += ' fc-last';
15760 cls: 'fc-border-separate',
15761 style : 'width:100%',
15769 cls : 'fc-first fc-last',
15787 cls : 'fc-content',
15788 style : "position: relative;",
15791 cls : 'fc-view fc-view-month fc-grid',
15792 style : 'position: relative',
15793 unselectable : 'on',
15796 cls : 'fc-event-container',
15797 style : 'position:absolute;z-index:8;top:0;left:0;'
15815 initEvents : function()
15818 throw "can not find store for calendar";
15824 style: "text-align:center",
15828 style: "background-color:white;width:50%;margin:250 auto",
15832 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15843 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15845 var size = this.el.select('.fc-content', true).first().getSize();
15846 this.maskEl.setSize(size.width, size.height);
15847 this.maskEl.enableDisplayMode("block");
15848 if(!this.loadMask){
15849 this.maskEl.hide();
15852 this.store = Roo.factory(this.store, Roo.data);
15853 this.store.on('load', this.onLoad, this);
15854 this.store.on('beforeload', this.onBeforeLoad, this);
15858 this.cells = this.el.select('.fc-day',true);
15859 //Roo.log(this.cells);
15860 this.textNodes = this.el.query('.fc-day-number');
15861 this.cells.addClassOnOver('fc-state-hover');
15863 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15864 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15865 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15866 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15868 this.on('monthchange', this.onMonthChange, this);
15870 this.update(new Date().clearTime());
15873 resize : function() {
15874 var sz = this.el.getSize();
15876 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15877 this.el.select('.fc-day-content div',true).setHeight(34);
15882 showPrevMonth : function(e){
15883 this.update(this.activeDate.add("mo", -1));
15885 showToday : function(e){
15886 this.update(new Date().clearTime());
15889 showNextMonth : function(e){
15890 this.update(this.activeDate.add("mo", 1));
15894 showPrevYear : function(){
15895 this.update(this.activeDate.add("y", -1));
15899 showNextYear : function(){
15900 this.update(this.activeDate.add("y", 1));
15905 update : function(date)
15907 var vd = this.activeDate;
15908 this.activeDate = date;
15909 // if(vd && this.el){
15910 // var t = date.getTime();
15911 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15912 // Roo.log('using add remove');
15914 // this.fireEvent('monthchange', this, date);
15916 // this.cells.removeClass("fc-state-highlight");
15917 // this.cells.each(function(c){
15918 // if(c.dateValue == t){
15919 // c.addClass("fc-state-highlight");
15920 // setTimeout(function(){
15921 // try{c.dom.firstChild.focus();}catch(e){}
15931 var days = date.getDaysInMonth();
15933 var firstOfMonth = date.getFirstDateOfMonth();
15934 var startingPos = firstOfMonth.getDay()-this.startDay;
15936 if(startingPos < this.startDay){
15940 var pm = date.add(Date.MONTH, -1);
15941 var prevStart = pm.getDaysInMonth()-startingPos;
15943 this.cells = this.el.select('.fc-day',true);
15944 this.textNodes = this.el.query('.fc-day-number');
15945 this.cells.addClassOnOver('fc-state-hover');
15947 var cells = this.cells.elements;
15948 var textEls = this.textNodes;
15950 Roo.each(cells, function(cell){
15951 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15954 days += startingPos;
15956 // convert everything to numbers so it's fast
15957 var day = 86400000;
15958 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15961 //Roo.log(prevStart);
15963 var today = new Date().clearTime().getTime();
15964 var sel = date.clearTime().getTime();
15965 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15966 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15967 var ddMatch = this.disabledDatesRE;
15968 var ddText = this.disabledDatesText;
15969 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15970 var ddaysText = this.disabledDaysText;
15971 var format = this.format;
15973 var setCellClass = function(cal, cell){
15977 //Roo.log('set Cell Class');
15979 var t = d.getTime();
15983 cell.dateValue = t;
15985 cell.className += " fc-today";
15986 cell.className += " fc-state-highlight";
15987 cell.title = cal.todayText;
15990 // disable highlight in other month..
15991 //cell.className += " fc-state-highlight";
15996 cell.className = " fc-state-disabled";
15997 cell.title = cal.minText;
16001 cell.className = " fc-state-disabled";
16002 cell.title = cal.maxText;
16006 if(ddays.indexOf(d.getDay()) != -1){
16007 cell.title = ddaysText;
16008 cell.className = " fc-state-disabled";
16011 if(ddMatch && format){
16012 var fvalue = d.dateFormat(format);
16013 if(ddMatch.test(fvalue)){
16014 cell.title = ddText.replace("%0", fvalue);
16015 cell.className = " fc-state-disabled";
16019 if (!cell.initialClassName) {
16020 cell.initialClassName = cell.dom.className;
16023 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16028 for(; i < startingPos; i++) {
16029 textEls[i].innerHTML = (++prevStart);
16030 d.setDate(d.getDate()+1);
16032 cells[i].className = "fc-past fc-other-month";
16033 setCellClass(this, cells[i]);
16038 for(; i < days; i++){
16039 intDay = i - startingPos + 1;
16040 textEls[i].innerHTML = (intDay);
16041 d.setDate(d.getDate()+1);
16043 cells[i].className = ''; // "x-date-active";
16044 setCellClass(this, cells[i]);
16048 for(; i < 42; i++) {
16049 textEls[i].innerHTML = (++extraDays);
16050 d.setDate(d.getDate()+1);
16052 cells[i].className = "fc-future fc-other-month";
16053 setCellClass(this, cells[i]);
16056 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16058 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16060 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16061 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16063 if(totalRows != 6){
16064 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16065 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16068 this.fireEvent('monthchange', this, date);
16072 if(!this.internalRender){
16073 var main = this.el.dom.firstChild;
16074 var w = main.offsetWidth;
16075 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16076 Roo.fly(main).setWidth(w);
16077 this.internalRender = true;
16078 // opera does not respect the auto grow header center column
16079 // then, after it gets a width opera refuses to recalculate
16080 // without a second pass
16081 if(Roo.isOpera && !this.secondPass){
16082 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16083 this.secondPass = true;
16084 this.update.defer(10, this, [date]);
16091 findCell : function(dt) {
16092 dt = dt.clearTime().getTime();
16094 this.cells.each(function(c){
16095 //Roo.log("check " +c.dateValue + '?=' + dt);
16096 if(c.dateValue == dt){
16106 findCells : function(ev) {
16107 var s = ev.start.clone().clearTime().getTime();
16109 var e= ev.end.clone().clearTime().getTime();
16112 this.cells.each(function(c){
16113 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16115 if(c.dateValue > e){
16118 if(c.dateValue < s){
16127 // findBestRow: function(cells)
16131 // for (var i =0 ; i < cells.length;i++) {
16132 // ret = Math.max(cells[i].rows || 0,ret);
16139 addItem : function(ev)
16141 // look for vertical location slot in
16142 var cells = this.findCells(ev);
16144 // ev.row = this.findBestRow(cells);
16146 // work out the location.
16150 for(var i =0; i < cells.length; i++) {
16152 cells[i].row = cells[0].row;
16155 cells[i].row = cells[i].row + 1;
16165 if (crow.start.getY() == cells[i].getY()) {
16167 crow.end = cells[i];
16184 cells[0].events.push(ev);
16186 this.calevents.push(ev);
16189 clearEvents: function() {
16191 if(!this.calevents){
16195 Roo.each(this.cells.elements, function(c){
16201 Roo.each(this.calevents, function(e) {
16202 Roo.each(e.els, function(el) {
16203 el.un('mouseenter' ,this.onEventEnter, this);
16204 el.un('mouseleave' ,this.onEventLeave, this);
16209 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16215 renderEvents: function()
16219 this.cells.each(function(c) {
16228 if(c.row != c.events.length){
16229 r = 4 - (4 - (c.row - c.events.length));
16232 c.events = ev.slice(0, r);
16233 c.more = ev.slice(r);
16235 if(c.more.length && c.more.length == 1){
16236 c.events.push(c.more.pop());
16239 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16243 this.cells.each(function(c) {
16245 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16248 for (var e = 0; e < c.events.length; e++){
16249 var ev = c.events[e];
16250 var rows = ev.rows;
16252 for(var i = 0; i < rows.length; i++) {
16254 // how many rows should it span..
16257 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16258 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16260 unselectable : "on",
16263 cls: 'fc-event-inner',
16267 // cls: 'fc-event-time',
16268 // html : cells.length > 1 ? '' : ev.time
16272 cls: 'fc-event-title',
16273 html : String.format('{0}', ev.title)
16280 cls: 'ui-resizable-handle ui-resizable-e',
16281 html : '  '
16288 cfg.cls += ' fc-event-start';
16290 if ((i+1) == rows.length) {
16291 cfg.cls += ' fc-event-end';
16294 var ctr = _this.el.select('.fc-event-container',true).first();
16295 var cg = ctr.createChild(cfg);
16297 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16298 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16300 var r = (c.more.length) ? 1 : 0;
16301 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16302 cg.setWidth(ebox.right - sbox.x -2);
16304 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16305 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16306 cg.on('click', _this.onEventClick, _this, ev);
16317 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16318 style : 'position: absolute',
16319 unselectable : "on",
16322 cls: 'fc-event-inner',
16326 cls: 'fc-event-title',
16334 cls: 'ui-resizable-handle ui-resizable-e',
16335 html : '  '
16341 var ctr = _this.el.select('.fc-event-container',true).first();
16342 var cg = ctr.createChild(cfg);
16344 var sbox = c.select('.fc-day-content',true).first().getBox();
16345 var ebox = c.select('.fc-day-content',true).first().getBox();
16347 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16348 cg.setWidth(ebox.right - sbox.x -2);
16350 cg.on('click', _this.onMoreEventClick, _this, c.more);
16360 onEventEnter: function (e, el,event,d) {
16361 this.fireEvent('evententer', this, el, event);
16364 onEventLeave: function (e, el,event,d) {
16365 this.fireEvent('eventleave', this, el, event);
16368 onEventClick: function (e, el,event,d) {
16369 this.fireEvent('eventclick', this, el, event);
16372 onMonthChange: function () {
16376 onMoreEventClick: function(e, el, more)
16380 this.calpopover.placement = 'right';
16381 this.calpopover.setTitle('More');
16383 this.calpopover.setContent('');
16385 var ctr = this.calpopover.el.select('.popover-content', true).first();
16387 Roo.each(more, function(m){
16389 cls : 'fc-event-hori fc-event-draggable',
16392 var cg = ctr.createChild(cfg);
16394 cg.on('click', _this.onEventClick, _this, m);
16397 this.calpopover.show(el);
16402 onLoad: function ()
16404 this.calevents = [];
16407 if(this.store.getCount() > 0){
16408 this.store.data.each(function(d){
16411 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16412 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16413 time : d.data.start_time,
16414 title : d.data.title,
16415 description : d.data.description,
16416 venue : d.data.venue
16421 this.renderEvents();
16423 if(this.calevents.length && this.loadMask){
16424 this.maskEl.hide();
16428 onBeforeLoad: function()
16430 this.clearEvents();
16432 this.maskEl.show();
16446 * @class Roo.bootstrap.Popover
16447 * @extends Roo.bootstrap.Component
16448 * Bootstrap Popover class
16449 * @cfg {String} html contents of the popover (or false to use children..)
16450 * @cfg {String} title of popover (or false to hide)
16451 * @cfg {String} placement how it is placed
16452 * @cfg {String} trigger click || hover (or false to trigger manually)
16453 * @cfg {String} over what (parent or false to trigger manually.)
16454 * @cfg {Number} delay - delay before showing
16457 * Create a new Popover
16458 * @param {Object} config The config object
16461 Roo.bootstrap.Popover = function(config){
16462 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16468 * After the popover show
16470 * @param {Roo.bootstrap.Popover} this
16475 * After the popover hide
16477 * @param {Roo.bootstrap.Popover} this
16483 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16485 title: 'Fill in a title',
16488 placement : 'right',
16489 trigger : 'hover', // hover
16495 can_build_overlaid : false,
16497 getChildContainer : function()
16499 return this.el.select('.popover-content',true).first();
16502 getAutoCreate : function(){
16505 cls : 'popover roo-dynamic',
16506 style: 'display:block',
16512 cls : 'popover-inner',
16516 cls: 'popover-title',
16520 cls : 'popover-content',
16531 setTitle: function(str)
16534 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16536 setContent: function(str)
16539 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16541 // as it get's added to the bottom of the page.
16542 onRender : function(ct, position)
16544 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16546 var cfg = Roo.apply({}, this.getAutoCreate());
16550 cfg.cls += ' ' + this.cls;
16553 cfg.style = this.style;
16555 //Roo.log("adding to ");
16556 this.el = Roo.get(document.body).createChild(cfg, position);
16557 // Roo.log(this.el);
16562 initEvents : function()
16564 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16565 this.el.enableDisplayMode('block');
16567 if (this.over === false) {
16570 if (this.triggers === false) {
16573 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16574 var triggers = this.trigger ? this.trigger.split(' ') : [];
16575 Roo.each(triggers, function(trigger) {
16577 if (trigger == 'click') {
16578 on_el.on('click', this.toggle, this);
16579 } else if (trigger != 'manual') {
16580 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16581 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16583 on_el.on(eventIn ,this.enter, this);
16584 on_el.on(eventOut, this.leave, this);
16595 toggle : function () {
16596 this.hoverState == 'in' ? this.leave() : this.enter();
16599 enter : function () {
16601 clearTimeout(this.timeout);
16603 this.hoverState = 'in';
16605 if (!this.delay || !this.delay.show) {
16610 this.timeout = setTimeout(function () {
16611 if (_t.hoverState == 'in') {
16614 }, this.delay.show)
16617 leave : function() {
16618 clearTimeout(this.timeout);
16620 this.hoverState = 'out';
16622 if (!this.delay || !this.delay.hide) {
16627 this.timeout = setTimeout(function () {
16628 if (_t.hoverState == 'out') {
16631 }, this.delay.hide)
16634 show : function (on_el)
16637 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16641 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16642 if (this.html !== false) {
16643 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16645 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16646 if (!this.title.length) {
16647 this.el.select('.popover-title',true).hide();
16650 var placement = typeof this.placement == 'function' ?
16651 this.placement.call(this, this.el, on_el) :
16654 var autoToken = /\s?auto?\s?/i;
16655 var autoPlace = autoToken.test(placement);
16657 placement = placement.replace(autoToken, '') || 'top';
16661 //this.el.setXY([0,0]);
16663 this.el.dom.style.display='block';
16664 this.el.addClass(placement);
16666 //this.el.appendTo(on_el);
16668 var p = this.getPosition();
16669 var box = this.el.getBox();
16674 var align = Roo.bootstrap.Popover.alignment[placement];
16675 this.el.alignTo(on_el, align[0],align[1]);
16676 //var arrow = this.el.select('.arrow',true).first();
16677 //arrow.set(align[2],
16679 this.el.addClass('in');
16682 if (this.el.hasClass('fade')) {
16686 this.hoverState = 'in';
16688 this.fireEvent('show', this);
16693 this.el.setXY([0,0]);
16694 this.el.removeClass('in');
16696 this.hoverState = null;
16698 this.fireEvent('hide', this);
16703 Roo.bootstrap.Popover.alignment = {
16704 'left' : ['r-l', [-10,0], 'right'],
16705 'right' : ['l-r', [10,0], 'left'],
16706 'bottom' : ['t-b', [0,10], 'top'],
16707 'top' : [ 'b-t', [0,-10], 'bottom']
16718 * @class Roo.bootstrap.Progress
16719 * @extends Roo.bootstrap.Component
16720 * Bootstrap Progress class
16721 * @cfg {Boolean} striped striped of the progress bar
16722 * @cfg {Boolean} active animated of the progress bar
16726 * Create a new Progress
16727 * @param {Object} config The config object
16730 Roo.bootstrap.Progress = function(config){
16731 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16734 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16739 getAutoCreate : function(){
16747 cfg.cls += ' progress-striped';
16751 cfg.cls += ' active';
16770 * @class Roo.bootstrap.ProgressBar
16771 * @extends Roo.bootstrap.Component
16772 * Bootstrap ProgressBar class
16773 * @cfg {Number} aria_valuenow aria-value now
16774 * @cfg {Number} aria_valuemin aria-value min
16775 * @cfg {Number} aria_valuemax aria-value max
16776 * @cfg {String} label label for the progress bar
16777 * @cfg {String} panel (success | info | warning | danger )
16778 * @cfg {String} role role of the progress bar
16779 * @cfg {String} sr_only text
16783 * Create a new ProgressBar
16784 * @param {Object} config The config object
16787 Roo.bootstrap.ProgressBar = function(config){
16788 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16791 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16795 aria_valuemax : 100,
16801 getAutoCreate : function()
16806 cls: 'progress-bar',
16807 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16819 cfg.role = this.role;
16822 if(this.aria_valuenow){
16823 cfg['aria-valuenow'] = this.aria_valuenow;
16826 if(this.aria_valuemin){
16827 cfg['aria-valuemin'] = this.aria_valuemin;
16830 if(this.aria_valuemax){
16831 cfg['aria-valuemax'] = this.aria_valuemax;
16834 if(this.label && !this.sr_only){
16835 cfg.html = this.label;
16839 cfg.cls += ' progress-bar-' + this.panel;
16845 update : function(aria_valuenow)
16847 this.aria_valuenow = aria_valuenow;
16849 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16864 * @class Roo.bootstrap.TabGroup
16865 * @extends Roo.bootstrap.Column
16866 * Bootstrap Column class
16867 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16868 * @cfg {Boolean} carousel true to make the group behave like a carousel
16869 * @cfg {Boolean} bullets show bullets for the panels
16870 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16871 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16872 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16873 * @cfg {Boolean} showarrow (true|false) show arrow default true
16876 * Create a new TabGroup
16877 * @param {Object} config The config object
16880 Roo.bootstrap.TabGroup = function(config){
16881 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16883 this.navId = Roo.id();
16886 Roo.bootstrap.TabGroup.register(this);
16890 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16893 transition : false,
16898 slideOnTouch : false,
16901 getAutoCreate : function()
16903 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16905 cfg.cls += ' tab-content';
16907 if (this.carousel) {
16908 cfg.cls += ' carousel slide';
16911 cls : 'carousel-inner',
16915 if(this.bullets && !Roo.isTouch){
16918 cls : 'carousel-bullets',
16922 if(this.bullets_cls){
16923 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16930 cfg.cn[0].cn.push(bullets);
16933 if(this.showarrow){
16934 cfg.cn[0].cn.push({
16936 class : 'carousel-arrow',
16940 class : 'carousel-prev',
16944 class : 'fa fa-chevron-left'
16950 class : 'carousel-next',
16954 class : 'fa fa-chevron-right'
16967 initEvents: function()
16969 if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
16970 this.el.on("touchstart", this.onTouchStart, this);
16973 if(this.autoslide){
16976 this.slideFn = window.setInterval(function() {
16977 _this.showPanelNext();
16981 if(this.showarrow){
16982 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
16983 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
16989 onTouchStart : function(e, el, o)
16991 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16995 this.showPanelNext();
16998 getChildContainer : function()
17000 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17004 * register a Navigation item
17005 * @param {Roo.bootstrap.NavItem} the navitem to add
17007 register : function(item)
17009 this.tabs.push( item);
17010 item.navId = this.navId; // not really needed..
17015 getActivePanel : function()
17018 Roo.each(this.tabs, function(t) {
17028 getPanelByName : function(n)
17031 Roo.each(this.tabs, function(t) {
17032 if (t.tabId == n) {
17040 indexOfPanel : function(p)
17043 Roo.each(this.tabs, function(t,i) {
17044 if (t.tabId == p.tabId) {
17053 * show a specific panel
17054 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17055 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17057 showPanel : function (pan)
17059 if(this.transition || typeof(pan) == 'undefined'){
17060 Roo.log("waiting for the transitionend");
17064 if (typeof(pan) == 'number') {
17065 pan = this.tabs[pan];
17068 if (typeof(pan) == 'string') {
17069 pan = this.getPanelByName(pan);
17072 var cur = this.getActivePanel();
17075 Roo.log('pan or acitve pan is undefined');
17079 if (pan.tabId == this.getActivePanel().tabId) {
17083 if (false === cur.fireEvent('beforedeactivate')) {
17087 if(this.bullets > 0 && !Roo.isTouch){
17088 this.setActiveBullet(this.indexOfPanel(pan));
17091 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17093 this.transition = true;
17094 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17095 var lr = dir == 'next' ? 'left' : 'right';
17096 pan.el.addClass(dir); // or prev
17097 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17098 cur.el.addClass(lr); // or right
17099 pan.el.addClass(lr);
17102 cur.el.on('transitionend', function() {
17103 Roo.log("trans end?");
17105 pan.el.removeClass([lr,dir]);
17106 pan.setActive(true);
17108 cur.el.removeClass([lr]);
17109 cur.setActive(false);
17111 _this.transition = false;
17113 }, this, { single: true } );
17118 cur.setActive(false);
17119 pan.setActive(true);
17124 showPanelNext : function()
17126 var i = this.indexOfPanel(this.getActivePanel());
17128 if (i >= this.tabs.length - 1 && !this.autoslide) {
17132 if (i >= this.tabs.length - 1 && this.autoslide) {
17136 this.showPanel(this.tabs[i+1]);
17139 showPanelPrev : function()
17141 var i = this.indexOfPanel(this.getActivePanel());
17143 if (i < 1 && !this.autoslide) {
17147 if (i < 1 && this.autoslide) {
17148 i = this.tabs.length;
17151 this.showPanel(this.tabs[i-1]);
17155 addBullet: function()
17157 if(!this.bullets || Roo.isTouch){
17160 var ctr = this.el.select('.carousel-bullets',true).first();
17161 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17162 var bullet = ctr.createChild({
17163 cls : 'bullet bullet-' + i
17164 },ctr.dom.lastChild);
17169 bullet.on('click', (function(e, el, o, ii, t){
17171 e.preventDefault();
17173 this.showPanel(ii);
17175 if(this.autoslide && this.slideFn){
17176 clearInterval(this.slideFn);
17177 this.slideFn = window.setInterval(function() {
17178 _this.showPanelNext();
17182 }).createDelegate(this, [i, bullet], true));
17187 setActiveBullet : function(i)
17193 Roo.each(this.el.select('.bullet', true).elements, function(el){
17194 el.removeClass('selected');
17197 var bullet = this.el.select('.bullet-' + i, true).first();
17203 bullet.addClass('selected');
17214 Roo.apply(Roo.bootstrap.TabGroup, {
17218 * register a Navigation Group
17219 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17221 register : function(navgrp)
17223 this.groups[navgrp.navId] = navgrp;
17227 * fetch a Navigation Group based on the navigation ID
17228 * if one does not exist , it will get created.
17229 * @param {string} the navgroup to add
17230 * @returns {Roo.bootstrap.NavGroup} the navgroup
17232 get: function(navId) {
17233 if (typeof(this.groups[navId]) == 'undefined') {
17234 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17236 return this.groups[navId] ;
17251 * @class Roo.bootstrap.TabPanel
17252 * @extends Roo.bootstrap.Component
17253 * Bootstrap TabPanel class
17254 * @cfg {Boolean} active panel active
17255 * @cfg {String} html panel content
17256 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17257 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17258 * @cfg {String} href click to link..
17262 * Create a new TabPanel
17263 * @param {Object} config The config object
17266 Roo.bootstrap.TabPanel = function(config){
17267 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17271 * Fires when the active status changes
17272 * @param {Roo.bootstrap.TabPanel} this
17273 * @param {Boolean} state the new state
17278 * @event beforedeactivate
17279 * Fires before a tab is de-activated - can be used to do validation on a form.
17280 * @param {Roo.bootstrap.TabPanel} this
17281 * @return {Boolean} false if there is an error
17284 'beforedeactivate': true
17287 this.tabId = this.tabId || Roo.id();
17291 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17299 getAutoCreate : function(){
17302 // item is needed for carousel - not sure if it has any effect otherwise
17303 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17304 html: this.html || ''
17308 cfg.cls += ' active';
17312 cfg.tabId = this.tabId;
17319 initEvents: function()
17321 var p = this.parent();
17322 this.navId = this.navId || p.navId;
17324 if (typeof(this.navId) != 'undefined') {
17325 // not really needed.. but just in case.. parent should be a NavGroup.
17326 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17330 var i = tg.tabs.length - 1;
17332 if(this.active && tg.bullets > 0 && i < tg.bullets){
17333 tg.setActiveBullet(i);
17337 if(this.href.length){
17338 this.el.on('click', this.onClick, this);
17343 onRender : function(ct, position)
17345 // Roo.log("Call onRender: " + this.xtype);
17347 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17355 setActive: function(state)
17357 Roo.log("panel - set active " + this.tabId + "=" + state);
17359 this.active = state;
17361 this.el.removeClass('active');
17363 } else if (!this.el.hasClass('active')) {
17364 this.el.addClass('active');
17367 this.fireEvent('changed', this, state);
17370 onClick: function(e)
17372 e.preventDefault();
17374 window.location.href = this.href;
17391 * @class Roo.bootstrap.DateField
17392 * @extends Roo.bootstrap.Input
17393 * Bootstrap DateField class
17394 * @cfg {Number} weekStart default 0
17395 * @cfg {String} viewMode default empty, (months|years)
17396 * @cfg {String} minViewMode default empty, (months|years)
17397 * @cfg {Number} startDate default -Infinity
17398 * @cfg {Number} endDate default Infinity
17399 * @cfg {Boolean} todayHighlight default false
17400 * @cfg {Boolean} todayBtn default false
17401 * @cfg {Boolean} calendarWeeks default false
17402 * @cfg {Object} daysOfWeekDisabled default empty
17403 * @cfg {Boolean} singleMode default false (true | false)
17405 * @cfg {Boolean} keyboardNavigation default true
17406 * @cfg {String} language default en
17409 * Create a new DateField
17410 * @param {Object} config The config object
17413 Roo.bootstrap.DateField = function(config){
17414 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17418 * Fires when this field show.
17419 * @param {Roo.bootstrap.DateField} this
17420 * @param {Mixed} date The date value
17425 * Fires when this field hide.
17426 * @param {Roo.bootstrap.DateField} this
17427 * @param {Mixed} date The date value
17432 * Fires when select a date.
17433 * @param {Roo.bootstrap.DateField} this
17434 * @param {Mixed} date The date value
17438 * @event beforeselect
17439 * Fires when before select a date.
17440 * @param {Roo.bootstrap.DateField} this
17441 * @param {Mixed} date The date value
17443 beforeselect : true
17447 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17450 * @cfg {String} format
17451 * The default date format string which can be overriden for localization support. The format must be
17452 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17456 * @cfg {String} altFormats
17457 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17458 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17460 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17468 todayHighlight : false,
17474 keyboardNavigation: true,
17476 calendarWeeks: false,
17478 startDate: -Infinity,
17482 daysOfWeekDisabled: [],
17486 singleMode : false,
17488 UTCDate: function()
17490 return new Date(Date.UTC.apply(Date, arguments));
17493 UTCToday: function()
17495 var today = new Date();
17496 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17499 getDate: function() {
17500 var d = this.getUTCDate();
17501 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17504 getUTCDate: function() {
17508 setDate: function(d) {
17509 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17512 setUTCDate: function(d) {
17514 this.setValue(this.formatDate(this.date));
17517 onRender: function(ct, position)
17520 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17522 this.language = this.language || 'en';
17523 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17524 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17526 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17527 this.format = this.format || 'm/d/y';
17528 this.isInline = false;
17529 this.isInput = true;
17530 this.component = this.el.select('.add-on', true).first() || false;
17531 this.component = (this.component && this.component.length === 0) ? false : this.component;
17532 this.hasInput = this.component && this.inputEl().length;
17534 if (typeof(this.minViewMode === 'string')) {
17535 switch (this.minViewMode) {
17537 this.minViewMode = 1;
17540 this.minViewMode = 2;
17543 this.minViewMode = 0;
17548 if (typeof(this.viewMode === 'string')) {
17549 switch (this.viewMode) {
17562 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17564 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17566 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17568 this.picker().on('mousedown', this.onMousedown, this);
17569 this.picker().on('click', this.onClick, this);
17571 this.picker().addClass('datepicker-dropdown');
17573 this.startViewMode = this.viewMode;
17575 if(this.singleMode){
17576 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17577 v.setVisibilityMode(Roo.Element.DISPLAY);
17581 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17582 v.setStyle('width', '189px');
17586 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17587 if(!this.calendarWeeks){
17592 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17593 v.attr('colspan', function(i, val){
17594 return parseInt(val) + 1;
17599 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17601 this.setStartDate(this.startDate);
17602 this.setEndDate(this.endDate);
17604 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17611 if(this.isInline) {
17616 picker : function()
17618 return this.pickerEl;
17619 // return this.el.select('.datepicker', true).first();
17622 fillDow: function()
17624 var dowCnt = this.weekStart;
17633 if(this.calendarWeeks){
17641 while (dowCnt < this.weekStart + 7) {
17645 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17649 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17652 fillMonths: function()
17655 var months = this.picker().select('>.datepicker-months td', true).first();
17657 months.dom.innerHTML = '';
17663 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17666 months.createChild(month);
17673 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;
17675 if (this.date < this.startDate) {
17676 this.viewDate = new Date(this.startDate);
17677 } else if (this.date > this.endDate) {
17678 this.viewDate = new Date(this.endDate);
17680 this.viewDate = new Date(this.date);
17688 var d = new Date(this.viewDate),
17689 year = d.getUTCFullYear(),
17690 month = d.getUTCMonth(),
17691 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17692 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17693 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17694 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17695 currentDate = this.date && this.date.valueOf(),
17696 today = this.UTCToday();
17698 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17700 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17702 // this.picker.select('>tfoot th.today').
17703 // .text(dates[this.language].today)
17704 // .toggle(this.todayBtn !== false);
17706 this.updateNavArrows();
17709 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17711 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17713 prevMonth.setUTCDate(day);
17715 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17717 var nextMonth = new Date(prevMonth);
17719 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17721 nextMonth = nextMonth.valueOf();
17723 var fillMonths = false;
17725 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17727 while(prevMonth.valueOf() < nextMonth) {
17730 if (prevMonth.getUTCDay() === this.weekStart) {
17732 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17740 if(this.calendarWeeks){
17741 // ISO 8601: First week contains first thursday.
17742 // ISO also states week starts on Monday, but we can be more abstract here.
17744 // Start of current week: based on weekstart/current date
17745 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17746 // Thursday of this week
17747 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17748 // First Thursday of year, year from thursday
17749 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17750 // Calendar week: ms between thursdays, div ms per day, div 7 days
17751 calWeek = (th - yth) / 864e5 / 7 + 1;
17753 fillMonths.cn.push({
17761 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17763 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17766 if (this.todayHighlight &&
17767 prevMonth.getUTCFullYear() == today.getFullYear() &&
17768 prevMonth.getUTCMonth() == today.getMonth() &&
17769 prevMonth.getUTCDate() == today.getDate()) {
17770 clsName += ' today';
17773 if (currentDate && prevMonth.valueOf() === currentDate) {
17774 clsName += ' active';
17777 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17778 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17779 clsName += ' disabled';
17782 fillMonths.cn.push({
17784 cls: 'day ' + clsName,
17785 html: prevMonth.getDate()
17788 prevMonth.setDate(prevMonth.getDate()+1);
17791 var currentYear = this.date && this.date.getUTCFullYear();
17792 var currentMonth = this.date && this.date.getUTCMonth();
17794 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17796 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17797 v.removeClass('active');
17799 if(currentYear === year && k === currentMonth){
17800 v.addClass('active');
17803 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17804 v.addClass('disabled');
17810 year = parseInt(year/10, 10) * 10;
17812 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17814 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17817 for (var i = -1; i < 11; i++) {
17818 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17820 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17828 showMode: function(dir)
17831 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17834 Roo.each(this.picker().select('>div',true).elements, function(v){
17835 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17838 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17843 if(this.isInline) {
17847 this.picker().removeClass(['bottom', 'top']);
17849 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17851 * place to the top of element!
17855 this.picker().addClass('top');
17856 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17861 this.picker().addClass('bottom');
17863 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17866 parseDate : function(value)
17868 if(!value || value instanceof Date){
17871 var v = Date.parseDate(value, this.format);
17872 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17873 v = Date.parseDate(value, 'Y-m-d');
17875 if(!v && this.altFormats){
17876 if(!this.altFormatsArray){
17877 this.altFormatsArray = this.altFormats.split("|");
17879 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17880 v = Date.parseDate(value, this.altFormatsArray[i]);
17886 formatDate : function(date, fmt)
17888 return (!date || !(date instanceof Date)) ?
17889 date : date.dateFormat(fmt || this.format);
17892 onFocus : function()
17894 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17898 onBlur : function()
17900 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17902 var d = this.inputEl().getValue();
17911 this.picker().show();
17915 this.fireEvent('show', this, this.date);
17920 if(this.isInline) {
17923 this.picker().hide();
17924 this.viewMode = this.startViewMode;
17927 this.fireEvent('hide', this, this.date);
17931 onMousedown: function(e)
17933 e.stopPropagation();
17934 e.preventDefault();
17939 Roo.bootstrap.DateField.superclass.keyup.call(this);
17943 setValue: function(v)
17945 if(this.fireEvent('beforeselect', this, v) !== false){
17946 var d = new Date(this.parseDate(v) ).clearTime();
17948 if(isNaN(d.getTime())){
17949 this.date = this.viewDate = '';
17950 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17954 v = this.formatDate(d);
17956 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17958 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17962 this.fireEvent('select', this, this.date);
17966 getValue: function()
17968 return this.formatDate(this.date);
17971 fireKey: function(e)
17973 if (!this.picker().isVisible()){
17974 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17980 var dateChanged = false,
17982 newDate, newViewDate;
17987 e.preventDefault();
17991 if (!this.keyboardNavigation) {
17994 dir = e.keyCode == 37 ? -1 : 1;
17997 newDate = this.moveYear(this.date, dir);
17998 newViewDate = this.moveYear(this.viewDate, dir);
17999 } else if (e.shiftKey){
18000 newDate = this.moveMonth(this.date, dir);
18001 newViewDate = this.moveMonth(this.viewDate, dir);
18003 newDate = new Date(this.date);
18004 newDate.setUTCDate(this.date.getUTCDate() + dir);
18005 newViewDate = new Date(this.viewDate);
18006 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18008 if (this.dateWithinRange(newDate)){
18009 this.date = newDate;
18010 this.viewDate = newViewDate;
18011 this.setValue(this.formatDate(this.date));
18013 e.preventDefault();
18014 dateChanged = true;
18019 if (!this.keyboardNavigation) {
18022 dir = e.keyCode == 38 ? -1 : 1;
18024 newDate = this.moveYear(this.date, dir);
18025 newViewDate = this.moveYear(this.viewDate, dir);
18026 } else if (e.shiftKey){
18027 newDate = this.moveMonth(this.date, dir);
18028 newViewDate = this.moveMonth(this.viewDate, dir);
18030 newDate = new Date(this.date);
18031 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18032 newViewDate = new Date(this.viewDate);
18033 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18035 if (this.dateWithinRange(newDate)){
18036 this.date = newDate;
18037 this.viewDate = newViewDate;
18038 this.setValue(this.formatDate(this.date));
18040 e.preventDefault();
18041 dateChanged = true;
18045 this.setValue(this.formatDate(this.date));
18047 e.preventDefault();
18050 this.setValue(this.formatDate(this.date));
18064 onClick: function(e)
18066 e.stopPropagation();
18067 e.preventDefault();
18069 var target = e.getTarget();
18071 if(target.nodeName.toLowerCase() === 'i'){
18072 target = Roo.get(target).dom.parentNode;
18075 var nodeName = target.nodeName;
18076 var className = target.className;
18077 var html = target.innerHTML;
18078 //Roo.log(nodeName);
18080 switch(nodeName.toLowerCase()) {
18082 switch(className) {
18088 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18089 switch(this.viewMode){
18091 this.viewDate = this.moveMonth(this.viewDate, dir);
18095 this.viewDate = this.moveYear(this.viewDate, dir);
18101 var date = new Date();
18102 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18104 this.setValue(this.formatDate(this.date));
18111 if (className.indexOf('disabled') < 0) {
18112 this.viewDate.setUTCDate(1);
18113 if (className.indexOf('month') > -1) {
18114 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18116 var year = parseInt(html, 10) || 0;
18117 this.viewDate.setUTCFullYear(year);
18121 if(this.singleMode){
18122 this.setValue(this.formatDate(this.viewDate));
18133 //Roo.log(className);
18134 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18135 var day = parseInt(html, 10) || 1;
18136 var year = this.viewDate.getUTCFullYear(),
18137 month = this.viewDate.getUTCMonth();
18139 if (className.indexOf('old') > -1) {
18146 } else if (className.indexOf('new') > -1) {
18154 //Roo.log([year,month,day]);
18155 this.date = this.UTCDate(year, month, day,0,0,0,0);
18156 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18158 //Roo.log(this.formatDate(this.date));
18159 this.setValue(this.formatDate(this.date));
18166 setStartDate: function(startDate)
18168 this.startDate = startDate || -Infinity;
18169 if (this.startDate !== -Infinity) {
18170 this.startDate = this.parseDate(this.startDate);
18173 this.updateNavArrows();
18176 setEndDate: function(endDate)
18178 this.endDate = endDate || Infinity;
18179 if (this.endDate !== Infinity) {
18180 this.endDate = this.parseDate(this.endDate);
18183 this.updateNavArrows();
18186 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18188 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18189 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18190 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18192 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18193 return parseInt(d, 10);
18196 this.updateNavArrows();
18199 updateNavArrows: function()
18201 if(this.singleMode){
18205 var d = new Date(this.viewDate),
18206 year = d.getUTCFullYear(),
18207 month = d.getUTCMonth();
18209 Roo.each(this.picker().select('.prev', true).elements, function(v){
18211 switch (this.viewMode) {
18214 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18220 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18227 Roo.each(this.picker().select('.next', true).elements, function(v){
18229 switch (this.viewMode) {
18232 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18238 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18246 moveMonth: function(date, dir)
18251 var new_date = new Date(date.valueOf()),
18252 day = new_date.getUTCDate(),
18253 month = new_date.getUTCMonth(),
18254 mag = Math.abs(dir),
18256 dir = dir > 0 ? 1 : -1;
18259 // If going back one month, make sure month is not current month
18260 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18262 return new_date.getUTCMonth() == month;
18264 // If going forward one month, make sure month is as expected
18265 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18267 return new_date.getUTCMonth() != new_month;
18269 new_month = month + dir;
18270 new_date.setUTCMonth(new_month);
18271 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18272 if (new_month < 0 || new_month > 11) {
18273 new_month = (new_month + 12) % 12;
18276 // For magnitudes >1, move one month at a time...
18277 for (var i=0; i<mag; i++) {
18278 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18279 new_date = this.moveMonth(new_date, dir);
18281 // ...then reset the day, keeping it in the new month
18282 new_month = new_date.getUTCMonth();
18283 new_date.setUTCDate(day);
18285 return new_month != new_date.getUTCMonth();
18288 // Common date-resetting loop -- if date is beyond end of month, make it
18291 new_date.setUTCDate(--day);
18292 new_date.setUTCMonth(new_month);
18297 moveYear: function(date, dir)
18299 return this.moveMonth(date, dir*12);
18302 dateWithinRange: function(date)
18304 return date >= this.startDate && date <= this.endDate;
18310 this.picker().remove();
18313 validateValue : function(value)
18315 if(value.length < 1) {
18316 if(this.allowBlank){
18322 if(value.length < this.minLength){
18325 if(value.length > this.maxLength){
18329 var vt = Roo.form.VTypes;
18330 if(!vt[this.vtype](value, this)){
18334 if(typeof this.validator == "function"){
18335 var msg = this.validator(value);
18341 if(this.regex && !this.regex.test(value)){
18345 if(typeof(this.parseDate(value)) == 'undefined'){
18349 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18353 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18363 Roo.apply(Roo.bootstrap.DateField, {
18374 html: '<i class="fa fa-arrow-left"/>'
18384 html: '<i class="fa fa-arrow-right"/>'
18426 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18427 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18428 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18429 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18430 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18443 navFnc: 'FullYear',
18448 navFnc: 'FullYear',
18453 Roo.apply(Roo.bootstrap.DateField, {
18457 cls: 'datepicker dropdown-menu roo-dynamic',
18461 cls: 'datepicker-days',
18465 cls: 'table-condensed',
18467 Roo.bootstrap.DateField.head,
18471 Roo.bootstrap.DateField.footer
18478 cls: 'datepicker-months',
18482 cls: 'table-condensed',
18484 Roo.bootstrap.DateField.head,
18485 Roo.bootstrap.DateField.content,
18486 Roo.bootstrap.DateField.footer
18493 cls: 'datepicker-years',
18497 cls: 'table-condensed',
18499 Roo.bootstrap.DateField.head,
18500 Roo.bootstrap.DateField.content,
18501 Roo.bootstrap.DateField.footer
18520 * @class Roo.bootstrap.TimeField
18521 * @extends Roo.bootstrap.Input
18522 * Bootstrap DateField class
18526 * Create a new TimeField
18527 * @param {Object} config The config object
18530 Roo.bootstrap.TimeField = function(config){
18531 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18535 * Fires when this field show.
18536 * @param {Roo.bootstrap.DateField} thisthis
18537 * @param {Mixed} date The date value
18542 * Fires when this field hide.
18543 * @param {Roo.bootstrap.DateField} this
18544 * @param {Mixed} date The date value
18549 * Fires when select a date.
18550 * @param {Roo.bootstrap.DateField} this
18551 * @param {Mixed} date The date value
18557 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18560 * @cfg {String} format
18561 * The default time format string which can be overriden for localization support. The format must be
18562 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18566 onRender: function(ct, position)
18569 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18571 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18573 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18575 this.pop = this.picker().select('>.datepicker-time',true).first();
18576 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18578 this.picker().on('mousedown', this.onMousedown, this);
18579 this.picker().on('click', this.onClick, this);
18581 this.picker().addClass('datepicker-dropdown');
18586 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18587 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18588 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18589 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18590 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18591 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18595 fireKey: function(e){
18596 if (!this.picker().isVisible()){
18597 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18603 e.preventDefault();
18611 this.onTogglePeriod();
18614 this.onIncrementMinutes();
18617 this.onDecrementMinutes();
18626 onClick: function(e) {
18627 e.stopPropagation();
18628 e.preventDefault();
18631 picker : function()
18633 return this.el.select('.datepicker', true).first();
18636 fillTime: function()
18638 var time = this.pop.select('tbody', true).first();
18640 time.dom.innerHTML = '';
18655 cls: 'hours-up glyphicon glyphicon-chevron-up'
18675 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18696 cls: 'timepicker-hour',
18711 cls: 'timepicker-minute',
18726 cls: 'btn btn-primary period',
18748 cls: 'hours-down glyphicon glyphicon-chevron-down'
18768 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18786 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18793 var hours = this.time.getHours();
18794 var minutes = this.time.getMinutes();
18807 hours = hours - 12;
18811 hours = '0' + hours;
18815 minutes = '0' + minutes;
18818 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18819 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18820 this.pop.select('button', true).first().dom.innerHTML = period;
18826 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18828 var cls = ['bottom'];
18830 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18837 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18842 this.picker().addClass(cls.join('-'));
18846 Roo.each(cls, function(c){
18848 _this.picker().setTop(_this.inputEl().getHeight());
18852 _this.picker().setTop(0 - _this.picker().getHeight());
18857 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18861 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18868 onFocus : function()
18870 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18874 onBlur : function()
18876 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18882 this.picker().show();
18887 this.fireEvent('show', this, this.date);
18892 this.picker().hide();
18895 this.fireEvent('hide', this, this.date);
18898 setTime : function()
18901 this.setValue(this.time.format(this.format));
18903 this.fireEvent('select', this, this.date);
18908 onMousedown: function(e){
18909 e.stopPropagation();
18910 e.preventDefault();
18913 onIncrementHours: function()
18915 Roo.log('onIncrementHours');
18916 this.time = this.time.add(Date.HOUR, 1);
18921 onDecrementHours: function()
18923 Roo.log('onDecrementHours');
18924 this.time = this.time.add(Date.HOUR, -1);
18928 onIncrementMinutes: function()
18930 Roo.log('onIncrementMinutes');
18931 this.time = this.time.add(Date.MINUTE, 1);
18935 onDecrementMinutes: function()
18937 Roo.log('onDecrementMinutes');
18938 this.time = this.time.add(Date.MINUTE, -1);
18942 onTogglePeriod: function()
18944 Roo.log('onTogglePeriod');
18945 this.time = this.time.add(Date.HOUR, 12);
18952 Roo.apply(Roo.bootstrap.TimeField, {
18982 cls: 'btn btn-info ok',
18994 Roo.apply(Roo.bootstrap.TimeField, {
18998 cls: 'datepicker dropdown-menu',
19002 cls: 'datepicker-time',
19006 cls: 'table-condensed',
19008 Roo.bootstrap.TimeField.content,
19009 Roo.bootstrap.TimeField.footer
19028 * @class Roo.bootstrap.MonthField
19029 * @extends Roo.bootstrap.Input
19030 * Bootstrap MonthField class
19032 * @cfg {String} language default en
19035 * Create a new MonthField
19036 * @param {Object} config The config object
19039 Roo.bootstrap.MonthField = function(config){
19040 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19045 * Fires when this field show.
19046 * @param {Roo.bootstrap.MonthField} this
19047 * @param {Mixed} date The date value
19052 * Fires when this field hide.
19053 * @param {Roo.bootstrap.MonthField} this
19054 * @param {Mixed} date The date value
19059 * Fires when select a date.
19060 * @param {Roo.bootstrap.MonthField} this
19061 * @param {String} oldvalue The old value
19062 * @param {String} newvalue The new value
19068 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19070 onRender: function(ct, position)
19073 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19075 this.language = this.language || 'en';
19076 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19077 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19079 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19080 this.isInline = false;
19081 this.isInput = true;
19082 this.component = this.el.select('.add-on', true).first() || false;
19083 this.component = (this.component && this.component.length === 0) ? false : this.component;
19084 this.hasInput = this.component && this.inputEL().length;
19086 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19088 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19090 this.picker().on('mousedown', this.onMousedown, this);
19091 this.picker().on('click', this.onClick, this);
19093 this.picker().addClass('datepicker-dropdown');
19095 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19096 v.setStyle('width', '189px');
19103 if(this.isInline) {
19109 setValue: function(v, suppressEvent)
19111 var o = this.getValue();
19113 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19117 if(suppressEvent !== true){
19118 this.fireEvent('select', this, o, v);
19123 getValue: function()
19128 onClick: function(e)
19130 e.stopPropagation();
19131 e.preventDefault();
19133 var target = e.getTarget();
19135 if(target.nodeName.toLowerCase() === 'i'){
19136 target = Roo.get(target).dom.parentNode;
19139 var nodeName = target.nodeName;
19140 var className = target.className;
19141 var html = target.innerHTML;
19143 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19147 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19149 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19155 picker : function()
19157 return this.pickerEl;
19160 fillMonths: function()
19163 var months = this.picker().select('>.datepicker-months td', true).first();
19165 months.dom.innerHTML = '';
19171 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19174 months.createChild(month);
19183 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19184 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19187 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19188 e.removeClass('active');
19190 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19191 e.addClass('active');
19198 if(this.isInline) {
19202 this.picker().removeClass(['bottom', 'top']);
19204 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19206 * place to the top of element!
19210 this.picker().addClass('top');
19211 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19216 this.picker().addClass('bottom');
19218 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19221 onFocus : function()
19223 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19227 onBlur : function()
19229 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19231 var d = this.inputEl().getValue();
19240 this.picker().show();
19241 this.picker().select('>.datepicker-months', true).first().show();
19245 this.fireEvent('show', this, this.date);
19250 if(this.isInline) {
19253 this.picker().hide();
19254 this.fireEvent('hide', this, this.date);
19258 onMousedown: function(e)
19260 e.stopPropagation();
19261 e.preventDefault();
19266 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19270 fireKey: function(e)
19272 if (!this.picker().isVisible()){
19273 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19284 e.preventDefault();
19288 dir = e.keyCode == 37 ? -1 : 1;
19290 this.vIndex = this.vIndex + dir;
19292 if(this.vIndex < 0){
19296 if(this.vIndex > 11){
19300 if(isNaN(this.vIndex)){
19304 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19310 dir = e.keyCode == 38 ? -1 : 1;
19312 this.vIndex = this.vIndex + dir * 4;
19314 if(this.vIndex < 0){
19318 if(this.vIndex > 11){
19322 if(isNaN(this.vIndex)){
19326 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19331 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19332 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19336 e.preventDefault();
19339 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19340 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19356 this.picker().remove();
19361 Roo.apply(Roo.bootstrap.MonthField, {
19380 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19381 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19386 Roo.apply(Roo.bootstrap.MonthField, {
19390 cls: 'datepicker dropdown-menu roo-dynamic',
19394 cls: 'datepicker-months',
19398 cls: 'table-condensed',
19400 Roo.bootstrap.DateField.content
19420 * @class Roo.bootstrap.CheckBox
19421 * @extends Roo.bootstrap.Input
19422 * Bootstrap CheckBox class
19424 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19425 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19426 * @cfg {String} boxLabel The text that appears beside the checkbox
19427 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19428 * @cfg {Boolean} checked initnal the element
19429 * @cfg {Boolean} inline inline the element (default false)
19430 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19433 * Create a new CheckBox
19434 * @param {Object} config The config object
19437 Roo.bootstrap.CheckBox = function(config){
19438 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19443 * Fires when the element is checked or unchecked.
19444 * @param {Roo.bootstrap.CheckBox} this This input
19445 * @param {Boolean} checked The new checked value
19452 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19454 inputType: 'checkbox',
19462 getAutoCreate : function()
19464 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19470 cfg.cls = 'form-group ' + this.inputType; //input-group
19473 cfg.cls += ' ' + this.inputType + '-inline';
19479 type : this.inputType,
19480 value : this.inputValue,
19481 cls : 'roo-' + this.inputType, //'form-box',
19482 placeholder : this.placeholder || ''
19486 if(this.inputType != 'radio'){
19490 cls : 'roo-hidden-value',
19491 value : this.checked ? this.valueOff : this.inputValue
19496 if (this.weight) { // Validity check?
19497 cfg.cls += " " + this.inputType + "-" + this.weight;
19500 if (this.disabled) {
19501 input.disabled=true;
19505 input.checked = this.checked;
19512 input.name = this.name;
19514 if(this.inputType != 'radio'){
19515 hidden.name = this.name;
19516 input.name = '_hidden_' + this.name;
19521 input.cls += ' input-' + this.size;
19526 ['xs','sm','md','lg'].map(function(size){
19527 if (settings[size]) {
19528 cfg.cls += ' col-' + size + '-' + settings[size];
19532 var inputblock = input;
19534 if (this.before || this.after) {
19537 cls : 'input-group',
19542 inputblock.cn.push({
19544 cls : 'input-group-addon',
19549 inputblock.cn.push(input);
19551 if(this.inputType != 'radio'){
19552 inputblock.cn.push(hidden);
19556 inputblock.cn.push({
19558 cls : 'input-group-addon',
19565 if (align ==='left' && this.fieldLabel.length) {
19566 // Roo.log("left and has label");
19572 cls : 'control-label col-md-' + this.labelWidth,
19573 html : this.fieldLabel
19577 cls : "col-md-" + (12 - this.labelWidth),
19584 } else if ( this.fieldLabel.length) {
19585 // Roo.log(" label");
19589 tag: this.boxLabel ? 'span' : 'label',
19591 cls: 'control-label box-input-label',
19592 //cls : 'input-group-addon',
19593 html : this.fieldLabel
19603 // Roo.log(" no label && no align");
19604 cfg.cn = [ inputblock ] ;
19610 var boxLabelCfg = {
19612 //'for': id, // box label is handled by onclick - so no for...
19614 html: this.boxLabel
19618 boxLabelCfg.tooltip = this.tooltip;
19621 cfg.cn.push(boxLabelCfg);
19624 if(this.inputType != 'radio'){
19625 cfg.cn.push(hidden);
19633 * return the real input element.
19635 inputEl: function ()
19637 return this.el.select('input.roo-' + this.inputType,true).first();
19639 hiddenEl: function ()
19641 return this.el.select('input.roo-hidden-value',true).first();
19644 labelEl: function()
19646 return this.el.select('label.control-label',true).first();
19648 /* depricated... */
19652 return this.labelEl();
19655 boxLabelEl: function()
19657 return this.el.select('label.box-label',true).first();
19660 initEvents : function()
19662 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19664 this.inputEl().on('click', this.onClick, this);
19666 if (this.boxLabel) {
19667 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19670 this.startValue = this.getValue();
19673 Roo.bootstrap.CheckBox.register(this);
19677 onClick : function()
19679 this.setChecked(!this.checked);
19682 setChecked : function(state,suppressEvent)
19684 this.startValue = this.getValue();
19686 if(this.inputType == 'radio'){
19688 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19689 e.dom.checked = false;
19692 this.inputEl().dom.checked = true;
19694 this.inputEl().dom.value = this.inputValue;
19696 if(suppressEvent !== true){
19697 this.fireEvent('check', this, true);
19705 this.checked = state;
19707 this.inputEl().dom.checked = state;
19710 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
19712 if(suppressEvent !== true){
19713 this.fireEvent('check', this, state);
19719 getValue : function()
19721 if(this.inputType == 'radio'){
19722 return this.getGroupValue();
19725 return this.hiddenEl().dom.value;
19729 getGroupValue : function()
19731 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19735 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19738 setValue : function(v,suppressEvent)
19740 if(this.inputType == 'radio'){
19741 this.setGroupValue(v, suppressEvent);
19745 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19750 setGroupValue : function(v, suppressEvent)
19752 this.startValue = this.getValue();
19754 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19755 e.dom.checked = false;
19757 if(e.dom.value == v){
19758 e.dom.checked = true;
19762 if(suppressEvent !== true){
19763 this.fireEvent('check', this, true);
19771 validate : function()
19775 (this.inputType == 'radio' && this.validateRadio()) ||
19776 (this.inputType == 'checkbox' && this.validateCheckbox())
19782 this.markInvalid();
19786 validateRadio : function()
19788 if(this.allowBlank){
19794 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19795 if(!e.dom.checked){
19807 validateCheckbox : function()
19810 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19813 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19821 for(var i in group){
19826 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19833 * Mark this field as valid
19835 markValid : function()
19837 if(this.allowBlank){
19843 this.fireEvent('valid', this);
19845 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19848 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19855 if(this.inputType == 'radio'){
19856 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19857 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19858 e.findParent('.form-group', false, true).addClass(_this.validClass);
19865 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19866 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19870 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19876 for(var i in group){
19877 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19878 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19883 * Mark this field as invalid
19884 * @param {String} msg The validation message
19886 markInvalid : function(msg)
19888 if(this.allowBlank){
19894 this.fireEvent('invalid', this, msg);
19896 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19899 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19903 label.markInvalid();
19906 if(this.inputType == 'radio'){
19907 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19908 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19909 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19916 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19917 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19921 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19927 for(var i in group){
19928 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19929 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19934 disable : function()
19936 if(this.inputType != 'radio'){
19937 Roo.bootstrap.CheckBox.superclass.disable.call(this);
19944 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19945 _this.getActionEl().addClass(this.disabledClass);
19946 e.dom.disabled = true;
19950 this.disabled = true;
19951 this.fireEvent("disable", this);
19955 enable : function()
19957 if(this.inputType != 'radio'){
19958 Roo.bootstrap.CheckBox.superclass.enable.call(this);
19965 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19966 _this.getActionEl().removeClass(this.disabledClass);
19967 e.dom.disabled = false;
19971 this.disabled = false;
19972 this.fireEvent("enable", this);
19978 Roo.apply(Roo.bootstrap.CheckBox, {
19983 * register a CheckBox Group
19984 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19986 register : function(checkbox)
19988 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19989 this.groups[checkbox.groupId] = {};
19992 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19996 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20000 * fetch a CheckBox Group based on the group ID
20001 * @param {string} the group ID
20002 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20004 get: function(groupId) {
20005 if (typeof(this.groups[groupId]) == 'undefined') {
20009 return this.groups[groupId] ;
20021 *<div class="radio">
20023 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
20024 Option one is this and that—be sure to include why it's great
20031 *<label class="radio-inline">fieldLabel</label>
20032 *<label class="radio-inline">
20033 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
20041 * @class Roo.bootstrap.Radio
20042 * @extends Roo.bootstrap.CheckBox
20043 * Bootstrap Radio class
20046 * Create a new Radio
20047 * @param {Object} config The config object
20050 Roo.bootstrap.Radio = function(config){
20051 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20055 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
20057 inputType: 'radio',
20061 getAutoCreate : function()
20063 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20064 align = align || 'left'; // default...
20071 tag : this.inline ? 'span' : 'div',
20072 cls : 'form-group',
20076 var inline = this.inline ? ' radio-inline' : '';
20080 // does not need for, as we wrap the input with it..
20082 cls : 'control-label box-label' + inline,
20085 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
20089 //cls : 'control-label' + inline,
20090 html : this.fieldLabel,
20091 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
20097 type : this.inputType,
20098 //value : (!this.checked) ? this.valueOff : this.inputValue,
20099 value : this.inputValue,
20101 placeholder : this.placeholder || '' // ?? needed????
20104 if (this.weight) { // Validity check?
20105 input.cls += " radio-" + this.weight;
20107 if (this.disabled) {
20108 input.disabled=true;
20112 input.checked = this.checked;
20116 input.name = this.name;
20120 input.cls += ' input-' + this.size;
20123 //?? can span's inline have a width??
20126 ['xs','sm','md','lg'].map(function(size){
20127 if (settings[size]) {
20128 cfg.cls += ' col-' + size + '-' + settings[size];
20132 var inputblock = input;
20134 if (this.before || this.after) {
20137 cls : 'input-group',
20142 inputblock.cn.push({
20144 cls : 'input-group-addon',
20148 inputblock.cn.push(input);
20150 inputblock.cn.push({
20152 cls : 'input-group-addon',
20160 if (this.fieldLabel && this.fieldLabel.length) {
20161 cfg.cn.push(fieldLabel);
20164 // normal bootstrap puts the input inside the label.
20165 // however with our styled version - it has to go after the input.
20167 //lbl.cn.push(inputblock);
20171 cls: 'radio' + inline,
20178 cfg.cn.push( lblwrap);
20183 html: this.boxLabel
20192 initEvents : function()
20194 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20196 this.inputEl().on('click', this.onClick, this);
20197 if (this.boxLabel) {
20198 //Roo.log('find label');
20199 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
20204 inputEl: function ()
20206 return this.el.select('input.roo-radio',true).first();
20208 onClick : function()
20211 this.setChecked(true);
20214 setChecked : function(state,suppressEvent)
20217 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20218 v.dom.checked = false;
20221 Roo.log(this.inputEl().dom);
20222 this.checked = state;
20223 this.inputEl().dom.checked = state;
20225 if(suppressEvent !== true){
20226 this.fireEvent('check', this, state);
20229 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
20233 getGroupValue : function()
20236 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
20237 if(v.dom.checked == true){
20238 value = v.dom.value;
20246 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
20247 * @return {Mixed} value The field value
20249 getValue : function(){
20250 return this.getGroupValue();
20254 //<script type="text/javascript">
20257 * Based Ext JS Library 1.1.1
20258 * Copyright(c) 2006-2007, Ext JS, LLC.
20264 * @class Roo.HtmlEditorCore
20265 * @extends Roo.Component
20266 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20268 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20271 Roo.HtmlEditorCore = function(config){
20274 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20279 * @event initialize
20280 * Fires when the editor is fully initialized (including the iframe)
20281 * @param {Roo.HtmlEditorCore} this
20286 * Fires when the editor is first receives the focus. Any insertion must wait
20287 * until after this event.
20288 * @param {Roo.HtmlEditorCore} this
20292 * @event beforesync
20293 * Fires before the textarea is updated with content from the editor iframe. Return false
20294 * to cancel the sync.
20295 * @param {Roo.HtmlEditorCore} this
20296 * @param {String} html
20300 * @event beforepush
20301 * Fires before the iframe editor is updated with content from the textarea. Return false
20302 * to cancel the push.
20303 * @param {Roo.HtmlEditorCore} this
20304 * @param {String} html
20309 * Fires when the textarea is updated with content from the editor iframe.
20310 * @param {Roo.HtmlEditorCore} this
20311 * @param {String} html
20316 * Fires when the iframe editor is updated with content from the textarea.
20317 * @param {Roo.HtmlEditorCore} this
20318 * @param {String} html
20323 * @event editorevent
20324 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20325 * @param {Roo.HtmlEditorCore} this
20331 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20333 // defaults : white / black...
20334 this.applyBlacklists();
20341 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20345 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20351 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20356 * @cfg {Number} height (in pixels)
20360 * @cfg {Number} width (in pixels)
20365 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20368 stylesheets: false,
20373 // private properties
20374 validationEvent : false,
20376 initialized : false,
20378 sourceEditMode : false,
20379 onFocus : Roo.emptyFn,
20381 hideMode:'offsets',
20385 // blacklist + whitelisted elements..
20392 * Protected method that will not generally be called directly. It
20393 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20394 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20396 getDocMarkup : function(){
20400 // inherit styels from page...??
20401 if (this.stylesheets === false) {
20403 Roo.get(document.head).select('style').each(function(node) {
20404 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20407 Roo.get(document.head).select('link').each(function(node) {
20408 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20411 } else if (!this.stylesheets.length) {
20413 st = '<style type="text/css">' +
20414 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20420 st += '<style type="text/css">' +
20421 'IMG { cursor: pointer } ' +
20425 return '<html><head>' + st +
20426 //<style type="text/css">' +
20427 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20429 ' </head><body class="roo-htmleditor-body"></body></html>';
20433 onRender : function(ct, position)
20436 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20437 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20440 this.el.dom.style.border = '0 none';
20441 this.el.dom.setAttribute('tabIndex', -1);
20442 this.el.addClass('x-hidden hide');
20446 if(Roo.isIE){ // fix IE 1px bogus margin
20447 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20451 this.frameId = Roo.id();
20455 var iframe = this.owner.wrap.createChild({
20457 cls: 'form-control', // bootstrap..
20459 name: this.frameId,
20460 frameBorder : 'no',
20461 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20466 this.iframe = iframe.dom;
20468 this.assignDocWin();
20470 this.doc.designMode = 'on';
20473 this.doc.write(this.getDocMarkup());
20477 var task = { // must defer to wait for browser to be ready
20479 //console.log("run task?" + this.doc.readyState);
20480 this.assignDocWin();
20481 if(this.doc.body || this.doc.readyState == 'complete'){
20483 this.doc.designMode="on";
20487 Roo.TaskMgr.stop(task);
20488 this.initEditor.defer(10, this);
20495 Roo.TaskMgr.start(task);
20500 onResize : function(w, h)
20502 Roo.log('resize: ' +w + ',' + h );
20503 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20507 if(typeof w == 'number'){
20509 this.iframe.style.width = w + 'px';
20511 if(typeof h == 'number'){
20513 this.iframe.style.height = h + 'px';
20515 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20522 * Toggles the editor between standard and source edit mode.
20523 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20525 toggleSourceEdit : function(sourceEditMode){
20527 this.sourceEditMode = sourceEditMode === true;
20529 if(this.sourceEditMode){
20531 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20534 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20535 //this.iframe.className = '';
20538 //this.setSize(this.owner.wrap.getSize());
20539 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20546 * Protected method that will not generally be called directly. If you need/want
20547 * custom HTML cleanup, this is the method you should override.
20548 * @param {String} html The HTML to be cleaned
20549 * return {String} The cleaned HTML
20551 cleanHtml : function(html){
20552 html = String(html);
20553 if(html.length > 5){
20554 if(Roo.isSafari){ // strip safari nonsense
20555 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20558 if(html == ' '){
20565 * HTML Editor -> Textarea
20566 * Protected method that will not generally be called directly. Syncs the contents
20567 * of the editor iframe with the textarea.
20569 syncValue : function(){
20570 if(this.initialized){
20571 var bd = (this.doc.body || this.doc.documentElement);
20572 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20573 var html = bd.innerHTML;
20575 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20576 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20578 html = '<div style="'+m[0]+'">' + html + '</div>';
20581 html = this.cleanHtml(html);
20582 // fix up the special chars.. normaly like back quotes in word...
20583 // however we do not want to do this with chinese..
20584 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20585 var cc = b.charCodeAt();
20587 (cc >= 0x4E00 && cc < 0xA000 ) ||
20588 (cc >= 0x3400 && cc < 0x4E00 ) ||
20589 (cc >= 0xf900 && cc < 0xfb00 )
20595 if(this.owner.fireEvent('beforesync', this, html) !== false){
20596 this.el.dom.value = html;
20597 this.owner.fireEvent('sync', this, html);
20603 * Protected method that will not generally be called directly. Pushes the value of the textarea
20604 * into the iframe editor.
20606 pushValue : function(){
20607 if(this.initialized){
20608 var v = this.el.dom.value.trim();
20610 // if(v.length < 1){
20614 if(this.owner.fireEvent('beforepush', this, v) !== false){
20615 var d = (this.doc.body || this.doc.documentElement);
20617 this.cleanUpPaste();
20618 this.el.dom.value = d.innerHTML;
20619 this.owner.fireEvent('push', this, v);
20625 deferFocus : function(){
20626 this.focus.defer(10, this);
20630 focus : function(){
20631 if(this.win && !this.sourceEditMode){
20638 assignDocWin: function()
20640 var iframe = this.iframe;
20643 this.doc = iframe.contentWindow.document;
20644 this.win = iframe.contentWindow;
20646 // if (!Roo.get(this.frameId)) {
20649 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20650 // this.win = Roo.get(this.frameId).dom.contentWindow;
20652 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20656 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20657 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20662 initEditor : function(){
20663 //console.log("INIT EDITOR");
20664 this.assignDocWin();
20668 this.doc.designMode="on";
20670 this.doc.write(this.getDocMarkup());
20673 var dbody = (this.doc.body || this.doc.documentElement);
20674 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20675 // this copies styles from the containing element into thsi one..
20676 // not sure why we need all of this..
20677 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20679 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20680 //ss['background-attachment'] = 'fixed'; // w3c
20681 dbody.bgProperties = 'fixed'; // ie
20682 //Roo.DomHelper.applyStyles(dbody, ss);
20683 Roo.EventManager.on(this.doc, {
20684 //'mousedown': this.onEditorEvent,
20685 'mouseup': this.onEditorEvent,
20686 'dblclick': this.onEditorEvent,
20687 'click': this.onEditorEvent,
20688 'keyup': this.onEditorEvent,
20693 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20695 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20696 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20698 this.initialized = true;
20700 this.owner.fireEvent('initialize', this);
20705 onDestroy : function(){
20711 //for (var i =0; i < this.toolbars.length;i++) {
20712 // // fixme - ask toolbars for heights?
20713 // this.toolbars[i].onDestroy();
20716 //this.wrap.dom.innerHTML = '';
20717 //this.wrap.remove();
20722 onFirstFocus : function(){
20724 this.assignDocWin();
20727 this.activated = true;
20730 if(Roo.isGecko){ // prevent silly gecko errors
20732 var s = this.win.getSelection();
20733 if(!s.focusNode || s.focusNode.nodeType != 3){
20734 var r = s.getRangeAt(0);
20735 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20740 this.execCmd('useCSS', true);
20741 this.execCmd('styleWithCSS', false);
20744 this.owner.fireEvent('activate', this);
20748 adjustFont: function(btn){
20749 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20750 //if(Roo.isSafari){ // safari
20753 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20754 if(Roo.isSafari){ // safari
20755 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20756 v = (v < 10) ? 10 : v;
20757 v = (v > 48) ? 48 : v;
20758 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20763 v = Math.max(1, v+adjust);
20765 this.execCmd('FontSize', v );
20768 onEditorEvent : function(e)
20770 this.owner.fireEvent('editorevent', this, e);
20771 // this.updateToolbar();
20772 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20775 insertTag : function(tg)
20777 // could be a bit smarter... -> wrap the current selected tRoo..
20778 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20780 range = this.createRange(this.getSelection());
20781 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20782 wrappingNode.appendChild(range.extractContents());
20783 range.insertNode(wrappingNode);
20790 this.execCmd("formatblock", tg);
20794 insertText : function(txt)
20798 var range = this.createRange();
20799 range.deleteContents();
20800 //alert(Sender.getAttribute('label'));
20802 range.insertNode(this.doc.createTextNode(txt));
20808 * Executes a Midas editor command on the editor document and performs necessary focus and
20809 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20810 * @param {String} cmd The Midas command
20811 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20813 relayCmd : function(cmd, value){
20815 this.execCmd(cmd, value);
20816 this.owner.fireEvent('editorevent', this);
20817 //this.updateToolbar();
20818 this.owner.deferFocus();
20822 * Executes a Midas editor command directly on the editor document.
20823 * For visual commands, you should use {@link #relayCmd} instead.
20824 * <b>This should only be called after the editor is initialized.</b>
20825 * @param {String} cmd The Midas command
20826 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20828 execCmd : function(cmd, value){
20829 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20836 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20838 * @param {String} text | dom node..
20840 insertAtCursor : function(text)
20845 if(!this.activated){
20851 var r = this.doc.selection.createRange();
20862 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20866 // from jquery ui (MIT licenced)
20868 var win = this.win;
20870 if (win.getSelection && win.getSelection().getRangeAt) {
20871 range = win.getSelection().getRangeAt(0);
20872 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20873 range.insertNode(node);
20874 } else if (win.document.selection && win.document.selection.createRange) {
20875 // no firefox support
20876 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20877 win.document.selection.createRange().pasteHTML(txt);
20879 // no firefox support
20880 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20881 this.execCmd('InsertHTML', txt);
20890 mozKeyPress : function(e){
20892 var c = e.getCharCode(), cmd;
20895 c = String.fromCharCode(c).toLowerCase();
20909 this.cleanUpPaste.defer(100, this);
20917 e.preventDefault();
20925 fixKeys : function(){ // load time branching for fastest keydown performance
20927 return function(e){
20928 var k = e.getKey(), r;
20931 r = this.doc.selection.createRange();
20934 r.pasteHTML('    ');
20941 r = this.doc.selection.createRange();
20943 var target = r.parentElement();
20944 if(!target || target.tagName.toLowerCase() != 'li'){
20946 r.pasteHTML('<br />');
20952 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20953 this.cleanUpPaste.defer(100, this);
20959 }else if(Roo.isOpera){
20960 return function(e){
20961 var k = e.getKey();
20965 this.execCmd('InsertHTML','    ');
20968 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20969 this.cleanUpPaste.defer(100, this);
20974 }else if(Roo.isSafari){
20975 return function(e){
20976 var k = e.getKey();
20980 this.execCmd('InsertText','\t');
20984 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20985 this.cleanUpPaste.defer(100, this);
20993 getAllAncestors: function()
20995 var p = this.getSelectedNode();
20998 a.push(p); // push blank onto stack..
20999 p = this.getParentElement();
21003 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21007 a.push(this.doc.body);
21011 lastSelNode : false,
21014 getSelection : function()
21016 this.assignDocWin();
21017 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21020 getSelectedNode: function()
21022 // this may only work on Gecko!!!
21024 // should we cache this!!!!
21029 var range = this.createRange(this.getSelection()).cloneRange();
21032 var parent = range.parentElement();
21034 var testRange = range.duplicate();
21035 testRange.moveToElementText(parent);
21036 if (testRange.inRange(range)) {
21039 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21042 parent = parent.parentElement;
21047 // is ancestor a text element.
21048 var ac = range.commonAncestorContainer;
21049 if (ac.nodeType == 3) {
21050 ac = ac.parentNode;
21053 var ar = ac.childNodes;
21056 var other_nodes = [];
21057 var has_other_nodes = false;
21058 for (var i=0;i<ar.length;i++) {
21059 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21062 // fullly contained node.
21064 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21069 // probably selected..
21070 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21071 other_nodes.push(ar[i]);
21075 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21080 has_other_nodes = true;
21082 if (!nodes.length && other_nodes.length) {
21083 nodes= other_nodes;
21085 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21091 createRange: function(sel)
21093 // this has strange effects when using with
21094 // top toolbar - not sure if it's a great idea.
21095 //this.editor.contentWindow.focus();
21096 if (typeof sel != "undefined") {
21098 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21100 return this.doc.createRange();
21103 return this.doc.createRange();
21106 getParentElement: function()
21109 this.assignDocWin();
21110 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21112 var range = this.createRange(sel);
21115 var p = range.commonAncestorContainer;
21116 while (p.nodeType == 3) { // text node
21127 * Range intersection.. the hard stuff...
21131 * [ -- selected range --- ]
21135 * if end is before start or hits it. fail.
21136 * if start is after end or hits it fail.
21138 * if either hits (but other is outside. - then it's not
21144 // @see http://www.thismuchiknow.co.uk/?p=64.
21145 rangeIntersectsNode : function(range, node)
21147 var nodeRange = node.ownerDocument.createRange();
21149 nodeRange.selectNode(node);
21151 nodeRange.selectNodeContents(node);
21154 var rangeStartRange = range.cloneRange();
21155 rangeStartRange.collapse(true);
21157 var rangeEndRange = range.cloneRange();
21158 rangeEndRange.collapse(false);
21160 var nodeStartRange = nodeRange.cloneRange();
21161 nodeStartRange.collapse(true);
21163 var nodeEndRange = nodeRange.cloneRange();
21164 nodeEndRange.collapse(false);
21166 return rangeStartRange.compareBoundaryPoints(
21167 Range.START_TO_START, nodeEndRange) == -1 &&
21168 rangeEndRange.compareBoundaryPoints(
21169 Range.START_TO_START, nodeStartRange) == 1;
21173 rangeCompareNode : function(range, node)
21175 var nodeRange = node.ownerDocument.createRange();
21177 nodeRange.selectNode(node);
21179 nodeRange.selectNodeContents(node);
21183 range.collapse(true);
21185 nodeRange.collapse(true);
21187 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21188 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21190 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21192 var nodeIsBefore = ss == 1;
21193 var nodeIsAfter = ee == -1;
21195 if (nodeIsBefore && nodeIsAfter) {
21198 if (!nodeIsBefore && nodeIsAfter) {
21199 return 1; //right trailed.
21202 if (nodeIsBefore && !nodeIsAfter) {
21203 return 2; // left trailed.
21209 // private? - in a new class?
21210 cleanUpPaste : function()
21212 // cleans up the whole document..
21213 Roo.log('cleanuppaste');
21215 this.cleanUpChildren(this.doc.body);
21216 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21217 if (clean != this.doc.body.innerHTML) {
21218 this.doc.body.innerHTML = clean;
21223 cleanWordChars : function(input) {// change the chars to hex code
21224 var he = Roo.HtmlEditorCore;
21226 var output = input;
21227 Roo.each(he.swapCodes, function(sw) {
21228 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21230 output = output.replace(swapper, sw[1]);
21237 cleanUpChildren : function (n)
21239 if (!n.childNodes.length) {
21242 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21243 this.cleanUpChild(n.childNodes[i]);
21250 cleanUpChild : function (node)
21253 //console.log(node);
21254 if (node.nodeName == "#text") {
21255 // clean up silly Windows -- stuff?
21258 if (node.nodeName == "#comment") {
21259 node.parentNode.removeChild(node);
21260 // clean up silly Windows -- stuff?
21263 var lcname = node.tagName.toLowerCase();
21264 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21265 // whitelist of tags..
21267 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21269 node.parentNode.removeChild(node);
21274 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21276 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21277 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21279 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21280 // remove_keep_children = true;
21283 if (remove_keep_children) {
21284 this.cleanUpChildren(node);
21285 // inserts everything just before this node...
21286 while (node.childNodes.length) {
21287 var cn = node.childNodes[0];
21288 node.removeChild(cn);
21289 node.parentNode.insertBefore(cn, node);
21291 node.parentNode.removeChild(node);
21295 if (!node.attributes || !node.attributes.length) {
21296 this.cleanUpChildren(node);
21300 function cleanAttr(n,v)
21303 if (v.match(/^\./) || v.match(/^\//)) {
21306 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21309 if (v.match(/^#/)) {
21312 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21313 node.removeAttribute(n);
21317 var cwhite = this.cwhite;
21318 var cblack = this.cblack;
21320 function cleanStyle(n,v)
21322 if (v.match(/expression/)) { //XSS?? should we even bother..
21323 node.removeAttribute(n);
21327 var parts = v.split(/;/);
21330 Roo.each(parts, function(p) {
21331 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21335 var l = p.split(':').shift().replace(/\s+/g,'');
21336 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21338 if ( cwhite.length && cblack.indexOf(l) > -1) {
21339 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21340 //node.removeAttribute(n);
21344 // only allow 'c whitelisted system attributes'
21345 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21346 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21347 //node.removeAttribute(n);
21357 if (clean.length) {
21358 node.setAttribute(n, clean.join(';'));
21360 node.removeAttribute(n);
21366 for (var i = node.attributes.length-1; i > -1 ; i--) {
21367 var a = node.attributes[i];
21370 if (a.name.toLowerCase().substr(0,2)=='on') {
21371 node.removeAttribute(a.name);
21374 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21375 node.removeAttribute(a.name);
21378 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21379 cleanAttr(a.name,a.value); // fixme..
21382 if (a.name == 'style') {
21383 cleanStyle(a.name,a.value);
21386 /// clean up MS crap..
21387 // tecnically this should be a list of valid class'es..
21390 if (a.name == 'class') {
21391 if (a.value.match(/^Mso/)) {
21392 node.className = '';
21395 if (a.value.match(/body/)) {
21396 node.className = '';
21407 this.cleanUpChildren(node);
21413 * Clean up MS wordisms...
21415 cleanWord : function(node)
21420 this.cleanWord(this.doc.body);
21423 if (node.nodeName == "#text") {
21424 // clean up silly Windows -- stuff?
21427 if (node.nodeName == "#comment") {
21428 node.parentNode.removeChild(node);
21429 // clean up silly Windows -- stuff?
21433 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21434 node.parentNode.removeChild(node);
21438 // remove - but keep children..
21439 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21440 while (node.childNodes.length) {
21441 var cn = node.childNodes[0];
21442 node.removeChild(cn);
21443 node.parentNode.insertBefore(cn, node);
21445 node.parentNode.removeChild(node);
21446 this.iterateChildren(node, this.cleanWord);
21450 if (node.className.length) {
21452 var cn = node.className.split(/\W+/);
21454 Roo.each(cn, function(cls) {
21455 if (cls.match(/Mso[a-zA-Z]+/)) {
21460 node.className = cna.length ? cna.join(' ') : '';
21462 node.removeAttribute("class");
21466 if (node.hasAttribute("lang")) {
21467 node.removeAttribute("lang");
21470 if (node.hasAttribute("style")) {
21472 var styles = node.getAttribute("style").split(";");
21474 Roo.each(styles, function(s) {
21475 if (!s.match(/:/)) {
21478 var kv = s.split(":");
21479 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21482 // what ever is left... we allow.
21485 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21486 if (!nstyle.length) {
21487 node.removeAttribute('style');
21490 this.iterateChildren(node, this.cleanWord);
21496 * iterateChildren of a Node, calling fn each time, using this as the scole..
21497 * @param {DomNode} node node to iterate children of.
21498 * @param {Function} fn method of this class to call on each item.
21500 iterateChildren : function(node, fn)
21502 if (!node.childNodes.length) {
21505 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21506 fn.call(this, node.childNodes[i])
21512 * cleanTableWidths.
21514 * Quite often pasting from word etc.. results in tables with column and widths.
21515 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21518 cleanTableWidths : function(node)
21523 this.cleanTableWidths(this.doc.body);
21528 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21531 Roo.log(node.tagName);
21532 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21533 this.iterateChildren(node, this.cleanTableWidths);
21536 if (node.hasAttribute('width')) {
21537 node.removeAttribute('width');
21541 if (node.hasAttribute("style")) {
21544 var styles = node.getAttribute("style").split(";");
21546 Roo.each(styles, function(s) {
21547 if (!s.match(/:/)) {
21550 var kv = s.split(":");
21551 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21554 // what ever is left... we allow.
21557 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21558 if (!nstyle.length) {
21559 node.removeAttribute('style');
21563 this.iterateChildren(node, this.cleanTableWidths);
21571 domToHTML : function(currentElement, depth, nopadtext) {
21573 depth = depth || 0;
21574 nopadtext = nopadtext || false;
21576 if (!currentElement) {
21577 return this.domToHTML(this.doc.body);
21580 //Roo.log(currentElement);
21582 var allText = false;
21583 var nodeName = currentElement.nodeName;
21584 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21586 if (nodeName == '#text') {
21588 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21593 if (nodeName != 'BODY') {
21596 // Prints the node tagName, such as <A>, <IMG>, etc
21599 for(i = 0; i < currentElement.attributes.length;i++) {
21601 var aname = currentElement.attributes.item(i).name;
21602 if (!currentElement.attributes.item(i).value.length) {
21605 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21608 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21617 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21620 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21625 // Traverse the tree
21627 var currentElementChild = currentElement.childNodes.item(i);
21628 var allText = true;
21629 var innerHTML = '';
21631 while (currentElementChild) {
21632 // Formatting code (indent the tree so it looks nice on the screen)
21633 var nopad = nopadtext;
21634 if (lastnode == 'SPAN') {
21638 if (currentElementChild.nodeName == '#text') {
21639 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21640 toadd = nopadtext ? toadd : toadd.trim();
21641 if (!nopad && toadd.length > 80) {
21642 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21644 innerHTML += toadd;
21647 currentElementChild = currentElement.childNodes.item(i);
21653 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21655 // Recursively traverse the tree structure of the child node
21656 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21657 lastnode = currentElementChild.nodeName;
21659 currentElementChild=currentElement.childNodes.item(i);
21665 // The remaining code is mostly for formatting the tree
21666 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21671 ret+= "</"+tagName+">";
21677 applyBlacklists : function()
21679 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21680 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21684 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21685 if (b.indexOf(tag) > -1) {
21688 this.white.push(tag);
21692 Roo.each(w, function(tag) {
21693 if (b.indexOf(tag) > -1) {
21696 if (this.white.indexOf(tag) > -1) {
21699 this.white.push(tag);
21704 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21705 if (w.indexOf(tag) > -1) {
21708 this.black.push(tag);
21712 Roo.each(b, function(tag) {
21713 if (w.indexOf(tag) > -1) {
21716 if (this.black.indexOf(tag) > -1) {
21719 this.black.push(tag);
21724 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21725 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21729 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21730 if (b.indexOf(tag) > -1) {
21733 this.cwhite.push(tag);
21737 Roo.each(w, function(tag) {
21738 if (b.indexOf(tag) > -1) {
21741 if (this.cwhite.indexOf(tag) > -1) {
21744 this.cwhite.push(tag);
21749 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21750 if (w.indexOf(tag) > -1) {
21753 this.cblack.push(tag);
21757 Roo.each(b, function(tag) {
21758 if (w.indexOf(tag) > -1) {
21761 if (this.cblack.indexOf(tag) > -1) {
21764 this.cblack.push(tag);
21769 setStylesheets : function(stylesheets)
21771 if(typeof(stylesheets) == 'string'){
21772 Roo.get(this.iframe.contentDocument.head).createChild({
21774 rel : 'stylesheet',
21783 Roo.each(stylesheets, function(s) {
21788 Roo.get(_this.iframe.contentDocument.head).createChild({
21790 rel : 'stylesheet',
21799 removeStylesheets : function()
21803 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21808 // hide stuff that is not compatible
21822 * @event specialkey
21826 * @cfg {String} fieldClass @hide
21829 * @cfg {String} focusClass @hide
21832 * @cfg {String} autoCreate @hide
21835 * @cfg {String} inputType @hide
21838 * @cfg {String} invalidClass @hide
21841 * @cfg {String} invalidText @hide
21844 * @cfg {String} msgFx @hide
21847 * @cfg {String} validateOnBlur @hide
21851 Roo.HtmlEditorCore.white = [
21852 'area', 'br', 'img', 'input', 'hr', 'wbr',
21854 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21855 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21856 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21857 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21858 'table', 'ul', 'xmp',
21860 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21863 'dir', 'menu', 'ol', 'ul', 'dl',
21869 Roo.HtmlEditorCore.black = [
21870 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21872 'base', 'basefont', 'bgsound', 'blink', 'body',
21873 'frame', 'frameset', 'head', 'html', 'ilayer',
21874 'iframe', 'layer', 'link', 'meta', 'object',
21875 'script', 'style' ,'title', 'xml' // clean later..
21877 Roo.HtmlEditorCore.clean = [
21878 'script', 'style', 'title', 'xml'
21880 Roo.HtmlEditorCore.remove = [
21885 Roo.HtmlEditorCore.ablack = [
21889 Roo.HtmlEditorCore.aclean = [
21890 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21894 Roo.HtmlEditorCore.pwhite= [
21895 'http', 'https', 'mailto'
21898 // white listed style attributes.
21899 Roo.HtmlEditorCore.cwhite= [
21900 // 'text-align', /// default is to allow most things..
21906 // black listed style attributes.
21907 Roo.HtmlEditorCore.cblack= [
21908 // 'font-size' -- this can be set by the project
21912 Roo.HtmlEditorCore.swapCodes =[
21931 * @class Roo.bootstrap.HtmlEditor
21932 * @extends Roo.bootstrap.TextArea
21933 * Bootstrap HtmlEditor class
21936 * Create a new HtmlEditor
21937 * @param {Object} config The config object
21940 Roo.bootstrap.HtmlEditor = function(config){
21941 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21942 if (!this.toolbars) {
21943 this.toolbars = [];
21945 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21948 * @event initialize
21949 * Fires when the editor is fully initialized (including the iframe)
21950 * @param {HtmlEditor} this
21955 * Fires when the editor is first receives the focus. Any insertion must wait
21956 * until after this event.
21957 * @param {HtmlEditor} this
21961 * @event beforesync
21962 * Fires before the textarea is updated with content from the editor iframe. Return false
21963 * to cancel the sync.
21964 * @param {HtmlEditor} this
21965 * @param {String} html
21969 * @event beforepush
21970 * Fires before the iframe editor is updated with content from the textarea. Return false
21971 * to cancel the push.
21972 * @param {HtmlEditor} this
21973 * @param {String} html
21978 * Fires when the textarea is updated with content from the editor iframe.
21979 * @param {HtmlEditor} this
21980 * @param {String} html
21985 * Fires when the iframe editor is updated with content from the textarea.
21986 * @param {HtmlEditor} this
21987 * @param {String} html
21991 * @event editmodechange
21992 * Fires when the editor switches edit modes
21993 * @param {HtmlEditor} this
21994 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21996 editmodechange: true,
21998 * @event editorevent
21999 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22000 * @param {HtmlEditor} this
22004 * @event firstfocus
22005 * Fires when on first focus - needed by toolbars..
22006 * @param {HtmlEditor} this
22011 * Auto save the htmlEditor value as a file into Events
22012 * @param {HtmlEditor} this
22016 * @event savedpreview
22017 * preview the saved version of htmlEditor
22018 * @param {HtmlEditor} this
22025 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22029 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22034 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22039 * @cfg {Number} height (in pixels)
22043 * @cfg {Number} width (in pixels)
22048 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22051 stylesheets: false,
22056 // private properties
22057 validationEvent : false,
22059 initialized : false,
22062 onFocus : Roo.emptyFn,
22064 hideMode:'offsets',
22067 tbContainer : false,
22069 toolbarContainer :function() {
22070 return this.wrap.select('.x-html-editor-tb',true).first();
22074 * Protected method that will not generally be called directly. It
22075 * is called when the editor creates its toolbar. Override this method if you need to
22076 * add custom toolbar buttons.
22077 * @param {HtmlEditor} editor
22079 createToolbar : function(){
22081 Roo.log("create toolbars");
22083 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22084 this.toolbars[0].render(this.toolbarContainer());
22088 // if (!editor.toolbars || !editor.toolbars.length) {
22089 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22092 // for (var i =0 ; i < editor.toolbars.length;i++) {
22093 // editor.toolbars[i] = Roo.factory(
22094 // typeof(editor.toolbars[i]) == 'string' ?
22095 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22096 // Roo.bootstrap.HtmlEditor);
22097 // editor.toolbars[i].init(editor);
22103 onRender : function(ct, position)
22105 // Roo.log("Call onRender: " + this.xtype);
22107 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22109 this.wrap = this.inputEl().wrap({
22110 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22113 this.editorcore.onRender(ct, position);
22115 if (this.resizable) {
22116 this.resizeEl = new Roo.Resizable(this.wrap, {
22120 minHeight : this.height,
22121 height: this.height,
22122 handles : this.resizable,
22125 resize : function(r, w, h) {
22126 _t.onResize(w,h); // -something
22132 this.createToolbar(this);
22135 if(!this.width && this.resizable){
22136 this.setSize(this.wrap.getSize());
22138 if (this.resizeEl) {
22139 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22140 // should trigger onReize..
22146 onResize : function(w, h)
22148 Roo.log('resize: ' +w + ',' + h );
22149 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22153 if(this.inputEl() ){
22154 if(typeof w == 'number'){
22155 var aw = w - this.wrap.getFrameWidth('lr');
22156 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22159 if(typeof h == 'number'){
22160 var tbh = -11; // fixme it needs to tool bar size!
22161 for (var i =0; i < this.toolbars.length;i++) {
22162 // fixme - ask toolbars for heights?
22163 tbh += this.toolbars[i].el.getHeight();
22164 //if (this.toolbars[i].footer) {
22165 // tbh += this.toolbars[i].footer.el.getHeight();
22173 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22174 ah -= 5; // knock a few pixes off for look..
22175 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22179 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22180 this.editorcore.onResize(ew,eh);
22185 * Toggles the editor between standard and source edit mode.
22186 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22188 toggleSourceEdit : function(sourceEditMode)
22190 this.editorcore.toggleSourceEdit(sourceEditMode);
22192 if(this.editorcore.sourceEditMode){
22193 Roo.log('editor - showing textarea');
22196 // Roo.log(this.syncValue());
22198 this.inputEl().removeClass(['hide', 'x-hidden']);
22199 this.inputEl().dom.removeAttribute('tabIndex');
22200 this.inputEl().focus();
22202 Roo.log('editor - hiding textarea');
22204 // Roo.log(this.pushValue());
22207 this.inputEl().addClass(['hide', 'x-hidden']);
22208 this.inputEl().dom.setAttribute('tabIndex', -1);
22209 //this.deferFocus();
22212 if(this.resizable){
22213 this.setSize(this.wrap.getSize());
22216 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22219 // private (for BoxComponent)
22220 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22222 // private (for BoxComponent)
22223 getResizeEl : function(){
22227 // private (for BoxComponent)
22228 getPositionEl : function(){
22233 initEvents : function(){
22234 this.originalValue = this.getValue();
22238 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22241 // markInvalid : Roo.emptyFn,
22243 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22246 // clearInvalid : Roo.emptyFn,
22248 setValue : function(v){
22249 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22250 this.editorcore.pushValue();
22255 deferFocus : function(){
22256 this.focus.defer(10, this);
22260 focus : function(){
22261 this.editorcore.focus();
22267 onDestroy : function(){
22273 for (var i =0; i < this.toolbars.length;i++) {
22274 // fixme - ask toolbars for heights?
22275 this.toolbars[i].onDestroy();
22278 this.wrap.dom.innerHTML = '';
22279 this.wrap.remove();
22284 onFirstFocus : function(){
22285 //Roo.log("onFirstFocus");
22286 this.editorcore.onFirstFocus();
22287 for (var i =0; i < this.toolbars.length;i++) {
22288 this.toolbars[i].onFirstFocus();
22294 syncValue : function()
22296 this.editorcore.syncValue();
22299 pushValue : function()
22301 this.editorcore.pushValue();
22305 // hide stuff that is not compatible
22319 * @event specialkey
22323 * @cfg {String} fieldClass @hide
22326 * @cfg {String} focusClass @hide
22329 * @cfg {String} autoCreate @hide
22332 * @cfg {String} inputType @hide
22335 * @cfg {String} invalidClass @hide
22338 * @cfg {String} invalidText @hide
22341 * @cfg {String} msgFx @hide
22344 * @cfg {String} validateOnBlur @hide
22353 Roo.namespace('Roo.bootstrap.htmleditor');
22355 * @class Roo.bootstrap.HtmlEditorToolbar1
22360 new Roo.bootstrap.HtmlEditor({
22363 new Roo.bootstrap.HtmlEditorToolbar1({
22364 disable : { fonts: 1 , format: 1, ..., ... , ...],
22370 * @cfg {Object} disable List of elements to disable..
22371 * @cfg {Array} btns List of additional buttons.
22375 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22378 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22381 Roo.apply(this, config);
22383 // default disabled, based on 'good practice'..
22384 this.disable = this.disable || {};
22385 Roo.applyIf(this.disable, {
22388 specialElements : true
22390 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22392 this.editor = config.editor;
22393 this.editorcore = config.editor.editorcore;
22395 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22397 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22398 // dont call parent... till later.
22400 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22405 editorcore : false,
22410 "h1","h2","h3","h4","h5","h6",
22412 "abbr", "acronym", "address", "cite", "samp", "var",
22416 onRender : function(ct, position)
22418 // Roo.log("Call onRender: " + this.xtype);
22420 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22422 this.el.dom.style.marginBottom = '0';
22424 var editorcore = this.editorcore;
22425 var editor= this.editor;
22428 var btn = function(id,cmd , toggle, handler){
22430 var event = toggle ? 'toggle' : 'click';
22435 xns: Roo.bootstrap,
22438 enableToggle:toggle !== false,
22440 pressed : toggle ? false : null,
22443 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22444 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22453 xns: Roo.bootstrap,
22454 glyphicon : 'font',
22458 xns: Roo.bootstrap,
22462 Roo.each(this.formats, function(f) {
22463 style.menu.items.push({
22465 xns: Roo.bootstrap,
22466 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22471 editorcore.insertTag(this.tagname);
22478 children.push(style);
22481 btn('bold',false,true);
22482 btn('italic',false,true);
22483 btn('align-left', 'justifyleft',true);
22484 btn('align-center', 'justifycenter',true);
22485 btn('align-right' , 'justifyright',true);
22486 btn('link', false, false, function(btn) {
22487 //Roo.log("create link?");
22488 var url = prompt(this.createLinkText, this.defaultLinkValue);
22489 if(url && url != 'http:/'+'/'){
22490 this.editorcore.relayCmd('createlink', url);
22493 btn('list','insertunorderedlist',true);
22494 btn('pencil', false,true, function(btn){
22497 this.toggleSourceEdit(btn.pressed);
22503 xns: Roo.bootstrap,
22508 xns: Roo.bootstrap,
22513 cog.menu.items.push({
22515 xns: Roo.bootstrap,
22516 html : Clean styles,
22521 editorcore.insertTag(this.tagname);
22530 this.xtype = 'NavSimplebar';
22532 for(var i=0;i< children.length;i++) {
22534 this.buttons.add(this.addxtypeChild(children[i]));
22538 editor.on('editorevent', this.updateToolbar, this);
22540 onBtnClick : function(id)
22542 this.editorcore.relayCmd(id);
22543 this.editorcore.focus();
22547 * Protected method that will not generally be called directly. It triggers
22548 * a toolbar update by reading the markup state of the current selection in the editor.
22550 updateToolbar: function(){
22552 if(!this.editorcore.activated){
22553 this.editor.onFirstFocus(); // is this neeed?
22557 var btns = this.buttons;
22558 var doc = this.editorcore.doc;
22559 btns.get('bold').setActive(doc.queryCommandState('bold'));
22560 btns.get('italic').setActive(doc.queryCommandState('italic'));
22561 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22563 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22564 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22565 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22567 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22568 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22571 var ans = this.editorcore.getAllAncestors();
22572 if (this.formatCombo) {
22575 var store = this.formatCombo.store;
22576 this.formatCombo.setValue("");
22577 for (var i =0; i < ans.length;i++) {
22578 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22580 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22588 // hides menus... - so this cant be on a menu...
22589 Roo.bootstrap.MenuMgr.hideAll();
22591 Roo.bootstrap.MenuMgr.hideAll();
22592 //this.editorsyncValue();
22594 onFirstFocus: function() {
22595 this.buttons.each(function(item){
22599 toggleSourceEdit : function(sourceEditMode){
22602 if(sourceEditMode){
22603 Roo.log("disabling buttons");
22604 this.buttons.each( function(item){
22605 if(item.cmd != 'pencil'){
22611 Roo.log("enabling buttons");
22612 if(this.editorcore.initialized){
22613 this.buttons.each( function(item){
22619 Roo.log("calling toggole on editor");
22620 // tell the editor that it's been pressed..
22621 this.editor.toggleSourceEdit(sourceEditMode);
22631 * @class Roo.bootstrap.Table.AbstractSelectionModel
22632 * @extends Roo.util.Observable
22633 * Abstract base class for grid SelectionModels. It provides the interface that should be
22634 * implemented by descendant classes. This class should not be directly instantiated.
22637 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22638 this.locked = false;
22639 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22643 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22644 /** @ignore Called by the grid automatically. Do not call directly. */
22645 init : function(grid){
22651 * Locks the selections.
22654 this.locked = true;
22658 * Unlocks the selections.
22660 unlock : function(){
22661 this.locked = false;
22665 * Returns true if the selections are locked.
22666 * @return {Boolean}
22668 isLocked : function(){
22669 return this.locked;
22673 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22674 * @class Roo.bootstrap.Table.RowSelectionModel
22675 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22676 * It supports multiple selections and keyboard selection/navigation.
22678 * @param {Object} config
22681 Roo.bootstrap.Table.RowSelectionModel = function(config){
22682 Roo.apply(this, config);
22683 this.selections = new Roo.util.MixedCollection(false, function(o){
22688 this.lastActive = false;
22692 * @event selectionchange
22693 * Fires when the selection changes
22694 * @param {SelectionModel} this
22696 "selectionchange" : true,
22698 * @event afterselectionchange
22699 * Fires after the selection changes (eg. by key press or clicking)
22700 * @param {SelectionModel} this
22702 "afterselectionchange" : true,
22704 * @event beforerowselect
22705 * Fires when a row is selected being selected, return false to cancel.
22706 * @param {SelectionModel} this
22707 * @param {Number} rowIndex The selected index
22708 * @param {Boolean} keepExisting False if other selections will be cleared
22710 "beforerowselect" : true,
22713 * Fires when a row is selected.
22714 * @param {SelectionModel} this
22715 * @param {Number} rowIndex The selected index
22716 * @param {Roo.data.Record} r The record
22718 "rowselect" : true,
22720 * @event rowdeselect
22721 * Fires when a row is deselected.
22722 * @param {SelectionModel} this
22723 * @param {Number} rowIndex The selected index
22725 "rowdeselect" : true
22727 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22728 this.locked = false;
22731 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22733 * @cfg {Boolean} singleSelect
22734 * True to allow selection of only one row at a time (defaults to false)
22736 singleSelect : false,
22739 initEvents : function()
22742 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22743 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
22744 //}else{ // allow click to work like normal
22745 // this.grid.on("rowclick", this.handleDragableRowClick, this);
22747 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
22748 this.grid.on("rowclick", this.handleMouseDown, this);
22750 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22751 "up" : function(e){
22753 this.selectPrevious(e.shiftKey);
22754 }else if(this.last !== false && this.lastActive !== false){
22755 var last = this.last;
22756 this.selectRange(this.last, this.lastActive-1);
22757 this.grid.getView().focusRow(this.lastActive);
22758 if(last !== false){
22762 this.selectFirstRow();
22764 this.fireEvent("afterselectionchange", this);
22766 "down" : function(e){
22768 this.selectNext(e.shiftKey);
22769 }else if(this.last !== false && this.lastActive !== false){
22770 var last = this.last;
22771 this.selectRange(this.last, this.lastActive+1);
22772 this.grid.getView().focusRow(this.lastActive);
22773 if(last !== false){
22777 this.selectFirstRow();
22779 this.fireEvent("afterselectionchange", this);
22783 this.grid.store.on('load', function(){
22784 this.selections.clear();
22787 var view = this.grid.view;
22788 view.on("refresh", this.onRefresh, this);
22789 view.on("rowupdated", this.onRowUpdated, this);
22790 view.on("rowremoved", this.onRemove, this);
22795 onRefresh : function()
22797 var ds = this.grid.store, i, v = this.grid.view;
22798 var s = this.selections;
22799 s.each(function(r){
22800 if((i = ds.indexOfId(r.id)) != -1){
22809 onRemove : function(v, index, r){
22810 this.selections.remove(r);
22814 onRowUpdated : function(v, index, r){
22815 if(this.isSelected(r)){
22816 v.onRowSelect(index);
22822 * @param {Array} records The records to select
22823 * @param {Boolean} keepExisting (optional) True to keep existing selections
22825 selectRecords : function(records, keepExisting)
22828 this.clearSelections();
22830 var ds = this.grid.store;
22831 for(var i = 0, len = records.length; i < len; i++){
22832 this.selectRow(ds.indexOf(records[i]), true);
22837 * Gets the number of selected rows.
22840 getCount : function(){
22841 return this.selections.length;
22845 * Selects the first row in the grid.
22847 selectFirstRow : function(){
22852 * Select the last row.
22853 * @param {Boolean} keepExisting (optional) True to keep existing selections
22855 selectLastRow : function(keepExisting){
22856 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22857 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
22861 * Selects the row immediately following the last selected row.
22862 * @param {Boolean} keepExisting (optional) True to keep existing selections
22864 selectNext : function(keepExisting)
22866 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
22867 this.selectRow(this.last+1, keepExisting);
22868 this.grid.getView().focusRow(this.last);
22873 * Selects the row that precedes the last selected row.
22874 * @param {Boolean} keepExisting (optional) True to keep existing selections
22876 selectPrevious : function(keepExisting){
22878 this.selectRow(this.last-1, keepExisting);
22879 this.grid.getView().focusRow(this.last);
22884 * Returns the selected records
22885 * @return {Array} Array of selected records
22887 getSelections : function(){
22888 return [].concat(this.selections.items);
22892 * Returns the first selected record.
22895 getSelected : function(){
22896 return this.selections.itemAt(0);
22901 * Clears all selections.
22903 clearSelections : function(fast)
22909 var ds = this.grid.store;
22910 var s = this.selections;
22911 s.each(function(r){
22912 this.deselectRow(ds.indexOfId(r.id));
22916 this.selections.clear();
22923 * Selects all rows.
22925 selectAll : function(){
22929 this.selections.clear();
22930 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
22931 this.selectRow(i, true);
22936 * Returns True if there is a selection.
22937 * @return {Boolean}
22939 hasSelection : function(){
22940 return this.selections.length > 0;
22944 * Returns True if the specified row is selected.
22945 * @param {Number/Record} record The record or index of the record to check
22946 * @return {Boolean}
22948 isSelected : function(index){
22949 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
22950 return (r && this.selections.key(r.id) ? true : false);
22954 * Returns True if the specified record id is selected.
22955 * @param {String} id The id of record to check
22956 * @return {Boolean}
22958 isIdSelected : function(id){
22959 return (this.selections.key(id) ? true : false);
22964 handleMouseDBClick : function(e, t){
22968 handleMouseDown : function(e, t)
22970 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
22971 if(this.isLocked() || rowIndex < 0 ){
22974 if(e.shiftKey && this.last !== false){
22975 var last = this.last;
22976 this.selectRange(last, rowIndex, e.ctrlKey);
22977 this.last = last; // reset the last
22981 var isSelected = this.isSelected(rowIndex);
22982 //Roo.log("select row:" + rowIndex);
22984 this.deselectRow(rowIndex);
22986 this.selectRow(rowIndex, true);
22990 if(e.button !== 0 && isSelected){
22991 alert('rowIndex 2: ' + rowIndex);
22992 view.focusRow(rowIndex);
22993 }else if(e.ctrlKey && isSelected){
22994 this.deselectRow(rowIndex);
22995 }else if(!isSelected){
22996 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22997 view.focusRow(rowIndex);
23001 this.fireEvent("afterselectionchange", this);
23004 handleDragableRowClick : function(grid, rowIndex, e)
23006 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23007 this.selectRow(rowIndex, false);
23008 grid.view.focusRow(rowIndex);
23009 this.fireEvent("afterselectionchange", this);
23014 * Selects multiple rows.
23015 * @param {Array} rows Array of the indexes of the row to select
23016 * @param {Boolean} keepExisting (optional) True to keep existing selections
23018 selectRows : function(rows, keepExisting){
23020 this.clearSelections();
23022 for(var i = 0, len = rows.length; i < len; i++){
23023 this.selectRow(rows[i], true);
23028 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23029 * @param {Number} startRow The index of the first row in the range
23030 * @param {Number} endRow The index of the last row in the range
23031 * @param {Boolean} keepExisting (optional) True to retain existing selections
23033 selectRange : function(startRow, endRow, keepExisting){
23038 this.clearSelections();
23040 if(startRow <= endRow){
23041 for(var i = startRow; i <= endRow; i++){
23042 this.selectRow(i, true);
23045 for(var i = startRow; i >= endRow; i--){
23046 this.selectRow(i, true);
23052 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23053 * @param {Number} startRow The index of the first row in the range
23054 * @param {Number} endRow The index of the last row in the range
23056 deselectRange : function(startRow, endRow, preventViewNotify){
23060 for(var i = startRow; i <= endRow; i++){
23061 this.deselectRow(i, preventViewNotify);
23067 * @param {Number} row The index of the row to select
23068 * @param {Boolean} keepExisting (optional) True to keep existing selections
23070 selectRow : function(index, keepExisting, preventViewNotify)
23072 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23075 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23076 if(!keepExisting || this.singleSelect){
23077 this.clearSelections();
23080 var r = this.grid.store.getAt(index);
23081 //console.log('selectRow - record id :' + r.id);
23083 this.selections.add(r);
23084 this.last = this.lastActive = index;
23085 if(!preventViewNotify){
23086 var proxy = new Roo.Element(
23087 this.grid.getRowDom(index)
23089 proxy.addClass('bg-info info');
23091 this.fireEvent("rowselect", this, index, r);
23092 this.fireEvent("selectionchange", this);
23098 * @param {Number} row The index of the row to deselect
23100 deselectRow : function(index, preventViewNotify)
23105 if(this.last == index){
23108 if(this.lastActive == index){
23109 this.lastActive = false;
23112 var r = this.grid.store.getAt(index);
23117 this.selections.remove(r);
23118 //.console.log('deselectRow - record id :' + r.id);
23119 if(!preventViewNotify){
23121 var proxy = new Roo.Element(
23122 this.grid.getRowDom(index)
23124 proxy.removeClass('bg-info info');
23126 this.fireEvent("rowdeselect", this, index);
23127 this.fireEvent("selectionchange", this);
23131 restoreLast : function(){
23133 this.last = this._last;
23138 acceptsNav : function(row, col, cm){
23139 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23143 onEditorKey : function(field, e){
23144 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23149 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23151 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23153 }else if(k == e.ENTER && !e.ctrlKey){
23157 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23159 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23161 }else if(k == e.ESC){
23165 g.startEditing(newCell[0], newCell[1]);
23171 * Ext JS Library 1.1.1
23172 * Copyright(c) 2006-2007, Ext JS, LLC.
23174 * Originally Released Under LGPL - original licence link has changed is not relivant.
23177 * <script type="text/javascript">
23181 * @class Roo.bootstrap.PagingToolbar
23182 * @extends Roo.bootstrap.NavSimplebar
23183 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23185 * Create a new PagingToolbar
23186 * @param {Object} config The config object
23187 * @param {Roo.data.Store} store
23189 Roo.bootstrap.PagingToolbar = function(config)
23191 // old args format still supported... - xtype is prefered..
23192 // created from xtype...
23194 this.ds = config.dataSource;
23196 if (config.store && !this.ds) {
23197 this.store= Roo.factory(config.store, Roo.data);
23198 this.ds = this.store;
23199 this.ds.xmodule = this.xmodule || false;
23202 this.toolbarItems = [];
23203 if (config.items) {
23204 this.toolbarItems = config.items;
23207 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23212 this.bind(this.ds);
23215 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23219 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23221 * @cfg {Roo.data.Store} dataSource
23222 * The underlying data store providing the paged data
23225 * @cfg {String/HTMLElement/Element} container
23226 * container The id or element that will contain the toolbar
23229 * @cfg {Boolean} displayInfo
23230 * True to display the displayMsg (defaults to false)
23233 * @cfg {Number} pageSize
23234 * The number of records to display per page (defaults to 20)
23238 * @cfg {String} displayMsg
23239 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23241 displayMsg : 'Displaying {0} - {1} of {2}',
23243 * @cfg {String} emptyMsg
23244 * The message to display when no records are found (defaults to "No data to display")
23246 emptyMsg : 'No data to display',
23248 * Customizable piece of the default paging text (defaults to "Page")
23251 beforePageText : "Page",
23253 * Customizable piece of the default paging text (defaults to "of %0")
23256 afterPageText : "of {0}",
23258 * Customizable piece of the default paging text (defaults to "First Page")
23261 firstText : "First Page",
23263 * Customizable piece of the default paging text (defaults to "Previous Page")
23266 prevText : "Previous Page",
23268 * Customizable piece of the default paging text (defaults to "Next Page")
23271 nextText : "Next Page",
23273 * Customizable piece of the default paging text (defaults to "Last Page")
23276 lastText : "Last Page",
23278 * Customizable piece of the default paging text (defaults to "Refresh")
23281 refreshText : "Refresh",
23285 onRender : function(ct, position)
23287 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23288 this.navgroup.parentId = this.id;
23289 this.navgroup.onRender(this.el, null);
23290 // add the buttons to the navgroup
23292 if(this.displayInfo){
23293 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23294 this.displayEl = this.el.select('.x-paging-info', true).first();
23295 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23296 // this.displayEl = navel.el.select('span',true).first();
23302 Roo.each(_this.buttons, function(e){ // this might need to use render????
23303 Roo.factory(e).onRender(_this.el, null);
23307 Roo.each(_this.toolbarItems, function(e) {
23308 _this.navgroup.addItem(e);
23312 this.first = this.navgroup.addItem({
23313 tooltip: this.firstText,
23315 icon : 'fa fa-backward',
23317 preventDefault: true,
23318 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23321 this.prev = this.navgroup.addItem({
23322 tooltip: this.prevText,
23324 icon : 'fa fa-step-backward',
23326 preventDefault: true,
23327 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23329 //this.addSeparator();
23332 var field = this.navgroup.addItem( {
23334 cls : 'x-paging-position',
23336 html : this.beforePageText +
23337 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23338 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23341 this.field = field.el.select('input', true).first();
23342 this.field.on("keydown", this.onPagingKeydown, this);
23343 this.field.on("focus", function(){this.dom.select();});
23346 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23347 //this.field.setHeight(18);
23348 //this.addSeparator();
23349 this.next = this.navgroup.addItem({
23350 tooltip: this.nextText,
23352 html : ' <i class="fa fa-step-forward">',
23354 preventDefault: true,
23355 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23357 this.last = this.navgroup.addItem({
23358 tooltip: this.lastText,
23359 icon : 'fa fa-forward',
23362 preventDefault: true,
23363 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23365 //this.addSeparator();
23366 this.loading = this.navgroup.addItem({
23367 tooltip: this.refreshText,
23368 icon: 'fa fa-refresh',
23369 preventDefault: true,
23370 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23376 updateInfo : function(){
23377 if(this.displayEl){
23378 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23379 var msg = count == 0 ?
23383 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23385 this.displayEl.update(msg);
23390 onLoad : function(ds, r, o){
23391 this.cursor = o.params ? o.params.start : 0;
23392 var d = this.getPageData(),
23396 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23397 this.field.dom.value = ap;
23398 this.first.setDisabled(ap == 1);
23399 this.prev.setDisabled(ap == 1);
23400 this.next.setDisabled(ap == ps);
23401 this.last.setDisabled(ap == ps);
23402 this.loading.enable();
23407 getPageData : function(){
23408 var total = this.ds.getTotalCount();
23411 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23412 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23417 onLoadError : function(){
23418 this.loading.enable();
23422 onPagingKeydown : function(e){
23423 var k = e.getKey();
23424 var d = this.getPageData();
23426 var v = this.field.dom.value, pageNum;
23427 if(!v || isNaN(pageNum = parseInt(v, 10))){
23428 this.field.dom.value = d.activePage;
23431 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23432 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23435 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))
23437 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23438 this.field.dom.value = pageNum;
23439 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23442 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23444 var v = this.field.dom.value, pageNum;
23445 var increment = (e.shiftKey) ? 10 : 1;
23446 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23449 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23450 this.field.dom.value = d.activePage;
23453 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23455 this.field.dom.value = parseInt(v, 10) + increment;
23456 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23457 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23464 beforeLoad : function(){
23466 this.loading.disable();
23471 onClick : function(which){
23480 ds.load({params:{start: 0, limit: this.pageSize}});
23483 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23486 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23489 var total = ds.getTotalCount();
23490 var extra = total % this.pageSize;
23491 var lastStart = extra ? (total - extra) : total-this.pageSize;
23492 ds.load({params:{start: lastStart, limit: this.pageSize}});
23495 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23501 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23502 * @param {Roo.data.Store} store The data store to unbind
23504 unbind : function(ds){
23505 ds.un("beforeload", this.beforeLoad, this);
23506 ds.un("load", this.onLoad, this);
23507 ds.un("loadexception", this.onLoadError, this);
23508 ds.un("remove", this.updateInfo, this);
23509 ds.un("add", this.updateInfo, this);
23510 this.ds = undefined;
23514 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23515 * @param {Roo.data.Store} store The data store to bind
23517 bind : function(ds){
23518 ds.on("beforeload", this.beforeLoad, this);
23519 ds.on("load", this.onLoad, this);
23520 ds.on("loadexception", this.onLoadError, this);
23521 ds.on("remove", this.updateInfo, this);
23522 ds.on("add", this.updateInfo, this);
23533 * @class Roo.bootstrap.MessageBar
23534 * @extends Roo.bootstrap.Component
23535 * Bootstrap MessageBar class
23536 * @cfg {String} html contents of the MessageBar
23537 * @cfg {String} weight (info | success | warning | danger) default info
23538 * @cfg {String} beforeClass insert the bar before the given class
23539 * @cfg {Boolean} closable (true | false) default false
23540 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23543 * Create a new Element
23544 * @param {Object} config The config object
23547 Roo.bootstrap.MessageBar = function(config){
23548 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23551 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23557 beforeClass: 'bootstrap-sticky-wrap',
23559 getAutoCreate : function(){
23563 cls: 'alert alert-dismissable alert-' + this.weight,
23568 html: this.html || ''
23574 cfg.cls += ' alert-messages-fixed';
23588 onRender : function(ct, position)
23590 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23593 var cfg = Roo.apply({}, this.getAutoCreate());
23597 cfg.cls += ' ' + this.cls;
23600 cfg.style = this.style;
23602 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23604 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23607 this.el.select('>button.close').on('click', this.hide, this);
23613 if (!this.rendered) {
23619 this.fireEvent('show', this);
23625 if (!this.rendered) {
23631 this.fireEvent('hide', this);
23634 update : function()
23636 // var e = this.el.dom.firstChild;
23638 // if(this.closable){
23639 // e = e.nextSibling;
23642 // e.data = this.html || '';
23644 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23660 * @class Roo.bootstrap.Graph
23661 * @extends Roo.bootstrap.Component
23662 * Bootstrap Graph class
23666 @cfg {String} graphtype bar | vbar | pie
23667 @cfg {number} g_x coodinator | centre x (pie)
23668 @cfg {number} g_y coodinator | centre y (pie)
23669 @cfg {number} g_r radius (pie)
23670 @cfg {number} g_height height of the chart (respected by all elements in the set)
23671 @cfg {number} g_width width of the chart (respected by all elements in the set)
23672 @cfg {Object} title The title of the chart
23675 -opts (object) options for the chart
23677 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23678 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23680 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.
23681 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23683 o stretch (boolean)
23685 -opts (object) options for the pie
23688 o startAngle (number)
23689 o endAngle (number)
23693 * Create a new Input
23694 * @param {Object} config The config object
23697 Roo.bootstrap.Graph = function(config){
23698 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23704 * The img click event for the img.
23705 * @param {Roo.EventObject} e
23711 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23722 //g_colors: this.colors,
23729 getAutoCreate : function(){
23740 onRender : function(ct,position){
23743 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23745 if (typeof(Raphael) == 'undefined') {
23746 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23750 this.raphael = Raphael(this.el.dom);
23752 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23753 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23754 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23755 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23757 r.text(160, 10, "Single Series Chart").attr(txtattr);
23758 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23759 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23760 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23762 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23763 r.barchart(330, 10, 300, 220, data1);
23764 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23765 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23768 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23769 // r.barchart(30, 30, 560, 250, xdata, {
23770 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23771 // axis : "0 0 1 1",
23772 // axisxlabels : xdata
23773 // //yvalues : cols,
23776 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23778 // this.load(null,xdata,{
23779 // axis : "0 0 1 1",
23780 // axisxlabels : xdata
23785 load : function(graphtype,xdata,opts)
23787 this.raphael.clear();
23789 graphtype = this.graphtype;
23794 var r = this.raphael,
23795 fin = function () {
23796 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23798 fout = function () {
23799 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23801 pfin = function() {
23802 this.sector.stop();
23803 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23806 this.label[0].stop();
23807 this.label[0].attr({ r: 7.5 });
23808 this.label[1].attr({ "font-weight": 800 });
23811 pfout = function() {
23812 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23815 this.label[0].animate({ r: 5 }, 500, "bounce");
23816 this.label[1].attr({ "font-weight": 400 });
23822 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23825 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23828 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23829 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23831 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23838 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23843 setTitle: function(o)
23848 initEvents: function() {
23851 this.el.on('click', this.onClick, this);
23855 onClick : function(e)
23857 Roo.log('img onclick');
23858 this.fireEvent('click', this, e);
23870 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23873 * @class Roo.bootstrap.dash.NumberBox
23874 * @extends Roo.bootstrap.Component
23875 * Bootstrap NumberBox class
23876 * @cfg {String} headline Box headline
23877 * @cfg {String} content Box content
23878 * @cfg {String} icon Box icon
23879 * @cfg {String} footer Footer text
23880 * @cfg {String} fhref Footer href
23883 * Create a new NumberBox
23884 * @param {Object} config The config object
23888 Roo.bootstrap.dash.NumberBox = function(config){
23889 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23893 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23902 getAutoCreate : function(){
23906 cls : 'small-box ',
23914 cls : 'roo-headline',
23915 html : this.headline
23919 cls : 'roo-content',
23920 html : this.content
23934 cls : 'ion ' + this.icon
23943 cls : 'small-box-footer',
23944 href : this.fhref || '#',
23948 cfg.cn.push(footer);
23955 onRender : function(ct,position){
23956 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23963 setHeadline: function (value)
23965 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23968 setFooter: function (value, href)
23970 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23973 this.el.select('a.small-box-footer',true).first().attr('href', href);
23978 setContent: function (value)
23980 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23983 initEvents: function()
23997 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24000 * @class Roo.bootstrap.dash.TabBox
24001 * @extends Roo.bootstrap.Component
24002 * Bootstrap TabBox class
24003 * @cfg {String} title Title of the TabBox
24004 * @cfg {String} icon Icon of the TabBox
24005 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24006 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24009 * Create a new TabBox
24010 * @param {Object} config The config object
24014 Roo.bootstrap.dash.TabBox = function(config){
24015 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24020 * When a pane is added
24021 * @param {Roo.bootstrap.dash.TabPane} pane
24025 * @event activatepane
24026 * When a pane is activated
24027 * @param {Roo.bootstrap.dash.TabPane} pane
24029 "activatepane" : true
24037 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24042 tabScrollable : false,
24044 getChildContainer : function()
24046 return this.el.select('.tab-content', true).first();
24049 getAutoCreate : function(){
24053 cls: 'pull-left header',
24061 cls: 'fa ' + this.icon
24067 cls: 'nav nav-tabs pull-right',
24073 if(this.tabScrollable){
24080 cls: 'nav nav-tabs pull-right',
24091 cls: 'nav-tabs-custom',
24096 cls: 'tab-content no-padding',
24104 initEvents : function()
24106 //Roo.log('add add pane handler');
24107 this.on('addpane', this.onAddPane, this);
24110 * Updates the box title
24111 * @param {String} html to set the title to.
24113 setTitle : function(value)
24115 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24117 onAddPane : function(pane)
24119 this.panes.push(pane);
24120 //Roo.log('addpane');
24122 // tabs are rendere left to right..
24123 if(!this.showtabs){
24127 var ctr = this.el.select('.nav-tabs', true).first();
24130 var existing = ctr.select('.nav-tab',true);
24131 var qty = existing.getCount();;
24134 var tab = ctr.createChild({
24136 cls : 'nav-tab' + (qty ? '' : ' active'),
24144 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24147 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24149 pane.el.addClass('active');
24154 onTabClick : function(ev,un,ob,pane)
24156 //Roo.log('tab - prev default');
24157 ev.preventDefault();
24160 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24161 pane.tab.addClass('active');
24162 //Roo.log(pane.title);
24163 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24164 // technically we should have a deactivate event.. but maybe add later.
24165 // and it should not de-activate the selected tab...
24166 this.fireEvent('activatepane', pane);
24167 pane.el.addClass('active');
24168 pane.fireEvent('activate');
24173 getActivePane : function()
24176 Roo.each(this.panes, function(p) {
24177 if(p.el.hasClass('active')){
24198 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24200 * @class Roo.bootstrap.TabPane
24201 * @extends Roo.bootstrap.Component
24202 * Bootstrap TabPane class
24203 * @cfg {Boolean} active (false | true) Default false
24204 * @cfg {String} title title of panel
24208 * Create a new TabPane
24209 * @param {Object} config The config object
24212 Roo.bootstrap.dash.TabPane = function(config){
24213 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24219 * When a pane is activated
24220 * @param {Roo.bootstrap.dash.TabPane} pane
24227 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24232 // the tabBox that this is attached to.
24235 getAutoCreate : function()
24243 cfg.cls += ' active';
24248 initEvents : function()
24250 //Roo.log('trigger add pane handler');
24251 this.parent().fireEvent('addpane', this)
24255 * Updates the tab title
24256 * @param {String} html to set the title to.
24258 setTitle: function(str)
24264 this.tab.select('a', true).first().dom.innerHTML = str;
24281 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24284 * @class Roo.bootstrap.menu.Menu
24285 * @extends Roo.bootstrap.Component
24286 * Bootstrap Menu class - container for Menu
24287 * @cfg {String} html Text of the menu
24288 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24289 * @cfg {String} icon Font awesome icon
24290 * @cfg {String} pos Menu align to (top | bottom) default bottom
24294 * Create a new Menu
24295 * @param {Object} config The config object
24299 Roo.bootstrap.menu.Menu = function(config){
24300 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24304 * @event beforeshow
24305 * Fires before this menu is displayed
24306 * @param {Roo.bootstrap.menu.Menu} this
24310 * @event beforehide
24311 * Fires before this menu is hidden
24312 * @param {Roo.bootstrap.menu.Menu} this
24317 * Fires after this menu is displayed
24318 * @param {Roo.bootstrap.menu.Menu} this
24323 * Fires after this menu is hidden
24324 * @param {Roo.bootstrap.menu.Menu} this
24329 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24330 * @param {Roo.bootstrap.menu.Menu} this
24331 * @param {Roo.EventObject} e
24338 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24342 weight : 'default',
24347 getChildContainer : function() {
24348 if(this.isSubMenu){
24352 return this.el.select('ul.dropdown-menu', true).first();
24355 getAutoCreate : function()
24360 cls : 'roo-menu-text',
24368 cls : 'fa ' + this.icon
24379 cls : 'dropdown-button btn btn-' + this.weight,
24384 cls : 'dropdown-toggle btn btn-' + this.weight,
24394 cls : 'dropdown-menu'
24400 if(this.pos == 'top'){
24401 cfg.cls += ' dropup';
24404 if(this.isSubMenu){
24407 cls : 'dropdown-menu'
24414 onRender : function(ct, position)
24416 this.isSubMenu = ct.hasClass('dropdown-submenu');
24418 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24421 initEvents : function()
24423 if(this.isSubMenu){
24427 this.hidden = true;
24429 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24430 this.triggerEl.on('click', this.onTriggerPress, this);
24432 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24433 this.buttonEl.on('click', this.onClick, this);
24439 if(this.isSubMenu){
24443 return this.el.select('ul.dropdown-menu', true).first();
24446 onClick : function(e)
24448 this.fireEvent("click", this, e);
24451 onTriggerPress : function(e)
24453 if (this.isVisible()) {
24460 isVisible : function(){
24461 return !this.hidden;
24466 this.fireEvent("beforeshow", this);
24468 this.hidden = false;
24469 this.el.addClass('open');
24471 Roo.get(document).on("mouseup", this.onMouseUp, this);
24473 this.fireEvent("show", this);
24480 this.fireEvent("beforehide", this);
24482 this.hidden = true;
24483 this.el.removeClass('open');
24485 Roo.get(document).un("mouseup", this.onMouseUp);
24487 this.fireEvent("hide", this);
24490 onMouseUp : function()
24504 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24507 * @class Roo.bootstrap.menu.Item
24508 * @extends Roo.bootstrap.Component
24509 * Bootstrap MenuItem class
24510 * @cfg {Boolean} submenu (true | false) default false
24511 * @cfg {String} html text of the item
24512 * @cfg {String} href the link
24513 * @cfg {Boolean} disable (true | false) default false
24514 * @cfg {Boolean} preventDefault (true | false) default true
24515 * @cfg {String} icon Font awesome icon
24516 * @cfg {String} pos Submenu align to (left | right) default right
24520 * Create a new Item
24521 * @param {Object} config The config object
24525 Roo.bootstrap.menu.Item = function(config){
24526 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24530 * Fires when the mouse is hovering over this menu
24531 * @param {Roo.bootstrap.menu.Item} this
24532 * @param {Roo.EventObject} e
24537 * Fires when the mouse exits this menu
24538 * @param {Roo.bootstrap.menu.Item} this
24539 * @param {Roo.EventObject} e
24545 * The raw click event for the entire grid.
24546 * @param {Roo.EventObject} e
24552 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24557 preventDefault: true,
24562 getAutoCreate : function()
24567 cls : 'roo-menu-item-text',
24575 cls : 'fa ' + this.icon
24584 href : this.href || '#',
24591 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24595 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24597 if(this.pos == 'left'){
24598 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24605 initEvents : function()
24607 this.el.on('mouseover', this.onMouseOver, this);
24608 this.el.on('mouseout', this.onMouseOut, this);
24610 this.el.select('a', true).first().on('click', this.onClick, this);
24614 onClick : function(e)
24616 if(this.preventDefault){
24617 e.preventDefault();
24620 this.fireEvent("click", this, e);
24623 onMouseOver : function(e)
24625 if(this.submenu && this.pos == 'left'){
24626 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24629 this.fireEvent("mouseover", this, e);
24632 onMouseOut : function(e)
24634 this.fireEvent("mouseout", this, e);
24646 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24649 * @class Roo.bootstrap.menu.Separator
24650 * @extends Roo.bootstrap.Component
24651 * Bootstrap Separator class
24654 * Create a new Separator
24655 * @param {Object} config The config object
24659 Roo.bootstrap.menu.Separator = function(config){
24660 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24663 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24665 getAutoCreate : function(){
24686 * @class Roo.bootstrap.Tooltip
24687 * Bootstrap Tooltip class
24688 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24689 * to determine which dom element triggers the tooltip.
24691 * It needs to add support for additional attributes like tooltip-position
24694 * Create a new Toolti
24695 * @param {Object} config The config object
24698 Roo.bootstrap.Tooltip = function(config){
24699 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24702 Roo.apply(Roo.bootstrap.Tooltip, {
24704 * @function init initialize tooltip monitoring.
24708 currentTip : false,
24709 currentRegion : false,
24715 Roo.get(document).on('mouseover', this.enter ,this);
24716 Roo.get(document).on('mouseout', this.leave, this);
24719 this.currentTip = new Roo.bootstrap.Tooltip();
24722 enter : function(ev)
24724 var dom = ev.getTarget();
24726 //Roo.log(['enter',dom]);
24727 var el = Roo.fly(dom);
24728 if (this.currentEl) {
24730 //Roo.log(this.currentEl);
24731 //Roo.log(this.currentEl.contains(dom));
24732 if (this.currentEl == el) {
24735 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24741 if (this.currentTip.el) {
24742 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24746 if(!el || el.dom == document){
24752 // you can not look for children, as if el is the body.. then everythign is the child..
24753 if (!el.attr('tooltip')) { //
24754 if (!el.select("[tooltip]").elements.length) {
24757 // is the mouse over this child...?
24758 bindEl = el.select("[tooltip]").first();
24759 var xy = ev.getXY();
24760 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24761 //Roo.log("not in region.");
24764 //Roo.log("child element over..");
24767 this.currentEl = bindEl;
24768 this.currentTip.bind(bindEl);
24769 this.currentRegion = Roo.lib.Region.getRegion(dom);
24770 this.currentTip.enter();
24773 leave : function(ev)
24775 var dom = ev.getTarget();
24776 //Roo.log(['leave',dom]);
24777 if (!this.currentEl) {
24782 if (dom != this.currentEl.dom) {
24785 var xy = ev.getXY();
24786 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24789 // only activate leave if mouse cursor is outside... bounding box..
24794 if (this.currentTip) {
24795 this.currentTip.leave();
24797 //Roo.log('clear currentEl');
24798 this.currentEl = false;
24803 'left' : ['r-l', [-2,0], 'right'],
24804 'right' : ['l-r', [2,0], 'left'],
24805 'bottom' : ['t-b', [0,2], 'top'],
24806 'top' : [ 'b-t', [0,-2], 'bottom']
24812 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24817 delay : null, // can be { show : 300 , hide: 500}
24821 hoverState : null, //???
24823 placement : 'bottom',
24825 getAutoCreate : function(){
24832 cls : 'tooltip-arrow'
24835 cls : 'tooltip-inner'
24842 bind : function(el)
24848 enter : function () {
24850 if (this.timeout != null) {
24851 clearTimeout(this.timeout);
24854 this.hoverState = 'in';
24855 //Roo.log("enter - show");
24856 if (!this.delay || !this.delay.show) {
24861 this.timeout = setTimeout(function () {
24862 if (_t.hoverState == 'in') {
24865 }, this.delay.show);
24869 clearTimeout(this.timeout);
24871 this.hoverState = 'out';
24872 if (!this.delay || !this.delay.hide) {
24878 this.timeout = setTimeout(function () {
24879 //Roo.log("leave - timeout");
24881 if (_t.hoverState == 'out') {
24883 Roo.bootstrap.Tooltip.currentEl = false;
24891 this.render(document.body);
24894 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24896 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24898 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24900 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24902 var placement = typeof this.placement == 'function' ?
24903 this.placement.call(this, this.el, on_el) :
24906 var autoToken = /\s?auto?\s?/i;
24907 var autoPlace = autoToken.test(placement);
24909 placement = placement.replace(autoToken, '') || 'top';
24913 //this.el.setXY([0,0]);
24915 //this.el.dom.style.display='block';
24917 //this.el.appendTo(on_el);
24919 var p = this.getPosition();
24920 var box = this.el.getBox();
24926 var align = Roo.bootstrap.Tooltip.alignment[placement];
24928 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24930 if(placement == 'top' || placement == 'bottom'){
24932 placement = 'right';
24935 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24936 placement = 'left';
24939 var scroll = Roo.select('body', true).first().getScroll();
24941 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
24947 align = Roo.bootstrap.Tooltip.alignment[placement];
24949 this.el.alignTo(this.bindEl, align[0],align[1]);
24950 //var arrow = this.el.select('.arrow',true).first();
24951 //arrow.set(align[2],
24953 this.el.addClass(placement);
24955 this.el.addClass('in fade');
24957 this.hoverState = null;
24959 if (this.el.hasClass('fade')) {
24970 //this.el.setXY([0,0]);
24971 this.el.removeClass('in');
24987 * @class Roo.bootstrap.LocationPicker
24988 * @extends Roo.bootstrap.Component
24989 * Bootstrap LocationPicker class
24990 * @cfg {Number} latitude Position when init default 0
24991 * @cfg {Number} longitude Position when init default 0
24992 * @cfg {Number} zoom default 15
24993 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24994 * @cfg {Boolean} mapTypeControl default false
24995 * @cfg {Boolean} disableDoubleClickZoom default false
24996 * @cfg {Boolean} scrollwheel default true
24997 * @cfg {Boolean} streetViewControl default false
24998 * @cfg {Number} radius default 0
24999 * @cfg {String} locationName
25000 * @cfg {Boolean} draggable default true
25001 * @cfg {Boolean} enableAutocomplete default false
25002 * @cfg {Boolean} enableReverseGeocode default true
25003 * @cfg {String} markerTitle
25006 * Create a new LocationPicker
25007 * @param {Object} config The config object
25011 Roo.bootstrap.LocationPicker = function(config){
25013 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25018 * Fires when the picker initialized.
25019 * @param {Roo.bootstrap.LocationPicker} this
25020 * @param {Google Location} location
25024 * @event positionchanged
25025 * Fires when the picker position changed.
25026 * @param {Roo.bootstrap.LocationPicker} this
25027 * @param {Google Location} location
25029 positionchanged : true,
25032 * Fires when the map resize.
25033 * @param {Roo.bootstrap.LocationPicker} this
25038 * Fires when the map show.
25039 * @param {Roo.bootstrap.LocationPicker} this
25044 * Fires when the map hide.
25045 * @param {Roo.bootstrap.LocationPicker} this
25050 * Fires when click the map.
25051 * @param {Roo.bootstrap.LocationPicker} this
25052 * @param {Map event} e
25056 * @event mapRightClick
25057 * Fires when right click the map.
25058 * @param {Roo.bootstrap.LocationPicker} this
25059 * @param {Map event} e
25061 mapRightClick : true,
25063 * @event markerClick
25064 * Fires when click the marker.
25065 * @param {Roo.bootstrap.LocationPicker} this
25066 * @param {Map event} e
25068 markerClick : true,
25070 * @event markerRightClick
25071 * Fires when right click the marker.
25072 * @param {Roo.bootstrap.LocationPicker} this
25073 * @param {Map event} e
25075 markerRightClick : true,
25077 * @event OverlayViewDraw
25078 * Fires when OverlayView Draw
25079 * @param {Roo.bootstrap.LocationPicker} this
25081 OverlayViewDraw : true,
25083 * @event OverlayViewOnAdd
25084 * Fires when OverlayView Draw
25085 * @param {Roo.bootstrap.LocationPicker} this
25087 OverlayViewOnAdd : true,
25089 * @event OverlayViewOnRemove
25090 * Fires when OverlayView Draw
25091 * @param {Roo.bootstrap.LocationPicker} this
25093 OverlayViewOnRemove : true,
25095 * @event OverlayViewShow
25096 * Fires when OverlayView Draw
25097 * @param {Roo.bootstrap.LocationPicker} this
25098 * @param {Pixel} cpx
25100 OverlayViewShow : true,
25102 * @event OverlayViewHide
25103 * Fires when OverlayView Draw
25104 * @param {Roo.bootstrap.LocationPicker} this
25106 OverlayViewHide : true,
25108 * @event loadexception
25109 * Fires when load google lib failed.
25110 * @param {Roo.bootstrap.LocationPicker} this
25112 loadexception : true
25117 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25119 gMapContext: false,
25125 mapTypeControl: false,
25126 disableDoubleClickZoom: false,
25128 streetViewControl: false,
25132 enableAutocomplete: false,
25133 enableReverseGeocode: true,
25136 getAutoCreate: function()
25141 cls: 'roo-location-picker'
25147 initEvents: function(ct, position)
25149 if(!this.el.getWidth() || this.isApplied()){
25153 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25158 initial: function()
25160 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25161 this.fireEvent('loadexception', this);
25165 if(!this.mapTypeId){
25166 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25169 this.gMapContext = this.GMapContext();
25171 this.initOverlayView();
25173 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25177 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25178 _this.setPosition(_this.gMapContext.marker.position);
25181 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25182 _this.fireEvent('mapClick', this, event);
25186 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25187 _this.fireEvent('mapRightClick', this, event);
25191 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25192 _this.fireEvent('markerClick', this, event);
25196 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25197 _this.fireEvent('markerRightClick', this, event);
25201 this.setPosition(this.gMapContext.location);
25203 this.fireEvent('initial', this, this.gMapContext.location);
25206 initOverlayView: function()
25210 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25214 _this.fireEvent('OverlayViewDraw', _this);
25219 _this.fireEvent('OverlayViewOnAdd', _this);
25222 onRemove: function()
25224 _this.fireEvent('OverlayViewOnRemove', _this);
25227 show: function(cpx)
25229 _this.fireEvent('OverlayViewShow', _this, cpx);
25234 _this.fireEvent('OverlayViewHide', _this);
25240 fromLatLngToContainerPixel: function(event)
25242 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25245 isApplied: function()
25247 return this.getGmapContext() == false ? false : true;
25250 getGmapContext: function()
25252 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25255 GMapContext: function()
25257 var position = new google.maps.LatLng(this.latitude, this.longitude);
25259 var _map = new google.maps.Map(this.el.dom, {
25262 mapTypeId: this.mapTypeId,
25263 mapTypeControl: this.mapTypeControl,
25264 disableDoubleClickZoom: this.disableDoubleClickZoom,
25265 scrollwheel: this.scrollwheel,
25266 streetViewControl: this.streetViewControl,
25267 locationName: this.locationName,
25268 draggable: this.draggable,
25269 enableAutocomplete: this.enableAutocomplete,
25270 enableReverseGeocode: this.enableReverseGeocode
25273 var _marker = new google.maps.Marker({
25274 position: position,
25276 title: this.markerTitle,
25277 draggable: this.draggable
25284 location: position,
25285 radius: this.radius,
25286 locationName: this.locationName,
25287 addressComponents: {
25288 formatted_address: null,
25289 addressLine1: null,
25290 addressLine2: null,
25292 streetNumber: null,
25296 stateOrProvince: null
25299 domContainer: this.el.dom,
25300 geodecoder: new google.maps.Geocoder()
25304 drawCircle: function(center, radius, options)
25306 if (this.gMapContext.circle != null) {
25307 this.gMapContext.circle.setMap(null);
25311 options = Roo.apply({}, options, {
25312 strokeColor: "#0000FF",
25313 strokeOpacity: .35,
25315 fillColor: "#0000FF",
25319 options.map = this.gMapContext.map;
25320 options.radius = radius;
25321 options.center = center;
25322 this.gMapContext.circle = new google.maps.Circle(options);
25323 return this.gMapContext.circle;
25329 setPosition: function(location)
25331 this.gMapContext.location = location;
25332 this.gMapContext.marker.setPosition(location);
25333 this.gMapContext.map.panTo(location);
25334 this.drawCircle(location, this.gMapContext.radius, {});
25338 if (this.gMapContext.settings.enableReverseGeocode) {
25339 this.gMapContext.geodecoder.geocode({
25340 latLng: this.gMapContext.location
25341 }, function(results, status) {
25343 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25344 _this.gMapContext.locationName = results[0].formatted_address;
25345 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25347 _this.fireEvent('positionchanged', this, location);
25354 this.fireEvent('positionchanged', this, location);
25359 google.maps.event.trigger(this.gMapContext.map, "resize");
25361 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25363 this.fireEvent('resize', this);
25366 setPositionByLatLng: function(latitude, longitude)
25368 this.setPosition(new google.maps.LatLng(latitude, longitude));
25371 getCurrentPosition: function()
25374 latitude: this.gMapContext.location.lat(),
25375 longitude: this.gMapContext.location.lng()
25379 getAddressName: function()
25381 return this.gMapContext.locationName;
25384 getAddressComponents: function()
25386 return this.gMapContext.addressComponents;
25389 address_component_from_google_geocode: function(address_components)
25393 for (var i = 0; i < address_components.length; i++) {
25394 var component = address_components[i];
25395 if (component.types.indexOf("postal_code") >= 0) {
25396 result.postalCode = component.short_name;
25397 } else if (component.types.indexOf("street_number") >= 0) {
25398 result.streetNumber = component.short_name;
25399 } else if (component.types.indexOf("route") >= 0) {
25400 result.streetName = component.short_name;
25401 } else if (component.types.indexOf("neighborhood") >= 0) {
25402 result.city = component.short_name;
25403 } else if (component.types.indexOf("locality") >= 0) {
25404 result.city = component.short_name;
25405 } else if (component.types.indexOf("sublocality") >= 0) {
25406 result.district = component.short_name;
25407 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25408 result.stateOrProvince = component.short_name;
25409 } else if (component.types.indexOf("country") >= 0) {
25410 result.country = component.short_name;
25414 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25415 result.addressLine2 = "";
25419 setZoomLevel: function(zoom)
25421 this.gMapContext.map.setZoom(zoom);
25434 this.fireEvent('show', this);
25445 this.fireEvent('hide', this);
25450 Roo.apply(Roo.bootstrap.LocationPicker, {
25452 OverlayView : function(map, options)
25454 options = options || {};
25468 * @class Roo.bootstrap.Alert
25469 * @extends Roo.bootstrap.Component
25470 * Bootstrap Alert class
25471 * @cfg {String} title The title of alert
25472 * @cfg {String} html The content of alert
25473 * @cfg {String} weight ( success | info | warning | danger )
25474 * @cfg {String} faicon font-awesomeicon
25477 * Create a new alert
25478 * @param {Object} config The config object
25482 Roo.bootstrap.Alert = function(config){
25483 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25487 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25494 getAutoCreate : function()
25503 cls : 'roo-alert-icon'
25508 cls : 'roo-alert-title',
25513 cls : 'roo-alert-text',
25520 cfg.cn[0].cls += ' fa ' + this.faicon;
25524 cfg.cls += ' alert-' + this.weight;
25530 initEvents: function()
25532 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25535 setTitle : function(str)
25537 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25540 setText : function(str)
25542 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25545 setWeight : function(weight)
25548 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25551 this.weight = weight;
25553 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25556 setIcon : function(icon)
25559 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25562 this.faicon = icon;
25564 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25585 * @class Roo.bootstrap.UploadCropbox
25586 * @extends Roo.bootstrap.Component
25587 * Bootstrap UploadCropbox class
25588 * @cfg {String} emptyText show when image has been loaded
25589 * @cfg {String} rotateNotify show when image too small to rotate
25590 * @cfg {Number} errorTimeout default 3000
25591 * @cfg {Number} minWidth default 300
25592 * @cfg {Number} minHeight default 300
25593 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25594 * @cfg {Boolean} isDocument (true|false) default false
25595 * @cfg {String} url action url
25596 * @cfg {String} paramName default 'imageUpload'
25597 * @cfg {String} method default POST
25598 * @cfg {Boolean} loadMask (true|false) default true
25599 * @cfg {Boolean} loadingText default 'Loading...'
25602 * Create a new UploadCropbox
25603 * @param {Object} config The config object
25606 Roo.bootstrap.UploadCropbox = function(config){
25607 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25611 * @event beforeselectfile
25612 * Fire before select file
25613 * @param {Roo.bootstrap.UploadCropbox} this
25615 "beforeselectfile" : true,
25618 * Fire after initEvent
25619 * @param {Roo.bootstrap.UploadCropbox} this
25624 * Fire after initEvent
25625 * @param {Roo.bootstrap.UploadCropbox} this
25626 * @param {String} data
25631 * Fire when preparing the file data
25632 * @param {Roo.bootstrap.UploadCropbox} this
25633 * @param {Object} file
25638 * Fire when get exception
25639 * @param {Roo.bootstrap.UploadCropbox} this
25640 * @param {XMLHttpRequest} xhr
25642 "exception" : true,
25644 * @event beforeloadcanvas
25645 * Fire before load the canvas
25646 * @param {Roo.bootstrap.UploadCropbox} this
25647 * @param {String} src
25649 "beforeloadcanvas" : true,
25652 * Fire when trash image
25653 * @param {Roo.bootstrap.UploadCropbox} this
25658 * Fire when download the image
25659 * @param {Roo.bootstrap.UploadCropbox} this
25663 * @event footerbuttonclick
25664 * Fire when footerbuttonclick
25665 * @param {Roo.bootstrap.UploadCropbox} this
25666 * @param {String} type
25668 "footerbuttonclick" : true,
25672 * @param {Roo.bootstrap.UploadCropbox} this
25677 * Fire when rotate the image
25678 * @param {Roo.bootstrap.UploadCropbox} this
25679 * @param {String} pos
25684 * Fire when inspect the file
25685 * @param {Roo.bootstrap.UploadCropbox} this
25686 * @param {Object} file
25691 * Fire when xhr upload the file
25692 * @param {Roo.bootstrap.UploadCropbox} this
25693 * @param {Object} data
25698 * Fire when arrange the file data
25699 * @param {Roo.bootstrap.UploadCropbox} this
25700 * @param {Object} formData
25705 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25708 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25710 emptyText : 'Click to upload image',
25711 rotateNotify : 'Image is too small to rotate',
25712 errorTimeout : 3000,
25726 cropType : 'image/jpeg',
25728 canvasLoaded : false,
25729 isDocument : false,
25731 paramName : 'imageUpload',
25733 loadingText : 'Loading...',
25736 getAutoCreate : function()
25740 cls : 'roo-upload-cropbox',
25744 cls : 'roo-upload-cropbox-selector',
25749 cls : 'roo-upload-cropbox-body',
25750 style : 'cursor:pointer',
25754 cls : 'roo-upload-cropbox-preview'
25758 cls : 'roo-upload-cropbox-thumb'
25762 cls : 'roo-upload-cropbox-empty-notify',
25763 html : this.emptyText
25767 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25768 html : this.rotateNotify
25774 cls : 'roo-upload-cropbox-footer',
25777 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25787 onRender : function(ct, position)
25789 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25791 if (this.buttons.length) {
25793 Roo.each(this.buttons, function(bb) {
25795 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25797 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25803 this.maskEl = this.el;
25807 initEvents : function()
25809 this.urlAPI = (window.createObjectURL && window) ||
25810 (window.URL && URL.revokeObjectURL && URL) ||
25811 (window.webkitURL && webkitURL);
25813 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25814 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25816 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25817 this.selectorEl.hide();
25819 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25820 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25822 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25823 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25824 this.thumbEl.hide();
25826 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25827 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25829 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25830 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25831 this.errorEl.hide();
25833 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25834 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25835 this.footerEl.hide();
25837 this.setThumbBoxSize();
25843 this.fireEvent('initial', this);
25850 window.addEventListener("resize", function() { _this.resize(); } );
25852 this.bodyEl.on('click', this.beforeSelectFile, this);
25855 this.bodyEl.on('touchstart', this.onTouchStart, this);
25856 this.bodyEl.on('touchmove', this.onTouchMove, this);
25857 this.bodyEl.on('touchend', this.onTouchEnd, this);
25861 this.bodyEl.on('mousedown', this.onMouseDown, this);
25862 this.bodyEl.on('mousemove', this.onMouseMove, this);
25863 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25864 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25865 Roo.get(document).on('mouseup', this.onMouseUp, this);
25868 this.selectorEl.on('change', this.onFileSelected, this);
25874 this.baseScale = 1;
25876 this.baseRotate = 1;
25877 this.dragable = false;
25878 this.pinching = false;
25881 this.cropData = false;
25882 this.notifyEl.dom.innerHTML = this.emptyText;
25884 this.selectorEl.dom.value = '';
25888 resize : function()
25890 if(this.fireEvent('resize', this) != false){
25891 this.setThumbBoxPosition();
25892 this.setCanvasPosition();
25896 onFooterButtonClick : function(e, el, o, type)
25899 case 'rotate-left' :
25900 this.onRotateLeft(e);
25902 case 'rotate-right' :
25903 this.onRotateRight(e);
25906 this.beforeSelectFile(e);
25921 this.fireEvent('footerbuttonclick', this, type);
25924 beforeSelectFile : function(e)
25926 e.preventDefault();
25928 if(this.fireEvent('beforeselectfile', this) != false){
25929 this.selectorEl.dom.click();
25933 onFileSelected : function(e)
25935 e.preventDefault();
25937 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25941 var file = this.selectorEl.dom.files[0];
25943 if(this.fireEvent('inspect', this, file) != false){
25944 this.prepare(file);
25949 trash : function(e)
25951 this.fireEvent('trash', this);
25954 download : function(e)
25956 this.fireEvent('download', this);
25959 loadCanvas : function(src)
25961 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25965 this.imageEl = document.createElement('img');
25969 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25971 this.imageEl.src = src;
25975 onLoadCanvas : function()
25977 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25978 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25980 this.bodyEl.un('click', this.beforeSelectFile, this);
25982 this.notifyEl.hide();
25983 this.thumbEl.show();
25984 this.footerEl.show();
25986 this.baseRotateLevel();
25988 if(this.isDocument){
25989 this.setThumbBoxSize();
25992 this.setThumbBoxPosition();
25994 this.baseScaleLevel();
26000 this.canvasLoaded = true;
26003 this.maskEl.unmask();
26008 setCanvasPosition : function()
26010 if(!this.canvasEl){
26014 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26015 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26017 this.previewEl.setLeft(pw);
26018 this.previewEl.setTop(ph);
26022 onMouseDown : function(e)
26026 this.dragable = true;
26027 this.pinching = false;
26029 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26030 this.dragable = false;
26034 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26035 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26039 onMouseMove : function(e)
26043 if(!this.canvasLoaded){
26047 if (!this.dragable){
26051 var minX = Math.ceil(this.thumbEl.getLeft(true));
26052 var minY = Math.ceil(this.thumbEl.getTop(true));
26054 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26055 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26057 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26058 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26060 x = x - this.mouseX;
26061 y = y - this.mouseY;
26063 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26064 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26066 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26067 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26069 this.previewEl.setLeft(bgX);
26070 this.previewEl.setTop(bgY);
26072 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26073 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26076 onMouseUp : function(e)
26080 this.dragable = false;
26083 onMouseWheel : function(e)
26087 this.startScale = this.scale;
26089 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26091 if(!this.zoomable()){
26092 this.scale = this.startScale;
26101 zoomable : function()
26103 var minScale = this.thumbEl.getWidth() / this.minWidth;
26105 if(this.minWidth < this.minHeight){
26106 minScale = this.thumbEl.getHeight() / this.minHeight;
26109 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26110 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26114 (this.rotate == 0 || this.rotate == 180) &&
26116 width > this.imageEl.OriginWidth ||
26117 height > this.imageEl.OriginHeight ||
26118 (width < this.minWidth && height < this.minHeight)
26126 (this.rotate == 90 || this.rotate == 270) &&
26128 width > this.imageEl.OriginWidth ||
26129 height > this.imageEl.OriginHeight ||
26130 (width < this.minHeight && height < this.minWidth)
26137 !this.isDocument &&
26138 (this.rotate == 0 || this.rotate == 180) &&
26140 width < this.minWidth ||
26141 width > this.imageEl.OriginWidth ||
26142 height < this.minHeight ||
26143 height > this.imageEl.OriginHeight
26150 !this.isDocument &&
26151 (this.rotate == 90 || this.rotate == 270) &&
26153 width < this.minHeight ||
26154 width > this.imageEl.OriginWidth ||
26155 height < this.minWidth ||
26156 height > this.imageEl.OriginHeight
26166 onRotateLeft : function(e)
26168 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26170 var minScale = this.thumbEl.getWidth() / this.minWidth;
26172 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26173 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26175 this.startScale = this.scale;
26177 while (this.getScaleLevel() < minScale){
26179 this.scale = this.scale + 1;
26181 if(!this.zoomable()){
26186 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26187 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26192 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26199 this.scale = this.startScale;
26201 this.onRotateFail();
26206 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26208 if(this.isDocument){
26209 this.setThumbBoxSize();
26210 this.setThumbBoxPosition();
26211 this.setCanvasPosition();
26216 this.fireEvent('rotate', this, 'left');
26220 onRotateRight : function(e)
26222 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26224 var minScale = this.thumbEl.getWidth() / this.minWidth;
26226 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26227 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26229 this.startScale = this.scale;
26231 while (this.getScaleLevel() < minScale){
26233 this.scale = this.scale + 1;
26235 if(!this.zoomable()){
26240 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26241 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26246 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26253 this.scale = this.startScale;
26255 this.onRotateFail();
26260 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26262 if(this.isDocument){
26263 this.setThumbBoxSize();
26264 this.setThumbBoxPosition();
26265 this.setCanvasPosition();
26270 this.fireEvent('rotate', this, 'right');
26273 onRotateFail : function()
26275 this.errorEl.show(true);
26279 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26284 this.previewEl.dom.innerHTML = '';
26286 var canvasEl = document.createElement("canvas");
26288 var contextEl = canvasEl.getContext("2d");
26290 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26291 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26292 var center = this.imageEl.OriginWidth / 2;
26294 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26295 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26296 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26297 center = this.imageEl.OriginHeight / 2;
26300 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26302 contextEl.translate(center, center);
26303 contextEl.rotate(this.rotate * Math.PI / 180);
26305 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26307 this.canvasEl = document.createElement("canvas");
26309 this.contextEl = this.canvasEl.getContext("2d");
26311 switch (this.rotate) {
26314 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26315 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26317 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26322 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26323 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26325 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26326 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);
26330 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26335 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26336 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26338 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26339 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);
26343 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);
26348 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26349 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26351 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26352 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26356 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);
26363 this.previewEl.appendChild(this.canvasEl);
26365 this.setCanvasPosition();
26370 if(!this.canvasLoaded){
26374 var imageCanvas = document.createElement("canvas");
26376 var imageContext = imageCanvas.getContext("2d");
26378 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26379 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26381 var center = imageCanvas.width / 2;
26383 imageContext.translate(center, center);
26385 imageContext.rotate(this.rotate * Math.PI / 180);
26387 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26389 var canvas = document.createElement("canvas");
26391 var context = canvas.getContext("2d");
26393 canvas.width = this.minWidth;
26394 canvas.height = this.minHeight;
26396 switch (this.rotate) {
26399 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26400 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26402 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26403 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26405 var targetWidth = this.minWidth - 2 * x;
26406 var targetHeight = this.minHeight - 2 * y;
26410 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26411 scale = targetWidth / width;
26414 if(x > 0 && y == 0){
26415 scale = targetHeight / height;
26418 if(x > 0 && y > 0){
26419 scale = targetWidth / width;
26421 if(width < height){
26422 scale = targetHeight / height;
26426 context.scale(scale, scale);
26428 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26429 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26431 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26432 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26434 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26439 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26440 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26442 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26443 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26445 var targetWidth = this.minWidth - 2 * x;
26446 var targetHeight = this.minHeight - 2 * y;
26450 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26451 scale = targetWidth / width;
26454 if(x > 0 && y == 0){
26455 scale = targetHeight / height;
26458 if(x > 0 && y > 0){
26459 scale = targetWidth / width;
26461 if(width < height){
26462 scale = targetHeight / height;
26466 context.scale(scale, scale);
26468 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26469 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26471 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26472 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26474 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26476 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26481 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26482 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26484 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26485 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26487 var targetWidth = this.minWidth - 2 * x;
26488 var targetHeight = this.minHeight - 2 * y;
26492 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26493 scale = targetWidth / width;
26496 if(x > 0 && y == 0){
26497 scale = targetHeight / height;
26500 if(x > 0 && y > 0){
26501 scale = targetWidth / width;
26503 if(width < height){
26504 scale = targetHeight / height;
26508 context.scale(scale, scale);
26510 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26511 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26513 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26514 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26516 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26517 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26519 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26524 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26525 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26527 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26528 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26530 var targetWidth = this.minWidth - 2 * x;
26531 var targetHeight = this.minHeight - 2 * y;
26535 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26536 scale = targetWidth / width;
26539 if(x > 0 && y == 0){
26540 scale = targetHeight / height;
26543 if(x > 0 && y > 0){
26544 scale = targetWidth / width;
26546 if(width < height){
26547 scale = targetHeight / height;
26551 context.scale(scale, scale);
26553 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26554 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26556 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26557 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26559 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26561 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26568 this.cropData = canvas.toDataURL(this.cropType);
26570 if(this.fireEvent('crop', this, this.cropData) !== false){
26571 this.process(this.file, this.cropData);
26578 setThumbBoxSize : function()
26582 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26583 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26584 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26586 this.minWidth = width;
26587 this.minHeight = height;
26589 if(this.rotate == 90 || this.rotate == 270){
26590 this.minWidth = height;
26591 this.minHeight = width;
26596 width = Math.ceil(this.minWidth * height / this.minHeight);
26598 if(this.minWidth > this.minHeight){
26600 height = Math.ceil(this.minHeight * width / this.minWidth);
26603 this.thumbEl.setStyle({
26604 width : width + 'px',
26605 height : height + 'px'
26612 setThumbBoxPosition : function()
26614 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26615 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26617 this.thumbEl.setLeft(x);
26618 this.thumbEl.setTop(y);
26622 baseRotateLevel : function()
26624 this.baseRotate = 1;
26627 typeof(this.exif) != 'undefined' &&
26628 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26629 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26631 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26634 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26638 baseScaleLevel : function()
26642 if(this.isDocument){
26644 if(this.baseRotate == 6 || this.baseRotate == 8){
26646 height = this.thumbEl.getHeight();
26647 this.baseScale = height / this.imageEl.OriginWidth;
26649 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26650 width = this.thumbEl.getWidth();
26651 this.baseScale = width / this.imageEl.OriginHeight;
26657 height = this.thumbEl.getHeight();
26658 this.baseScale = height / this.imageEl.OriginHeight;
26660 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26661 width = this.thumbEl.getWidth();
26662 this.baseScale = width / this.imageEl.OriginWidth;
26668 if(this.baseRotate == 6 || this.baseRotate == 8){
26670 width = this.thumbEl.getHeight();
26671 this.baseScale = width / this.imageEl.OriginHeight;
26673 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
26674 height = this.thumbEl.getWidth();
26675 this.baseScale = height / this.imageEl.OriginHeight;
26678 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26679 height = this.thumbEl.getWidth();
26680 this.baseScale = height / this.imageEl.OriginHeight;
26682 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
26683 width = this.thumbEl.getHeight();
26684 this.baseScale = width / this.imageEl.OriginWidth;
26691 width = this.thumbEl.getWidth();
26692 this.baseScale = width / this.imageEl.OriginWidth;
26694 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26695 height = this.thumbEl.getHeight();
26696 this.baseScale = height / this.imageEl.OriginHeight;
26699 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26701 height = this.thumbEl.getHeight();
26702 this.baseScale = height / this.imageEl.OriginHeight;
26704 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26705 width = this.thumbEl.getWidth();
26706 this.baseScale = width / this.imageEl.OriginWidth;
26714 getScaleLevel : function()
26716 return this.baseScale * Math.pow(1.1, this.scale);
26719 onTouchStart : function(e)
26721 if(!this.canvasLoaded){
26722 this.beforeSelectFile(e);
26726 var touches = e.browserEvent.touches;
26732 if(touches.length == 1){
26733 this.onMouseDown(e);
26737 if(touches.length != 2){
26743 for(var i = 0, finger; finger = touches[i]; i++){
26744 coords.push(finger.pageX, finger.pageY);
26747 var x = Math.pow(coords[0] - coords[2], 2);
26748 var y = Math.pow(coords[1] - coords[3], 2);
26750 this.startDistance = Math.sqrt(x + y);
26752 this.startScale = this.scale;
26754 this.pinching = true;
26755 this.dragable = false;
26759 onTouchMove : function(e)
26761 if(!this.pinching && !this.dragable){
26765 var touches = e.browserEvent.touches;
26772 this.onMouseMove(e);
26778 for(var i = 0, finger; finger = touches[i]; i++){
26779 coords.push(finger.pageX, finger.pageY);
26782 var x = Math.pow(coords[0] - coords[2], 2);
26783 var y = Math.pow(coords[1] - coords[3], 2);
26785 this.endDistance = Math.sqrt(x + y);
26787 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26789 if(!this.zoomable()){
26790 this.scale = this.startScale;
26798 onTouchEnd : function(e)
26800 this.pinching = false;
26801 this.dragable = false;
26805 process : function(file, crop)
26808 this.maskEl.mask(this.loadingText);
26811 this.xhr = new XMLHttpRequest();
26813 file.xhr = this.xhr;
26815 this.xhr.open(this.method, this.url, true);
26818 "Accept": "application/json",
26819 "Cache-Control": "no-cache",
26820 "X-Requested-With": "XMLHttpRequest"
26823 for (var headerName in headers) {
26824 var headerValue = headers[headerName];
26826 this.xhr.setRequestHeader(headerName, headerValue);
26832 this.xhr.onload = function()
26834 _this.xhrOnLoad(_this.xhr);
26837 this.xhr.onerror = function()
26839 _this.xhrOnError(_this.xhr);
26842 var formData = new FormData();
26844 formData.append('returnHTML', 'NO');
26847 formData.append('crop', crop);
26850 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26851 formData.append(this.paramName, file, file.name);
26854 if(typeof(file.filename) != 'undefined'){
26855 formData.append('filename', file.filename);
26858 if(typeof(file.mimetype) != 'undefined'){
26859 formData.append('mimetype', file.mimetype);
26862 if(this.fireEvent('arrange', this, formData) != false){
26863 this.xhr.send(formData);
26867 xhrOnLoad : function(xhr)
26870 this.maskEl.unmask();
26873 if (xhr.readyState !== 4) {
26874 this.fireEvent('exception', this, xhr);
26878 var response = Roo.decode(xhr.responseText);
26880 if(!response.success){
26881 this.fireEvent('exception', this, xhr);
26885 var response = Roo.decode(xhr.responseText);
26887 this.fireEvent('upload', this, response);
26891 xhrOnError : function()
26894 this.maskEl.unmask();
26897 Roo.log('xhr on error');
26899 var response = Roo.decode(xhr.responseText);
26905 prepare : function(file)
26908 this.maskEl.mask(this.loadingText);
26914 if(typeof(file) === 'string'){
26915 this.loadCanvas(file);
26919 if(!file || !this.urlAPI){
26924 this.cropType = file.type;
26928 if(this.fireEvent('prepare', this, this.file) != false){
26930 var reader = new FileReader();
26932 reader.onload = function (e) {
26933 if (e.target.error) {
26934 Roo.log(e.target.error);
26938 var buffer = e.target.result,
26939 dataView = new DataView(buffer),
26941 maxOffset = dataView.byteLength - 4,
26945 if (dataView.getUint16(0) === 0xffd8) {
26946 while (offset < maxOffset) {
26947 markerBytes = dataView.getUint16(offset);
26949 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26950 markerLength = dataView.getUint16(offset + 2) + 2;
26951 if (offset + markerLength > dataView.byteLength) {
26952 Roo.log('Invalid meta data: Invalid segment size.');
26956 if(markerBytes == 0xffe1){
26957 _this.parseExifData(
26964 offset += markerLength;
26974 var url = _this.urlAPI.createObjectURL(_this.file);
26976 _this.loadCanvas(url);
26981 reader.readAsArrayBuffer(this.file);
26987 parseExifData : function(dataView, offset, length)
26989 var tiffOffset = offset + 10,
26993 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26994 // No Exif data, might be XMP data instead
26998 // Check for the ASCII code for "Exif" (0x45786966):
26999 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27000 // No Exif data, might be XMP data instead
27003 if (tiffOffset + 8 > dataView.byteLength) {
27004 Roo.log('Invalid Exif data: Invalid segment size.');
27007 // Check for the two null bytes:
27008 if (dataView.getUint16(offset + 8) !== 0x0000) {
27009 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27012 // Check the byte alignment:
27013 switch (dataView.getUint16(tiffOffset)) {
27015 littleEndian = true;
27018 littleEndian = false;
27021 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27024 // Check for the TIFF tag marker (0x002A):
27025 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27026 Roo.log('Invalid Exif data: Missing TIFF marker.');
27029 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27030 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27032 this.parseExifTags(
27035 tiffOffset + dirOffset,
27040 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27045 if (dirOffset + 6 > dataView.byteLength) {
27046 Roo.log('Invalid Exif data: Invalid directory offset.');
27049 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27050 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27051 if (dirEndOffset + 4 > dataView.byteLength) {
27052 Roo.log('Invalid Exif data: Invalid directory size.');
27055 for (i = 0; i < tagsNumber; i += 1) {
27059 dirOffset + 2 + 12 * i, // tag offset
27063 // Return the offset to the next directory:
27064 return dataView.getUint32(dirEndOffset, littleEndian);
27067 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27069 var tag = dataView.getUint16(offset, littleEndian);
27071 this.exif[tag] = this.getExifValue(
27075 dataView.getUint16(offset + 2, littleEndian), // tag type
27076 dataView.getUint32(offset + 4, littleEndian), // tag length
27081 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27083 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27092 Roo.log('Invalid Exif data: Invalid tag type.');
27096 tagSize = tagType.size * length;
27097 // Determine if the value is contained in the dataOffset bytes,
27098 // or if the value at the dataOffset is a pointer to the actual data:
27099 dataOffset = tagSize > 4 ?
27100 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27101 if (dataOffset + tagSize > dataView.byteLength) {
27102 Roo.log('Invalid Exif data: Invalid data offset.');
27105 if (length === 1) {
27106 return tagType.getValue(dataView, dataOffset, littleEndian);
27109 for (i = 0; i < length; i += 1) {
27110 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27113 if (tagType.ascii) {
27115 // Concatenate the chars:
27116 for (i = 0; i < values.length; i += 1) {
27118 // Ignore the terminating NULL byte(s):
27119 if (c === '\u0000') {
27131 Roo.apply(Roo.bootstrap.UploadCropbox, {
27133 'Orientation': 0x0112
27137 1: 0, //'top-left',
27139 3: 180, //'bottom-right',
27140 // 4: 'bottom-left',
27142 6: 90, //'right-top',
27143 // 7: 'right-bottom',
27144 8: 270 //'left-bottom'
27148 // byte, 8-bit unsigned int:
27150 getValue: function (dataView, dataOffset) {
27151 return dataView.getUint8(dataOffset);
27155 // ascii, 8-bit byte:
27157 getValue: function (dataView, dataOffset) {
27158 return String.fromCharCode(dataView.getUint8(dataOffset));
27163 // short, 16 bit int:
27165 getValue: function (dataView, dataOffset, littleEndian) {
27166 return dataView.getUint16(dataOffset, littleEndian);
27170 // long, 32 bit int:
27172 getValue: function (dataView, dataOffset, littleEndian) {
27173 return dataView.getUint32(dataOffset, littleEndian);
27177 // rational = two long values, first is numerator, second is denominator:
27179 getValue: function (dataView, dataOffset, littleEndian) {
27180 return dataView.getUint32(dataOffset, littleEndian) /
27181 dataView.getUint32(dataOffset + 4, littleEndian);
27185 // slong, 32 bit signed int:
27187 getValue: function (dataView, dataOffset, littleEndian) {
27188 return dataView.getInt32(dataOffset, littleEndian);
27192 // srational, two slongs, first is numerator, second is denominator:
27194 getValue: function (dataView, dataOffset, littleEndian) {
27195 return dataView.getInt32(dataOffset, littleEndian) /
27196 dataView.getInt32(dataOffset + 4, littleEndian);
27206 cls : 'btn-group roo-upload-cropbox-rotate-left',
27207 action : 'rotate-left',
27211 cls : 'btn btn-default',
27212 html : '<i class="fa fa-undo"></i>'
27218 cls : 'btn-group roo-upload-cropbox-picture',
27219 action : 'picture',
27223 cls : 'btn btn-default',
27224 html : '<i class="fa fa-picture-o"></i>'
27230 cls : 'btn-group roo-upload-cropbox-rotate-right',
27231 action : 'rotate-right',
27235 cls : 'btn btn-default',
27236 html : '<i class="fa fa-repeat"></i>'
27244 cls : 'btn-group roo-upload-cropbox-rotate-left',
27245 action : 'rotate-left',
27249 cls : 'btn btn-default',
27250 html : '<i class="fa fa-undo"></i>'
27256 cls : 'btn-group roo-upload-cropbox-download',
27257 action : 'download',
27261 cls : 'btn btn-default',
27262 html : '<i class="fa fa-download"></i>'
27268 cls : 'btn-group roo-upload-cropbox-crop',
27273 cls : 'btn btn-default',
27274 html : '<i class="fa fa-crop"></i>'
27280 cls : 'btn-group roo-upload-cropbox-trash',
27285 cls : 'btn btn-default',
27286 html : '<i class="fa fa-trash"></i>'
27292 cls : 'btn-group roo-upload-cropbox-rotate-right',
27293 action : 'rotate-right',
27297 cls : 'btn btn-default',
27298 html : '<i class="fa fa-repeat"></i>'
27306 cls : 'btn-group roo-upload-cropbox-rotate-left',
27307 action : 'rotate-left',
27311 cls : 'btn btn-default',
27312 html : '<i class="fa fa-undo"></i>'
27318 cls : 'btn-group roo-upload-cropbox-rotate-right',
27319 action : 'rotate-right',
27323 cls : 'btn btn-default',
27324 html : '<i class="fa fa-repeat"></i>'
27337 * @class Roo.bootstrap.DocumentManager
27338 * @extends Roo.bootstrap.Component
27339 * Bootstrap DocumentManager class
27340 * @cfg {String} paramName default 'imageUpload'
27341 * @cfg {String} method default POST
27342 * @cfg {String} url action url
27343 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27344 * @cfg {Boolean} multiple multiple upload default true
27345 * @cfg {Number} thumbSize default 300
27346 * @cfg {String} fieldLabel
27347 * @cfg {Number} labelWidth default 4
27348 * @cfg {String} labelAlign (left|top) default left
27349 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27352 * Create a new DocumentManager
27353 * @param {Object} config The config object
27356 Roo.bootstrap.DocumentManager = function(config){
27357 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27362 * Fire when initial the DocumentManager
27363 * @param {Roo.bootstrap.DocumentManager} this
27368 * inspect selected file
27369 * @param {Roo.bootstrap.DocumentManager} this
27370 * @param {File} file
27375 * Fire when xhr load exception
27376 * @param {Roo.bootstrap.DocumentManager} this
27377 * @param {XMLHttpRequest} xhr
27379 "exception" : true,
27382 * prepare the form data
27383 * @param {Roo.bootstrap.DocumentManager} this
27384 * @param {Object} formData
27389 * Fire when remove the file
27390 * @param {Roo.bootstrap.DocumentManager} this
27391 * @param {Object} file
27396 * Fire after refresh the file
27397 * @param {Roo.bootstrap.DocumentManager} this
27402 * Fire after click the image
27403 * @param {Roo.bootstrap.DocumentManager} this
27404 * @param {Object} file
27409 * Fire when upload a image and editable set to true
27410 * @param {Roo.bootstrap.DocumentManager} this
27411 * @param {Object} file
27415 * @event beforeselectfile
27416 * Fire before select file
27417 * @param {Roo.bootstrap.DocumentManager} this
27419 "beforeselectfile" : true,
27422 * Fire before process file
27423 * @param {Roo.bootstrap.DocumentManager} this
27424 * @param {Object} file
27431 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27440 paramName : 'imageUpload',
27443 labelAlign : 'left',
27450 getAutoCreate : function()
27452 var managerWidget = {
27454 cls : 'roo-document-manager',
27458 cls : 'roo-document-manager-selector',
27463 cls : 'roo-document-manager-uploader',
27467 cls : 'roo-document-manager-upload-btn',
27468 html : '<i class="fa fa-plus"></i>'
27479 cls : 'column col-md-12',
27484 if(this.fieldLabel.length){
27489 cls : 'column col-md-12',
27490 html : this.fieldLabel
27494 cls : 'column col-md-12',
27499 if(this.labelAlign == 'left'){
27503 cls : 'column col-md-' + this.labelWidth,
27504 html : this.fieldLabel
27508 cls : 'column col-md-' + (12 - this.labelWidth),
27518 cls : 'row clearfix',
27526 initEvents : function()
27528 this.managerEl = this.el.select('.roo-document-manager', true).first();
27529 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27531 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27532 this.selectorEl.hide();
27535 this.selectorEl.attr('multiple', 'multiple');
27538 this.selectorEl.on('change', this.onFileSelected, this);
27540 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27541 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27543 this.uploader.on('click', this.onUploaderClick, this);
27545 this.renderProgressDialog();
27549 window.addEventListener("resize", function() { _this.refresh(); } );
27551 this.fireEvent('initial', this);
27554 renderProgressDialog : function()
27558 this.progressDialog = new Roo.bootstrap.Modal({
27559 cls : 'roo-document-manager-progress-dialog',
27560 allow_close : false,
27570 btnclick : function() {
27571 _this.uploadCancel();
27577 this.progressDialog.render(Roo.get(document.body));
27579 this.progress = new Roo.bootstrap.Progress({
27580 cls : 'roo-document-manager-progress',
27585 this.progress.render(this.progressDialog.getChildContainer());
27587 this.progressBar = new Roo.bootstrap.ProgressBar({
27588 cls : 'roo-document-manager-progress-bar',
27591 aria_valuemax : 12,
27595 this.progressBar.render(this.progress.getChildContainer());
27598 onUploaderClick : function(e)
27600 e.preventDefault();
27602 if(this.fireEvent('beforeselectfile', this) != false){
27603 this.selectorEl.dom.click();
27608 onFileSelected : function(e)
27610 e.preventDefault();
27612 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27616 Roo.each(this.selectorEl.dom.files, function(file){
27617 if(this.fireEvent('inspect', this, file) != false){
27618 this.files.push(file);
27628 this.selectorEl.dom.value = '';
27630 if(!this.files.length){
27634 if(this.boxes > 0 && this.files.length > this.boxes){
27635 this.files = this.files.slice(0, this.boxes);
27638 this.uploader.show();
27640 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27641 this.uploader.hide();
27650 Roo.each(this.files, function(file){
27652 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27653 var f = this.renderPreview(file);
27658 if(file.type.indexOf('image') != -1){
27659 this.delegates.push(
27661 _this.process(file);
27662 }).createDelegate(this)
27670 _this.process(file);
27671 }).createDelegate(this)
27676 this.files = files;
27678 this.delegates = this.delegates.concat(docs);
27680 if(!this.delegates.length){
27685 this.progressBar.aria_valuemax = this.delegates.length;
27692 arrange : function()
27694 if(!this.delegates.length){
27695 this.progressDialog.hide();
27700 var delegate = this.delegates.shift();
27702 this.progressDialog.show();
27704 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27706 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27711 refresh : function()
27713 this.uploader.show();
27715 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27716 this.uploader.hide();
27719 Roo.isTouch ? this.closable(false) : this.closable(true);
27721 this.fireEvent('refresh', this);
27724 onRemove : function(e, el, o)
27726 e.preventDefault();
27728 this.fireEvent('remove', this, o);
27732 remove : function(o)
27736 Roo.each(this.files, function(file){
27737 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27746 this.files = files;
27753 Roo.each(this.files, function(file){
27758 file.target.remove();
27767 onClick : function(e, el, o)
27769 e.preventDefault();
27771 this.fireEvent('click', this, o);
27775 closable : function(closable)
27777 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27779 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27791 xhrOnLoad : function(xhr)
27793 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27797 if (xhr.readyState !== 4) {
27799 this.fireEvent('exception', this, xhr);
27803 var response = Roo.decode(xhr.responseText);
27805 if(!response.success){
27807 this.fireEvent('exception', this, xhr);
27811 var file = this.renderPreview(response.data);
27813 this.files.push(file);
27819 xhrOnError : function(xhr)
27821 Roo.log('xhr on error');
27823 var response = Roo.decode(xhr.responseText);
27830 process : function(file)
27832 if(this.fireEvent('process', this, file) !== false){
27833 if(this.editable && file.type.indexOf('image') != -1){
27834 this.fireEvent('edit', this, file);
27838 this.uploadStart(file, false);
27845 uploadStart : function(file, crop)
27847 this.xhr = new XMLHttpRequest();
27849 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27854 file.xhr = this.xhr;
27856 this.managerEl.createChild({
27858 cls : 'roo-document-manager-loading',
27862 tooltip : file.name,
27863 cls : 'roo-document-manager-thumb',
27864 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27870 this.xhr.open(this.method, this.url, true);
27873 "Accept": "application/json",
27874 "Cache-Control": "no-cache",
27875 "X-Requested-With": "XMLHttpRequest"
27878 for (var headerName in headers) {
27879 var headerValue = headers[headerName];
27881 this.xhr.setRequestHeader(headerName, headerValue);
27887 this.xhr.onload = function()
27889 _this.xhrOnLoad(_this.xhr);
27892 this.xhr.onerror = function()
27894 _this.xhrOnError(_this.xhr);
27897 var formData = new FormData();
27899 formData.append('returnHTML', 'NO');
27902 formData.append('crop', crop);
27905 formData.append(this.paramName, file, file.name);
27907 if(this.fireEvent('prepare', this, formData) != false){
27908 this.xhr.send(formData);
27912 uploadCancel : function()
27919 this.delegates = [];
27921 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27928 renderPreview : function(file)
27930 if(typeof(file.target) != 'undefined' && file.target){
27934 var previewEl = this.managerEl.createChild({
27936 cls : 'roo-document-manager-preview',
27940 tooltip : file.filename,
27941 cls : 'roo-document-manager-thumb',
27942 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27947 html : '<i class="fa fa-times-circle"></i>'
27952 var close = previewEl.select('button.close', true).first();
27954 close.on('click', this.onRemove, this, file);
27956 file.target = previewEl;
27958 var image = previewEl.select('img', true).first();
27962 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27964 image.on('click', this.onClick, this, file);
27970 onPreviewLoad : function(file, image)
27972 if(typeof(file.target) == 'undefined' || !file.target){
27976 var width = image.dom.naturalWidth || image.dom.width;
27977 var height = image.dom.naturalHeight || image.dom.height;
27979 if(width > height){
27980 file.target.addClass('wide');
27984 file.target.addClass('tall');
27989 uploadFromSource : function(file, crop)
27991 this.xhr = new XMLHttpRequest();
27993 this.managerEl.createChild({
27995 cls : 'roo-document-manager-loading',
27999 tooltip : file.name,
28000 cls : 'roo-document-manager-thumb',
28001 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28007 this.xhr.open(this.method, this.url, true);
28010 "Accept": "application/json",
28011 "Cache-Control": "no-cache",
28012 "X-Requested-With": "XMLHttpRequest"
28015 for (var headerName in headers) {
28016 var headerValue = headers[headerName];
28018 this.xhr.setRequestHeader(headerName, headerValue);
28024 this.xhr.onload = function()
28026 _this.xhrOnLoad(_this.xhr);
28029 this.xhr.onerror = function()
28031 _this.xhrOnError(_this.xhr);
28034 var formData = new FormData();
28036 formData.append('returnHTML', 'NO');
28038 formData.append('crop', crop);
28040 if(typeof(file.filename) != 'undefined'){
28041 formData.append('filename', file.filename);
28044 if(typeof(file.mimetype) != 'undefined'){
28045 formData.append('mimetype', file.mimetype);
28048 if(this.fireEvent('prepare', this, formData) != false){
28049 this.xhr.send(formData);
28059 * @class Roo.bootstrap.DocumentViewer
28060 * @extends Roo.bootstrap.Component
28061 * Bootstrap DocumentViewer class
28064 * Create a new DocumentViewer
28065 * @param {Object} config The config object
28068 Roo.bootstrap.DocumentViewer = function(config){
28069 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28074 * Fire after initEvent
28075 * @param {Roo.bootstrap.DocumentViewer} this
28081 * @param {Roo.bootstrap.DocumentViewer} this
28086 * Fire after trash button
28087 * @param {Roo.bootstrap.DocumentViewer} this
28094 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28096 getAutoCreate : function()
28100 cls : 'roo-document-viewer',
28104 cls : 'roo-document-viewer-body',
28108 cls : 'roo-document-viewer-thumb',
28112 cls : 'roo-document-viewer-image'
28120 cls : 'roo-document-viewer-footer',
28123 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28131 cls : 'btn btn-default roo-document-viewer-trash',
28132 html : '<i class="fa fa-trash"></i>'
28145 initEvents : function()
28148 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28149 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28151 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28152 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28154 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28155 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28157 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28158 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28160 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28161 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28163 this.bodyEl.on('click', this.onClick, this);
28165 this.trashBtn.on('click', this.onTrash, this);
28169 initial : function()
28171 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
28174 this.fireEvent('initial', this);
28178 onClick : function(e)
28180 e.preventDefault();
28182 this.fireEvent('click', this);
28185 onTrash : function(e)
28187 e.preventDefault();
28189 this.fireEvent('trash', this);
28201 * @class Roo.bootstrap.NavProgressBar
28202 * @extends Roo.bootstrap.Component
28203 * Bootstrap NavProgressBar class
28206 * Create a new nav progress bar
28207 * @param {Object} config The config object
28210 Roo.bootstrap.NavProgressBar = function(config){
28211 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28213 this.bullets = this.bullets || [];
28215 // Roo.bootstrap.NavProgressBar.register(this);
28219 * Fires when the active item changes
28220 * @param {Roo.bootstrap.NavProgressBar} this
28221 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28222 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28229 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28234 getAutoCreate : function()
28236 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28240 cls : 'roo-navigation-bar-group',
28244 cls : 'roo-navigation-top-bar'
28248 cls : 'roo-navigation-bullets-bar',
28252 cls : 'roo-navigation-bar'
28259 cls : 'roo-navigation-bottom-bar'
28269 initEvents: function()
28274 onRender : function(ct, position)
28276 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28278 if(this.bullets.length){
28279 Roo.each(this.bullets, function(b){
28288 addItem : function(cfg)
28290 var item = new Roo.bootstrap.NavProgressItem(cfg);
28292 item.parentId = this.id;
28293 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28296 var top = new Roo.bootstrap.Element({
28298 cls : 'roo-navigation-bar-text'
28301 var bottom = new Roo.bootstrap.Element({
28303 cls : 'roo-navigation-bar-text'
28306 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28307 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28309 var topText = new Roo.bootstrap.Element({
28311 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28314 var bottomText = new Roo.bootstrap.Element({
28316 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28319 topText.onRender(top.el, null);
28320 bottomText.onRender(bottom.el, null);
28323 item.bottomEl = bottom;
28326 this.barItems.push(item);
28331 getActive : function()
28333 var active = false;
28335 Roo.each(this.barItems, function(v){
28337 if (!v.isActive()) {
28349 setActiveItem : function(item)
28353 Roo.each(this.barItems, function(v){
28354 if (v.rid == item.rid) {
28358 if (v.isActive()) {
28359 v.setActive(false);
28364 item.setActive(true);
28366 this.fireEvent('changed', this, item, prev);
28369 getBarItem: function(rid)
28373 Roo.each(this.barItems, function(e) {
28374 if (e.rid != rid) {
28385 indexOfItem : function(item)
28389 Roo.each(this.barItems, function(v, i){
28391 if (v.rid != item.rid) {
28402 setActiveNext : function()
28404 var i = this.indexOfItem(this.getActive());
28406 if (i > this.barItems.length) {
28410 this.setActiveItem(this.barItems[i+1]);
28413 setActivePrev : function()
28415 var i = this.indexOfItem(this.getActive());
28421 this.setActiveItem(this.barItems[i-1]);
28424 format : function()
28426 if(!this.barItems.length){
28430 var width = 100 / this.barItems.length;
28432 Roo.each(this.barItems, function(i){
28433 i.el.setStyle('width', width + '%');
28434 i.topEl.el.setStyle('width', width + '%');
28435 i.bottomEl.el.setStyle('width', width + '%');
28444 * Nav Progress Item
28449 * @class Roo.bootstrap.NavProgressItem
28450 * @extends Roo.bootstrap.Component
28451 * Bootstrap NavProgressItem class
28452 * @cfg {String} rid the reference id
28453 * @cfg {Boolean} active (true|false) Is item active default false
28454 * @cfg {Boolean} disabled (true|false) Is item active default false
28455 * @cfg {String} html
28456 * @cfg {String} position (top|bottom) text position default bottom
28457 * @cfg {String} icon show icon instead of number
28460 * Create a new NavProgressItem
28461 * @param {Object} config The config object
28463 Roo.bootstrap.NavProgressItem = function(config){
28464 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28469 * The raw click event for the entire grid.
28470 * @param {Roo.bootstrap.NavProgressItem} this
28471 * @param {Roo.EventObject} e
28478 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28484 position : 'bottom',
28487 getAutoCreate : function()
28489 var iconCls = 'roo-navigation-bar-item-icon';
28491 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28495 cls: 'roo-navigation-bar-item',
28505 cfg.cls += ' active';
28508 cfg.cls += ' disabled';
28514 disable : function()
28516 this.setDisabled(true);
28519 enable : function()
28521 this.setDisabled(false);
28524 initEvents: function()
28526 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28528 this.iconEl.on('click', this.onClick, this);
28531 onClick : function(e)
28533 e.preventDefault();
28539 if(this.fireEvent('click', this, e) === false){
28543 this.parent().setActiveItem(this);
28546 isActive: function ()
28548 return this.active;
28551 setActive : function(state)
28553 if(this.active == state){
28557 this.active = state;
28560 this.el.addClass('active');
28564 this.el.removeClass('active');
28569 setDisabled : function(state)
28571 if(this.disabled == state){
28575 this.disabled = state;
28578 this.el.addClass('disabled');
28582 this.el.removeClass('disabled');
28585 tooltipEl : function()
28587 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
28600 * @class Roo.bootstrap.FieldLabel
28601 * @extends Roo.bootstrap.Component
28602 * Bootstrap FieldLabel class
28603 * @cfg {String} html contents of the element
28604 * @cfg {String} tag tag of the element default label
28605 * @cfg {String} cls class of the element
28606 * @cfg {String} target label target
28607 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
28608 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
28609 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
28610 * @cfg {String} iconTooltip default "This field is required"
28613 * Create a new FieldLabel
28614 * @param {Object} config The config object
28617 Roo.bootstrap.FieldLabel = function(config){
28618 Roo.bootstrap.Element.superclass.constructor.call(this, config);
28623 * Fires after the field has been marked as invalid.
28624 * @param {Roo.form.FieldLabel} this
28625 * @param {String} msg The validation message
28630 * Fires after the field has been validated with no errors.
28631 * @param {Roo.form.FieldLabel} this
28637 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
28644 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
28645 validClass : 'text-success fa fa-lg fa-check',
28646 iconTooltip : 'This field is required',
28648 getAutoCreate : function(){
28652 cls : 'roo-bootstrap-field-label ' + this.cls,
28658 tooltip : this.iconTooltip
28670 initEvents: function()
28672 Roo.bootstrap.Element.superclass.initEvents.call(this);
28674 this.iconEl = this.el.select('i', true).first();
28676 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
28678 Roo.bootstrap.FieldLabel.register(this);
28682 * Mark this field as valid
28684 markValid : function()
28686 this.iconEl.show();
28688 this.iconEl.removeClass(this.invalidClass);
28690 this.iconEl.addClass(this.validClass);
28692 this.fireEvent('valid', this);
28696 * Mark this field as invalid
28697 * @param {String} msg The validation message
28699 markInvalid : function(msg)
28701 this.iconEl.show();
28703 this.iconEl.removeClass(this.validClass);
28705 this.iconEl.addClass(this.invalidClass);
28707 this.fireEvent('invalid', this, msg);
28713 Roo.apply(Roo.bootstrap.FieldLabel, {
28718 * register a FieldLabel Group
28719 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28721 register : function(label)
28723 if(this.groups.hasOwnProperty(label.target)){
28727 this.groups[label.target] = label;
28731 * fetch a FieldLabel Group based on the target
28732 * @param {string} target
28733 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28735 get: function(target) {
28736 if (typeof(this.groups[target]) == 'undefined') {
28740 return this.groups[target] ;
28749 * page DateSplitField.
28755 * @class Roo.bootstrap.DateSplitField
28756 * @extends Roo.bootstrap.Component
28757 * Bootstrap DateSplitField class
28758 * @cfg {string} fieldLabel - the label associated
28759 * @cfg {Number} labelWidth set the width of label (0-12)
28760 * @cfg {String} labelAlign (top|left)
28761 * @cfg {Boolean} dayAllowBlank (true|false) default false
28762 * @cfg {Boolean} monthAllowBlank (true|false) default false
28763 * @cfg {Boolean} yearAllowBlank (true|false) default false
28764 * @cfg {string} dayPlaceholder
28765 * @cfg {string} monthPlaceholder
28766 * @cfg {string} yearPlaceholder
28767 * @cfg {string} dayFormat default 'd'
28768 * @cfg {string} monthFormat default 'm'
28769 * @cfg {string} yearFormat default 'Y'
28773 * Create a new DateSplitField
28774 * @param {Object} config The config object
28777 Roo.bootstrap.DateSplitField = function(config){
28778 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28784 * getting the data of years
28785 * @param {Roo.bootstrap.DateSplitField} this
28786 * @param {Object} years
28791 * getting the data of days
28792 * @param {Roo.bootstrap.DateSplitField} this
28793 * @param {Object} days
28798 * Fires after the field has been marked as invalid.
28799 * @param {Roo.form.Field} this
28800 * @param {String} msg The validation message
28805 * Fires after the field has been validated with no errors.
28806 * @param {Roo.form.Field} this
28812 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28815 labelAlign : 'top',
28817 dayAllowBlank : false,
28818 monthAllowBlank : false,
28819 yearAllowBlank : false,
28820 dayPlaceholder : '',
28821 monthPlaceholder : '',
28822 yearPlaceholder : '',
28826 isFormField : true,
28828 getAutoCreate : function()
28832 cls : 'row roo-date-split-field-group',
28837 cls : 'form-hidden-field roo-date-split-field-group-value',
28843 if(this.fieldLabel){
28846 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28850 html : this.fieldLabel
28856 Roo.each(['day', 'month', 'year'], function(t){
28859 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28866 inputEl: function ()
28868 return this.el.select('.roo-date-split-field-group-value', true).first();
28871 onRender : function(ct, position)
28875 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28877 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28879 this.dayField = new Roo.bootstrap.ComboBox({
28880 allowBlank : this.dayAllowBlank,
28881 alwaysQuery : true,
28882 displayField : 'value',
28885 forceSelection : true,
28887 placeholder : this.dayPlaceholder,
28888 selectOnFocus : true,
28889 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28890 triggerAction : 'all',
28892 valueField : 'value',
28893 store : new Roo.data.SimpleStore({
28894 data : (function() {
28896 _this.fireEvent('days', _this, days);
28899 fields : [ 'value' ]
28902 select : function (_self, record, index)
28904 _this.setValue(_this.getValue());
28909 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28911 this.monthField = new Roo.bootstrap.MonthField({
28912 after : '<i class=\"fa fa-calendar\"></i>',
28913 allowBlank : this.monthAllowBlank,
28914 placeholder : this.monthPlaceholder,
28917 render : function (_self)
28919 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28920 e.preventDefault();
28924 select : function (_self, oldvalue, newvalue)
28926 _this.setValue(_this.getValue());
28931 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28933 this.yearField = new Roo.bootstrap.ComboBox({
28934 allowBlank : this.yearAllowBlank,
28935 alwaysQuery : true,
28936 displayField : 'value',
28939 forceSelection : true,
28941 placeholder : this.yearPlaceholder,
28942 selectOnFocus : true,
28943 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28944 triggerAction : 'all',
28946 valueField : 'value',
28947 store : new Roo.data.SimpleStore({
28948 data : (function() {
28950 _this.fireEvent('years', _this, years);
28953 fields : [ 'value' ]
28956 select : function (_self, record, index)
28958 _this.setValue(_this.getValue());
28963 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28966 setValue : function(v, format)
28968 this.inputEl.dom.value = v;
28970 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28972 var d = Date.parseDate(v, f);
28979 this.setDay(d.format(this.dayFormat));
28980 this.setMonth(d.format(this.monthFormat));
28981 this.setYear(d.format(this.yearFormat));
28988 setDay : function(v)
28990 this.dayField.setValue(v);
28991 this.inputEl.dom.value = this.getValue();
28996 setMonth : function(v)
28998 this.monthField.setValue(v, true);
28999 this.inputEl.dom.value = this.getValue();
29004 setYear : function(v)
29006 this.yearField.setValue(v);
29007 this.inputEl.dom.value = this.getValue();
29012 getDay : function()
29014 return this.dayField.getValue();
29017 getMonth : function()
29019 return this.monthField.getValue();
29022 getYear : function()
29024 return this.yearField.getValue();
29027 getValue : function()
29029 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29031 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29041 this.inputEl.dom.value = '';
29046 validate : function()
29048 var d = this.dayField.validate();
29049 var m = this.monthField.validate();
29050 var y = this.yearField.validate();
29055 (!this.dayAllowBlank && !d) ||
29056 (!this.monthAllowBlank && !m) ||
29057 (!this.yearAllowBlank && !y)
29062 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29071 this.markInvalid();
29076 markValid : function()
29079 var label = this.el.select('label', true).first();
29080 var icon = this.el.select('i.fa-star', true).first();
29086 this.fireEvent('valid', this);
29090 * Mark this field as invalid
29091 * @param {String} msg The validation message
29093 markInvalid : function(msg)
29096 var label = this.el.select('label', true).first();
29097 var icon = this.el.select('i.fa-star', true).first();
29099 if(label && !icon){
29100 this.el.select('.roo-date-split-field-label', true).createChild({
29102 cls : 'text-danger fa fa-lg fa-star',
29103 tooltip : 'This field is required',
29104 style : 'margin-right:5px;'
29108 this.fireEvent('invalid', this, msg);
29111 clearInvalid : function()
29113 var label = this.el.select('label', true).first();
29114 var icon = this.el.select('i.fa-star', true).first();
29120 this.fireEvent('valid', this);
29123 getName: function()
29133 * http://masonry.desandro.com
29135 * The idea is to render all the bricks based on vertical width...
29137 * The original code extends 'outlayer' - we might need to use that....
29143 * @class Roo.bootstrap.LayoutMasonry
29144 * @extends Roo.bootstrap.Component
29145 * Bootstrap Layout Masonry class
29148 * Create a new Element
29149 * @param {Object} config The config object
29152 Roo.bootstrap.LayoutMasonry = function(config){
29153 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29159 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29162 * @cfg {Boolean} isLayoutInstant = no animation?
29164 isLayoutInstant : false, // needed?
29167 * @cfg {Number} boxWidth width of the columns
29172 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29177 * @cfg {Number} padWidth padding below box..
29182 * @cfg {Number} gutter gutter width..
29187 * @cfg {Number} maxCols maximum number of columns
29193 * @cfg {Boolean} isAutoInitial defalut true
29195 isAutoInitial : true,
29200 * @cfg {Boolean} isHorizontal defalut false
29202 isHorizontal : false,
29204 currentSize : null,
29210 bricks: null, //CompositeElement
29214 _isLayoutInited : false,
29216 // isAlternative : false, // only use for vertical layout...
29219 * @cfg {Number} alternativePadWidth padding below box..
29221 alternativePadWidth : 50,
29223 getAutoCreate : function(){
29227 cls: 'blog-masonary-wrapper ' + this.cls,
29229 cls : 'mas-boxes masonary'
29236 getChildContainer: function( )
29238 if (this.boxesEl) {
29239 return this.boxesEl;
29242 this.boxesEl = this.el.select('.mas-boxes').first();
29244 return this.boxesEl;
29248 initEvents : function()
29252 if(this.isAutoInitial){
29253 Roo.log('hook children rendered');
29254 this.on('childrenrendered', function() {
29255 Roo.log('children rendered');
29261 initial : function()
29263 this.currentSize = this.el.getBox(true);
29265 Roo.EventManager.onWindowResize(this.resize, this);
29267 if(!this.isAutoInitial){
29275 //this.layout.defer(500,this);
29279 resize : function()
29283 var cs = this.el.getBox(true);
29285 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29286 Roo.log("no change in with or X");
29290 this.currentSize = cs;
29296 layout : function()
29298 this._resetLayout();
29300 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29302 this.layoutItems( isInstant );
29304 this._isLayoutInited = true;
29308 _resetLayout : function()
29310 if(this.isHorizontal){
29311 this.horizontalMeasureColumns();
29315 this.verticalMeasureColumns();
29319 verticalMeasureColumns : function()
29321 this.getContainerWidth();
29323 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29324 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29328 var boxWidth = this.boxWidth + this.padWidth;
29330 if(this.containerWidth < this.boxWidth){
29331 boxWidth = this.containerWidth
29334 var containerWidth = this.containerWidth;
29336 var cols = Math.floor(containerWidth / boxWidth);
29338 this.cols = Math.max( cols, 1 );
29340 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29342 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29344 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29346 this.colWidth = boxWidth + avail - this.padWidth;
29348 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29349 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29352 horizontalMeasureColumns : function()
29354 this.getContainerWidth();
29356 var boxWidth = this.boxWidth;
29358 if(this.containerWidth < boxWidth){
29359 boxWidth = this.containerWidth;
29362 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29364 this.el.setHeight(boxWidth);
29368 getContainerWidth : function()
29370 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29373 layoutItems : function( isInstant )
29375 var items = Roo.apply([], this.bricks);
29377 if(this.isHorizontal){
29378 this._horizontalLayoutItems( items , isInstant );
29382 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29383 // this._verticalAlternativeLayoutItems( items , isInstant );
29387 this._verticalLayoutItems( items , isInstant );
29391 _verticalLayoutItems : function ( items , isInstant)
29393 if ( !items || !items.length ) {
29398 ['xs', 'xs', 'xs', 'tall'],
29399 ['xs', 'xs', 'tall'],
29400 ['xs', 'xs', 'sm'],
29401 ['xs', 'xs', 'xs'],
29407 ['sm', 'xs', 'xs'],
29411 ['tall', 'xs', 'xs', 'xs'],
29412 ['tall', 'xs', 'xs'],
29424 Roo.each(items, function(item, k){
29426 switch (item.size) {
29427 // these layouts take up a full box,
29438 boxes.push([item]);
29461 var filterPattern = function(box, length)
29469 var pattern = box.slice(0, length);
29473 Roo.each(pattern, function(i){
29474 format.push(i.size);
29477 Roo.each(standard, function(s){
29479 if(String(s) != String(format)){
29488 if(!match && length == 1){
29493 filterPattern(box, length - 1);
29497 queue.push(pattern);
29499 box = box.slice(length, box.length);
29501 filterPattern(box, 4);
29507 Roo.each(boxes, function(box, k){
29513 if(box.length == 1){
29518 filterPattern(box, 4);
29522 this._processVerticalLayoutQueue( queue, isInstant );
29526 // _verticalAlternativeLayoutItems : function( items , isInstant )
29528 // if ( !items || !items.length ) {
29532 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
29536 _horizontalLayoutItems : function ( items , isInstant)
29538 if ( !items || !items.length || items.length < 3) {
29544 var eItems = items.slice(0, 3);
29546 items = items.slice(3, items.length);
29549 ['xs', 'xs', 'xs', 'wide'],
29550 ['xs', 'xs', 'wide'],
29551 ['xs', 'xs', 'sm'],
29552 ['xs', 'xs', 'xs'],
29558 ['sm', 'xs', 'xs'],
29562 ['wide', 'xs', 'xs', 'xs'],
29563 ['wide', 'xs', 'xs'],
29576 Roo.each(items, function(item, k){
29578 switch (item.size) {
29589 boxes.push([item]);
29613 var filterPattern = function(box, length)
29621 var pattern = box.slice(0, length);
29625 Roo.each(pattern, function(i){
29626 format.push(i.size);
29629 Roo.each(standard, function(s){
29631 if(String(s) != String(format)){
29640 if(!match && length == 1){
29645 filterPattern(box, length - 1);
29649 queue.push(pattern);
29651 box = box.slice(length, box.length);
29653 filterPattern(box, 4);
29659 Roo.each(boxes, function(box, k){
29665 if(box.length == 1){
29670 filterPattern(box, 4);
29677 var pos = this.el.getBox(true);
29681 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29683 var hit_end = false;
29685 Roo.each(queue, function(box){
29689 Roo.each(box, function(b){
29691 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29701 Roo.each(box, function(b){
29703 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29706 mx = Math.max(mx, b.x);
29710 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29714 Roo.each(box, function(b){
29716 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29730 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29733 /** Sets position of item in DOM
29734 * @param {Element} item
29735 * @param {Number} x - horizontal position
29736 * @param {Number} y - vertical position
29737 * @param {Boolean} isInstant - disables transitions
29739 _processVerticalLayoutQueue : function( queue, isInstant )
29741 var pos = this.el.getBox(true);
29746 for (var i = 0; i < this.cols; i++){
29750 Roo.each(queue, function(box, k){
29752 var col = k % this.cols;
29754 Roo.each(box, function(b,kk){
29756 b.el.position('absolute');
29758 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29759 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29761 if(b.size == 'md-left' || b.size == 'md-right'){
29762 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29763 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29766 b.el.setWidth(width);
29767 b.el.setHeight(height);
29769 b.el.select('iframe',true).setSize(width,height);
29773 for (var i = 0; i < this.cols; i++){
29775 if(maxY[i] < maxY[col]){
29780 col = Math.min(col, i);
29784 x = pos.x + col * (this.colWidth + this.padWidth);
29788 var positions = [];
29790 switch (box.length){
29792 positions = this.getVerticalOneBoxColPositions(x, y, box);
29795 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29798 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29801 positions = this.getVerticalFourBoxColPositions(x, y, box);
29807 Roo.each(box, function(b,kk){
29809 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29811 var sz = b.el.getSize();
29813 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29821 for (var i = 0; i < this.cols; i++){
29822 mY = Math.max(mY, maxY[i]);
29825 this.el.setHeight(mY - pos.y);
29829 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29831 // var pos = this.el.getBox(true);
29834 // var maxX = pos.right;
29836 // var maxHeight = 0;
29838 // Roo.each(items, function(item, k){
29842 // item.el.position('absolute');
29844 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29846 // item.el.setWidth(width);
29848 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29850 // item.el.setHeight(height);
29853 // item.el.setXY([x, y], isInstant ? false : true);
29855 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29858 // y = y + height + this.alternativePadWidth;
29860 // maxHeight = maxHeight + height + this.alternativePadWidth;
29864 // this.el.setHeight(maxHeight);
29868 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29870 var pos = this.el.getBox(true);
29875 var maxX = pos.right;
29877 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29879 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29881 Roo.each(queue, function(box, k){
29883 Roo.each(box, function(b, kk){
29885 b.el.position('absolute');
29887 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29888 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29890 if(b.size == 'md-left' || b.size == 'md-right'){
29891 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29892 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29895 b.el.setWidth(width);
29896 b.el.setHeight(height);
29904 var positions = [];
29906 switch (box.length){
29908 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29911 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29914 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29917 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29923 Roo.each(box, function(b,kk){
29925 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29927 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29935 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29937 Roo.each(eItems, function(b,k){
29939 b.size = (k == 0) ? 'sm' : 'xs';
29940 b.x = (k == 0) ? 2 : 1;
29941 b.y = (k == 0) ? 2 : 1;
29943 b.el.position('absolute');
29945 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29947 b.el.setWidth(width);
29949 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29951 b.el.setHeight(height);
29955 var positions = [];
29958 x : maxX - this.unitWidth * 2 - this.gutter,
29963 x : maxX - this.unitWidth,
29964 y : minY + (this.unitWidth + this.gutter) * 2
29968 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29972 Roo.each(eItems, function(b,k){
29974 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29980 getVerticalOneBoxColPositions : function(x, y, box)
29984 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29986 if(box[0].size == 'md-left'){
29990 if(box[0].size == 'md-right'){
29995 x : x + (this.unitWidth + this.gutter) * rand,
30002 getVerticalTwoBoxColPositions : function(x, y, box)
30006 if(box[0].size == 'xs'){
30010 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30014 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30028 x : x + (this.unitWidth + this.gutter) * 2,
30029 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30036 getVerticalThreeBoxColPositions : function(x, y, box)
30040 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30048 x : x + (this.unitWidth + this.gutter) * 1,
30053 x : x + (this.unitWidth + this.gutter) * 2,
30061 if(box[0].size == 'xs' && box[1].size == 'xs'){
30070 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30074 x : x + (this.unitWidth + this.gutter) * 1,
30088 x : x + (this.unitWidth + this.gutter) * 2,
30093 x : x + (this.unitWidth + this.gutter) * 2,
30094 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30101 getVerticalFourBoxColPositions : function(x, y, box)
30105 if(box[0].size == 'xs'){
30114 y : y + (this.unitHeight + this.gutter) * 1
30119 y : y + (this.unitHeight + this.gutter) * 2
30123 x : x + (this.unitWidth + this.gutter) * 1,
30137 x : x + (this.unitWidth + this.gutter) * 2,
30142 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30143 y : y + (this.unitHeight + this.gutter) * 1
30147 x : x + (this.unitWidth + this.gutter) * 2,
30148 y : y + (this.unitWidth + this.gutter) * 2
30155 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30159 if(box[0].size == 'md-left'){
30161 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30168 if(box[0].size == 'md-right'){
30170 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30171 y : minY + (this.unitWidth + this.gutter) * 1
30177 var rand = Math.floor(Math.random() * (4 - box[0].y));
30180 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30181 y : minY + (this.unitWidth + this.gutter) * rand
30188 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30192 if(box[0].size == 'xs'){
30195 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30200 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30201 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30209 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30214 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30215 y : minY + (this.unitWidth + this.gutter) * 2
30222 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30226 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30229 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30234 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30235 y : minY + (this.unitWidth + this.gutter) * 1
30239 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30240 y : minY + (this.unitWidth + this.gutter) * 2
30247 if(box[0].size == 'xs' && box[1].size == 'xs'){
30250 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30255 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30260 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30261 y : minY + (this.unitWidth + this.gutter) * 1
30269 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30274 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30275 y : minY + (this.unitWidth + this.gutter) * 2
30279 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30280 y : minY + (this.unitWidth + this.gutter) * 2
30287 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30291 if(box[0].size == 'xs'){
30294 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30299 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30304 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),
30309 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30310 y : minY + (this.unitWidth + this.gutter) * 1
30318 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30323 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30324 y : minY + (this.unitWidth + this.gutter) * 2
30328 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30329 y : minY + (this.unitWidth + this.gutter) * 2
30333 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),
30334 y : minY + (this.unitWidth + this.gutter) * 2
30348 * http://masonry.desandro.com
30350 * The idea is to render all the bricks based on vertical width...
30352 * The original code extends 'outlayer' - we might need to use that....
30358 * @class Roo.bootstrap.LayoutMasonryAuto
30359 * @extends Roo.bootstrap.Component
30360 * Bootstrap Layout Masonry class
30363 * Create a new Element
30364 * @param {Object} config The config object
30367 Roo.bootstrap.LayoutMasonryAuto = function(config){
30368 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30371 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30374 * @cfg {Boolean} isFitWidth - resize the width..
30376 isFitWidth : false, // options..
30378 * @cfg {Boolean} isOriginLeft = left align?
30380 isOriginLeft : true,
30382 * @cfg {Boolean} isOriginTop = top align?
30384 isOriginTop : false,
30386 * @cfg {Boolean} isLayoutInstant = no animation?
30388 isLayoutInstant : false, // needed?
30390 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30392 isResizingContainer : true,
30394 * @cfg {Number} columnWidth width of the columns
30400 * @cfg {Number} maxCols maximum number of columns
30405 * @cfg {Number} padHeight padding below box..
30411 * @cfg {Boolean} isAutoInitial defalut true
30414 isAutoInitial : true,
30420 initialColumnWidth : 0,
30421 currentSize : null,
30423 colYs : null, // array.
30430 bricks: null, //CompositeElement
30431 cols : 0, // array?
30432 // element : null, // wrapped now this.el
30433 _isLayoutInited : null,
30436 getAutoCreate : function(){
30440 cls: 'blog-masonary-wrapper ' + this.cls,
30442 cls : 'mas-boxes masonary'
30449 getChildContainer: function( )
30451 if (this.boxesEl) {
30452 return this.boxesEl;
30455 this.boxesEl = this.el.select('.mas-boxes').first();
30457 return this.boxesEl;
30461 initEvents : function()
30465 if(this.isAutoInitial){
30466 Roo.log('hook children rendered');
30467 this.on('childrenrendered', function() {
30468 Roo.log('children rendered');
30475 initial : function()
30477 this.reloadItems();
30479 this.currentSize = this.el.getBox(true);
30481 /// was window resize... - let's see if this works..
30482 Roo.EventManager.onWindowResize(this.resize, this);
30484 if(!this.isAutoInitial){
30489 this.layout.defer(500,this);
30492 reloadItems: function()
30494 this.bricks = this.el.select('.masonry-brick', true);
30496 this.bricks.each(function(b) {
30497 //Roo.log(b.getSize());
30498 if (!b.attr('originalwidth')) {
30499 b.attr('originalwidth', b.getSize().width);
30504 Roo.log(this.bricks.elements.length);
30507 resize : function()
30510 var cs = this.el.getBox(true);
30512 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30513 Roo.log("no change in with or X");
30516 this.currentSize = cs;
30520 layout : function()
30523 this._resetLayout();
30524 //this._manageStamps();
30526 // don't animate first layout
30527 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30528 this.layoutItems( isInstant );
30530 // flag for initalized
30531 this._isLayoutInited = true;
30534 layoutItems : function( isInstant )
30536 //var items = this._getItemsForLayout( this.items );
30537 // original code supports filtering layout items.. we just ignore it..
30539 this._layoutItems( this.bricks , isInstant );
30541 this._postLayout();
30543 _layoutItems : function ( items , isInstant)
30545 //this.fireEvent( 'layout', this, items );
30548 if ( !items || !items.elements.length ) {
30549 // no items, emit event with empty array
30554 items.each(function(item) {
30555 Roo.log("layout item");
30557 // get x/y object from method
30558 var position = this._getItemLayoutPosition( item );
30560 position.item = item;
30561 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
30562 queue.push( position );
30565 this._processLayoutQueue( queue );
30567 /** Sets position of item in DOM
30568 * @param {Element} item
30569 * @param {Number} x - horizontal position
30570 * @param {Number} y - vertical position
30571 * @param {Boolean} isInstant - disables transitions
30573 _processLayoutQueue : function( queue )
30575 for ( var i=0, len = queue.length; i < len; i++ ) {
30576 var obj = queue[i];
30577 obj.item.position('absolute');
30578 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
30584 * Any logic you want to do after each layout,
30585 * i.e. size the container
30587 _postLayout : function()
30589 this.resizeContainer();
30592 resizeContainer : function()
30594 if ( !this.isResizingContainer ) {
30597 var size = this._getContainerSize();
30599 this.el.setSize(size.width,size.height);
30600 this.boxesEl.setSize(size.width,size.height);
30606 _resetLayout : function()
30608 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
30609 this.colWidth = this.el.getWidth();
30610 //this.gutter = this.el.getWidth();
30612 this.measureColumns();
30618 this.colYs.push( 0 );
30624 measureColumns : function()
30626 this.getContainerWidth();
30627 // if columnWidth is 0, default to outerWidth of first item
30628 if ( !this.columnWidth ) {
30629 var firstItem = this.bricks.first();
30630 Roo.log(firstItem);
30631 this.columnWidth = this.containerWidth;
30632 if (firstItem && firstItem.attr('originalwidth') ) {
30633 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
30635 // columnWidth fall back to item of first element
30636 Roo.log("set column width?");
30637 this.initialColumnWidth = this.columnWidth ;
30639 // if first elem has no width, default to size of container
30644 if (this.initialColumnWidth) {
30645 this.columnWidth = this.initialColumnWidth;
30650 // column width is fixed at the top - however if container width get's smaller we should
30653 // this bit calcs how man columns..
30655 var columnWidth = this.columnWidth += this.gutter;
30657 // calculate columns
30658 var containerWidth = this.containerWidth + this.gutter;
30660 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
30661 // fix rounding errors, typically with gutters
30662 var excess = columnWidth - containerWidth % columnWidth;
30665 // if overshoot is less than a pixel, round up, otherwise floor it
30666 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
30667 cols = Math[ mathMethod ]( cols );
30668 this.cols = Math.max( cols, 1 );
30669 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30671 // padding positioning..
30672 var totalColWidth = this.cols * this.columnWidth;
30673 var padavail = this.containerWidth - totalColWidth;
30674 // so for 2 columns - we need 3 'pads'
30676 var padNeeded = (1+this.cols) * this.padWidth;
30678 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
30680 this.columnWidth += padExtra
30681 //this.padWidth = Math.floor(padavail / ( this.cols));
30683 // adjust colum width so that padding is fixed??
30685 // we have 3 columns ... total = width * 3
30686 // we have X left over... that should be used by
30688 //if (this.expandC) {
30696 getContainerWidth : function()
30698 /* // container is parent if fit width
30699 var container = this.isFitWidth ? this.element.parentNode : this.element;
30700 // check that this.size and size are there
30701 // IE8 triggers resize on body size change, so they might not be
30703 var size = getSize( container ); //FIXME
30704 this.containerWidth = size && size.innerWidth; //FIXME
30707 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30711 _getItemLayoutPosition : function( item ) // what is item?
30713 // we resize the item to our columnWidth..
30715 item.setWidth(this.columnWidth);
30716 item.autoBoxAdjust = false;
30718 var sz = item.getSize();
30720 // how many columns does this brick span
30721 var remainder = this.containerWidth % this.columnWidth;
30723 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30724 // round if off by 1 pixel, otherwise use ceil
30725 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30726 colSpan = Math.min( colSpan, this.cols );
30728 // normally this should be '1' as we dont' currently allow multi width columns..
30730 var colGroup = this._getColGroup( colSpan );
30731 // get the minimum Y value from the columns
30732 var minimumY = Math.min.apply( Math, colGroup );
30733 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30735 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30737 // position the brick
30739 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30740 y: this.currentSize.y + minimumY + this.padHeight
30744 // apply setHeight to necessary columns
30745 var setHeight = minimumY + sz.height + this.padHeight;
30746 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30748 var setSpan = this.cols + 1 - colGroup.length;
30749 for ( var i = 0; i < setSpan; i++ ) {
30750 this.colYs[ shortColIndex + i ] = setHeight ;
30757 * @param {Number} colSpan - number of columns the element spans
30758 * @returns {Array} colGroup
30760 _getColGroup : function( colSpan )
30762 if ( colSpan < 2 ) {
30763 // if brick spans only one column, use all the column Ys
30768 // how many different places could this brick fit horizontally
30769 var groupCount = this.cols + 1 - colSpan;
30770 // for each group potential horizontal position
30771 for ( var i = 0; i < groupCount; i++ ) {
30772 // make an array of colY values for that one group
30773 var groupColYs = this.colYs.slice( i, i + colSpan );
30774 // and get the max value of the array
30775 colGroup[i] = Math.max.apply( Math, groupColYs );
30780 _manageStamp : function( stamp )
30782 var stampSize = stamp.getSize();
30783 var offset = stamp.getBox();
30784 // get the columns that this stamp affects
30785 var firstX = this.isOriginLeft ? offset.x : offset.right;
30786 var lastX = firstX + stampSize.width;
30787 var firstCol = Math.floor( firstX / this.columnWidth );
30788 firstCol = Math.max( 0, firstCol );
30790 var lastCol = Math.floor( lastX / this.columnWidth );
30791 // lastCol should not go over if multiple of columnWidth #425
30792 lastCol -= lastX % this.columnWidth ? 0 : 1;
30793 lastCol = Math.min( this.cols - 1, lastCol );
30795 // set colYs to bottom of the stamp
30796 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30799 for ( var i = firstCol; i <= lastCol; i++ ) {
30800 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30805 _getContainerSize : function()
30807 this.maxY = Math.max.apply( Math, this.colYs );
30812 if ( this.isFitWidth ) {
30813 size.width = this._getContainerFitWidth();
30819 _getContainerFitWidth : function()
30821 var unusedCols = 0;
30822 // count unused columns
30825 if ( this.colYs[i] !== 0 ) {
30830 // fit container to columns that have been used
30831 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30834 needsResizeLayout : function()
30836 var previousWidth = this.containerWidth;
30837 this.getContainerWidth();
30838 return previousWidth !== this.containerWidth;
30853 * @class Roo.bootstrap.MasonryBrick
30854 * @extends Roo.bootstrap.Component
30855 * Bootstrap MasonryBrick class
30858 * Create a new MasonryBrick
30859 * @param {Object} config The config object
30862 Roo.bootstrap.MasonryBrick = function(config){
30863 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30869 * When a MasonryBrick is clcik
30870 * @param {Roo.bootstrap.MasonryBrick} this
30871 * @param {Roo.EventObject} e
30877 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30880 * @cfg {String} title
30884 * @cfg {String} html
30888 * @cfg {String} bgimage
30892 * @cfg {String} videourl
30896 * @cfg {String} cls
30900 * @cfg {String} href
30904 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30909 * @cfg {String} (center|bottom) placetitle
30913 getAutoCreate : function()
30915 var cls = 'masonry-brick';
30917 if(this.href.length){
30918 cls += ' masonry-brick-link';
30921 if(this.bgimage.length){
30922 cls += ' masonry-brick-image';
30926 cls += ' masonry-' + this.size + '-brick';
30929 if(this.placetitle.length){
30931 switch (this.placetitle) {
30933 cls += ' masonry-center-title';
30936 cls += ' masonry-bottom-title';
30943 if(!this.html.length && !this.bgimage.length){
30944 cls += ' masonry-center-title';
30947 if(!this.html.length && this.bgimage.length){
30948 cls += ' masonry-bottom-title';
30953 cls += ' ' + this.cls;
30957 tag: (this.href.length) ? 'a' : 'div',
30962 cls: 'masonry-brick-paragraph',
30968 if(this.href.length){
30969 cfg.href = this.href;
30972 var cn = cfg.cn[0].cn;
30974 if(this.title.length){
30977 cls: 'masonry-brick-title',
30982 if(this.html.length){
30985 cls: 'masonry-brick-text',
30989 if (!this.title.length && !this.html.length) {
30990 cfg.cn[0].cls += ' hide';
30993 if(this.bgimage.length){
30996 cls: 'masonry-brick-image-view',
31000 if(this.videourl.length){
31001 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31002 // youtube support only?
31005 cls: 'masonry-brick-image-view',
31008 allowfullscreen : true
31017 initEvents: function()
31019 switch (this.size) {
31021 // this.intSize = 1;
31026 // this.intSize = 2;
31033 // this.intSize = 3;
31038 // this.intSize = 3;
31043 // this.intSize = 3;
31048 // this.intSize = 3;
31060 this.el.on('touchstart', this.onTouchStart, this);
31061 this.el.on('touchmove', this.onTouchMove, this);
31062 this.el.on('touchend', this.onTouchEnd, this);
31063 this.el.on('contextmenu', this.onContextMenu, this);
31065 this.el.on('mouseenter' ,this.enter, this);
31066 this.el.on('mouseleave', this.leave, this);
31069 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31070 this.parent().bricks.push(this);
31075 onClick: function(e, el)
31081 var time = this.endTimer - this.startTimer;
31089 e.preventDefault();
31092 enter: function(e, el)
31094 e.preventDefault();
31096 if(this.bgimage.length && this.html.length){
31097 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31101 leave: function(e, el)
31103 e.preventDefault();
31105 if(this.bgimage.length && this.html.length){
31106 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31110 onTouchStart: function(e, el)
31112 // e.preventDefault();
31114 this.touchmoved = false;
31116 if(!this.bgimage.length || !this.html.length){
31120 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31122 this.timer = new Date().getTime();
31126 onTouchMove: function(e, el)
31128 this.touchmoved = true;
31131 onContextMenu : function(e,el)
31133 e.preventDefault();
31134 e.stopPropagation();
31138 onTouchEnd: function(e, el)
31140 // e.preventDefault();
31142 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31149 if(!this.bgimage.length || !this.html.length){
31151 if(this.href.length){
31152 window.location.href = this.href;
31158 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31160 window.location.href = this.href;
31175 * @class Roo.bootstrap.Brick
31176 * @extends Roo.bootstrap.Component
31177 * Bootstrap Brick class
31180 * Create a new Brick
31181 * @param {Object} config The config object
31184 Roo.bootstrap.Brick = function(config){
31185 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31191 * When a Brick is click
31192 * @param {Roo.bootstrap.Brick} this
31193 * @param {Roo.EventObject} e
31199 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31202 * @cfg {String} title
31206 * @cfg {String} html
31210 * @cfg {String} bgimage
31214 * @cfg {String} cls
31218 * @cfg {String} href
31222 * @cfg {String} video
31226 * @cfg {Boolean} square
31230 getAutoCreate : function()
31232 var cls = 'roo-brick';
31234 if(this.href.length){
31235 cls += ' roo-brick-link';
31238 if(this.bgimage.length){
31239 cls += ' roo-brick-image';
31242 if(!this.html.length && !this.bgimage.length){
31243 cls += ' roo-brick-center-title';
31246 if(!this.html.length && this.bgimage.length){
31247 cls += ' roo-brick-bottom-title';
31251 cls += ' ' + this.cls;
31255 tag: (this.href.length) ? 'a' : 'div',
31260 cls: 'roo-brick-paragraph',
31266 if(this.href.length){
31267 cfg.href = this.href;
31270 var cn = cfg.cn[0].cn;
31272 if(this.title.length){
31275 cls: 'roo-brick-title',
31280 if(this.html.length){
31283 cls: 'roo-brick-text',
31290 if(this.bgimage.length){
31293 cls: 'roo-brick-image-view',
31301 initEvents: function()
31303 if(this.title.length || this.html.length){
31304 this.el.on('mouseenter' ,this.enter, this);
31305 this.el.on('mouseleave', this.leave, this);
31309 Roo.EventManager.onWindowResize(this.resize, this);
31314 resize : function()
31316 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
31318 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
31319 // paragraph.setHeight(paragraph.getWidth());
31321 if(this.bgimage.length){
31322 var image = this.el.select('.roo-brick-image-view', true).first();
31323 image.setWidth(paragraph.getWidth());
31324 image.setHeight(paragraph.getWidth());
31329 enter: function(e, el)
31331 e.preventDefault();
31333 if(this.bgimage.length){
31334 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
31335 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
31339 leave: function(e, el)
31341 e.preventDefault();
31343 if(this.bgimage.length){
31344 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
31345 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
31355 * Ext JS Library 1.1.1
31356 * Copyright(c) 2006-2007, Ext JS, LLC.
31358 * Originally Released Under LGPL - original licence link has changed is not relivant.
31361 * <script type="text/javascript">
31366 * @class Roo.bootstrap.SplitBar
31367 * @extends Roo.util.Observable
31368 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
31372 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
31373 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
31374 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
31375 split.minSize = 100;
31376 split.maxSize = 600;
31377 split.animate = true;
31378 split.on('moved', splitterMoved);
31381 * Create a new SplitBar
31382 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
31383 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
31384 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31385 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
31386 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
31387 position of the SplitBar).
31389 Roo.bootstrap.SplitBar = function(cfg){
31394 // dragElement : elm
31395 // resizingElement: el,
31397 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
31398 // placement : Roo.bootstrap.SplitBar.LEFT ,
31399 // existingProxy ???
31402 this.el = Roo.get(cfg.dragElement, true);
31403 this.el.dom.unselectable = "on";
31405 this.resizingEl = Roo.get(cfg.resizingElement, true);
31409 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31410 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
31413 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
31416 * The minimum size of the resizing element. (Defaults to 0)
31422 * The maximum size of the resizing element. (Defaults to 2000)
31425 this.maxSize = 2000;
31428 * Whether to animate the transition to the new size
31431 this.animate = false;
31434 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
31437 this.useShim = false;
31442 if(!cfg.existingProxy){
31444 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
31446 this.proxy = Roo.get(cfg.existingProxy).dom;
31449 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
31452 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
31455 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
31458 this.dragSpecs = {};
31461 * @private The adapter to use to positon and resize elements
31463 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31464 this.adapter.init(this);
31466 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31468 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
31469 this.el.addClass("roo-splitbar-h");
31472 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
31473 this.el.addClass("roo-splitbar-v");
31479 * Fires when the splitter is moved (alias for {@link #event-moved})
31480 * @param {Roo.bootstrap.SplitBar} this
31481 * @param {Number} newSize the new width or height
31486 * Fires when the splitter is moved
31487 * @param {Roo.bootstrap.SplitBar} this
31488 * @param {Number} newSize the new width or height
31492 * @event beforeresize
31493 * Fires before the splitter is dragged
31494 * @param {Roo.bootstrap.SplitBar} this
31496 "beforeresize" : true,
31498 "beforeapply" : true
31501 Roo.util.Observable.call(this);
31504 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
31505 onStartProxyDrag : function(x, y){
31506 this.fireEvent("beforeresize", this);
31508 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
31510 o.enableDisplayMode("block");
31511 // all splitbars share the same overlay
31512 Roo.bootstrap.SplitBar.prototype.overlay = o;
31514 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31515 this.overlay.show();
31516 Roo.get(this.proxy).setDisplayed("block");
31517 var size = this.adapter.getElementSize(this);
31518 this.activeMinSize = this.getMinimumSize();;
31519 this.activeMaxSize = this.getMaximumSize();;
31520 var c1 = size - this.activeMinSize;
31521 var c2 = Math.max(this.activeMaxSize - size, 0);
31522 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31523 this.dd.resetConstraints();
31524 this.dd.setXConstraint(
31525 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
31526 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
31528 this.dd.setYConstraint(0, 0);
31530 this.dd.resetConstraints();
31531 this.dd.setXConstraint(0, 0);
31532 this.dd.setYConstraint(
31533 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
31534 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
31537 this.dragSpecs.startSize = size;
31538 this.dragSpecs.startPoint = [x, y];
31539 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
31543 * @private Called after the drag operation by the DDProxy
31545 onEndProxyDrag : function(e){
31546 Roo.get(this.proxy).setDisplayed(false);
31547 var endPoint = Roo.lib.Event.getXY(e);
31549 this.overlay.hide();
31552 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31553 newSize = this.dragSpecs.startSize +
31554 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
31555 endPoint[0] - this.dragSpecs.startPoint[0] :
31556 this.dragSpecs.startPoint[0] - endPoint[0]
31559 newSize = this.dragSpecs.startSize +
31560 (this.placement == Roo.bootstrap.SplitBar.TOP ?
31561 endPoint[1] - this.dragSpecs.startPoint[1] :
31562 this.dragSpecs.startPoint[1] - endPoint[1]
31565 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
31566 if(newSize != this.dragSpecs.startSize){
31567 if(this.fireEvent('beforeapply', this, newSize) !== false){
31568 this.adapter.setElementSize(this, newSize);
31569 this.fireEvent("moved", this, newSize);
31570 this.fireEvent("resize", this, newSize);
31576 * Get the adapter this SplitBar uses
31577 * @return The adapter object
31579 getAdapter : function(){
31580 return this.adapter;
31584 * Set the adapter this SplitBar uses
31585 * @param {Object} adapter A SplitBar adapter object
31587 setAdapter : function(adapter){
31588 this.adapter = adapter;
31589 this.adapter.init(this);
31593 * Gets the minimum size for the resizing element
31594 * @return {Number} The minimum size
31596 getMinimumSize : function(){
31597 return this.minSize;
31601 * Sets the minimum size for the resizing element
31602 * @param {Number} minSize The minimum size
31604 setMinimumSize : function(minSize){
31605 this.minSize = minSize;
31609 * Gets the maximum size for the resizing element
31610 * @return {Number} The maximum size
31612 getMaximumSize : function(){
31613 return this.maxSize;
31617 * Sets the maximum size for the resizing element
31618 * @param {Number} maxSize The maximum size
31620 setMaximumSize : function(maxSize){
31621 this.maxSize = maxSize;
31625 * Sets the initialize size for the resizing element
31626 * @param {Number} size The initial size
31628 setCurrentSize : function(size){
31629 var oldAnimate = this.animate;
31630 this.animate = false;
31631 this.adapter.setElementSize(this, size);
31632 this.animate = oldAnimate;
31636 * Destroy this splitbar.
31637 * @param {Boolean} removeEl True to remove the element
31639 destroy : function(removeEl){
31641 this.shim.remove();
31644 this.proxy.parentNode.removeChild(this.proxy);
31652 * @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.
31654 Roo.bootstrap.SplitBar.createProxy = function(dir){
31655 var proxy = new Roo.Element(document.createElement("div"));
31656 proxy.unselectable();
31657 var cls = 'roo-splitbar-proxy';
31658 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
31659 document.body.appendChild(proxy.dom);
31664 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
31665 * Default Adapter. It assumes the splitter and resizing element are not positioned
31666 * elements and only gets/sets the width of the element. Generally used for table based layouts.
31668 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
31671 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
31672 // do nothing for now
31673 init : function(s){
31677 * Called before drag operations to get the current size of the resizing element.
31678 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31680 getElementSize : function(s){
31681 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31682 return s.resizingEl.getWidth();
31684 return s.resizingEl.getHeight();
31689 * Called after drag operations to set the size of the resizing element.
31690 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31691 * @param {Number} newSize The new size to set
31692 * @param {Function} onComplete A function to be invoked when resizing is complete
31694 setElementSize : function(s, newSize, onComplete){
31695 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31697 s.resizingEl.setWidth(newSize);
31699 onComplete(s, newSize);
31702 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
31707 s.resizingEl.setHeight(newSize);
31709 onComplete(s, newSize);
31712 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
31719 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
31720 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
31721 * Adapter that moves the splitter element to align with the resized sizing element.
31722 * Used with an absolute positioned SplitBar.
31723 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
31724 * document.body, make sure you assign an id to the body element.
31726 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
31727 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31728 this.container = Roo.get(container);
31731 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
31732 init : function(s){
31733 this.basic.init(s);
31736 getElementSize : function(s){
31737 return this.basic.getElementSize(s);
31740 setElementSize : function(s, newSize, onComplete){
31741 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
31744 moveSplitter : function(s){
31745 var yes = Roo.bootstrap.SplitBar;
31746 switch(s.placement){
31748 s.el.setX(s.resizingEl.getRight());
31751 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
31754 s.el.setY(s.resizingEl.getBottom());
31757 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
31764 * Orientation constant - Create a vertical SplitBar
31768 Roo.bootstrap.SplitBar.VERTICAL = 1;
31771 * Orientation constant - Create a horizontal SplitBar
31775 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
31778 * Placement constant - The resizing element is to the left of the splitter element
31782 Roo.bootstrap.SplitBar.LEFT = 1;
31785 * Placement constant - The resizing element is to the right of the splitter element
31789 Roo.bootstrap.SplitBar.RIGHT = 2;
31792 * Placement constant - The resizing element is positioned above the splitter element
31796 Roo.bootstrap.SplitBar.TOP = 3;
31799 * Placement constant - The resizing element is positioned under splitter element
31803 Roo.bootstrap.SplitBar.BOTTOM = 4;
31804 Roo.namespace("Roo.bootstrap.layout");/*
31806 * Ext JS Library 1.1.1
31807 * Copyright(c) 2006-2007, Ext JS, LLC.
31809 * Originally Released Under LGPL - original licence link has changed is not relivant.
31812 * <script type="text/javascript">
31816 * @class Roo.bootstrap.layout.Manager
31817 * @extends Roo.bootstrap.Component
31818 * Base class for layout managers.
31820 Roo.bootstrap.layout.Manager = function(config)
31822 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
31828 /** false to disable window resize monitoring @type Boolean */
31829 this.monitorWindowResize = true;
31834 * Fires when a layout is performed.
31835 * @param {Roo.LayoutManager} this
31839 * @event regionresized
31840 * Fires when the user resizes a region.
31841 * @param {Roo.LayoutRegion} region The resized region
31842 * @param {Number} newSize The new size (width for east/west, height for north/south)
31844 "regionresized" : true,
31846 * @event regioncollapsed
31847 * Fires when a region is collapsed.
31848 * @param {Roo.LayoutRegion} region The collapsed region
31850 "regioncollapsed" : true,
31852 * @event regionexpanded
31853 * Fires when a region is expanded.
31854 * @param {Roo.LayoutRegion} region The expanded region
31856 "regionexpanded" : true
31858 this.updating = false;
31861 this.el = Roo.get(config.el);
31867 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31872 monitorWindowResize : true,
31878 onRender : function(ct, position)
31881 this.el = Roo.get(ct);
31887 initEvents: function()
31891 // ie scrollbar fix
31892 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31893 document.body.scroll = "no";
31894 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31895 this.el.position('relative');
31897 this.id = this.el.id;
31898 this.el.addClass("roo-layout-container");
31899 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31900 if(this.el.dom != document.body ) {
31901 this.el.on('resize', this.layout,this);
31902 this.el.on('show', this.layout,this);
31908 * Returns true if this layout is currently being updated
31909 * @return {Boolean}
31911 isUpdating : function(){
31912 return this.updating;
31916 * Suspend the LayoutManager from doing auto-layouts while
31917 * making multiple add or remove calls
31919 beginUpdate : function(){
31920 this.updating = true;
31924 * Restore auto-layouts and optionally disable the manager from performing a layout
31925 * @param {Boolean} noLayout true to disable a layout update
31927 endUpdate : function(noLayout){
31928 this.updating = false;
31934 layout: function(){
31938 onRegionResized : function(region, newSize){
31939 this.fireEvent("regionresized", region, newSize);
31943 onRegionCollapsed : function(region){
31944 this.fireEvent("regioncollapsed", region);
31947 onRegionExpanded : function(region){
31948 this.fireEvent("regionexpanded", region);
31952 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31953 * performs box-model adjustments.
31954 * @return {Object} The size as an object {width: (the width), height: (the height)}
31956 getViewSize : function()
31959 if(this.el.dom != document.body){
31960 size = this.el.getSize();
31962 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31964 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31965 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31970 * Returns the Element this layout is bound to.
31971 * @return {Roo.Element}
31973 getEl : function(){
31978 * Returns the specified region.
31979 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31980 * @return {Roo.LayoutRegion}
31982 getRegion : function(target){
31983 return this.regions[target.toLowerCase()];
31986 onWindowResize : function(){
31987 if(this.monitorWindowResize){
31993 * Ext JS Library 1.1.1
31994 * Copyright(c) 2006-2007, Ext JS, LLC.
31996 * Originally Released Under LGPL - original licence link has changed is not relivant.
31999 * <script type="text/javascript">
32002 * @class Roo.bootstrap.layout.Border
32003 * @extends Roo.bootstrap.layout.Manager
32004 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32005 * please see: examples/bootstrap/nested.html<br><br>
32007 <b>The container the layout is rendered into can be either the body element or any other element.
32008 If it is not the body element, the container needs to either be an absolute positioned element,
32009 or you will need to add "position:relative" to the css of the container. You will also need to specify
32010 the container size if it is not the body element.</b>
32013 * Create a new Border
32014 * @param {Object} config Configuration options
32016 Roo.bootstrap.layout.Border = function(config){
32017 config = config || {};
32018 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
32022 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32023 if(config[region]){
32024 config[region].region = region;
32025 this.addRegion(config[region]);
32031 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
32033 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
32035 * Creates and adds a new region if it doesn't already exist.
32036 * @param {String} target The target region key (north, south, east, west or center).
32037 * @param {Object} config The regions config object
32038 * @return {BorderLayoutRegion} The new region
32040 addRegion : function(config)
32042 if(!this.regions[config.region]){
32043 var r = this.factory(config);
32044 this.bindRegion(r);
32046 return this.regions[config.region];
32050 bindRegion : function(r){
32051 this.regions[r.config.region] = r;
32053 r.on("visibilitychange", this.layout, this);
32054 r.on("paneladded", this.layout, this);
32055 r.on("panelremoved", this.layout, this);
32056 r.on("invalidated", this.layout, this);
32057 r.on("resized", this.onRegionResized, this);
32058 r.on("collapsed", this.onRegionCollapsed, this);
32059 r.on("expanded", this.onRegionExpanded, this);
32063 * Performs a layout update.
32065 layout : function()
32067 if(this.updating) {
32071 // render all the rebions if they have not been done alreayd?
32072 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
32073 if(this.regions[region] && !this.regions[region].bodyEl){
32074 this.regions[region].onRender(this.el)
32078 var size = this.getViewSize();
32079 var w = size.width;
32080 var h = size.height;
32085 //var x = 0, y = 0;
32087 var rs = this.regions;
32088 var north = rs["north"];
32089 var south = rs["south"];
32090 var west = rs["west"];
32091 var east = rs["east"];
32092 var center = rs["center"];
32093 //if(this.hideOnLayout){ // not supported anymore
32094 //c.el.setStyle("display", "none");
32096 if(north && north.isVisible()){
32097 var b = north.getBox();
32098 var m = north.getMargins();
32099 b.width = w - (m.left+m.right);
32102 centerY = b.height + b.y + m.bottom;
32103 centerH -= centerY;
32104 north.updateBox(this.safeBox(b));
32106 if(south && south.isVisible()){
32107 var b = south.getBox();
32108 var m = south.getMargins();
32109 b.width = w - (m.left+m.right);
32111 var totalHeight = (b.height + m.top + m.bottom);
32112 b.y = h - totalHeight + m.top;
32113 centerH -= totalHeight;
32114 south.updateBox(this.safeBox(b));
32116 if(west && west.isVisible()){
32117 var b = west.getBox();
32118 var m = west.getMargins();
32119 b.height = centerH - (m.top+m.bottom);
32121 b.y = centerY + m.top;
32122 var totalWidth = (b.width + m.left + m.right);
32123 centerX += totalWidth;
32124 centerW -= totalWidth;
32125 west.updateBox(this.safeBox(b));
32127 if(east && east.isVisible()){
32128 var b = east.getBox();
32129 var m = east.getMargins();
32130 b.height = centerH - (m.top+m.bottom);
32131 var totalWidth = (b.width + m.left + m.right);
32132 b.x = w - totalWidth + m.left;
32133 b.y = centerY + m.top;
32134 centerW -= totalWidth;
32135 east.updateBox(this.safeBox(b));
32138 var m = center.getMargins();
32140 x: centerX + m.left,
32141 y: centerY + m.top,
32142 width: centerW - (m.left+m.right),
32143 height: centerH - (m.top+m.bottom)
32145 //if(this.hideOnLayout){
32146 //center.el.setStyle("display", "block");
32148 center.updateBox(this.safeBox(centerBox));
32151 this.fireEvent("layout", this);
32155 safeBox : function(box){
32156 box.width = Math.max(0, box.width);
32157 box.height = Math.max(0, box.height);
32162 * Adds a ContentPanel (or subclass) to this layout.
32163 * @param {String} target The target region key (north, south, east, west or center).
32164 * @param {Roo.ContentPanel} panel The panel to add
32165 * @return {Roo.ContentPanel} The added panel
32167 add : function(target, panel){
32169 target = target.toLowerCase();
32170 return this.regions[target].add(panel);
32174 * Remove a ContentPanel (or subclass) to this layout.
32175 * @param {String} target The target region key (north, south, east, west or center).
32176 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32177 * @return {Roo.ContentPanel} The removed panel
32179 remove : function(target, panel){
32180 target = target.toLowerCase();
32181 return this.regions[target].remove(panel);
32185 * Searches all regions for a panel with the specified id
32186 * @param {String} panelId
32187 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32189 findPanel : function(panelId){
32190 var rs = this.regions;
32191 for(var target in rs){
32192 if(typeof rs[target] != "function"){
32193 var p = rs[target].getPanel(panelId);
32203 * Searches all regions for a panel with the specified id and activates (shows) it.
32204 * @param {String/ContentPanel} panelId The panels id or the panel itself
32205 * @return {Roo.ContentPanel} The shown panel or null
32207 showPanel : function(panelId) {
32208 var rs = this.regions;
32209 for(var target in rs){
32210 var r = rs[target];
32211 if(typeof r != "function"){
32212 if(r.hasPanel(panelId)){
32213 return r.showPanel(panelId);
32221 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32222 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32225 restoreState : function(provider){
32227 provider = Roo.state.Manager;
32229 var sm = new Roo.LayoutStateManager();
32230 sm.init(this, provider);
32236 * Adds a xtype elements to the layout.
32240 xtype : 'ContentPanel',
32247 xtype : 'NestedLayoutPanel',
32253 items : [ ... list of content panels or nested layout panels.. ]
32257 * @param {Object} cfg Xtype definition of item to add.
32259 addxtype : function(cfg)
32261 // basically accepts a pannel...
32262 // can accept a layout region..!?!?
32263 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32266 // theory? children can only be panels??
32268 //if (!cfg.xtype.match(/Panel$/)) {
32273 if (typeof(cfg.region) == 'undefined') {
32274 Roo.log("Failed to add Panel, region was not set");
32278 var region = cfg.region;
32284 xitems = cfg.items;
32291 case 'Content': // ContentPanel (el, cfg)
32292 case 'Scroll': // ContentPanel (el, cfg)
32294 cfg.autoCreate = true;
32295 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32297 // var el = this.el.createChild();
32298 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
32301 this.add(region, ret);
32305 case 'TreePanel': // our new panel!
32306 cfg.el = this.el.createChild();
32307 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32308 this.add(region, ret);
32313 // create a new Layout (which is a Border Layout...
32315 var clayout = cfg.layout;
32316 clayout.el = this.el.createChild();
32317 clayout.items = clayout.items || [];
32321 // replace this exitems with the clayout ones..
32322 xitems = clayout.items;
32324 // force background off if it's in center...
32325 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
32326 cfg.background = false;
32328 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
32331 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32332 //console.log('adding nested layout panel ' + cfg.toSource());
32333 this.add(region, ret);
32334 nb = {}; /// find first...
32339 // needs grid and region
32341 //var el = this.getRegion(region).el.createChild();
32343 *var el = this.el.createChild();
32344 // create the grid first...
32345 cfg.grid.container = el;
32346 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
32349 if (region == 'center' && this.active ) {
32350 cfg.background = false;
32353 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
32355 this.add(region, ret);
32357 if (cfg.background) {
32358 // render grid on panel activation (if panel background)
32359 ret.on('activate', function(gp) {
32360 if (!gp.grid.rendered) {
32361 // gp.grid.render(el);
32365 // cfg.grid.render(el);
32371 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
32372 // it was the old xcomponent building that caused this before.
32373 // espeically if border is the top element in the tree.
32383 if (typeof(Roo[cfg.xtype]) != 'undefined') {
32385 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32386 this.add(region, ret);
32390 throw "Can not add '" + cfg.xtype + "' to Border";
32396 this.beginUpdate();
32400 Roo.each(xitems, function(i) {
32401 region = nb && i.region ? i.region : false;
32403 var add = ret.addxtype(i);
32406 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32407 if (!i.background) {
32408 abn[region] = nb[region] ;
32415 // make the last non-background panel active..
32416 //if (nb) { Roo.log(abn); }
32419 for(var r in abn) {
32420 region = this.getRegion(r);
32422 // tried using nb[r], but it does not work..
32424 region.showPanel(abn[r]);
32435 factory : function(cfg)
32438 var validRegions = Roo.bootstrap.layout.Border.regions;
32440 var target = cfg.region;
32443 var r = Roo.bootstrap.layout;
32447 return new r.North(cfg);
32449 return new r.South(cfg);
32451 return new r.East(cfg);
32453 return new r.West(cfg);
32455 return new r.Center(cfg);
32457 throw 'Layout region "'+target+'" not supported.';
32464 * Ext JS Library 1.1.1
32465 * Copyright(c) 2006-2007, Ext JS, LLC.
32467 * Originally Released Under LGPL - original licence link has changed is not relivant.
32470 * <script type="text/javascript">
32474 * @class Roo.bootstrap.layout.Basic
32475 * @extends Roo.util.Observable
32476 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32477 * and does not have a titlebar, tabs or any other features. All it does is size and position
32478 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32479 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32480 * @cfg {string} region the region that it inhabits..
32481 * @cfg {bool} skipConfig skip config?
32485 Roo.bootstrap.layout.Basic = function(config){
32487 this.mgr = config.mgr;
32489 this.position = config.region;
32491 var skipConfig = config.skipConfig;
32495 * @scope Roo.BasicLayoutRegion
32499 * @event beforeremove
32500 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32501 * @param {Roo.LayoutRegion} this
32502 * @param {Roo.ContentPanel} panel The panel
32503 * @param {Object} e The cancel event object
32505 "beforeremove" : true,
32507 * @event invalidated
32508 * Fires when the layout for this region is changed.
32509 * @param {Roo.LayoutRegion} this
32511 "invalidated" : true,
32513 * @event visibilitychange
32514 * Fires when this region is shown or hidden
32515 * @param {Roo.LayoutRegion} this
32516 * @param {Boolean} visibility true or false
32518 "visibilitychange" : true,
32520 * @event paneladded
32521 * Fires when a panel is added.
32522 * @param {Roo.LayoutRegion} this
32523 * @param {Roo.ContentPanel} panel The panel
32525 "paneladded" : true,
32527 * @event panelremoved
32528 * Fires when a panel is removed.
32529 * @param {Roo.LayoutRegion} this
32530 * @param {Roo.ContentPanel} panel The panel
32532 "panelremoved" : true,
32534 * @event beforecollapse
32535 * Fires when this region before collapse.
32536 * @param {Roo.LayoutRegion} this
32538 "beforecollapse" : true,
32541 * Fires when this region is collapsed.
32542 * @param {Roo.LayoutRegion} this
32544 "collapsed" : true,
32547 * Fires when this region is expanded.
32548 * @param {Roo.LayoutRegion} this
32553 * Fires when this region is slid into view.
32554 * @param {Roo.LayoutRegion} this
32556 "slideshow" : true,
32559 * Fires when this region slides out of view.
32560 * @param {Roo.LayoutRegion} this
32562 "slidehide" : true,
32564 * @event panelactivated
32565 * Fires when a panel is activated.
32566 * @param {Roo.LayoutRegion} this
32567 * @param {Roo.ContentPanel} panel The activated panel
32569 "panelactivated" : true,
32572 * Fires when the user resizes this region.
32573 * @param {Roo.LayoutRegion} this
32574 * @param {Number} newSize The new size (width for east/west, height for north/south)
32578 /** A collection of panels in this region. @type Roo.util.MixedCollection */
32579 this.panels = new Roo.util.MixedCollection();
32580 this.panels.getKey = this.getPanelId.createDelegate(this);
32582 this.activePanel = null;
32583 // ensure listeners are added...
32585 if (config.listeners || config.events) {
32586 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
32587 listeners : config.listeners || {},
32588 events : config.events || {}
32592 if(skipConfig !== true){
32593 this.applyConfig(config);
32597 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
32599 getPanelId : function(p){
32603 applyConfig : function(config){
32604 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32605 this.config = config;
32610 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
32611 * the width, for horizontal (north, south) the height.
32612 * @param {Number} newSize The new width or height
32614 resizeTo : function(newSize){
32615 var el = this.el ? this.el :
32616 (this.activePanel ? this.activePanel.getEl() : null);
32618 switch(this.position){
32621 el.setWidth(newSize);
32622 this.fireEvent("resized", this, newSize);
32626 el.setHeight(newSize);
32627 this.fireEvent("resized", this, newSize);
32633 getBox : function(){
32634 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
32637 getMargins : function(){
32638 return this.margins;
32641 updateBox : function(box){
32643 var el = this.activePanel.getEl();
32644 el.dom.style.left = box.x + "px";
32645 el.dom.style.top = box.y + "px";
32646 this.activePanel.setSize(box.width, box.height);
32650 * Returns the container element for this region.
32651 * @return {Roo.Element}
32653 getEl : function(){
32654 return this.activePanel;
32658 * Returns true if this region is currently visible.
32659 * @return {Boolean}
32661 isVisible : function(){
32662 return this.activePanel ? true : false;
32665 setActivePanel : function(panel){
32666 panel = this.getPanel(panel);
32667 if(this.activePanel && this.activePanel != panel){
32668 this.activePanel.setActiveState(false);
32669 this.activePanel.getEl().setLeftTop(-10000,-10000);
32671 this.activePanel = panel;
32672 panel.setActiveState(true);
32674 panel.setSize(this.box.width, this.box.height);
32676 this.fireEvent("panelactivated", this, panel);
32677 this.fireEvent("invalidated");
32681 * Show the specified panel.
32682 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
32683 * @return {Roo.ContentPanel} The shown panel or null
32685 showPanel : function(panel){
32686 panel = this.getPanel(panel);
32688 this.setActivePanel(panel);
32694 * Get the active panel for this region.
32695 * @return {Roo.ContentPanel} The active panel or null
32697 getActivePanel : function(){
32698 return this.activePanel;
32702 * Add the passed ContentPanel(s)
32703 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32704 * @return {Roo.ContentPanel} The panel added (if only one was added)
32706 add : function(panel){
32707 if(arguments.length > 1){
32708 for(var i = 0, len = arguments.length; i < len; i++) {
32709 this.add(arguments[i]);
32713 if(this.hasPanel(panel)){
32714 this.showPanel(panel);
32717 var el = panel.getEl();
32718 if(el.dom.parentNode != this.mgr.el.dom){
32719 this.mgr.el.dom.appendChild(el.dom);
32721 if(panel.setRegion){
32722 panel.setRegion(this);
32724 this.panels.add(panel);
32725 el.setStyle("position", "absolute");
32726 if(!panel.background){
32727 this.setActivePanel(panel);
32728 if(this.config.initialSize && this.panels.getCount()==1){
32729 this.resizeTo(this.config.initialSize);
32732 this.fireEvent("paneladded", this, panel);
32737 * Returns true if the panel is in this region.
32738 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32739 * @return {Boolean}
32741 hasPanel : function(panel){
32742 if(typeof panel == "object"){ // must be panel obj
32743 panel = panel.getId();
32745 return this.getPanel(panel) ? true : false;
32749 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32750 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32751 * @param {Boolean} preservePanel Overrides the config preservePanel option
32752 * @return {Roo.ContentPanel} The panel that was removed
32754 remove : function(panel, preservePanel){
32755 panel = this.getPanel(panel);
32760 this.fireEvent("beforeremove", this, panel, e);
32761 if(e.cancel === true){
32764 var panelId = panel.getId();
32765 this.panels.removeKey(panelId);
32770 * Returns the panel specified or null if it's not in this region.
32771 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32772 * @return {Roo.ContentPanel}
32774 getPanel : function(id){
32775 if(typeof id == "object"){ // must be panel obj
32778 return this.panels.get(id);
32782 * Returns this regions position (north/south/east/west/center).
32785 getPosition: function(){
32786 return this.position;
32790 * Ext JS Library 1.1.1
32791 * Copyright(c) 2006-2007, Ext JS, LLC.
32793 * Originally Released Under LGPL - original licence link has changed is not relivant.
32796 * <script type="text/javascript">
32800 * @class Roo.bootstrap.layout.Region
32801 * @extends Roo.bootstrap.layout.Basic
32802 * This class represents a region in a layout manager.
32804 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
32805 * @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})
32806 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
32807 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
32808 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
32809 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
32810 * @cfg {String} title The title for the region (overrides panel titles)
32811 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
32812 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
32813 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
32814 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
32815 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
32816 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
32817 * the space available, similar to FireFox 1.5 tabs (defaults to false)
32818 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
32819 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
32820 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
32822 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
32823 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
32824 * @cfg {Boolean} disableTabTips True to disable tab tooltips
32825 * @cfg {Number} width For East/West panels
32826 * @cfg {Number} height For North/South panels
32827 * @cfg {Boolean} split To show the splitter
32828 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
32830 * @cfg {string} cls Extra CSS classes to add to region
32832 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32833 * @cfg {string} region the region that it inhabits..
32836 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
32837 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
32839 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
32840 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
32841 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
32843 Roo.bootstrap.layout.Region = function(config)
32845 this.applyConfig(config);
32847 var mgr = config.mgr;
32848 var pos = config.region;
32849 config.skipConfig = true;
32850 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
32853 this.onRender(mgr.el);
32856 this.visible = true;
32857 this.collapsed = false;
32858 this.unrendered_panels = [];
32861 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32863 position: '', // set by wrapper (eg. north/south etc..)
32864 unrendered_panels : null, // unrendered panels.
32865 createBody : function(){
32866 /** This region's body element
32867 * @type Roo.Element */
32868 this.bodyEl = this.el.createChild({
32870 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32874 onRender: function(ctr, pos)
32876 var dh = Roo.DomHelper;
32877 /** This region's container element
32878 * @type Roo.Element */
32879 this.el = dh.append(ctr.dom, {
32881 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
32883 /** This region's title element
32884 * @type Roo.Element */
32886 this.titleEl = dh.append(this.el.dom,
32889 unselectable: "on",
32890 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32892 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32893 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32896 this.titleEl.enableDisplayMode();
32897 /** This region's title text element
32898 * @type HTMLElement */
32899 this.titleTextEl = this.titleEl.dom.firstChild;
32900 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32902 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32903 this.closeBtn.enableDisplayMode();
32904 this.closeBtn.on("click", this.closeClicked, this);
32905 this.closeBtn.hide();
32907 this.createBody(this.config);
32908 if(this.config.hideWhenEmpty){
32910 this.on("paneladded", this.validateVisibility, this);
32911 this.on("panelremoved", this.validateVisibility, this);
32913 if(this.autoScroll){
32914 this.bodyEl.setStyle("overflow", "auto");
32916 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
32918 //if(c.titlebar !== false){
32919 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
32920 this.titleEl.hide();
32922 this.titleEl.show();
32923 if(this.config.title){
32924 this.titleTextEl.innerHTML = this.config.title;
32928 if(this.config.collapsed){
32929 this.collapse(true);
32931 if(this.config.hidden){
32935 if (this.unrendered_panels && this.unrendered_panels.length) {
32936 for (var i =0;i< this.unrendered_panels.length; i++) {
32937 this.add(this.unrendered_panels[i]);
32939 this.unrendered_panels = null;
32945 applyConfig : function(c)
32948 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32949 var dh = Roo.DomHelper;
32950 if(c.titlebar !== false){
32951 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32952 this.collapseBtn.on("click", this.collapse, this);
32953 this.collapseBtn.enableDisplayMode();
32955 if(c.showPin === true || this.showPin){
32956 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32957 this.stickBtn.enableDisplayMode();
32958 this.stickBtn.on("click", this.expand, this);
32959 this.stickBtn.hide();
32964 /** This region's collapsed element
32965 * @type Roo.Element */
32968 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32969 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32972 if(c.floatable !== false){
32973 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32974 this.collapsedEl.on("click", this.collapseClick, this);
32977 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32978 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32979 id: "message", unselectable: "on", style:{"float":"left"}});
32980 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32982 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32983 this.expandBtn.on("click", this.expand, this);
32987 if(this.collapseBtn){
32988 this.collapseBtn.setVisible(c.collapsible == true);
32991 this.cmargins = c.cmargins || this.cmargins ||
32992 (this.position == "west" || this.position == "east" ?
32993 {top: 0, left: 2, right:2, bottom: 0} :
32994 {top: 2, left: 0, right:0, bottom: 2});
32996 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32999 this.bottomTabs = c.tabPosition != "top";
33001 this.autoScroll = c.autoScroll || false;
33006 this.duration = c.duration || .30;
33007 this.slideDuration = c.slideDuration || .45;
33012 * Returns true if this region is currently visible.
33013 * @return {Boolean}
33015 isVisible : function(){
33016 return this.visible;
33020 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33021 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33023 //setCollapsedTitle : function(title){
33024 // title = title || " ";
33025 // if(this.collapsedTitleTextEl){
33026 // this.collapsedTitleTextEl.innerHTML = title;
33030 getBox : function(){
33032 // if(!this.collapsed){
33033 b = this.el.getBox(false, true);
33035 // b = this.collapsedEl.getBox(false, true);
33040 getMargins : function(){
33041 return this.margins;
33042 //return this.collapsed ? this.cmargins : this.margins;
33045 highlight : function(){
33046 this.el.addClass("x-layout-panel-dragover");
33049 unhighlight : function(){
33050 this.el.removeClass("x-layout-panel-dragover");
33053 updateBox : function(box)
33055 if (!this.bodyEl) {
33056 return; // not rendered yet..
33060 if(!this.collapsed){
33061 this.el.dom.style.left = box.x + "px";
33062 this.el.dom.style.top = box.y + "px";
33063 this.updateBody(box.width, box.height);
33065 this.collapsedEl.dom.style.left = box.x + "px";
33066 this.collapsedEl.dom.style.top = box.y + "px";
33067 this.collapsedEl.setSize(box.width, box.height);
33070 this.tabs.autoSizeTabs();
33074 updateBody : function(w, h)
33077 this.el.setWidth(w);
33078 w -= this.el.getBorderWidth("rl");
33079 if(this.config.adjustments){
33080 w += this.config.adjustments[0];
33083 if(h !== null && h > 0){
33084 this.el.setHeight(h);
33085 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33086 h -= this.el.getBorderWidth("tb");
33087 if(this.config.adjustments){
33088 h += this.config.adjustments[1];
33090 this.bodyEl.setHeight(h);
33092 h = this.tabs.syncHeight(h);
33095 if(this.panelSize){
33096 w = w !== null ? w : this.panelSize.width;
33097 h = h !== null ? h : this.panelSize.height;
33099 if(this.activePanel){
33100 var el = this.activePanel.getEl();
33101 w = w !== null ? w : el.getWidth();
33102 h = h !== null ? h : el.getHeight();
33103 this.panelSize = {width: w, height: h};
33104 this.activePanel.setSize(w, h);
33106 if(Roo.isIE && this.tabs){
33107 this.tabs.el.repaint();
33112 * Returns the container element for this region.
33113 * @return {Roo.Element}
33115 getEl : function(){
33120 * Hides this region.
33123 //if(!this.collapsed){
33124 this.el.dom.style.left = "-2000px";
33127 // this.collapsedEl.dom.style.left = "-2000px";
33128 // this.collapsedEl.hide();
33130 this.visible = false;
33131 this.fireEvent("visibilitychange", this, false);
33135 * Shows this region if it was previously hidden.
33138 //if(!this.collapsed){
33141 // this.collapsedEl.show();
33143 this.visible = true;
33144 this.fireEvent("visibilitychange", this, true);
33147 closeClicked : function(){
33148 if(this.activePanel){
33149 this.remove(this.activePanel);
33153 collapseClick : function(e){
33155 e.stopPropagation();
33158 e.stopPropagation();
33164 * Collapses this region.
33165 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33168 collapse : function(skipAnim, skipCheck = false){
33169 if(this.collapsed) {
33173 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
33175 this.collapsed = true;
33177 this.split.el.hide();
33179 if(this.config.animate && skipAnim !== true){
33180 this.fireEvent("invalidated", this);
33181 this.animateCollapse();
33183 this.el.setLocation(-20000,-20000);
33185 this.collapsedEl.show();
33186 this.fireEvent("collapsed", this);
33187 this.fireEvent("invalidated", this);
33193 animateCollapse : function(){
33198 * Expands this region if it was previously collapsed.
33199 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33200 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33203 expand : function(e, skipAnim){
33205 e.stopPropagation();
33207 if(!this.collapsed || this.el.hasActiveFx()) {
33211 this.afterSlideIn();
33214 this.collapsed = false;
33215 if(this.config.animate && skipAnim !== true){
33216 this.animateExpand();
33220 this.split.el.show();
33222 this.collapsedEl.setLocation(-2000,-2000);
33223 this.collapsedEl.hide();
33224 this.fireEvent("invalidated", this);
33225 this.fireEvent("expanded", this);
33229 animateExpand : function(){
33233 initTabs : function()
33235 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
33237 var ts = new Roo.bootstrap.panel.Tabs({
33238 el: this.bodyEl.dom,
33239 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33240 disableTooltips: this.config.disableTabTips,
33241 toolbar : this.config.toolbar
33244 if(this.config.hideTabs){
33245 ts.stripWrap.setDisplayed(false);
33248 ts.resizeTabs = this.config.resizeTabs === true;
33249 ts.minTabWidth = this.config.minTabWidth || 40;
33250 ts.maxTabWidth = this.config.maxTabWidth || 250;
33251 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33252 ts.monitorResize = false;
33253 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
33254 ts.bodyEl.addClass('roo-layout-tabs-body');
33255 this.panels.each(this.initPanelAsTab, this);
33258 initPanelAsTab : function(panel){
33259 var ti = this.tabs.addTab(
33263 this.config.closeOnTab && panel.isClosable()
33265 if(panel.tabTip !== undefined){
33266 ti.setTooltip(panel.tabTip);
33268 ti.on("activate", function(){
33269 this.setActivePanel(panel);
33272 if(this.config.closeOnTab){
33273 ti.on("beforeclose", function(t, e){
33275 this.remove(panel);
33281 updatePanelTitle : function(panel, title)
33283 if(this.activePanel == panel){
33284 this.updateTitle(title);
33287 var ti = this.tabs.getTab(panel.getEl().id);
33289 if(panel.tabTip !== undefined){
33290 ti.setTooltip(panel.tabTip);
33295 updateTitle : function(title){
33296 if(this.titleTextEl && !this.config.title){
33297 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
33301 setActivePanel : function(panel)
33303 panel = this.getPanel(panel);
33304 if(this.activePanel && this.activePanel != panel){
33305 this.activePanel.setActiveState(false);
33307 this.activePanel = panel;
33308 panel.setActiveState(true);
33309 if(this.panelSize){
33310 panel.setSize(this.panelSize.width, this.panelSize.height);
33313 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
33315 this.updateTitle(panel.getTitle());
33317 this.fireEvent("invalidated", this);
33319 this.fireEvent("panelactivated", this, panel);
33323 * Shows the specified panel.
33324 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
33325 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
33327 showPanel : function(panel)
33329 panel = this.getPanel(panel);
33332 var tab = this.tabs.getTab(panel.getEl().id);
33333 if(tab.isHidden()){
33334 this.tabs.unhideTab(tab.id);
33338 this.setActivePanel(panel);
33345 * Get the active panel for this region.
33346 * @return {Roo.ContentPanel} The active panel or null
33348 getActivePanel : function(){
33349 return this.activePanel;
33352 validateVisibility : function(){
33353 if(this.panels.getCount() < 1){
33354 this.updateTitle(" ");
33355 this.closeBtn.hide();
33358 if(!this.isVisible()){
33365 * Adds the passed ContentPanel(s) to this region.
33366 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33367 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
33369 add : function(panel)
33371 if(arguments.length > 1){
33372 for(var i = 0, len = arguments.length; i < len; i++) {
33373 this.add(arguments[i]);
33378 // if we have not been rendered yet, then we can not really do much of this..
33379 if (!this.bodyEl) {
33380 this.unrendered_panels.push(panel);
33387 if(this.hasPanel(panel)){
33388 this.showPanel(panel);
33391 panel.setRegion(this);
33392 this.panels.add(panel);
33393 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
33394 // sinle panel - no tab...?? would it not be better to render it with the tabs,
33395 // and hide them... ???
33396 this.bodyEl.dom.appendChild(panel.getEl().dom);
33397 if(panel.background !== true){
33398 this.setActivePanel(panel);
33400 this.fireEvent("paneladded", this, panel);
33407 this.initPanelAsTab(panel);
33411 if(panel.background !== true){
33412 this.tabs.activate(panel.getEl().id);
33414 this.fireEvent("paneladded", this, panel);
33419 * Hides the tab for the specified panel.
33420 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33422 hidePanel : function(panel){
33423 if(this.tabs && (panel = this.getPanel(panel))){
33424 this.tabs.hideTab(panel.getEl().id);
33429 * Unhides the tab for a previously hidden panel.
33430 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33432 unhidePanel : function(panel){
33433 if(this.tabs && (panel = this.getPanel(panel))){
33434 this.tabs.unhideTab(panel.getEl().id);
33438 clearPanels : function(){
33439 while(this.panels.getCount() > 0){
33440 this.remove(this.panels.first());
33445 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33446 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33447 * @param {Boolean} preservePanel Overrides the config preservePanel option
33448 * @return {Roo.ContentPanel} The panel that was removed
33450 remove : function(panel, preservePanel)
33452 panel = this.getPanel(panel);
33457 this.fireEvent("beforeremove", this, panel, e);
33458 if(e.cancel === true){
33461 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33462 var panelId = panel.getId();
33463 this.panels.removeKey(panelId);
33465 document.body.appendChild(panel.getEl().dom);
33468 this.tabs.removeTab(panel.getEl().id);
33469 }else if (!preservePanel){
33470 this.bodyEl.dom.removeChild(panel.getEl().dom);
33472 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33473 var p = this.panels.first();
33474 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33475 tempEl.appendChild(p.getEl().dom);
33476 this.bodyEl.update("");
33477 this.bodyEl.dom.appendChild(p.getEl().dom);
33479 this.updateTitle(p.getTitle());
33481 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33482 this.setActivePanel(p);
33484 panel.setRegion(null);
33485 if(this.activePanel == panel){
33486 this.activePanel = null;
33488 if(this.config.autoDestroy !== false && preservePanel !== true){
33489 try{panel.destroy();}catch(e){}
33491 this.fireEvent("panelremoved", this, panel);
33496 * Returns the TabPanel component used by this region
33497 * @return {Roo.TabPanel}
33499 getTabs : function(){
33503 createTool : function(parentEl, className){
33504 var btn = Roo.DomHelper.append(parentEl, {
33506 cls: "x-layout-tools-button",
33509 cls: "roo-layout-tools-button-inner " + className,
33513 btn.addClassOnOver("roo-layout-tools-button-over");
33518 * Ext JS Library 1.1.1
33519 * Copyright(c) 2006-2007, Ext JS, LLC.
33521 * Originally Released Under LGPL - original licence link has changed is not relivant.
33524 * <script type="text/javascript">
33530 * @class Roo.SplitLayoutRegion
33531 * @extends Roo.LayoutRegion
33532 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33534 Roo.bootstrap.layout.Split = function(config){
33535 this.cursor = config.cursor;
33536 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
33539 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
33541 splitTip : "Drag to resize.",
33542 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33543 useSplitTips : false,
33545 applyConfig : function(config){
33546 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
33549 onRender : function(ctr,pos) {
33551 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
33552 if(!this.config.split){
33557 var splitEl = Roo.DomHelper.append(ctr.dom, {
33559 id: this.el.id + "-split",
33560 cls: "roo-layout-split roo-layout-split-"+this.position,
33563 /** The SplitBar for this region
33564 * @type Roo.SplitBar */
33565 // does not exist yet...
33566 Roo.log([this.position, this.orientation]);
33568 this.split = new Roo.bootstrap.SplitBar({
33569 dragElement : splitEl,
33570 resizingElement: this.el,
33571 orientation : this.orientation
33574 this.split.on("moved", this.onSplitMove, this);
33575 this.split.useShim = this.config.useShim === true;
33576 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33577 if(this.useSplitTips){
33578 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33580 //if(config.collapsible){
33581 // this.split.el.on("dblclick", this.collapse, this);
33584 if(typeof this.config.minSize != "undefined"){
33585 this.split.minSize = this.config.minSize;
33587 if(typeof this.config.maxSize != "undefined"){
33588 this.split.maxSize = this.config.maxSize;
33590 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
33591 this.hideSplitter();
33596 getHMaxSize : function(){
33597 var cmax = this.config.maxSize || 10000;
33598 var center = this.mgr.getRegion("center");
33599 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33602 getVMaxSize : function(){
33603 var cmax = this.config.maxSize || 10000;
33604 var center = this.mgr.getRegion("center");
33605 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33608 onSplitMove : function(split, newSize){
33609 this.fireEvent("resized", this, newSize);
33613 * Returns the {@link Roo.SplitBar} for this region.
33614 * @return {Roo.SplitBar}
33616 getSplitBar : function(){
33621 this.hideSplitter();
33622 Roo.bootstrap.layout.Split.superclass.hide.call(this);
33625 hideSplitter : function(){
33627 this.split.el.setLocation(-2000,-2000);
33628 this.split.el.hide();
33634 this.split.el.show();
33636 Roo.bootstrap.layout.Split.superclass.show.call(this);
33639 beforeSlide: function(){
33640 if(Roo.isGecko){// firefox overflow auto bug workaround
33641 this.bodyEl.clip();
33643 this.tabs.bodyEl.clip();
33645 if(this.activePanel){
33646 this.activePanel.getEl().clip();
33648 if(this.activePanel.beforeSlide){
33649 this.activePanel.beforeSlide();
33655 afterSlide : function(){
33656 if(Roo.isGecko){// firefox overflow auto bug workaround
33657 this.bodyEl.unclip();
33659 this.tabs.bodyEl.unclip();
33661 if(this.activePanel){
33662 this.activePanel.getEl().unclip();
33663 if(this.activePanel.afterSlide){
33664 this.activePanel.afterSlide();
33670 initAutoHide : function(){
33671 if(this.autoHide !== false){
33672 if(!this.autoHideHd){
33673 var st = new Roo.util.DelayedTask(this.slideIn, this);
33674 this.autoHideHd = {
33675 "mouseout": function(e){
33676 if(!e.within(this.el, true)){
33680 "mouseover" : function(e){
33686 this.el.on(this.autoHideHd);
33690 clearAutoHide : function(){
33691 if(this.autoHide !== false){
33692 this.el.un("mouseout", this.autoHideHd.mouseout);
33693 this.el.un("mouseover", this.autoHideHd.mouseover);
33697 clearMonitor : function(){
33698 Roo.get(document).un("click", this.slideInIf, this);
33701 // these names are backwards but not changed for compat
33702 slideOut : function(){
33703 if(this.isSlid || this.el.hasActiveFx()){
33706 this.isSlid = true;
33707 if(this.collapseBtn){
33708 this.collapseBtn.hide();
33710 this.closeBtnState = this.closeBtn.getStyle('display');
33711 this.closeBtn.hide();
33713 this.stickBtn.show();
33716 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
33717 this.beforeSlide();
33718 this.el.setStyle("z-index", 10001);
33719 this.el.slideIn(this.getSlideAnchor(), {
33720 callback: function(){
33722 this.initAutoHide();
33723 Roo.get(document).on("click", this.slideInIf, this);
33724 this.fireEvent("slideshow", this);
33731 afterSlideIn : function(){
33732 this.clearAutoHide();
33733 this.isSlid = false;
33734 this.clearMonitor();
33735 this.el.setStyle("z-index", "");
33736 if(this.collapseBtn){
33737 this.collapseBtn.show();
33739 this.closeBtn.setStyle('display', this.closeBtnState);
33741 this.stickBtn.hide();
33743 this.fireEvent("slidehide", this);
33746 slideIn : function(cb){
33747 if(!this.isSlid || this.el.hasActiveFx()){
33751 this.isSlid = false;
33752 this.beforeSlide();
33753 this.el.slideOut(this.getSlideAnchor(), {
33754 callback: function(){
33755 this.el.setLeftTop(-10000, -10000);
33757 this.afterSlideIn();
33765 slideInIf : function(e){
33766 if(!e.within(this.el)){
33771 animateCollapse : function(){
33772 this.beforeSlide();
33773 this.el.setStyle("z-index", 20000);
33774 var anchor = this.getSlideAnchor();
33775 this.el.slideOut(anchor, {
33776 callback : function(){
33777 this.el.setStyle("z-index", "");
33778 this.collapsedEl.slideIn(anchor, {duration:.3});
33780 this.el.setLocation(-10000,-10000);
33782 this.fireEvent("collapsed", this);
33789 animateExpand : function(){
33790 this.beforeSlide();
33791 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
33792 this.el.setStyle("z-index", 20000);
33793 this.collapsedEl.hide({
33796 this.el.slideIn(this.getSlideAnchor(), {
33797 callback : function(){
33798 this.el.setStyle("z-index", "");
33801 this.split.el.show();
33803 this.fireEvent("invalidated", this);
33804 this.fireEvent("expanded", this);
33832 getAnchor : function(){
33833 return this.anchors[this.position];
33836 getCollapseAnchor : function(){
33837 return this.canchors[this.position];
33840 getSlideAnchor : function(){
33841 return this.sanchors[this.position];
33844 getAlignAdj : function(){
33845 var cm = this.cmargins;
33846 switch(this.position){
33862 getExpandAdj : function(){
33863 var c = this.collapsedEl, cm = this.cmargins;
33864 switch(this.position){
33866 return [-(cm.right+c.getWidth()+cm.left), 0];
33869 return [cm.right+c.getWidth()+cm.left, 0];
33872 return [0, -(cm.top+cm.bottom+c.getHeight())];
33875 return [0, cm.top+cm.bottom+c.getHeight()];
33881 * Ext JS Library 1.1.1
33882 * Copyright(c) 2006-2007, Ext JS, LLC.
33884 * Originally Released Under LGPL - original licence link has changed is not relivant.
33887 * <script type="text/javascript">
33890 * These classes are private internal classes
33892 Roo.bootstrap.layout.Center = function(config){
33893 config.region = "center";
33894 Roo.bootstrap.layout.Region.call(this, config);
33895 this.visible = true;
33896 this.minWidth = config.minWidth || 20;
33897 this.minHeight = config.minHeight || 20;
33900 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
33902 // center panel can't be hidden
33906 // center panel can't be hidden
33909 getMinWidth: function(){
33910 return this.minWidth;
33913 getMinHeight: function(){
33914 return this.minHeight;
33927 Roo.bootstrap.layout.North = function(config)
33929 config.region = 'north';
33930 config.cursor = 'n-resize';
33932 Roo.bootstrap.layout.Split.call(this, config);
33936 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33937 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33938 this.split.el.addClass("roo-layout-split-v");
33940 var size = config.initialSize || config.height;
33941 if(typeof size != "undefined"){
33942 this.el.setHeight(size);
33945 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
33947 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33951 getBox : function(){
33952 if(this.collapsed){
33953 return this.collapsedEl.getBox();
33955 var box = this.el.getBox();
33957 box.height += this.split.el.getHeight();
33962 updateBox : function(box){
33963 if(this.split && !this.collapsed){
33964 box.height -= this.split.el.getHeight();
33965 this.split.el.setLeft(box.x);
33966 this.split.el.setTop(box.y+box.height);
33967 this.split.el.setWidth(box.width);
33969 if(this.collapsed){
33970 this.updateBody(box.width, null);
33972 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33980 Roo.bootstrap.layout.South = function(config){
33981 config.region = 'south';
33982 config.cursor = 's-resize';
33983 Roo.bootstrap.layout.Split.call(this, config);
33985 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33986 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33987 this.split.el.addClass("roo-layout-split-v");
33989 var size = config.initialSize || config.height;
33990 if(typeof size != "undefined"){
33991 this.el.setHeight(size);
33995 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33996 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33997 getBox : function(){
33998 if(this.collapsed){
33999 return this.collapsedEl.getBox();
34001 var box = this.el.getBox();
34003 var sh = this.split.el.getHeight();
34010 updateBox : function(box){
34011 if(this.split && !this.collapsed){
34012 var sh = this.split.el.getHeight();
34015 this.split.el.setLeft(box.x);
34016 this.split.el.setTop(box.y-sh);
34017 this.split.el.setWidth(box.width);
34019 if(this.collapsed){
34020 this.updateBody(box.width, null);
34022 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34026 Roo.bootstrap.layout.East = function(config){
34027 config.region = "east";
34028 config.cursor = "e-resize";
34029 Roo.bootstrap.layout.Split.call(this, config);
34031 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
34032 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34033 this.split.el.addClass("roo-layout-split-h");
34035 var size = config.initialSize || config.width;
34036 if(typeof size != "undefined"){
34037 this.el.setWidth(size);
34040 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
34041 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34042 getBox : function(){
34043 if(this.collapsed){
34044 return this.collapsedEl.getBox();
34046 var box = this.el.getBox();
34048 var sw = this.split.el.getWidth();
34055 updateBox : function(box){
34056 if(this.split && !this.collapsed){
34057 var sw = this.split.el.getWidth();
34059 this.split.el.setLeft(box.x);
34060 this.split.el.setTop(box.y);
34061 this.split.el.setHeight(box.height);
34064 if(this.collapsed){
34065 this.updateBody(null, box.height);
34067 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34071 Roo.bootstrap.layout.West = function(config){
34072 config.region = "west";
34073 config.cursor = "w-resize";
34075 Roo.bootstrap.layout.Split.call(this, config);
34077 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
34078 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
34079 this.split.el.addClass("roo-layout-split-h");
34083 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
34084 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
34086 onRender: function(ctr, pos)
34088 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
34089 var size = this.config.initialSize || this.config.width;
34090 if(typeof size != "undefined"){
34091 this.el.setWidth(size);
34095 getBox : function(){
34096 if(this.collapsed){
34097 return this.collapsedEl.getBox();
34099 var box = this.el.getBox();
34101 box.width += this.split.el.getWidth();
34106 updateBox : function(box){
34107 if(this.split && !this.collapsed){
34108 var sw = this.split.el.getWidth();
34110 this.split.el.setLeft(box.x+box.width);
34111 this.split.el.setTop(box.y);
34112 this.split.el.setHeight(box.height);
34114 if(this.collapsed){
34115 this.updateBody(null, box.height);
34117 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
34120 Roo.namespace("Roo.bootstrap.panel");/*
34122 * Ext JS Library 1.1.1
34123 * Copyright(c) 2006-2007, Ext JS, LLC.
34125 * Originally Released Under LGPL - original licence link has changed is not relivant.
34128 * <script type="text/javascript">
34131 * @class Roo.ContentPanel
34132 * @extends Roo.util.Observable
34133 * A basic ContentPanel element.
34134 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34135 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34136 * @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
34137 * @cfg {Boolean} closable True if the panel can be closed/removed
34138 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34139 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34140 * @cfg {Toolbar} toolbar A toolbar for this panel
34141 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34142 * @cfg {String} title The title for this panel
34143 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34144 * @cfg {String} url Calls {@link #setUrl} with this value
34145 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34146 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34147 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34148 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34151 * Create a new ContentPanel.
34152 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34153 * @param {String/Object} config A string to set only the title or a config object
34154 * @param {String} content (optional) Set the HTML content for this panel
34155 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34157 Roo.bootstrap.panel.Content = function( config){
34159 var el = config.el;
34160 var content = config.content;
34162 if(config.autoCreate){ // xtype is available if this is called from factory
34165 this.el = Roo.get(el);
34166 if(!this.el && config && config.autoCreate){
34167 if(typeof config.autoCreate == "object"){
34168 if(!config.autoCreate.id){
34169 config.autoCreate.id = config.id||el;
34171 this.el = Roo.DomHelper.append(document.body,
34172 config.autoCreate, true);
34174 var elcfg = { tag: "div",
34175 cls: "roo-layout-inactive-content",
34179 elcfg.html = config.html;
34183 this.el = Roo.DomHelper.append(document.body, elcfg , true);
34186 this.closable = false;
34187 this.loaded = false;
34188 this.active = false;
34191 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
34193 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
34195 this.wrapEl = this.el.wrap();
34197 if (config.toolbar.items) {
34198 ti = config.toolbar.items ;
34199 delete config.toolbar.items ;
34203 this.toolbar.render(this.wrapEl, 'before');
34204 for(var i =0;i < ti.length;i++) {
34205 // Roo.log(['add child', items[i]]);
34206 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34208 this.toolbar.items = nitems;
34209 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
34210 delete config.toolbar;
34214 // xtype created footer. - not sure if will work as we normally have to render first..
34215 if (this.footer && !this.footer.el && this.footer.xtype) {
34216 if (!this.wrapEl) {
34217 this.wrapEl = this.el.wrap();
34220 this.footer.container = this.wrapEl.createChild();
34222 this.footer = Roo.factory(this.footer, Roo);
34227 if(typeof config == "string"){
34228 this.title = config;
34230 Roo.apply(this, config);
34234 this.resizeEl = Roo.get(this.resizeEl, true);
34236 this.resizeEl = this.el;
34238 // handle view.xtype
34246 * Fires when this panel is activated.
34247 * @param {Roo.ContentPanel} this
34251 * @event deactivate
34252 * Fires when this panel is activated.
34253 * @param {Roo.ContentPanel} this
34255 "deactivate" : true,
34259 * Fires when this panel is resized if fitToFrame is true.
34260 * @param {Roo.ContentPanel} this
34261 * @param {Number} width The width after any component adjustments
34262 * @param {Number} height The height after any component adjustments
34268 * Fires when this tab is created
34269 * @param {Roo.ContentPanel} this
34280 if(this.autoScroll){
34281 this.resizeEl.setStyle("overflow", "auto");
34283 // fix randome scrolling
34284 //this.el.on('scroll', function() {
34285 // Roo.log('fix random scolling');
34286 // this.scrollTo('top',0);
34289 content = content || this.content;
34291 this.setContent(content);
34293 if(config && config.url){
34294 this.setUrl(this.url, this.params, this.loadOnce);
34299 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
34301 if (this.view && typeof(this.view.xtype) != 'undefined') {
34302 this.view.el = this.el.appendChild(document.createElement("div"));
34303 this.view = Roo.factory(this.view);
34304 this.view.render && this.view.render(false, '');
34308 this.fireEvent('render', this);
34311 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
34313 setRegion : function(region){
34314 this.region = region;
34315 this.setActiveClass(region && !this.background);
34319 setActiveClass: function(state)
34322 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
34323 this.el.setStyle('position','relative');
34325 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
34326 this.el.setStyle('position', 'absolute');
34331 * Returns the toolbar for this Panel if one was configured.
34332 * @return {Roo.Toolbar}
34334 getToolbar : function(){
34335 return this.toolbar;
34338 setActiveState : function(active)
34340 this.active = active;
34341 this.setActiveClass(active);
34343 this.fireEvent("deactivate", this);
34345 this.fireEvent("activate", this);
34349 * Updates this panel's element
34350 * @param {String} content The new content
34351 * @param {Boolean} loadScripts (optional) true to look for and process scripts
34353 setContent : function(content, loadScripts){
34354 this.el.update(content, loadScripts);
34357 ignoreResize : function(w, h){
34358 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
34361 this.lastSize = {width: w, height: h};
34366 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
34367 * @return {Roo.UpdateManager} The UpdateManager
34369 getUpdateManager : function(){
34370 return this.el.getUpdateManager();
34373 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
34374 * @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:
34377 url: "your-url.php",
34378 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
34379 callback: yourFunction,
34380 scope: yourObject, //(optional scope)
34383 text: "Loading...",
34388 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
34389 * 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.
34390 * @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}
34391 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
34392 * @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.
34393 * @return {Roo.ContentPanel} this
34396 var um = this.el.getUpdateManager();
34397 um.update.apply(um, arguments);
34403 * 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.
34404 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
34405 * @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)
34406 * @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)
34407 * @return {Roo.UpdateManager} The UpdateManager
34409 setUrl : function(url, params, loadOnce){
34410 if(this.refreshDelegate){
34411 this.removeListener("activate", this.refreshDelegate);
34413 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34414 this.on("activate", this.refreshDelegate);
34415 return this.el.getUpdateManager();
34418 _handleRefresh : function(url, params, loadOnce){
34419 if(!loadOnce || !this.loaded){
34420 var updater = this.el.getUpdateManager();
34421 updater.update(url, params, this._setLoaded.createDelegate(this));
34425 _setLoaded : function(){
34426 this.loaded = true;
34430 * Returns this panel's id
34433 getId : function(){
34438 * Returns this panel's element - used by regiosn to add.
34439 * @return {Roo.Element}
34441 getEl : function(){
34442 return this.wrapEl || this.el;
34447 adjustForComponents : function(width, height)
34449 //Roo.log('adjustForComponents ');
34450 if(this.resizeEl != this.el){
34451 width -= this.el.getFrameWidth('lr');
34452 height -= this.el.getFrameWidth('tb');
34455 var te = this.toolbar.getEl();
34456 height -= te.getHeight();
34457 te.setWidth(width);
34460 var te = this.footer.getEl();
34461 Roo.log("footer:" + te.getHeight());
34463 height -= te.getHeight();
34464 te.setWidth(width);
34468 if(this.adjustments){
34469 width += this.adjustments[0];
34470 height += this.adjustments[1];
34472 return {"width": width, "height": height};
34475 setSize : function(width, height){
34476 if(this.fitToFrame && !this.ignoreResize(width, height)){
34477 if(this.fitContainer && this.resizeEl != this.el){
34478 this.el.setSize(width, height);
34480 var size = this.adjustForComponents(width, height);
34481 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34482 this.fireEvent('resize', this, size.width, size.height);
34487 * Returns this panel's title
34490 getTitle : function(){
34495 * Set this panel's title
34496 * @param {String} title
34498 setTitle : function(title){
34499 this.title = title;
34501 this.region.updatePanelTitle(this, title);
34506 * Returns true is this panel was configured to be closable
34507 * @return {Boolean}
34509 isClosable : function(){
34510 return this.closable;
34513 beforeSlide : function(){
34515 this.resizeEl.clip();
34518 afterSlide : function(){
34520 this.resizeEl.unclip();
34524 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34525 * Will fail silently if the {@link #setUrl} method has not been called.
34526 * This does not activate the panel, just updates its content.
34528 refresh : function(){
34529 if(this.refreshDelegate){
34530 this.loaded = false;
34531 this.refreshDelegate();
34536 * Destroys this panel
34538 destroy : function(){
34539 this.el.removeAllListeners();
34540 var tempEl = document.createElement("span");
34541 tempEl.appendChild(this.el.dom);
34542 tempEl.innerHTML = "";
34548 * form - if the content panel contains a form - this is a reference to it.
34549 * @type {Roo.form.Form}
34553 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34554 * This contains a reference to it.
34560 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34570 * @param {Object} cfg Xtype definition of item to add.
34574 getChildContainer: function () {
34575 return this.getEl();
34580 var ret = new Roo.factory(cfg);
34585 if (cfg.xtype.match(/^Form$/)) {
34588 //if (this.footer) {
34589 // el = this.footer.container.insertSibling(false, 'before');
34591 el = this.el.createChild();
34594 this.form = new Roo.form.Form(cfg);
34597 if ( this.form.allItems.length) {
34598 this.form.render(el.dom);
34602 // should only have one of theses..
34603 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34604 // views.. should not be just added - used named prop 'view''
34606 cfg.el = this.el.appendChild(document.createElement("div"));
34609 var ret = new Roo.factory(cfg);
34611 ret.render && ret.render(false, ''); // render blank..
34621 * @class Roo.bootstrap.panel.Grid
34622 * @extends Roo.bootstrap.panel.Content
34624 * Create a new GridPanel.
34625 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
34626 * @param {Object} config A the config object
34632 Roo.bootstrap.panel.Grid = function(config)
34636 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34637 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
34639 config.el = this.wrapper;
34640 //this.el = this.wrapper;
34642 if (config.container) {
34643 // ctor'ed from a Border/panel.grid
34646 this.wrapper.setStyle("overflow", "hidden");
34647 this.wrapper.addClass('roo-grid-container');
34652 if(config.toolbar){
34653 var tool_el = this.wrapper.createChild();
34654 this.toolbar = Roo.factory(config.toolbar);
34656 if (config.toolbar.items) {
34657 ti = config.toolbar.items ;
34658 delete config.toolbar.items ;
34662 this.toolbar.render(tool_el);
34663 for(var i =0;i < ti.length;i++) {
34664 // Roo.log(['add child', items[i]]);
34665 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34667 this.toolbar.items = nitems;
34669 delete config.toolbar;
34672 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
34673 config.grid.scrollBody = true;;
34674 config.grid.monitorWindowResize = false; // turn off autosizing
34675 config.grid.autoHeight = false;
34676 config.grid.autoWidth = false;
34678 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
34680 if (config.background) {
34681 // render grid on panel activation (if panel background)
34682 this.on('activate', function(gp) {
34683 if (!gp.grid.rendered) {
34684 gp.grid.render(el);
34685 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34691 this.grid.render(this.wrapper);
34692 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34695 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
34696 // ??? needed ??? config.el = this.wrapper;
34701 // xtype created footer. - not sure if will work as we normally have to render first..
34702 if (this.footer && !this.footer.el && this.footer.xtype) {
34704 var ctr = this.grid.getView().getFooterPanel(true);
34705 this.footer.dataSource = this.grid.dataSource;
34706 this.footer = Roo.factory(this.footer, Roo);
34707 this.footer.render(ctr);
34717 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
34718 getId : function(){
34719 return this.grid.id;
34723 * Returns the grid for this panel
34724 * @return {Roo.bootstrap.Table}
34726 getGrid : function(){
34730 setSize : function(width, height){
34731 if(!this.ignoreResize(width, height)){
34732 var grid = this.grid;
34733 var size = this.adjustForComponents(width, height);
34734 var gridel = grid.getGridEl();
34735 gridel.setSize(size.width, size.height);
34737 var thd = grid.getGridEl().select('thead',true).first();
34738 var tbd = grid.getGridEl().select('tbody', true).first();
34740 tbd.setSize(width, height - thd.getHeight());
34749 beforeSlide : function(){
34750 this.grid.getView().scroller.clip();
34753 afterSlide : function(){
34754 this.grid.getView().scroller.unclip();
34757 destroy : function(){
34758 this.grid.destroy();
34760 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
34765 * @class Roo.bootstrap.panel.Nest
34766 * @extends Roo.bootstrap.panel.Content
34768 * Create a new Panel, that can contain a layout.Border.
34771 * @param {Roo.BorderLayout} layout The layout for this panel
34772 * @param {String/Object} config A string to set only the title or a config object
34774 Roo.bootstrap.panel.Nest = function(config)
34776 // construct with only one argument..
34777 /* FIXME - implement nicer consturctors
34778 if (layout.layout) {
34780 layout = config.layout;
34781 delete config.layout;
34783 if (layout.xtype && !layout.getEl) {
34784 // then layout needs constructing..
34785 layout = Roo.factory(layout, Roo);
34789 config.el = config.layout.getEl();
34791 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
34793 config.layout.monitorWindowResize = false; // turn off autosizing
34794 this.layout = config.layout;
34795 this.layout.getEl().addClass("roo-layout-nested-layout");
34802 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
34804 setSize : function(width, height){
34805 if(!this.ignoreResize(width, height)){
34806 var size = this.adjustForComponents(width, height);
34807 var el = this.layout.getEl();
34808 if (size.height < 1) {
34809 el.setWidth(size.width);
34811 el.setSize(size.width, size.height);
34813 var touch = el.dom.offsetWidth;
34814 this.layout.layout();
34815 // ie requires a double layout on the first pass
34816 if(Roo.isIE && !this.initialized){
34817 this.initialized = true;
34818 this.layout.layout();
34823 // activate all subpanels if not currently active..
34825 setActiveState : function(active){
34826 this.active = active;
34827 this.setActiveClass(active);
34830 this.fireEvent("deactivate", this);
34834 this.fireEvent("activate", this);
34835 // not sure if this should happen before or after..
34836 if (!this.layout) {
34837 return; // should not happen..
34840 for (var r in this.layout.regions) {
34841 reg = this.layout.getRegion(r);
34842 if (reg.getActivePanel()) {
34843 //reg.showPanel(reg.getActivePanel()); // force it to activate..
34844 reg.setActivePanel(reg.getActivePanel());
34847 if (!reg.panels.length) {
34850 reg.showPanel(reg.getPanel(0));
34859 * Returns the nested BorderLayout for this panel
34860 * @return {Roo.BorderLayout}
34862 getLayout : function(){
34863 return this.layout;
34867 * Adds a xtype elements to the layout of the nested panel
34871 xtype : 'ContentPanel',
34878 xtype : 'NestedLayoutPanel',
34884 items : [ ... list of content panels or nested layout panels.. ]
34888 * @param {Object} cfg Xtype definition of item to add.
34890 addxtype : function(cfg) {
34891 return this.layout.addxtype(cfg);
34896 * Ext JS Library 1.1.1
34897 * Copyright(c) 2006-2007, Ext JS, LLC.
34899 * Originally Released Under LGPL - original licence link has changed is not relivant.
34902 * <script type="text/javascript">
34905 * @class Roo.TabPanel
34906 * @extends Roo.util.Observable
34907 * A lightweight tab container.
34911 // basic tabs 1, built from existing content
34912 var tabs = new Roo.TabPanel("tabs1");
34913 tabs.addTab("script", "View Script");
34914 tabs.addTab("markup", "View Markup");
34915 tabs.activate("script");
34917 // more advanced tabs, built from javascript
34918 var jtabs = new Roo.TabPanel("jtabs");
34919 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
34921 // set up the UpdateManager
34922 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
34923 var updater = tab2.getUpdateManager();
34924 updater.setDefaultUrl("ajax1.htm");
34925 tab2.on('activate', updater.refresh, updater, true);
34927 // Use setUrl for Ajax loading
34928 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
34929 tab3.setUrl("ajax2.htm", null, true);
34932 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
34935 jtabs.activate("jtabs-1");
34938 * Create a new TabPanel.
34939 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
34940 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
34942 Roo.bootstrap.panel.Tabs = function(config){
34944 * The container element for this TabPanel.
34945 * @type Roo.Element
34947 this.el = Roo.get(config.el);
34950 if(typeof config == "boolean"){
34951 this.tabPosition = config ? "bottom" : "top";
34953 Roo.apply(this, config);
34957 if(this.tabPosition == "bottom"){
34958 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34959 this.el.addClass("roo-tabs-bottom");
34961 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
34962 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
34963 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
34965 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
34967 if(this.tabPosition != "bottom"){
34968 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
34969 * @type Roo.Element
34971 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34972 this.el.addClass("roo-tabs-top");
34976 this.bodyEl.setStyle("position", "relative");
34978 this.active = null;
34979 this.activateDelegate = this.activate.createDelegate(this);
34984 * Fires when the active tab changes
34985 * @param {Roo.TabPanel} this
34986 * @param {Roo.TabPanelItem} activePanel The new active tab
34990 * @event beforetabchange
34991 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
34992 * @param {Roo.TabPanel} this
34993 * @param {Object} e Set cancel to true on this object to cancel the tab change
34994 * @param {Roo.TabPanelItem} tab The tab being changed to
34996 "beforetabchange" : true
34999 Roo.EventManager.onWindowResize(this.onResize, this);
35000 this.cpad = this.el.getPadding("lr");
35001 this.hiddenCount = 0;
35004 // toolbar on the tabbar support...
35005 if (this.toolbar) {
35006 alert("no toolbar support yet");
35007 this.toolbar = false;
35009 var tcfg = this.toolbar;
35010 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
35011 this.toolbar = new Roo.Toolbar(tcfg);
35012 if (Roo.isSafari) {
35013 var tbl = tcfg.container.child('table', true);
35014 tbl.setAttribute('width', '100%');
35022 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
35025 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
35027 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
35029 tabPosition : "top",
35031 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
35033 currentTabWidth : 0,
35035 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
35039 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
35043 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
35045 preferredTabWidth : 175,
35047 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
35049 resizeTabs : false,
35051 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
35053 monitorResize : true,
35055 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
35060 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
35061 * @param {String} id The id of the div to use <b>or create</b>
35062 * @param {String} text The text for the tab
35063 * @param {String} content (optional) Content to put in the TabPanelItem body
35064 * @param {Boolean} closable (optional) True to create a close icon on the tab
35065 * @return {Roo.TabPanelItem} The created TabPanelItem
35067 addTab : function(id, text, content, closable)
35069 var item = new Roo.bootstrap.panel.TabItem({
35073 closable : closable
35075 this.addTabItem(item);
35077 item.setContent(content);
35083 * Returns the {@link Roo.TabPanelItem} with the specified id/index
35084 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
35085 * @return {Roo.TabPanelItem}
35087 getTab : function(id){
35088 return this.items[id];
35092 * Hides the {@link Roo.TabPanelItem} with the specified id/index
35093 * @param {String/Number} id The id or index of the TabPanelItem to hide.
35095 hideTab : function(id){
35096 var t = this.items[id];
35099 this.hiddenCount++;
35100 this.autoSizeTabs();
35105 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
35106 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
35108 unhideTab : function(id){
35109 var t = this.items[id];
35111 t.setHidden(false);
35112 this.hiddenCount--;
35113 this.autoSizeTabs();
35118 * Adds an existing {@link Roo.TabPanelItem}.
35119 * @param {Roo.TabPanelItem} item The TabPanelItem to add
35121 addTabItem : function(item){
35122 this.items[item.id] = item;
35123 this.items.push(item);
35124 // if(this.resizeTabs){
35125 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
35126 // this.autoSizeTabs();
35128 // item.autoSize();
35133 * Removes a {@link Roo.TabPanelItem}.
35134 * @param {String/Number} id The id or index of the TabPanelItem to remove.
35136 removeTab : function(id){
35137 var items = this.items;
35138 var tab = items[id];
35139 if(!tab) { return; }
35140 var index = items.indexOf(tab);
35141 if(this.active == tab && items.length > 1){
35142 var newTab = this.getNextAvailable(index);
35147 this.stripEl.dom.removeChild(tab.pnode.dom);
35148 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
35149 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
35151 items.splice(index, 1);
35152 delete this.items[tab.id];
35153 tab.fireEvent("close", tab);
35154 tab.purgeListeners();
35155 this.autoSizeTabs();
35158 getNextAvailable : function(start){
35159 var items = this.items;
35161 // look for a next tab that will slide over to
35162 // replace the one being removed
35163 while(index < items.length){
35164 var item = items[++index];
35165 if(item && !item.isHidden()){
35169 // if one isn't found select the previous tab (on the left)
35172 var item = items[--index];
35173 if(item && !item.isHidden()){
35181 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
35182 * @param {String/Number} id The id or index of the TabPanelItem to disable.
35184 disableTab : function(id){
35185 var tab = this.items[id];
35186 if(tab && this.active != tab){
35192 * Enables a {@link Roo.TabPanelItem} that is disabled.
35193 * @param {String/Number} id The id or index of the TabPanelItem to enable.
35195 enableTab : function(id){
35196 var tab = this.items[id];
35201 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
35202 * @param {String/Number} id The id or index of the TabPanelItem to activate.
35203 * @return {Roo.TabPanelItem} The TabPanelItem.
35205 activate : function(id){
35206 var tab = this.items[id];
35210 if(tab == this.active || tab.disabled){
35214 this.fireEvent("beforetabchange", this, e, tab);
35215 if(e.cancel !== true && !tab.disabled){
35217 this.active.hide();
35219 this.active = this.items[id];
35220 this.active.show();
35221 this.fireEvent("tabchange", this, this.active);
35227 * Gets the active {@link Roo.TabPanelItem}.
35228 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
35230 getActiveTab : function(){
35231 return this.active;
35235 * Updates the tab body element to fit the height of the container element
35236 * for overflow scrolling
35237 * @param {Number} targetHeight (optional) Override the starting height from the elements height
35239 syncHeight : function(targetHeight){
35240 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35241 var bm = this.bodyEl.getMargins();
35242 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
35243 this.bodyEl.setHeight(newHeight);
35247 onResize : function(){
35248 if(this.monitorResize){
35249 this.autoSizeTabs();
35254 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
35256 beginUpdate : function(){
35257 this.updating = true;
35261 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
35263 endUpdate : function(){
35264 this.updating = false;
35265 this.autoSizeTabs();
35269 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
35271 autoSizeTabs : function(){
35272 var count = this.items.length;
35273 var vcount = count - this.hiddenCount;
35274 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
35277 var w = Math.max(this.el.getWidth() - this.cpad, 10);
35278 var availWidth = Math.floor(w / vcount);
35279 var b = this.stripBody;
35280 if(b.getWidth() > w){
35281 var tabs = this.items;
35282 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
35283 if(availWidth < this.minTabWidth){
35284 /*if(!this.sleft){ // incomplete scrolling code
35285 this.createScrollButtons();
35288 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
35291 if(this.currentTabWidth < this.preferredTabWidth){
35292 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
35298 * Returns the number of tabs in this TabPanel.
35301 getCount : function(){
35302 return this.items.length;
35306 * Resizes all the tabs to the passed width
35307 * @param {Number} The new width
35309 setTabWidth : function(width){
35310 this.currentTabWidth = width;
35311 for(var i = 0, len = this.items.length; i < len; i++) {
35312 if(!this.items[i].isHidden()) {
35313 this.items[i].setWidth(width);
35319 * Destroys this TabPanel
35320 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
35322 destroy : function(removeEl){
35323 Roo.EventManager.removeResizeListener(this.onResize, this);
35324 for(var i = 0, len = this.items.length; i < len; i++){
35325 this.items[i].purgeListeners();
35327 if(removeEl === true){
35328 this.el.update("");
35333 createStrip : function(container)
35335 var strip = document.createElement("nav");
35336 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
35337 container.appendChild(strip);
35341 createStripList : function(strip)
35343 // div wrapper for retard IE
35344 // returns the "tr" element.
35345 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
35346 //'<div class="x-tabs-strip-wrap">'+
35347 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
35348 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
35349 return strip.firstChild; //.firstChild.firstChild.firstChild;
35351 createBody : function(container)
35353 var body = document.createElement("div");
35354 Roo.id(body, "tab-body");
35355 //Roo.fly(body).addClass("x-tabs-body");
35356 Roo.fly(body).addClass("tab-content");
35357 container.appendChild(body);
35360 createItemBody :function(bodyEl, id){
35361 var body = Roo.getDom(id);
35363 body = document.createElement("div");
35366 //Roo.fly(body).addClass("x-tabs-item-body");
35367 Roo.fly(body).addClass("tab-pane");
35368 bodyEl.insertBefore(body, bodyEl.firstChild);
35372 createStripElements : function(stripEl, text, closable)
35374 var td = document.createElement("li"); // was td..
35377 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
35380 stripEl.appendChild(td);
35382 td.className = "x-tabs-closable";
35383 if(!this.closeTpl){
35384 this.closeTpl = new Roo.Template(
35385 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
35386 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
35387 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
35390 var el = this.closeTpl.overwrite(td, {"text": text});
35391 var close = el.getElementsByTagName("div")[0];
35392 var inner = el.getElementsByTagName("em")[0];
35393 return {"el": el, "close": close, "inner": inner};
35396 // not sure what this is..
35398 //this.tabTpl = new Roo.Template(
35399 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
35400 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
35402 this.tabTpl = new Roo.Template(
35404 '<span unselectable="on"' +
35405 (this.disableTooltips ? '' : ' title="{text}"') +
35406 ' >{text}</span></span></a>'
35410 var el = this.tabTpl.overwrite(td, {"text": text});
35411 var inner = el.getElementsByTagName("span")[0];
35412 return {"el": el, "inner": inner};
35420 * @class Roo.TabPanelItem
35421 * @extends Roo.util.Observable
35422 * Represents an individual item (tab plus body) in a TabPanel.
35423 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
35424 * @param {String} id The id of this TabPanelItem
35425 * @param {String} text The text for the tab of this TabPanelItem
35426 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
35428 Roo.bootstrap.panel.TabItem = function(config){
35430 * The {@link Roo.TabPanel} this TabPanelItem belongs to
35431 * @type Roo.TabPanel
35433 this.tabPanel = config.panel;
35435 * The id for this TabPanelItem
35438 this.id = config.id;
35440 this.disabled = false;
35442 this.text = config.text;
35444 this.loaded = false;
35445 this.closable = config.closable;
35448 * The body element for this TabPanelItem.
35449 * @type Roo.Element
35451 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
35452 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
35453 this.bodyEl.setStyle("display", "block");
35454 this.bodyEl.setStyle("zoom", "1");
35455 //this.hideAction();
35457 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
35459 this.el = Roo.get(els.el);
35460 this.inner = Roo.get(els.inner, true);
35461 this.textEl = Roo.get(this.el.dom.firstChild, true);
35462 this.pnode = Roo.get(els.el.parentNode, true);
35463 this.el.on("mousedown", this.onTabMouseDown, this);
35464 this.el.on("click", this.onTabClick, this);
35466 if(config.closable){
35467 var c = Roo.get(els.close, true);
35468 c.dom.title = this.closeText;
35469 c.addClassOnOver("close-over");
35470 c.on("click", this.closeClick, this);
35476 * Fires when this tab becomes the active tab.
35477 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35478 * @param {Roo.TabPanelItem} this
35482 * @event beforeclose
35483 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
35484 * @param {Roo.TabPanelItem} this
35485 * @param {Object} e Set cancel to true on this object to cancel the close.
35487 "beforeclose": true,
35490 * Fires when this tab is closed.
35491 * @param {Roo.TabPanelItem} this
35495 * @event deactivate
35496 * Fires when this tab is no longer the active tab.
35497 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35498 * @param {Roo.TabPanelItem} this
35500 "deactivate" : true
35502 this.hidden = false;
35504 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
35507 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
35509 purgeListeners : function(){
35510 Roo.util.Observable.prototype.purgeListeners.call(this);
35511 this.el.removeAllListeners();
35514 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
35517 this.pnode.addClass("active");
35520 this.tabPanel.stripWrap.repaint();
35522 this.fireEvent("activate", this.tabPanel, this);
35526 * Returns true if this tab is the active tab.
35527 * @return {Boolean}
35529 isActive : function(){
35530 return this.tabPanel.getActiveTab() == this;
35534 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
35537 this.pnode.removeClass("active");
35539 this.fireEvent("deactivate", this.tabPanel, this);
35542 hideAction : function(){
35543 this.bodyEl.hide();
35544 this.bodyEl.setStyle("position", "absolute");
35545 this.bodyEl.setLeft("-20000px");
35546 this.bodyEl.setTop("-20000px");
35549 showAction : function(){
35550 this.bodyEl.setStyle("position", "relative");
35551 this.bodyEl.setTop("");
35552 this.bodyEl.setLeft("");
35553 this.bodyEl.show();
35557 * Set the tooltip for the tab.
35558 * @param {String} tooltip The tab's tooltip
35560 setTooltip : function(text){
35561 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
35562 this.textEl.dom.qtip = text;
35563 this.textEl.dom.removeAttribute('title');
35565 this.textEl.dom.title = text;
35569 onTabClick : function(e){
35570 e.preventDefault();
35571 this.tabPanel.activate(this.id);
35574 onTabMouseDown : function(e){
35575 e.preventDefault();
35576 this.tabPanel.activate(this.id);
35579 getWidth : function(){
35580 return this.inner.getWidth();
35583 setWidth : function(width){
35584 var iwidth = width - this.pnode.getPadding("lr");
35585 this.inner.setWidth(iwidth);
35586 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
35587 this.pnode.setWidth(width);
35591 * Show or hide the tab
35592 * @param {Boolean} hidden True to hide or false to show.
35594 setHidden : function(hidden){
35595 this.hidden = hidden;
35596 this.pnode.setStyle("display", hidden ? "none" : "");
35600 * Returns true if this tab is "hidden"
35601 * @return {Boolean}
35603 isHidden : function(){
35604 return this.hidden;
35608 * Returns the text for this tab
35611 getText : function(){
35615 autoSize : function(){
35616 //this.el.beginMeasure();
35617 this.textEl.setWidth(1);
35619 * #2804 [new] Tabs in Roojs
35620 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
35622 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
35623 //this.el.endMeasure();
35627 * Sets the text for the tab (Note: this also sets the tooltip text)
35628 * @param {String} text The tab's text and tooltip
35630 setText : function(text){
35632 this.textEl.update(text);
35633 this.setTooltip(text);
35634 //if(!this.tabPanel.resizeTabs){
35635 // this.autoSize();
35639 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
35641 activate : function(){
35642 this.tabPanel.activate(this.id);
35646 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
35648 disable : function(){
35649 if(this.tabPanel.active != this){
35650 this.disabled = true;
35651 this.pnode.addClass("disabled");
35656 * Enables this TabPanelItem if it was previously disabled.
35658 enable : function(){
35659 this.disabled = false;
35660 this.pnode.removeClass("disabled");
35664 * Sets the content for this TabPanelItem.
35665 * @param {String} content The content
35666 * @param {Boolean} loadScripts true to look for and load scripts
35668 setContent : function(content, loadScripts){
35669 this.bodyEl.update(content, loadScripts);
35673 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
35674 * @return {Roo.UpdateManager} The UpdateManager
35676 getUpdateManager : function(){
35677 return this.bodyEl.getUpdateManager();
35681 * Set a URL to be used to load the content for this TabPanelItem.
35682 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
35683 * @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)
35684 * @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)
35685 * @return {Roo.UpdateManager} The UpdateManager
35687 setUrl : function(url, params, loadOnce){
35688 if(this.refreshDelegate){
35689 this.un('activate', this.refreshDelegate);
35691 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35692 this.on("activate", this.refreshDelegate);
35693 return this.bodyEl.getUpdateManager();
35697 _handleRefresh : function(url, params, loadOnce){
35698 if(!loadOnce || !this.loaded){
35699 var updater = this.bodyEl.getUpdateManager();
35700 updater.update(url, params, this._setLoaded.createDelegate(this));
35705 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
35706 * Will fail silently if the setUrl method has not been called.
35707 * This does not activate the panel, just updates its content.
35709 refresh : function(){
35710 if(this.refreshDelegate){
35711 this.loaded = false;
35712 this.refreshDelegate();
35717 _setLoaded : function(){
35718 this.loaded = true;
35722 closeClick : function(e){
35725 this.fireEvent("beforeclose", this, o);
35726 if(o.cancel !== true){
35727 this.tabPanel.removeTab(this.id);
35731 * The text displayed in the tooltip for the close icon.
35734 closeText : "Close this tab"