4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
394 Roo.bootstrap.Body.superclass.constructor.call(this, config);
395 this.el = Roo.get(document.body);
396 if (this.cls && this.cls.length) {
397 Roo.get(document.body).addClass(this.cls);
401 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
403 is_body : true,// just to make sure it's constructed?
408 onRender : function(ct, position)
410 /* Roo.log("Roo.bootstrap.Body - onRender");
411 if (this.cls && this.cls.length) {
412 Roo.get(document.body).addClass(this.cls);
432 * @class Roo.bootstrap.ButtonGroup
433 * @extends Roo.bootstrap.Component
434 * Bootstrap ButtonGroup class
435 * @cfg {String} size lg | sm | xs (default empty normal)
436 * @cfg {String} align vertical | justified (default none)
437 * @cfg {String} direction up | down (default down)
438 * @cfg {Boolean} toolbar false | true
439 * @cfg {Boolean} btn true | false
444 * @param {Object} config The config object
447 Roo.bootstrap.ButtonGroup = function(config){
448 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
451 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
459 getAutoCreate : function(){
465 cfg.html = this.html || cfg.html;
476 if (['vertical','justified'].indexOf(this.align)!==-1) {
477 cfg.cls = 'btn-group-' + this.align;
479 if (this.align == 'justified') {
480 console.log(this.items);
484 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
485 cfg.cls += ' btn-group-' + this.size;
488 if (this.direction == 'up') {
489 cfg.cls += ' dropup' ;
505 * @class Roo.bootstrap.Button
506 * @extends Roo.bootstrap.Component
507 * Bootstrap Button class
508 * @cfg {String} html The button content
509 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
510 * @cfg {String} size ( lg | sm | xs)
511 * @cfg {String} tag ( a | input | submit)
512 * @cfg {String} href empty or href
513 * @cfg {Boolean} disabled default false;
514 * @cfg {Boolean} isClose default false;
515 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
516 * @cfg {String} badge text for badge
517 * @cfg {String} theme default
518 * @cfg {Boolean} inverse
519 * @cfg {Boolean} toggle
520 * @cfg {String} ontext text for on toggle state
521 * @cfg {String} offtext text for off toggle state
522 * @cfg {Boolean} defaulton
523 * @cfg {Boolean} preventDefault default true
524 * @cfg {Boolean} removeClass remove the standard class..
525 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
528 * Create a new button
529 * @param {Object} config The config object
533 Roo.bootstrap.Button = function(config){
534 Roo.bootstrap.Button.superclass.constructor.call(this, config);
539 * When a butotn is pressed
540 * @param {Roo.bootstrap.Button} this
541 * @param {Roo.EventObject} e
546 * After the button has been toggles
547 * @param {Roo.EventObject} e
548 * @param {boolean} pressed (also available as button.pressed)
554 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
572 preventDefault: true,
581 getAutoCreate : function(){
589 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
590 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
595 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
597 if (this.toggle == true) {
600 cls: 'slider-frame roo-button',
605 'data-off-text':'OFF',
606 cls: 'slider-button',
612 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
613 cfg.cls += ' '+this.weight;
622 cfg["aria-hidden"] = true;
624 cfg.html = "×";
630 if (this.theme==='default') {
631 cfg.cls = 'btn roo-button';
633 //if (this.parentType != 'Navbar') {
634 this.weight = this.weight.length ? this.weight : 'default';
636 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
638 cfg.cls += ' btn-' + this.weight;
640 } else if (this.theme==='glow') {
643 cfg.cls = 'btn-glow roo-button';
645 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
647 cfg.cls += ' ' + this.weight;
653 this.cls += ' inverse';
658 cfg.cls += ' active';
662 cfg.disabled = 'disabled';
666 Roo.log('changing to ul' );
668 this.glyphicon = 'caret';
671 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
673 //gsRoo.log(this.parentType);
674 if (this.parentType === 'Navbar' && !this.parent().bar) {
675 Roo.log('changing to li?');
684 href : this.href || '#'
687 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
688 cfg.cls += ' dropdown';
695 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
697 if (this.glyphicon) {
698 cfg.html = ' ' + cfg.html;
703 cls: 'glyphicon glyphicon-' + this.glyphicon
713 // cfg.cls='btn roo-button';
717 var value = cfg.html;
722 cls: 'glyphicon glyphicon-' + this.glyphicon,
741 cfg.cls += ' dropdown';
742 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
745 if (cfg.tag !== 'a' && this.href !== '') {
746 throw "Tag must be a to set href.";
747 } else if (this.href.length > 0) {
748 cfg.href = this.href;
751 if(this.removeClass){
756 cfg.target = this.target;
761 initEvents: function() {
762 // Roo.log('init events?');
763 // Roo.log(this.el.dom);
766 if (typeof (this.menu) != 'undefined') {
767 this.menu.parentType = this.xtype;
768 this.menu.triggerEl = this.el;
769 this.addxtype(Roo.apply({}, this.menu));
773 if (this.el.hasClass('roo-button')) {
774 this.el.on('click', this.onClick, this);
776 this.el.select('.roo-button').on('click', this.onClick, this);
779 if(this.removeClass){
780 this.el.on('click', this.onClick, this);
783 this.el.enableDisplayMode();
786 onClick : function(e)
793 Roo.log('button on click ');
794 if(this.preventDefault){
797 if (this.pressed === true || this.pressed === false) {
798 this.pressed = !this.pressed;
799 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
800 this.fireEvent('toggle', this, e, this.pressed);
804 this.fireEvent('click', this, e);
808 * Enables this button
812 this.disabled = false;
813 this.el.removeClass('disabled');
817 * Disable this button
821 this.disabled = true;
822 this.el.addClass('disabled');
825 * sets the active state on/off,
826 * @param {Boolean} state (optional) Force a particular state
828 setActive : function(v) {
830 this.el[v ? 'addClass' : 'removeClass']('active');
833 * toggles the current active state
835 toggleActive : function()
837 var active = this.el.hasClass('active');
838 this.setActive(!active);
842 setText : function(str)
844 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
848 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
871 * @class Roo.bootstrap.Column
872 * @extends Roo.bootstrap.Component
873 * Bootstrap Column class
874 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
875 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
876 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
877 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
878 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
879 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
880 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
881 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
884 * @cfg {Boolean} hidden (true|false) hide the element
885 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
886 * @cfg {String} fa (ban|check|...) font awesome icon
887 * @cfg {Number} fasize (1|2|....) font awsome size
889 * @cfg {String} icon (info-sign|check|...) glyphicon name
891 * @cfg {String} html content of column.
894 * Create a new Column
895 * @param {Object} config The config object
898 Roo.bootstrap.Column = function(config){
899 Roo.bootstrap.Column.superclass.constructor.call(this, config);
902 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
920 getAutoCreate : function(){
921 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
929 ['xs','sm','md','lg'].map(function(size){
930 //Roo.log( size + ':' + settings[size]);
932 if (settings[size+'off'] !== false) {
933 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
936 if (settings[size] === false) {
940 if (!settings[size]) { // 0 = hidden
941 cfg.cls += ' hidden-' + size;
944 cfg.cls += ' col-' + size + '-' + settings[size];
949 cfg.cls += ' hidden';
952 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
953 cfg.cls +=' alert alert-' + this.alert;
957 if (this.html.length) {
958 cfg.html = this.html;
962 if (this.fasize > 1) {
963 fasize = ' fa-' + this.fasize + 'x';
965 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
970 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
989 * @class Roo.bootstrap.Container
990 * @extends Roo.bootstrap.Component
991 * Bootstrap Container class
992 * @cfg {Boolean} jumbotron is it a jumbotron element
993 * @cfg {String} html content of element
994 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
995 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
996 * @cfg {String} header content of header (for panel)
997 * @cfg {String} footer content of footer (for panel)
998 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
999 * @cfg {String} tag (header|aside|section) type of HTML tag.
1000 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1001 * @cfg {String} fa font awesome icon
1002 * @cfg {String} icon (info-sign|check|...) glyphicon name
1003 * @cfg {Boolean} hidden (true|false) hide the element
1004 * @cfg {Boolean} expandable (true|false) default false
1005 * @cfg {Boolean} expanded (true|false) default true
1006 * @cfg {String} rheader contet on the right of header
1007 * @cfg {Boolean} clickable (true|false) default false
1011 * Create a new Container
1012 * @param {Object} config The config object
1015 Roo.bootstrap.Container = function(config){
1016 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1022 * After the panel has been expand
1024 * @param {Roo.bootstrap.Container} this
1029 * After the panel has been collapsed
1031 * @param {Roo.bootstrap.Container} this
1036 * When a element is chick
1037 * @param {Roo.bootstrap.Container} this
1038 * @param {Roo.EventObject} e
1044 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1062 getChildContainer : function() {
1068 if (this.panel.length) {
1069 return this.el.select('.panel-body',true).first();
1076 getAutoCreate : function(){
1079 tag : this.tag || 'div',
1083 if (this.jumbotron) {
1084 cfg.cls = 'jumbotron';
1089 // - this is applied by the parent..
1091 // cfg.cls = this.cls + '';
1094 if (this.sticky.length) {
1096 var bd = Roo.get(document.body);
1097 if (!bd.hasClass('bootstrap-sticky')) {
1098 bd.addClass('bootstrap-sticky');
1099 Roo.select('html',true).setStyle('height', '100%');
1102 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1106 if (this.well.length) {
1107 switch (this.well) {
1110 cfg.cls +=' well well-' +this.well;
1119 cfg.cls += ' hidden';
1123 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1124 cfg.cls +=' alert alert-' + this.alert;
1129 if (this.panel.length) {
1130 cfg.cls += ' panel panel-' + this.panel;
1132 if (this.header.length) {
1136 if(this.expandable){
1138 cfg.cls = cfg.cls + ' expandable';
1142 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1150 cls : 'panel-title',
1151 html : (this.expandable ? ' ' : '') + this.header
1155 cls: 'panel-header-right',
1161 cls : 'panel-heading',
1162 style : this.expandable ? 'cursor: pointer' : '',
1170 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1175 if (this.footer.length) {
1177 cls : 'panel-footer',
1186 body.html = this.html || cfg.html;
1187 // prefix with the icons..
1189 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1192 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1197 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1198 cfg.cls = 'container';
1204 initEvents: function()
1206 if(this.expandable){
1207 var headerEl = this.headerEl();
1210 headerEl.on('click', this.onToggleClick, this);
1215 this.el.on('click', this.onClick, this);
1220 onToggleClick : function()
1222 var headerEl = this.headerEl();
1238 if(this.fireEvent('expand', this)) {
1240 this.expanded = true;
1242 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1244 this.el.select('.panel-body',true).first().removeClass('hide');
1246 var toggleEl = this.toggleEl();
1252 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1257 collapse : function()
1259 if(this.fireEvent('collapse', this)) {
1261 this.expanded = false;
1263 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1264 this.el.select('.panel-body',true).first().addClass('hide');
1266 var toggleEl = this.toggleEl();
1272 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1276 toggleEl : function()
1278 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1282 return this.el.select('.panel-heading .fa',true).first();
1285 headerEl : function()
1287 if(!this.el || !this.panel.length || !this.header.length){
1291 return this.el.select('.panel-heading',true).first()
1294 titleEl : function()
1296 if(!this.el || !this.panel.length || !this.header.length){
1300 return this.el.select('.panel-title',true).first();
1303 setTitle : function(v)
1305 var titleEl = this.titleEl();
1311 titleEl.dom.innerHTML = v;
1314 getTitle : function()
1317 var titleEl = this.titleEl();
1323 return titleEl.dom.innerHTML;
1326 setRightTitle : function(v)
1328 var t = this.el.select('.panel-header-right',true).first();
1334 t.dom.innerHTML = v;
1337 onClick : function(e)
1341 this.fireEvent('click', this, e);
1355 * @class Roo.bootstrap.Img
1356 * @extends Roo.bootstrap.Component
1357 * Bootstrap Img class
1358 * @cfg {Boolean} imgResponsive false | true
1359 * @cfg {String} border rounded | circle | thumbnail
1360 * @cfg {String} src image source
1361 * @cfg {String} alt image alternative text
1362 * @cfg {String} href a tag href
1363 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1364 * @cfg {String} xsUrl xs image source
1365 * @cfg {String} smUrl sm image source
1366 * @cfg {String} mdUrl md image source
1367 * @cfg {String} lgUrl lg image source
1370 * Create a new Input
1371 * @param {Object} config The config object
1374 Roo.bootstrap.Img = function(config){
1375 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1381 * The img click event for the img.
1382 * @param {Roo.EventObject} e
1388 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1390 imgResponsive: true,
1400 getAutoCreate : function()
1402 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1403 return this.createSingleImg();
1408 cls: 'roo-image-responsive-group',
1413 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1415 if(!_this[size + 'Url']){
1421 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1422 html: _this.html || cfg.html,
1423 src: _this[size + 'Url']
1426 img.cls += ' roo-image-responsive-' + size;
1428 var s = ['xs', 'sm', 'md', 'lg'];
1430 s.splice(s.indexOf(size), 1);
1432 Roo.each(s, function(ss){
1433 img.cls += ' hidden-' + ss;
1436 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1437 cfg.cls += ' img-' + _this.border;
1441 cfg.alt = _this.alt;
1454 a.target = _this.target;
1458 cfg.cn.push((_this.href) ? a : img);
1465 createSingleImg : function()
1469 cls: (this.imgResponsive) ? 'img-responsive' : '',
1471 src : 'about:blank' // just incase src get's set to undefined?!?
1474 cfg.html = this.html || cfg.html;
1476 cfg.src = this.src || cfg.src;
1478 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1479 cfg.cls += ' img-' + this.border;
1496 a.target = this.target;
1501 return (this.href) ? a : cfg;
1504 initEvents: function()
1507 this.el.on('click', this.onClick, this);
1512 onClick : function(e)
1514 Roo.log('img onclick');
1515 this.fireEvent('click', this, e);
1529 * @class Roo.bootstrap.Link
1530 * @extends Roo.bootstrap.Component
1531 * Bootstrap Link Class
1532 * @cfg {String} alt image alternative text
1533 * @cfg {String} href a tag href
1534 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1535 * @cfg {String} html the content of the link.
1536 * @cfg {String} anchor name for the anchor link
1537 * @cfg {String} fa - favicon
1539 * @cfg {Boolean} preventDefault (true | false) default false
1543 * Create a new Input
1544 * @param {Object} config The config object
1547 Roo.bootstrap.Link = function(config){
1548 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1554 * The img click event for the img.
1555 * @param {Roo.EventObject} e
1561 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1565 preventDefault: false,
1571 getAutoCreate : function()
1573 var html = this.html || '';
1575 if (this.fa !== false) {
1576 html = '<i class="fa fa-' + this.fa + '"></i>';
1581 // anchor's do not require html/href...
1582 if (this.anchor === false) {
1584 cfg.href = this.href || '#';
1586 cfg.name = this.anchor;
1587 if (this.html !== false || this.fa !== false) {
1590 if (this.href !== false) {
1591 cfg.href = this.href;
1595 if(this.alt !== false){
1600 if(this.target !== false) {
1601 cfg.target = this.target;
1607 initEvents: function() {
1609 if(!this.href || this.preventDefault){
1610 this.el.on('click', this.onClick, this);
1614 onClick : function(e)
1616 if(this.preventDefault){
1619 //Roo.log('img onclick');
1620 this.fireEvent('click', this, e);
1633 * @class Roo.bootstrap.Header
1634 * @extends Roo.bootstrap.Component
1635 * Bootstrap Header class
1636 * @cfg {String} html content of header
1637 * @cfg {Number} level (1|2|3|4|5|6) default 1
1640 * Create a new Header
1641 * @param {Object} config The config object
1645 Roo.bootstrap.Header = function(config){
1646 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1649 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1657 getAutoCreate : function(){
1662 tag: 'h' + (1 *this.level),
1663 html: this.html || ''
1675 * Ext JS Library 1.1.1
1676 * Copyright(c) 2006-2007, Ext JS, LLC.
1678 * Originally Released Under LGPL - original licence link has changed is not relivant.
1681 * <script type="text/javascript">
1685 * @class Roo.bootstrap.MenuMgr
1686 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1689 Roo.bootstrap.MenuMgr = function(){
1690 var menus, active, groups = {}, attached = false, lastShow = new Date();
1692 // private - called when first menu is created
1695 active = new Roo.util.MixedCollection();
1696 Roo.get(document).addKeyListener(27, function(){
1697 if(active.length > 0){
1705 if(active && active.length > 0){
1706 var c = active.clone();
1716 if(active.length < 1){
1717 Roo.get(document).un("mouseup", onMouseDown);
1725 var last = active.last();
1726 lastShow = new Date();
1729 Roo.get(document).on("mouseup", onMouseDown);
1734 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1735 m.parentMenu.activeChild = m;
1736 }else if(last && last.isVisible()){
1737 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1742 function onBeforeHide(m){
1744 m.activeChild.hide();
1746 if(m.autoHideTimer){
1747 clearTimeout(m.autoHideTimer);
1748 delete m.autoHideTimer;
1753 function onBeforeShow(m){
1754 var pm = m.parentMenu;
1755 if(!pm && !m.allowOtherMenus){
1757 }else if(pm && pm.activeChild && active != m){
1758 pm.activeChild.hide();
1762 // private this should really trigger on mouseup..
1763 function onMouseDown(e){
1764 Roo.log("on Mouse Up");
1766 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1767 Roo.log("MenuManager hideAll");
1776 function onBeforeCheck(mi, state){
1778 var g = groups[mi.group];
1779 for(var i = 0, l = g.length; i < l; i++){
1781 g[i].setChecked(false);
1790 * Hides all menus that are currently visible
1792 hideAll : function(){
1797 register : function(menu){
1801 menus[menu.id] = menu;
1802 menu.on("beforehide", onBeforeHide);
1803 menu.on("hide", onHide);
1804 menu.on("beforeshow", onBeforeShow);
1805 menu.on("show", onShow);
1807 if(g && menu.events["checkchange"]){
1811 groups[g].push(menu);
1812 menu.on("checkchange", onCheck);
1817 * Returns a {@link Roo.menu.Menu} object
1818 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1819 * be used to generate and return a new Menu instance.
1821 get : function(menu){
1822 if(typeof menu == "string"){ // menu id
1824 }else if(menu.events){ // menu instance
1827 /*else if(typeof menu.length == 'number'){ // array of menu items?
1828 return new Roo.bootstrap.Menu({items:menu});
1829 }else{ // otherwise, must be a config
1830 return new Roo.bootstrap.Menu(menu);
1837 unregister : function(menu){
1838 delete menus[menu.id];
1839 menu.un("beforehide", onBeforeHide);
1840 menu.un("hide", onHide);
1841 menu.un("beforeshow", onBeforeShow);
1842 menu.un("show", onShow);
1844 if(g && menu.events["checkchange"]){
1845 groups[g].remove(menu);
1846 menu.un("checkchange", onCheck);
1851 registerCheckable : function(menuItem){
1852 var g = menuItem.group;
1857 groups[g].push(menuItem);
1858 menuItem.on("beforecheckchange", onBeforeCheck);
1863 unregisterCheckable : function(menuItem){
1864 var g = menuItem.group;
1866 groups[g].remove(menuItem);
1867 menuItem.un("beforecheckchange", onBeforeCheck);
1879 * @class Roo.bootstrap.Menu
1880 * @extends Roo.bootstrap.Component
1881 * Bootstrap Menu class - container for MenuItems
1882 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1883 * @cfg {bool} hidden if the menu should be hidden when rendered.
1884 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1885 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1889 * @param {Object} config The config object
1893 Roo.bootstrap.Menu = function(config){
1894 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1895 if (this.registerMenu && this.type != 'treeview') {
1896 Roo.bootstrap.MenuMgr.register(this);
1901 * Fires before this menu is displayed
1902 * @param {Roo.menu.Menu} this
1907 * Fires before this menu is hidden
1908 * @param {Roo.menu.Menu} this
1913 * Fires after this menu is displayed
1914 * @param {Roo.menu.Menu} this
1919 * Fires after this menu is hidden
1920 * @param {Roo.menu.Menu} this
1925 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1926 * @param {Roo.menu.Menu} this
1927 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1928 * @param {Roo.EventObject} e
1933 * Fires when the mouse is hovering over this menu
1934 * @param {Roo.menu.Menu} this
1935 * @param {Roo.EventObject} e
1936 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1941 * Fires when the mouse exits this menu
1942 * @param {Roo.menu.Menu} this
1943 * @param {Roo.EventObject} e
1944 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1949 * Fires when a menu item contained in this menu is clicked
1950 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1951 * @param {Roo.EventObject} e
1955 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1958 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1962 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1965 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1967 registerMenu : true,
1969 menuItems :false, // stores the menu items..
1979 getChildContainer : function() {
1983 getAutoCreate : function(){
1985 //if (['right'].indexOf(this.align)!==-1) {
1986 // cfg.cn[1].cls += ' pull-right'
1992 cls : 'dropdown-menu' ,
1993 style : 'z-index:1000'
1997 if (this.type === 'submenu') {
1998 cfg.cls = 'submenu active';
2000 if (this.type === 'treeview') {
2001 cfg.cls = 'treeview-menu';
2006 initEvents : function() {
2008 // Roo.log("ADD event");
2009 // Roo.log(this.triggerEl.dom);
2011 this.triggerEl.on('click', this.onTriggerClick, this);
2013 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2015 this.triggerEl.addClass('dropdown-toggle');
2018 this.el.on('touchstart' , this.onTouch, this);
2020 this.el.on('click' , this.onClick, this);
2022 this.el.on("mouseover", this.onMouseOver, this);
2023 this.el.on("mouseout", this.onMouseOut, this);
2027 findTargetItem : function(e)
2029 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2033 //Roo.log(t); Roo.log(t.id);
2035 //Roo.log(this.menuitems);
2036 return this.menuitems.get(t.id);
2038 //return this.items.get(t.menuItemId);
2044 onTouch : function(e)
2046 Roo.log("menu.onTouch");
2047 //e.stopEvent(); this make the user popdown broken
2051 onClick : function(e)
2053 Roo.log("menu.onClick");
2055 var t = this.findTargetItem(e);
2056 if(!t || t.isContainer){
2061 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2062 if(t == this.activeItem && t.shouldDeactivate(e)){
2063 this.activeItem.deactivate();
2064 delete this.activeItem;
2068 this.setActiveItem(t, true);
2076 Roo.log('pass click event');
2080 this.fireEvent("click", this, t, e);
2084 (function() { _this.hide(); }).defer(500);
2087 onMouseOver : function(e){
2088 var t = this.findTargetItem(e);
2091 // if(t.canActivate && !t.disabled){
2092 // this.setActiveItem(t, true);
2096 this.fireEvent("mouseover", this, e, t);
2098 isVisible : function(){
2099 return !this.hidden;
2101 onMouseOut : function(e){
2102 var t = this.findTargetItem(e);
2105 // if(t == this.activeItem && t.shouldDeactivate(e)){
2106 // this.activeItem.deactivate();
2107 // delete this.activeItem;
2110 this.fireEvent("mouseout", this, e, t);
2115 * Displays this menu relative to another element
2116 * @param {String/HTMLElement/Roo.Element} element The element to align to
2117 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2118 * the element (defaults to this.defaultAlign)
2119 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2121 show : function(el, pos, parentMenu){
2122 this.parentMenu = parentMenu;
2126 this.fireEvent("beforeshow", this);
2127 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2130 * Displays this menu at a specific xy position
2131 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2132 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2134 showAt : function(xy, parentMenu, /* private: */_e){
2135 this.parentMenu = parentMenu;
2140 this.fireEvent("beforeshow", this);
2141 //xy = this.el.adjustForConstraints(xy);
2145 this.hideMenuItems();
2146 this.hidden = false;
2147 this.triggerEl.addClass('open');
2149 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2150 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2153 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2158 this.fireEvent("show", this);
2164 this.doFocus.defer(50, this);
2168 doFocus : function(){
2170 this.focusEl.focus();
2175 * Hides this menu and optionally all parent menus
2176 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2178 hide : function(deep)
2181 this.hideMenuItems();
2182 if(this.el && this.isVisible()){
2183 this.fireEvent("beforehide", this);
2184 if(this.activeItem){
2185 this.activeItem.deactivate();
2186 this.activeItem = null;
2188 this.triggerEl.removeClass('open');;
2190 this.fireEvent("hide", this);
2192 if(deep === true && this.parentMenu){
2193 this.parentMenu.hide(true);
2197 onTriggerClick : function(e)
2199 Roo.log('trigger click');
2201 var target = e.getTarget();
2203 Roo.log(target.nodeName.toLowerCase());
2205 if(target.nodeName.toLowerCase() === 'i'){
2211 onTriggerPress : function(e)
2213 Roo.log('trigger press');
2214 //Roo.log(e.getTarget());
2215 // Roo.log(this.triggerEl.dom);
2217 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2218 var pel = Roo.get(e.getTarget());
2219 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2220 Roo.log('is treeview or dropdown?');
2224 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2228 if (this.isVisible()) {
2233 this.show(this.triggerEl, false, false);
2236 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2243 hideMenuItems : function()
2245 Roo.log("hide Menu Items");
2249 //$(backdrop).remove()
2250 this.el.select('.open',true).each(function(aa) {
2252 aa.removeClass('open');
2253 //var parent = getParent($(this))
2254 //var relatedTarget = { relatedTarget: this }
2256 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2257 //if (e.isDefaultPrevented()) return
2258 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2261 addxtypeChild : function (tree, cntr) {
2262 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2264 this.menuitems.add(comp);
2285 * @class Roo.bootstrap.MenuItem
2286 * @extends Roo.bootstrap.Component
2287 * Bootstrap MenuItem class
2288 * @cfg {String} html the menu label
2289 * @cfg {String} href the link
2290 * @cfg {Boolean} preventDefault do not trigger A href on clicks.
2291 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2292 * @cfg {Boolean} active used on sidebars to highlight active itesm
2293 * @cfg {String} fa favicon to show on left of menu item.
2294 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2298 * Create a new MenuItem
2299 * @param {Object} config The config object
2303 Roo.bootstrap.MenuItem = function(config){
2304 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2309 * The raw click event for the entire grid.
2310 * @param {Roo.bootstrap.MenuItem} this
2311 * @param {Roo.EventObject} e
2317 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2321 preventDefault: true,
2322 isContainer : false,
2326 getAutoCreate : function(){
2328 if(this.isContainer){
2331 cls: 'dropdown-menu-item'
2345 if (this.fa !== false) {
2348 cls : 'fa fa-' + this.fa
2357 cls: 'dropdown-menu-item',
2360 if (this.parent().type == 'treeview') {
2361 cfg.cls = 'treeview-menu';
2364 cfg.cls += ' active';
2369 anc.href = this.href || cfg.cn[0].href ;
2370 ctag.html = this.html || cfg.cn[0].html ;
2374 initEvents: function()
2376 if (this.parent().type == 'treeview') {
2377 this.el.select('a').on('click', this.onClick, this);
2380 this.menu.parentType = this.xtype;
2381 this.menu.triggerEl = this.el;
2382 this.menu = this.addxtype(Roo.apply({}, this.menu));
2386 onClick : function(e)
2388 Roo.log('item on click ');
2389 //if(this.preventDefault){
2390 // e.preventDefault();
2392 //this.parent().hideMenuItems();
2394 this.fireEvent('click', this, e);
2413 * @class Roo.bootstrap.MenuSeparator
2414 * @extends Roo.bootstrap.Component
2415 * Bootstrap MenuSeparator class
2418 * Create a new MenuItem
2419 * @param {Object} config The config object
2423 Roo.bootstrap.MenuSeparator = function(config){
2424 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2427 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2429 getAutoCreate : function(){
2448 * @class Roo.bootstrap.Modal
2449 * @extends Roo.bootstrap.Component
2450 * Bootstrap Modal class
2451 * @cfg {String} title Title of dialog
2452 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2453 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2454 * @cfg {Boolean} specificTitle default false
2455 * @cfg {Array} buttons Array of buttons or standard button set..
2456 * @cfg {String} buttonPosition (left|right|center) default right
2457 * @cfg {Boolean} animate default true
2458 * @cfg {Boolean} allow_close default true
2459 * @cfg {Boolean} fitwindow default true
2460 * @cfg {String} size (sm|lg) default empty
2464 * Create a new Modal Dialog
2465 * @param {Object} config The config object
2468 Roo.bootstrap.Modal = function(config){
2469 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2474 * The raw btnclick event for the button
2475 * @param {Roo.EventObject} e
2479 this.buttons = this.buttons || [];
2482 this.tmpl = Roo.factory(this.tmpl);
2487 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2489 title : 'test dialog',
2499 specificTitle: false,
2501 buttonPosition: 'right',
2520 onRender : function(ct, position)
2522 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2525 var cfg = Roo.apply({}, this.getAutoCreate());
2528 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2530 //if (!cfg.name.length) {
2534 cfg.cls += ' ' + this.cls;
2537 cfg.style = this.style;
2539 this.el = Roo.get(document.body).createChild(cfg, position);
2541 //var type = this.el.dom.type;
2544 if(this.tabIndex !== undefined){
2545 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2548 this.dialogEl = this.el.select('.modal-dialog',true).first();
2549 this.bodyEl = this.el.select('.modal-body',true).first();
2550 this.closeEl = this.el.select('.modal-header .close', true).first();
2551 this.footerEl = this.el.select('.modal-footer',true).first();
2552 this.titleEl = this.el.select('.modal-title',true).first();
2556 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2557 this.maskEl.enableDisplayMode("block");
2559 //this.el.addClass("x-dlg-modal");
2561 if (this.buttons.length) {
2562 Roo.each(this.buttons, function(bb) {
2563 var b = Roo.apply({}, bb);
2564 b.xns = b.xns || Roo.bootstrap;
2565 b.xtype = b.xtype || 'Button';
2566 if (typeof(b.listeners) == 'undefined') {
2567 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2570 var btn = Roo.factory(b);
2572 btn.render(this.el.select('.modal-footer div').first());
2576 // render the children.
2579 if(typeof(this.items) != 'undefined'){
2580 var items = this.items;
2583 for(var i =0;i < items.length;i++) {
2584 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2588 this.items = nitems;
2590 // where are these used - they used to be body/close/footer
2594 //this.el.addClass([this.fieldClass, this.cls]);
2598 getAutoCreate : function(){
2603 html : this.html || ''
2608 cls : 'modal-title',
2612 if(this.specificTitle){
2618 if (this.allow_close) {
2630 if(this.size.length){
2631 size = 'modal-' + this.size;
2636 style : 'display: none',
2639 cls: "modal-dialog " + size,
2642 cls : "modal-content",
2645 cls : 'modal-header',
2650 cls : 'modal-footer',
2654 cls: 'btn-' + this.buttonPosition
2671 modal.cls += ' fade';
2677 getChildContainer : function() {
2682 getButtonContainer : function() {
2683 return this.el.select('.modal-footer div',true).first();
2686 initEvents : function()
2688 if (this.allow_close) {
2689 this.closeEl.on('click', this.hide, this);
2691 Roo.EventManager.onWindowResize(this.resize, this, true);
2698 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2699 if (this.fitwindow) {
2700 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2701 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 30;
2706 setSize : function(w,h)
2716 if (!this.rendered) {
2720 this.el.setStyle('display', 'block');
2722 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2725 this.el.addClass('in');
2728 this.el.addClass('in');
2732 // not sure how we can show data in here..
2734 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2737 Roo.get(document.body).addClass("x-body-masked");
2738 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2740 this.el.setStyle('zIndex', '10001');
2742 this.fireEvent('show', this);
2743 this.items.forEach(function(e) {
2744 e.layout ? e.layout() : false;
2755 Roo.get(document.body).removeClass("x-body-masked");
2756 this.el.removeClass('in');
2757 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2759 if(this.animate){ // why
2761 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2763 this.el.setStyle('display', 'none');
2766 this.fireEvent('hide', this);
2769 addButton : function(str, cb)
2773 var b = Roo.apply({}, { html : str } );
2774 b.xns = b.xns || Roo.bootstrap;
2775 b.xtype = b.xtype || 'Button';
2776 if (typeof(b.listeners) == 'undefined') {
2777 b.listeners = { click : cb.createDelegate(this) };
2780 var btn = Roo.factory(b);
2782 btn.render(this.el.select('.modal-footer div').first());
2788 setDefaultButton : function(btn)
2790 //this.el.select('.modal-footer').()
2794 resizeTo: function(w,h)
2798 this.dialogEl.setWidth(w);
2799 if (this.diff === false) {
2800 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2803 this.bodyEl.setHeight(h-this.diff);
2807 setContentSize : function(w, h)
2811 onButtonClick: function(btn,e)
2814 this.fireEvent('btnclick', btn.name, e);
2817 * Set the title of the Dialog
2818 * @param {String} str new Title
2820 setTitle: function(str) {
2821 this.titleEl.dom.innerHTML = str;
2824 * Set the body of the Dialog
2825 * @param {String} str new Title
2827 setBody: function(str) {
2828 this.bodyEl.dom.innerHTML = str;
2831 * Set the body of the Dialog using the template
2832 * @param {Obj} data - apply this data to the template and replace the body contents.
2834 applyBody: function(obj)
2837 Roo.log("Error - using apply Body without a template");
2840 this.tmpl.overwrite(this.bodyEl, obj);
2846 Roo.apply(Roo.bootstrap.Modal, {
2848 * Button config that displays a single OK button
2857 * Button config that displays Yes and No buttons
2873 * Button config that displays OK and Cancel buttons
2888 * Button config that displays Yes, No and Cancel buttons
2911 * messagebox - can be used as a replace
2915 * @class Roo.MessageBox
2916 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2920 Roo.Msg.alert('Status', 'Changes saved successfully.');
2922 // Prompt for user data:
2923 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2925 // process text value...
2929 // Show a dialog using config options:
2931 title:'Save Changes?',
2932 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2933 buttons: Roo.Msg.YESNOCANCEL,
2940 Roo.bootstrap.MessageBox = function(){
2941 var dlg, opt, mask, waitTimer;
2942 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2943 var buttons, activeTextEl, bwidth;
2947 var handleButton = function(button){
2949 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2953 var handleHide = function(){
2955 dlg.el.removeClass(opt.cls);
2958 // Roo.TaskMgr.stop(waitTimer);
2959 // waitTimer = null;
2964 var updateButtons = function(b){
2967 buttons["ok"].hide();
2968 buttons["cancel"].hide();
2969 buttons["yes"].hide();
2970 buttons["no"].hide();
2971 //dlg.footer.dom.style.display = 'none';
2974 dlg.footerEl.dom.style.display = '';
2975 for(var k in buttons){
2976 if(typeof buttons[k] != "function"){
2979 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2980 width += buttons[k].el.getWidth()+15;
2990 var handleEsc = function(d, k, e){
2991 if(opt && opt.closable !== false){
3001 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3002 * @return {Roo.BasicDialog} The BasicDialog element
3004 getDialog : function(){
3006 dlg = new Roo.bootstrap.Modal( {
3009 //constraintoviewport:false,
3011 //collapsible : false,
3016 //buttonAlign:"center",
3017 closeClick : function(){
3018 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3021 handleButton("cancel");
3026 dlg.on("hide", handleHide);
3028 //dlg.addKeyListener(27, handleEsc);
3030 this.buttons = buttons;
3031 var bt = this.buttonText;
3032 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3033 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3034 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3035 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3037 bodyEl = dlg.bodyEl.createChild({
3039 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3040 '<textarea class="roo-mb-textarea"></textarea>' +
3041 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3043 msgEl = bodyEl.dom.firstChild;
3044 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3045 textboxEl.enableDisplayMode();
3046 textboxEl.addKeyListener([10,13], function(){
3047 if(dlg.isVisible() && opt && opt.buttons){
3050 }else if(opt.buttons.yes){
3051 handleButton("yes");
3055 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3056 textareaEl.enableDisplayMode();
3057 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3058 progressEl.enableDisplayMode();
3059 var pf = progressEl.dom.firstChild;
3061 pp = Roo.get(pf.firstChild);
3062 pp.setHeight(pf.offsetHeight);
3070 * Updates the message box body text
3071 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3072 * the XHTML-compliant non-breaking space character '&#160;')
3073 * @return {Roo.MessageBox} This message box
3075 updateText : function(text){
3076 if(!dlg.isVisible() && !opt.width){
3077 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3079 msgEl.innerHTML = text || ' ';
3081 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3082 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3084 Math.min(opt.width || cw , this.maxWidth),
3085 Math.max(opt.minWidth || this.minWidth, bwidth)
3088 activeTextEl.setWidth(w);
3090 if(dlg.isVisible()){
3091 dlg.fixedcenter = false;
3093 // to big, make it scroll. = But as usual stupid IE does not support
3096 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3097 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3098 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3100 bodyEl.dom.style.height = '';
3101 bodyEl.dom.style.overflowY = '';
3104 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3106 bodyEl.dom.style.overflowX = '';
3109 dlg.setContentSize(w, bodyEl.getHeight());
3110 if(dlg.isVisible()){
3111 dlg.fixedcenter = true;
3117 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3118 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3119 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3120 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3121 * @return {Roo.MessageBox} This message box
3123 updateProgress : function(value, text){
3125 this.updateText(text);
3127 if (pp) { // weird bug on my firefox - for some reason this is not defined
3128 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3134 * Returns true if the message box is currently displayed
3135 * @return {Boolean} True if the message box is visible, else false
3137 isVisible : function(){
3138 return dlg && dlg.isVisible();
3142 * Hides the message box if it is displayed
3145 if(this.isVisible()){
3151 * Displays a new message box, or reinitializes an existing message box, based on the config options
3152 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3153 * The following config object properties are supported:
3155 Property Type Description
3156 ---------- --------------- ------------------------------------------------------------------------------------
3157 animEl String/Element An id or Element from which the message box should animate as it opens and
3158 closes (defaults to undefined)
3159 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3160 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3161 closable Boolean False to hide the top-right close button (defaults to true). Note that
3162 progress and wait dialogs will ignore this property and always hide the
3163 close button as they can only be closed programmatically.
3164 cls String A custom CSS class to apply to the message box element
3165 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3166 displayed (defaults to 75)
3167 fn Function A callback function to execute after closing the dialog. The arguments to the
3168 function will be btn (the name of the button that was clicked, if applicable,
3169 e.g. "ok"), and text (the value of the active text field, if applicable).
3170 Progress and wait dialogs will ignore this option since they do not respond to
3171 user actions and can only be closed programmatically, so any required function
3172 should be called by the same code after it closes the dialog.
3173 icon String A CSS class that provides a background image to be used as an icon for
3174 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3175 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3176 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3177 modal Boolean False to allow user interaction with the page while the message box is
3178 displayed (defaults to true)
3179 msg String A string that will replace the existing message box body text (defaults
3180 to the XHTML-compliant non-breaking space character ' ')
3181 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3182 progress Boolean True to display a progress bar (defaults to false)
3183 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3184 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3185 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3186 title String The title text
3187 value String The string value to set into the active textbox element if displayed
3188 wait Boolean True to display a progress bar (defaults to false)
3189 width Number The width of the dialog in pixels
3196 msg: 'Please enter your address:',
3198 buttons: Roo.MessageBox.OKCANCEL,
3201 animEl: 'addAddressBtn'
3204 * @param {Object} config Configuration options
3205 * @return {Roo.MessageBox} This message box
3207 show : function(options)
3210 // this causes nightmares if you show one dialog after another
3211 // especially on callbacks..
3213 if(this.isVisible()){
3216 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3217 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3218 Roo.log("New Dialog Message:" + options.msg )
3219 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3220 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3223 var d = this.getDialog();
3225 d.setTitle(opt.title || " ");
3226 d.closeEl.setDisplayed(opt.closable !== false);
3227 activeTextEl = textboxEl;
3228 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3233 textareaEl.setHeight(typeof opt.multiline == "number" ?
3234 opt.multiline : this.defaultTextHeight);
3235 activeTextEl = textareaEl;
3244 progressEl.setDisplayed(opt.progress === true);
3245 this.updateProgress(0);
3246 activeTextEl.dom.value = opt.value || "";
3248 dlg.setDefaultButton(activeTextEl);
3250 var bs = opt.buttons;
3254 }else if(bs && bs.yes){
3255 db = buttons["yes"];
3257 dlg.setDefaultButton(db);
3259 bwidth = updateButtons(opt.buttons);
3260 this.updateText(opt.msg);
3262 d.el.addClass(opt.cls);
3264 d.proxyDrag = opt.proxyDrag === true;
3265 d.modal = opt.modal !== false;
3266 d.mask = opt.modal !== false ? mask : false;
3268 // force it to the end of the z-index stack so it gets a cursor in FF
3269 document.body.appendChild(dlg.el.dom);
3270 d.animateTarget = null;
3271 d.show(options.animEl);
3277 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3278 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3279 * and closing the message box when the process is complete.
3280 * @param {String} title The title bar text
3281 * @param {String} msg The message box body text
3282 * @return {Roo.MessageBox} This message box
3284 progress : function(title, msg){
3291 minWidth: this.minProgressWidth,
3298 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3299 * If a callback function is passed it will be called after the user clicks the button, and the
3300 * id of the button that was clicked will be passed as the only parameter to the callback
3301 * (could also be the top-right close button).
3302 * @param {String} title The title bar text
3303 * @param {String} msg The message box body text
3304 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3305 * @param {Object} scope (optional) The scope of the callback function
3306 * @return {Roo.MessageBox} This message box
3308 alert : function(title, msg, fn, scope){
3321 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3322 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3323 * You are responsible for closing the message box when the process is complete.
3324 * @param {String} msg The message box body text
3325 * @param {String} title (optional) The title bar text
3326 * @return {Roo.MessageBox} This message box
3328 wait : function(msg, title){
3339 waitTimer = Roo.TaskMgr.start({
3341 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3349 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3350 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3351 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3352 * @param {String} title The title bar text
3353 * @param {String} msg The message box body text
3354 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3355 * @param {Object} scope (optional) The scope of the callback function
3356 * @return {Roo.MessageBox} This message box
3358 confirm : function(title, msg, fn, scope){
3362 buttons: this.YESNO,
3371 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3372 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3373 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3374 * (could also be the top-right close button) and the text that was entered will be passed as the two
3375 * parameters to the callback.
3376 * @param {String} title The title bar text
3377 * @param {String} msg The message box body text
3378 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3379 * @param {Object} scope (optional) The scope of the callback function
3380 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3381 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3382 * @return {Roo.MessageBox} This message box
3384 prompt : function(title, msg, fn, scope, multiline){
3388 buttons: this.OKCANCEL,
3393 multiline: multiline,
3400 * Button config that displays a single OK button
3405 * Button config that displays Yes and No buttons
3408 YESNO : {yes:true, no:true},
3410 * Button config that displays OK and Cancel buttons
3413 OKCANCEL : {ok:true, cancel:true},
3415 * Button config that displays Yes, No and Cancel buttons
3418 YESNOCANCEL : {yes:true, no:true, cancel:true},
3421 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3424 defaultTextHeight : 75,
3426 * The maximum width in pixels of the message box (defaults to 600)
3431 * The minimum width in pixels of the message box (defaults to 100)
3436 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3437 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3440 minProgressWidth : 250,
3442 * An object containing the default button text strings that can be overriden for localized language support.
3443 * Supported properties are: ok, cancel, yes and no.
3444 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3457 * Shorthand for {@link Roo.MessageBox}
3459 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3460 Roo.Msg = Roo.Msg || Roo.MessageBox;
3469 * @class Roo.bootstrap.Navbar
3470 * @extends Roo.bootstrap.Component
3471 * Bootstrap Navbar class
3474 * Create a new Navbar
3475 * @param {Object} config The config object
3479 Roo.bootstrap.Navbar = function(config){
3480 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3484 * @event beforetoggle
3485 * Fire before toggle the menu
3486 * @param {Roo.EventObject} e
3488 "beforetoggle" : true
3492 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3501 getAutoCreate : function(){
3504 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3508 initEvents :function ()
3510 //Roo.log(this.el.select('.navbar-toggle',true));
3511 this.el.select('.navbar-toggle',true).on('click', function() {
3512 if(this.fireEvent('beforetoggle', this) !== false){
3513 this.el.select('.navbar-collapse',true).toggleClass('in');
3523 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3525 var size = this.el.getSize();
3526 this.maskEl.setSize(size.width, size.height);
3527 this.maskEl.enableDisplayMode("block");
3536 getChildContainer : function()
3538 if (this.el.select('.collapse').getCount()) {
3539 return this.el.select('.collapse',true).first();
3572 * @class Roo.bootstrap.NavSimplebar
3573 * @extends Roo.bootstrap.Navbar
3574 * Bootstrap Sidebar class
3576 * @cfg {Boolean} inverse is inverted color
3578 * @cfg {String} type (nav | pills | tabs)
3579 * @cfg {Boolean} arrangement stacked | justified
3580 * @cfg {String} align (left | right) alignment
3582 * @cfg {Boolean} main (true|false) main nav bar? default false
3583 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3585 * @cfg {String} tag (header|footer|nav|div) default is nav
3591 * Create a new Sidebar
3592 * @param {Object} config The config object
3596 Roo.bootstrap.NavSimplebar = function(config){
3597 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3600 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3616 getAutoCreate : function(){
3620 tag : this.tag || 'div',
3633 this.type = this.type || 'nav';
3634 if (['tabs','pills'].indexOf(this.type)!==-1) {
3635 cfg.cn[0].cls += ' nav-' + this.type
3639 if (this.type!=='nav') {
3640 Roo.log('nav type must be nav/tabs/pills')
3642 cfg.cn[0].cls += ' navbar-nav'
3648 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3649 cfg.cn[0].cls += ' nav-' + this.arrangement;
3653 if (this.align === 'right') {
3654 cfg.cn[0].cls += ' navbar-right';
3658 cfg.cls += ' navbar-inverse';
3685 * @class Roo.bootstrap.NavHeaderbar
3686 * @extends Roo.bootstrap.NavSimplebar
3687 * Bootstrap Sidebar class
3689 * @cfg {String} brand what is brand
3690 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3691 * @cfg {String} brand_href href of the brand
3692 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3693 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3694 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3695 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3698 * Create a new Sidebar
3699 * @param {Object} config The config object
3703 Roo.bootstrap.NavHeaderbar = function(config){
3704 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3708 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3715 desktopCenter : false,
3718 getAutoCreate : function(){
3721 tag: this.nav || 'nav',
3728 if (this.desktopCenter) {
3729 cn.push({cls : 'container', cn : []});
3736 cls: 'navbar-header',
3741 cls: 'navbar-toggle',
3742 'data-toggle': 'collapse',
3747 html: 'Toggle navigation'
3769 cls: 'collapse navbar-collapse',
3773 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3775 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3776 cfg.cls += ' navbar-' + this.position;
3778 // tag can override this..
3780 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3783 if (this.brand !== '') {
3786 href: this.brand_href ? this.brand_href : '#',
3787 cls: 'navbar-brand',
3795 cfg.cls += ' main-nav';
3803 getHeaderChildContainer : function()
3805 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3806 return this.el.select('.navbar-header',true).first();
3809 return this.getChildContainer();
3813 initEvents : function()
3815 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3817 if (this.autohide) {
3822 Roo.get(document).on('scroll',function(e) {
3823 var ns = Roo.get(document).getScroll().top;
3824 var os = prevScroll;
3828 ft.removeClass('slideDown');
3829 ft.addClass('slideUp');
3832 ft.removeClass('slideUp');
3833 ft.addClass('slideDown');
3854 * @class Roo.bootstrap.NavSidebar
3855 * @extends Roo.bootstrap.Navbar
3856 * Bootstrap Sidebar class
3859 * Create a new Sidebar
3860 * @param {Object} config The config object
3864 Roo.bootstrap.NavSidebar = function(config){
3865 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3868 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3870 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3872 getAutoCreate : function(){
3877 cls: 'sidebar sidebar-nav'
3899 * @class Roo.bootstrap.NavGroup
3900 * @extends Roo.bootstrap.Component
3901 * Bootstrap NavGroup class
3902 * @cfg {String} align (left|right)
3903 * @cfg {Boolean} inverse
3904 * @cfg {String} type (nav|pills|tab) default nav
3905 * @cfg {String} navId - reference Id for navbar.
3909 * Create a new nav group
3910 * @param {Object} config The config object
3913 Roo.bootstrap.NavGroup = function(config){
3914 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3917 Roo.bootstrap.NavGroup.register(this);
3921 * Fires when the active item changes
3922 * @param {Roo.bootstrap.NavGroup} this
3923 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3924 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3931 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3942 getAutoCreate : function()
3944 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3951 if (['tabs','pills'].indexOf(this.type)!==-1) {
3952 cfg.cls += ' nav-' + this.type
3954 if (this.type!=='nav') {
3955 Roo.log('nav type must be nav/tabs/pills')
3957 cfg.cls += ' navbar-nav'
3960 if (this.parent().sidebar) {
3963 cls: 'dashboard-menu sidebar-menu'
3969 if (this.form === true) {
3975 if (this.align === 'right') {
3976 cfg.cls += ' navbar-right';
3978 cfg.cls += ' navbar-left';
3982 if (this.align === 'right') {
3983 cfg.cls += ' navbar-right';
3987 cfg.cls += ' navbar-inverse';
3995 * sets the active Navigation item
3996 * @param {Roo.bootstrap.NavItem} the new current navitem
3998 setActiveItem : function(item)
4001 Roo.each(this.navItems, function(v){
4006 v.setActive(false, true);
4013 item.setActive(true, true);
4014 this.fireEvent('changed', this, item, prev);
4019 * gets the active Navigation item
4020 * @return {Roo.bootstrap.NavItem} the current navitem
4022 getActive : function()
4026 Roo.each(this.navItems, function(v){
4037 indexOfNav : function()
4041 Roo.each(this.navItems, function(v,i){
4052 * adds a Navigation item
4053 * @param {Roo.bootstrap.NavItem} the navitem to add
4055 addItem : function(cfg)
4057 var cn = new Roo.bootstrap.NavItem(cfg);
4059 cn.parentId = this.id;
4060 cn.onRender(this.el, null);
4064 * register a Navigation item
4065 * @param {Roo.bootstrap.NavItem} the navitem to add
4067 register : function(item)
4069 this.navItems.push( item);
4070 item.navId = this.navId;
4075 * clear all the Navigation item
4078 clearAll : function()
4081 this.el.dom.innerHTML = '';
4084 getNavItem: function(tabId)
4087 Roo.each(this.navItems, function(e) {
4088 if (e.tabId == tabId) {
4098 setActiveNext : function()
4100 var i = this.indexOfNav(this.getActive());
4101 if (i > this.navItems.length) {
4104 this.setActiveItem(this.navItems[i+1]);
4106 setActivePrev : function()
4108 var i = this.indexOfNav(this.getActive());
4112 this.setActiveItem(this.navItems[i-1]);
4114 clearWasActive : function(except) {
4115 Roo.each(this.navItems, function(e) {
4116 if (e.tabId != except.tabId && e.was_active) {
4117 e.was_active = false;
4124 getWasActive : function ()
4127 Roo.each(this.navItems, function(e) {
4142 Roo.apply(Roo.bootstrap.NavGroup, {
4146 * register a Navigation Group
4147 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4149 register : function(navgrp)
4151 this.groups[navgrp.navId] = navgrp;
4155 * fetch a Navigation Group based on the navigation ID
4156 * @param {string} the navgroup to add
4157 * @returns {Roo.bootstrap.NavGroup} the navgroup
4159 get: function(navId) {
4160 if (typeof(this.groups[navId]) == 'undefined') {
4162 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4164 return this.groups[navId] ;
4179 * @class Roo.bootstrap.NavItem
4180 * @extends Roo.bootstrap.Component
4181 * Bootstrap Navbar.NavItem class
4182 * @cfg {String} href link to
4183 * @cfg {String} html content of button
4184 * @cfg {String} badge text inside badge
4185 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4186 * @cfg {String} glyphicon name of glyphicon
4187 * @cfg {String} icon name of font awesome icon
4188 * @cfg {Boolean} active Is item active
4189 * @cfg {Boolean} disabled Is item disabled
4191 * @cfg {Boolean} preventDefault (true | false) default false
4192 * @cfg {String} tabId the tab that this item activates.
4193 * @cfg {String} tagtype (a|span) render as a href or span?
4194 * @cfg {Boolean} animateRef (true|false) link to element default false
4197 * Create a new Navbar Item
4198 * @param {Object} config The config object
4200 Roo.bootstrap.NavItem = function(config){
4201 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4206 * The raw click event for the entire grid.
4207 * @param {Roo.EventObject} e
4212 * Fires when the active item active state changes
4213 * @param {Roo.bootstrap.NavItem} this
4214 * @param {boolean} state the new state
4220 * Fires when scroll to element
4221 * @param {Roo.bootstrap.NavItem} this
4222 * @param {Object} options
4223 * @param {Roo.EventObject} e
4231 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4239 preventDefault : false,
4246 getAutoCreate : function(){
4255 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4257 if (this.disabled) {
4258 cfg.cls += ' disabled';
4261 if (this.href || this.html || this.glyphicon || this.icon) {
4265 href : this.href || "#",
4266 html: this.html || ''
4271 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4274 if(this.glyphicon) {
4275 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4280 cfg.cn[0].html += " <span class='caret'></span>";
4284 if (this.badge !== '') {
4286 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4294 initEvents: function()
4296 if (typeof (this.menu) != 'undefined') {
4297 this.menu.parentType = this.xtype;
4298 this.menu.triggerEl = this.el;
4299 this.menu = this.addxtype(Roo.apply({}, this.menu));
4302 this.el.select('a',true).on('click', this.onClick, this);
4304 if(this.tagtype == 'span'){
4305 this.el.select('span',true).on('click', this.onClick, this);
4308 // at this point parent should be available..
4309 this.parent().register(this);
4312 onClick : function(e)
4314 if (e.getTarget('.dropdown-menu-item')) {
4315 // did you click on a menu itemm.... - then don't trigger onclick..
4320 this.preventDefault ||
4323 Roo.log("NavItem - prevent Default?");
4327 if (this.disabled) {
4331 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4332 if (tg && tg.transition) {
4333 Roo.log("waiting for the transitionend");
4339 //Roo.log("fire event clicked");
4340 if(this.fireEvent('click', this, e) === false){
4344 if(this.tagtype == 'span'){
4348 //Roo.log(this.href);
4349 var ael = this.el.select('a',true).first();
4352 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4353 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4354 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4355 return; // ignore... - it's a 'hash' to another page.
4357 Roo.log("NavItem - prevent Default?");
4359 this.scrollToElement(e);
4363 var p = this.parent();
4365 if (['tabs','pills'].indexOf(p.type)!==-1) {
4366 if (typeof(p.setActiveItem) !== 'undefined') {
4367 p.setActiveItem(this);
4371 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4372 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4373 // remove the collapsed menu expand...
4374 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4378 isActive: function () {
4381 setActive : function(state, fire, is_was_active)
4383 if (this.active && !state && this.navId) {
4384 this.was_active = true;
4385 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4387 nv.clearWasActive(this);
4391 this.active = state;
4394 this.el.removeClass('active');
4395 } else if (!this.el.hasClass('active')) {
4396 this.el.addClass('active');
4399 this.fireEvent('changed', this, state);
4402 // show a panel if it's registered and related..
4404 if (!this.navId || !this.tabId || !state || is_was_active) {
4408 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4412 var pan = tg.getPanelByName(this.tabId);
4416 // if we can not flip to new panel - go back to old nav highlight..
4417 if (false == tg.showPanel(pan)) {
4418 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4420 var onav = nv.getWasActive();
4422 onav.setActive(true, false, true);
4431 // this should not be here...
4432 setDisabled : function(state)
4434 this.disabled = state;
4436 this.el.removeClass('disabled');
4437 } else if (!this.el.hasClass('disabled')) {
4438 this.el.addClass('disabled');
4444 * Fetch the element to display the tooltip on.
4445 * @return {Roo.Element} defaults to this.el
4447 tooltipEl : function()
4449 return this.el.select('' + this.tagtype + '', true).first();
4452 scrollToElement : function(e)
4454 var c = document.body;
4457 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4459 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4460 c = document.documentElement;
4463 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4469 var o = target.calcOffsetsTo(c);
4476 this.fireEvent('scrollto', this, options, e);
4478 Roo.get(c).scrollTo('top', options.value, true);
4491 * <span> icon </span>
4492 * <span> text </span>
4493 * <span>badge </span>
4497 * @class Roo.bootstrap.NavSidebarItem
4498 * @extends Roo.bootstrap.NavItem
4499 * Bootstrap Navbar.NavSidebarItem class
4500 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4501 * {bool} open is the menu open
4503 * Create a new Navbar Button
4504 * @param {Object} config The config object
4506 Roo.bootstrap.NavSidebarItem = function(config){
4507 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4512 * The raw click event for the entire grid.
4513 * @param {Roo.EventObject} e
4518 * Fires when the active item active state changes
4519 * @param {Roo.bootstrap.NavSidebarItem} this
4520 * @param {boolean} state the new state
4528 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4530 badgeWeight : 'default',
4534 getAutoCreate : function(){
4539 href : this.href || '#',
4551 html : this.html || ''
4556 cfg.cls += ' active';
4559 if (this.disabled) {
4560 cfg.cls += ' disabled';
4563 cfg.cls += ' open x-open';
4566 if (this.glyphicon || this.icon) {
4567 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4568 a.cn.push({ tag : 'i', cls : c }) ;
4573 if (this.badge !== '') {
4575 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4579 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4580 a.cls += 'dropdown-toggle treeview' ;
4588 initEvents : function()
4590 if (typeof (this.menu) != 'undefined') {
4591 this.menu.parentType = this.xtype;
4592 this.menu.triggerEl = this.el;
4593 this.menu = this.addxtype(Roo.apply({}, this.menu));
4596 this.el.on('click', this.onClick, this);
4599 if(this.badge !== ''){
4601 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4606 onClick : function(e)
4613 if(this.preventDefault){
4617 this.fireEvent('click', this);
4620 disable : function()
4622 this.setDisabled(true);
4627 this.setDisabled(false);
4630 setDisabled : function(state)
4632 if(this.disabled == state){
4636 this.disabled = state;
4639 this.el.addClass('disabled');
4643 this.el.removeClass('disabled');
4648 setActive : function(state)
4650 if(this.active == state){
4654 this.active = state;
4657 this.el.addClass('active');
4661 this.el.removeClass('active');
4666 isActive: function ()
4671 setBadge : function(str)
4677 this.badgeEl.dom.innerHTML = str;
4694 * @class Roo.bootstrap.Row
4695 * @extends Roo.bootstrap.Component
4696 * Bootstrap Row class (contains columns...)
4700 * @param {Object} config The config object
4703 Roo.bootstrap.Row = function(config){
4704 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4707 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4709 getAutoCreate : function(){
4728 * @class Roo.bootstrap.Element
4729 * @extends Roo.bootstrap.Component
4730 * Bootstrap Element class
4731 * @cfg {String} html contents of the element
4732 * @cfg {String} tag tag of the element
4733 * @cfg {String} cls class of the element
4734 * @cfg {Boolean} preventDefault (true|false) default false
4735 * @cfg {Boolean} clickable (true|false) default false
4738 * Create a new Element
4739 * @param {Object} config The config object
4742 Roo.bootstrap.Element = function(config){
4743 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4749 * When a element is chick
4750 * @param {Roo.bootstrap.Element} this
4751 * @param {Roo.EventObject} e
4757 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4762 preventDefault: false,
4765 getAutoCreate : function(){
4776 initEvents: function()
4778 Roo.bootstrap.Element.superclass.initEvents.call(this);
4781 this.el.on('click', this.onClick, this);
4786 onClick : function(e)
4788 if(this.preventDefault){
4792 this.fireEvent('click', this, e);
4795 getValue : function()
4797 return this.el.dom.innerHTML;
4800 setValue : function(value)
4802 this.el.dom.innerHTML = value;
4817 * @class Roo.bootstrap.Pagination
4818 * @extends Roo.bootstrap.Component
4819 * Bootstrap Pagination class
4820 * @cfg {String} size xs | sm | md | lg
4821 * @cfg {Boolean} inverse false | true
4824 * Create a new Pagination
4825 * @param {Object} config The config object
4828 Roo.bootstrap.Pagination = function(config){
4829 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4832 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4838 getAutoCreate : function(){
4844 cfg.cls += ' inverse';
4850 cfg.cls += " " + this.cls;
4868 * @class Roo.bootstrap.PaginationItem
4869 * @extends Roo.bootstrap.Component
4870 * Bootstrap PaginationItem class
4871 * @cfg {String} html text
4872 * @cfg {String} href the link
4873 * @cfg {Boolean} preventDefault (true | false) default true
4874 * @cfg {Boolean} active (true | false) default false
4875 * @cfg {Boolean} disabled default false
4879 * Create a new PaginationItem
4880 * @param {Object} config The config object
4884 Roo.bootstrap.PaginationItem = function(config){
4885 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4890 * The raw click event for the entire grid.
4891 * @param {Roo.EventObject} e
4897 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4901 preventDefault: true,
4906 getAutoCreate : function(){
4912 href : this.href ? this.href : '#',
4913 html : this.html ? this.html : ''
4923 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4927 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4933 initEvents: function() {
4935 this.el.on('click', this.onClick, this);
4938 onClick : function(e)
4940 Roo.log('PaginationItem on click ');
4941 if(this.preventDefault){
4949 this.fireEvent('click', this, e);
4965 * @class Roo.bootstrap.Slider
4966 * @extends Roo.bootstrap.Component
4967 * Bootstrap Slider class
4970 * Create a new Slider
4971 * @param {Object} config The config object
4974 Roo.bootstrap.Slider = function(config){
4975 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4978 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4980 getAutoCreate : function(){
4984 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4988 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5000 * Ext JS Library 1.1.1
5001 * Copyright(c) 2006-2007, Ext JS, LLC.
5003 * Originally Released Under LGPL - original licence link has changed is not relivant.
5006 * <script type="text/javascript">
5011 * @class Roo.grid.ColumnModel
5012 * @extends Roo.util.Observable
5013 * This is the default implementation of a ColumnModel used by the Grid. It defines
5014 * the columns in the grid.
5017 var colModel = new Roo.grid.ColumnModel([
5018 {header: "Ticker", width: 60, sortable: true, locked: true},
5019 {header: "Company Name", width: 150, sortable: true},
5020 {header: "Market Cap.", width: 100, sortable: true},
5021 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5022 {header: "Employees", width: 100, sortable: true, resizable: false}
5027 * The config options listed for this class are options which may appear in each
5028 * individual column definition.
5029 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5031 * @param {Object} config An Array of column config objects. See this class's
5032 * config objects for details.
5034 Roo.grid.ColumnModel = function(config){
5036 * The config passed into the constructor
5038 this.config = config;
5041 // if no id, create one
5042 // if the column does not have a dataIndex mapping,
5043 // map it to the order it is in the config
5044 for(var i = 0, len = config.length; i < len; i++){
5046 if(typeof c.dataIndex == "undefined"){
5049 if(typeof c.renderer == "string"){
5050 c.renderer = Roo.util.Format[c.renderer];
5052 if(typeof c.id == "undefined"){
5055 if(c.editor && c.editor.xtype){
5056 c.editor = Roo.factory(c.editor, Roo.grid);
5058 if(c.editor && c.editor.isFormField){
5059 c.editor = new Roo.grid.GridEditor(c.editor);
5061 this.lookup[c.id] = c;
5065 * The width of columns which have no width specified (defaults to 100)
5068 this.defaultWidth = 100;
5071 * Default sortable of columns which have no sortable specified (defaults to false)
5074 this.defaultSortable = false;
5078 * @event widthchange
5079 * Fires when the width of a column changes.
5080 * @param {ColumnModel} this
5081 * @param {Number} columnIndex The column index
5082 * @param {Number} newWidth The new width
5084 "widthchange": true,
5086 * @event headerchange
5087 * Fires when the text of a header changes.
5088 * @param {ColumnModel} this
5089 * @param {Number} columnIndex The column index
5090 * @param {Number} newText The new header text
5092 "headerchange": true,
5094 * @event hiddenchange
5095 * Fires when a column is hidden or "unhidden".
5096 * @param {ColumnModel} this
5097 * @param {Number} columnIndex The column index
5098 * @param {Boolean} hidden true if hidden, false otherwise
5100 "hiddenchange": true,
5102 * @event columnmoved
5103 * Fires when a column is moved.
5104 * @param {ColumnModel} this
5105 * @param {Number} oldIndex
5106 * @param {Number} newIndex
5108 "columnmoved" : true,
5110 * @event columlockchange
5111 * Fires when a column's locked state is changed
5112 * @param {ColumnModel} this
5113 * @param {Number} colIndex
5114 * @param {Boolean} locked true if locked
5116 "columnlockchange" : true
5118 Roo.grid.ColumnModel.superclass.constructor.call(this);
5120 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5122 * @cfg {String} header The header text to display in the Grid view.
5125 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5126 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5127 * specified, the column's index is used as an index into the Record's data Array.
5130 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5131 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5134 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5135 * Defaults to the value of the {@link #defaultSortable} property.
5136 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5139 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5142 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5145 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5148 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5151 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5152 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5153 * default renderer uses the raw data value. If an object is returned (bootstrap only)
5154 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5157 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5160 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5163 * @cfg {String} cursor (Optional)
5166 * @cfg {String} tooltip (Optional)
5169 * @cfg {Number} xs (Optional)
5172 * @cfg {Number} sm (Optional)
5175 * @cfg {Number} md (Optional)
5178 * @cfg {Number} lg (Optional)
5181 * Returns the id of the column at the specified index.
5182 * @param {Number} index The column index
5183 * @return {String} the id
5185 getColumnId : function(index){
5186 return this.config[index].id;
5190 * Returns the column for a specified id.
5191 * @param {String} id The column id
5192 * @return {Object} the column
5194 getColumnById : function(id){
5195 return this.lookup[id];
5200 * Returns the column for a specified dataIndex.
5201 * @param {String} dataIndex The column dataIndex
5202 * @return {Object|Boolean} the column or false if not found
5204 getColumnByDataIndex: function(dataIndex){
5205 var index = this.findColumnIndex(dataIndex);
5206 return index > -1 ? this.config[index] : false;
5210 * Returns the index for a specified column id.
5211 * @param {String} id The column id
5212 * @return {Number} the index, or -1 if not found
5214 getIndexById : function(id){
5215 for(var i = 0, len = this.config.length; i < len; i++){
5216 if(this.config[i].id == id){
5224 * Returns the index for a specified column dataIndex.
5225 * @param {String} dataIndex The column dataIndex
5226 * @return {Number} the index, or -1 if not found
5229 findColumnIndex : function(dataIndex){
5230 for(var i = 0, len = this.config.length; i < len; i++){
5231 if(this.config[i].dataIndex == dataIndex){
5239 moveColumn : function(oldIndex, newIndex){
5240 var c = this.config[oldIndex];
5241 this.config.splice(oldIndex, 1);
5242 this.config.splice(newIndex, 0, c);
5243 this.dataMap = null;
5244 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5247 isLocked : function(colIndex){
5248 return this.config[colIndex].locked === true;
5251 setLocked : function(colIndex, value, suppressEvent){
5252 if(this.isLocked(colIndex) == value){
5255 this.config[colIndex].locked = value;
5257 this.fireEvent("columnlockchange", this, colIndex, value);
5261 getTotalLockedWidth : function(){
5263 for(var i = 0; i < this.config.length; i++){
5264 if(this.isLocked(i) && !this.isHidden(i)){
5265 this.totalWidth += this.getColumnWidth(i);
5271 getLockedCount : function(){
5272 for(var i = 0, len = this.config.length; i < len; i++){
5273 if(!this.isLocked(i)){
5278 return this.config.length;
5282 * Returns the number of columns.
5285 getColumnCount : function(visibleOnly){
5286 if(visibleOnly === true){
5288 for(var i = 0, len = this.config.length; i < len; i++){
5289 if(!this.isHidden(i)){
5295 return this.config.length;
5299 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5300 * @param {Function} fn
5301 * @param {Object} scope (optional)
5302 * @return {Array} result
5304 getColumnsBy : function(fn, scope){
5306 for(var i = 0, len = this.config.length; i < len; i++){
5307 var c = this.config[i];
5308 if(fn.call(scope||this, c, i) === true){
5316 * Returns true if the specified column is sortable.
5317 * @param {Number} col The column index
5320 isSortable : function(col){
5321 if(typeof this.config[col].sortable == "undefined"){
5322 return this.defaultSortable;
5324 return this.config[col].sortable;
5328 * Returns the rendering (formatting) function defined for the column.
5329 * @param {Number} col The column index.
5330 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5332 getRenderer : function(col){
5333 if(!this.config[col].renderer){
5334 return Roo.grid.ColumnModel.defaultRenderer;
5336 return this.config[col].renderer;
5340 * Sets the rendering (formatting) function for a column.
5341 * @param {Number} col The column index
5342 * @param {Function} fn The function to use to process the cell's raw data
5343 * to return HTML markup for the grid view. The render function is called with
5344 * the following parameters:<ul>
5345 * <li>Data value.</li>
5346 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5347 * <li>css A CSS style string to apply to the table cell.</li>
5348 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5349 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5350 * <li>Row index</li>
5351 * <li>Column index</li>
5352 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5354 setRenderer : function(col, fn){
5355 this.config[col].renderer = fn;
5359 * Returns the width for the specified column.
5360 * @param {Number} col The column index
5363 getColumnWidth : function(col){
5364 return this.config[col].width * 1 || this.defaultWidth;
5368 * Sets the width for a column.
5369 * @param {Number} col The column index
5370 * @param {Number} width The new width
5372 setColumnWidth : function(col, width, suppressEvent){
5373 this.config[col].width = width;
5374 this.totalWidth = null;
5376 this.fireEvent("widthchange", this, col, width);
5381 * Returns the total width of all columns.
5382 * @param {Boolean} includeHidden True to include hidden column widths
5385 getTotalWidth : function(includeHidden){
5386 if(!this.totalWidth){
5387 this.totalWidth = 0;
5388 for(var i = 0, len = this.config.length; i < len; i++){
5389 if(includeHidden || !this.isHidden(i)){
5390 this.totalWidth += this.getColumnWidth(i);
5394 return this.totalWidth;
5398 * Returns the header for the specified column.
5399 * @param {Number} col The column index
5402 getColumnHeader : function(col){
5403 return this.config[col].header;
5407 * Sets the header for a column.
5408 * @param {Number} col The column index
5409 * @param {String} header The new header
5411 setColumnHeader : function(col, header){
5412 this.config[col].header = header;
5413 this.fireEvent("headerchange", this, col, header);
5417 * Returns the tooltip for the specified column.
5418 * @param {Number} col The column index
5421 getColumnTooltip : function(col){
5422 return this.config[col].tooltip;
5425 * Sets the tooltip for a column.
5426 * @param {Number} col The column index
5427 * @param {String} tooltip The new tooltip
5429 setColumnTooltip : function(col, tooltip){
5430 this.config[col].tooltip = tooltip;
5434 * Returns the dataIndex for the specified column.
5435 * @param {Number} col The column index
5438 getDataIndex : function(col){
5439 return this.config[col].dataIndex;
5443 * Sets the dataIndex for a column.
5444 * @param {Number} col The column index
5445 * @param {Number} dataIndex The new dataIndex
5447 setDataIndex : function(col, dataIndex){
5448 this.config[col].dataIndex = dataIndex;
5454 * Returns true if the cell is editable.
5455 * @param {Number} colIndex The column index
5456 * @param {Number} rowIndex The row index - this is nto actually used..?
5459 isCellEditable : function(colIndex, rowIndex){
5460 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5464 * Returns the editor defined for the cell/column.
5465 * return false or null to disable editing.
5466 * @param {Number} colIndex The column index
5467 * @param {Number} rowIndex The row index
5470 getCellEditor : function(colIndex, rowIndex){
5471 return this.config[colIndex].editor;
5475 * Sets if a column is editable.
5476 * @param {Number} col The column index
5477 * @param {Boolean} editable True if the column is editable
5479 setEditable : function(col, editable){
5480 this.config[col].editable = editable;
5485 * Returns true if the column is hidden.
5486 * @param {Number} colIndex The column index
5489 isHidden : function(colIndex){
5490 return this.config[colIndex].hidden;
5495 * Returns true if the column width cannot be changed
5497 isFixed : function(colIndex){
5498 return this.config[colIndex].fixed;
5502 * Returns true if the column can be resized
5505 isResizable : function(colIndex){
5506 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5509 * Sets if a column is hidden.
5510 * @param {Number} colIndex The column index
5511 * @param {Boolean} hidden True if the column is hidden
5513 setHidden : function(colIndex, hidden){
5514 this.config[colIndex].hidden = hidden;
5515 this.totalWidth = null;
5516 this.fireEvent("hiddenchange", this, colIndex, hidden);
5520 * Sets the editor for a column.
5521 * @param {Number} col The column index
5522 * @param {Object} editor The editor object
5524 setEditor : function(col, editor){
5525 this.config[col].editor = editor;
5529 Roo.grid.ColumnModel.defaultRenderer = function(value){
5530 if(typeof value == "string" && value.length < 1){
5536 // Alias for backwards compatibility
5537 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5540 * Ext JS Library 1.1.1
5541 * Copyright(c) 2006-2007, Ext JS, LLC.
5543 * Originally Released Under LGPL - original licence link has changed is not relivant.
5546 * <script type="text/javascript">
5550 * @class Roo.LoadMask
5551 * A simple utility class for generically masking elements while loading data. If the element being masked has
5552 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5553 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5554 * element's UpdateManager load indicator and will be destroyed after the initial load.
5556 * Create a new LoadMask
5557 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5558 * @param {Object} config The config object
5560 Roo.LoadMask = function(el, config){
5561 this.el = Roo.get(el);
5562 Roo.apply(this, config);
5564 this.store.on('beforeload', this.onBeforeLoad, this);
5565 this.store.on('load', this.onLoad, this);
5566 this.store.on('loadexception', this.onLoadException, this);
5567 this.removeMask = false;
5569 var um = this.el.getUpdateManager();
5570 um.showLoadIndicator = false; // disable the default indicator
5571 um.on('beforeupdate', this.onBeforeLoad, this);
5572 um.on('update', this.onLoad, this);
5573 um.on('failure', this.onLoad, this);
5574 this.removeMask = true;
5578 Roo.LoadMask.prototype = {
5580 * @cfg {Boolean} removeMask
5581 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5582 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5586 * The text to display in a centered loading message box (defaults to 'Loading...')
5590 * @cfg {String} msgCls
5591 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5593 msgCls : 'x-mask-loading',
5596 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5602 * Disables the mask to prevent it from being displayed
5604 disable : function(){
5605 this.disabled = true;
5609 * Enables the mask so that it can be displayed
5611 enable : function(){
5612 this.disabled = false;
5615 onLoadException : function()
5619 if (typeof(arguments[3]) != 'undefined') {
5620 Roo.MessageBox.alert("Error loading",arguments[3]);
5624 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5625 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5634 this.el.unmask(this.removeMask);
5639 this.el.unmask(this.removeMask);
5643 onBeforeLoad : function(){
5645 this.el.mask(this.msg, this.msgCls);
5650 destroy : function(){
5652 this.store.un('beforeload', this.onBeforeLoad, this);
5653 this.store.un('load', this.onLoad, this);
5654 this.store.un('loadexception', this.onLoadException, this);
5656 var um = this.el.getUpdateManager();
5657 um.un('beforeupdate', this.onBeforeLoad, this);
5658 um.un('update', this.onLoad, this);
5659 um.un('failure', this.onLoad, this);
5670 * @class Roo.bootstrap.Table
5671 * @extends Roo.bootstrap.Component
5672 * Bootstrap Table class
5673 * @cfg {String} cls table class
5674 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5675 * @cfg {String} bgcolor Specifies the background color for a table
5676 * @cfg {Number} border Specifies whether the table cells should have borders or not
5677 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5678 * @cfg {Number} cellspacing Specifies the space between cells
5679 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5680 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5681 * @cfg {String} sortable Specifies that the table should be sortable
5682 * @cfg {String} summary Specifies a summary of the content of a table
5683 * @cfg {Number} width Specifies the width of a table
5684 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5686 * @cfg {boolean} striped Should the rows be alternative striped
5687 * @cfg {boolean} bordered Add borders to the table
5688 * @cfg {boolean} hover Add hover highlighting
5689 * @cfg {boolean} condensed Format condensed
5690 * @cfg {boolean} responsive Format condensed
5691 * @cfg {Boolean} loadMask (true|false) default false
5692 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5693 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5694 * @cfg {Boolean} rowSelection (true|false) default false
5695 * @cfg {Boolean} cellSelection (true|false) default false
5696 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5697 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5701 * Create a new Table
5702 * @param {Object} config The config object
5705 Roo.bootstrap.Table = function(config){
5706 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5711 this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
5712 this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
5713 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5714 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5716 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5718 this.sm.grid = this;
5719 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5720 this.sm = this.selModel;
5721 this.sm.xmodule = this.xmodule || false;
5724 if (this.cm && typeof(this.cm.config) == 'undefined') {
5725 this.colModel = new Roo.grid.ColumnModel(this.cm);
5726 this.cm = this.colModel;
5727 this.cm.xmodule = this.xmodule || false;
5730 this.store= Roo.factory(this.store, Roo.data);
5731 this.ds = this.store;
5732 this.ds.xmodule = this.xmodule || false;
5735 if (this.footer && this.store) {
5736 this.footer.dataSource = this.ds;
5737 this.footer = Roo.factory(this.footer);
5744 * Fires when a cell is clicked
5745 * @param {Roo.bootstrap.Table} this
5746 * @param {Roo.Element} el
5747 * @param {Number} rowIndex
5748 * @param {Number} columnIndex
5749 * @param {Roo.EventObject} e
5753 * @event celldblclick
5754 * Fires when a cell is double clicked
5755 * @param {Roo.bootstrap.Table} this
5756 * @param {Roo.Element} el
5757 * @param {Number} rowIndex
5758 * @param {Number} columnIndex
5759 * @param {Roo.EventObject} e
5761 "celldblclick" : true,
5764 * Fires when a row is clicked
5765 * @param {Roo.bootstrap.Table} this
5766 * @param {Roo.Element} el
5767 * @param {Number} rowIndex
5768 * @param {Roo.EventObject} e
5772 * @event rowdblclick
5773 * Fires when a row is double clicked
5774 * @param {Roo.bootstrap.Table} this
5775 * @param {Roo.Element} el
5776 * @param {Number} rowIndex
5777 * @param {Roo.EventObject} e
5779 "rowdblclick" : true,
5782 * Fires when a mouseover occur
5783 * @param {Roo.bootstrap.Table} this
5784 * @param {Roo.Element} el
5785 * @param {Number} rowIndex
5786 * @param {Number} columnIndex
5787 * @param {Roo.EventObject} e
5792 * Fires when a mouseout occur
5793 * @param {Roo.bootstrap.Table} this
5794 * @param {Roo.Element} el
5795 * @param {Number} rowIndex
5796 * @param {Number} columnIndex
5797 * @param {Roo.EventObject} e
5802 * Fires when a row is rendered, so you can change add a style to it.
5803 * @param {Roo.bootstrap.Table} this
5804 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5808 * @event rowsrendered
5809 * Fires when all the rows have been rendered
5810 * @param {Roo.bootstrap.Table} this
5812 'rowsrendered' : true,
5814 * @event contextmenu
5815 * The raw contextmenu event for the entire grid.
5816 * @param {Roo.EventObject} e
5818 "contextmenu" : true,
5820 * @event rowcontextmenu
5821 * Fires when a row is right clicked
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Number} rowIndex
5824 * @param {Roo.EventObject} e
5826 "rowcontextmenu" : true,
5828 * @event cellcontextmenu
5829 * Fires when a cell is right clicked
5830 * @param {Roo.bootstrap.Table} this
5831 * @param {Number} rowIndex
5832 * @param {Number} cellIndex
5833 * @param {Roo.EventObject} e
5835 "cellcontextmenu" : true,
5837 * @event headercontextmenu
5838 * Fires when a header is right clicked
5839 * @param {Roo.bootstrap.Table} this
5840 * @param {Number} columnIndex
5841 * @param {Roo.EventObject} e
5843 "headercontextmenu" : true
5847 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5873 rowSelection : false,
5874 cellSelection : false,
5877 // Roo.Element - the tbody
5879 // Roo.Element - thead element
5882 container: false, // used by gridpanel...
5884 getAutoCreate : function()
5886 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5893 if (this.scrollBody) {
5894 cfg.cls += ' table-body-fixed';
5897 cfg.cls += ' table-striped';
5901 cfg.cls += ' table-hover';
5903 if (this.bordered) {
5904 cfg.cls += ' table-bordered';
5906 if (this.condensed) {
5907 cfg.cls += ' table-condensed';
5909 if (this.responsive) {
5910 cfg.cls += ' table-responsive';
5914 cfg.cls+= ' ' +this.cls;
5917 // this lot should be simplifed...
5920 cfg.align=this.align;
5923 cfg.bgcolor=this.bgcolor;
5926 cfg.border=this.border;
5928 if (this.cellpadding) {
5929 cfg.cellpadding=this.cellpadding;
5931 if (this.cellspacing) {
5932 cfg.cellspacing=this.cellspacing;
5935 cfg.frame=this.frame;
5938 cfg.rules=this.rules;
5940 if (this.sortable) {
5941 cfg.sortable=this.sortable;
5944 cfg.summary=this.summary;
5947 cfg.width=this.width;
5950 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5953 if(this.store || this.cm){
5954 if(this.headerShow){
5955 cfg.cn.push(this.renderHeader());
5958 cfg.cn.push(this.renderBody());
5960 if(this.footerShow){
5961 cfg.cn.push(this.renderFooter());
5963 // where does this come from?
5964 //cfg.cls+= ' TableGrid';
5967 return { cn : [ cfg ] };
5970 initEvents : function()
5972 if(!this.store || !this.cm){
5975 if (this.selModel) {
5976 this.selModel.initEvents();
5980 //Roo.log('initEvents with ds!!!!');
5982 this.mainBody = this.el.select('tbody', true).first();
5983 this.mainHead = this.el.select('thead', true).first();
5990 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5991 e.on('click', _this.sort, _this);
5994 this.el.on("click", this.onClick, this);
5995 this.el.on("dblclick", this.onDblClick, this);
5997 // why is this done????? = it breaks dialogs??
5998 //this.parent().el.setStyle('position', 'relative');
6002 this.footer.parentId = this.id;
6003 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6006 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6008 this.store.on('load', this.onLoad, this);
6009 this.store.on('beforeload', this.onBeforeLoad, this);
6010 this.store.on('update', this.onUpdate, this);
6011 this.store.on('add', this.onAdd, this);
6012 this.store.on("clear", this.clear, this);
6014 this.el.on("contextmenu", this.onContextMenu, this);
6016 this.mainBody.on('scroll', this.onBodyScroll, this);
6021 onContextMenu : function(e, t)
6023 this.processEvent("contextmenu", e);
6026 processEvent : function(name, e)
6028 if (name != 'touchstart' ) {
6029 this.fireEvent(name, e);
6032 var t = e.getTarget();
6034 var cell = Roo.get(t);
6040 if(cell.findParent('tfoot', false, true)){
6044 if(cell.findParent('thead', false, true)){
6046 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6047 cell = Roo.get(t).findParent('th', false, true);
6049 Roo.log("failed to find th in thead?");
6050 Roo.log(e.getTarget());
6055 var cellIndex = cell.dom.cellIndex;
6057 var ename = name == 'touchstart' ? 'click' : name;
6058 this.fireEvent("header" + ename, this, cellIndex, e);
6063 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6064 cell = Roo.get(t).findParent('td', false, true);
6066 Roo.log("failed to find th in tbody?");
6067 Roo.log(e.getTarget());
6072 var row = cell.findParent('tr', false, true);
6073 var cellIndex = cell.dom.cellIndex;
6074 var rowIndex = row.dom.rowIndex - 1;
6078 this.fireEvent("row" + name, this, rowIndex, e);
6082 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6088 onMouseover : function(e, el)
6090 var cell = Roo.get(el);
6096 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6097 cell = cell.findParent('td', false, true);
6100 var row = cell.findParent('tr', false, true);
6101 var cellIndex = cell.dom.cellIndex;
6102 var rowIndex = row.dom.rowIndex - 1; // start from 0
6104 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6108 onMouseout : function(e, el)
6110 var cell = Roo.get(el);
6116 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6117 cell = cell.findParent('td', false, true);
6120 var row = cell.findParent('tr', false, true);
6121 var cellIndex = cell.dom.cellIndex;
6122 var rowIndex = row.dom.rowIndex - 1; // start from 0
6124 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6128 onClick : function(e, el)
6130 var cell = Roo.get(el);
6132 if(!cell || (!this.cellSelection && !this.rowSelection)){
6136 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6137 cell = cell.findParent('td', false, true);
6140 if(!cell || typeof(cell) == 'undefined'){
6144 var row = cell.findParent('tr', false, true);
6146 if(!row || typeof(row) == 'undefined'){
6150 var cellIndex = cell.dom.cellIndex;
6151 var rowIndex = this.getRowIndex(row);
6153 // why??? - should these not be based on SelectionModel?
6154 if(this.cellSelection){
6155 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6158 if(this.rowSelection){
6159 this.fireEvent('rowclick', this, row, rowIndex, e);
6165 onDblClick : function(e,el)
6167 var cell = Roo.get(el);
6169 if(!cell || (!this.CellSelection && !this.RowSelection)){
6173 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6174 cell = cell.findParent('td', false, true);
6177 if(!cell || typeof(cell) == 'undefined'){
6181 var row = cell.findParent('tr', false, true);
6183 if(!row || typeof(row) == 'undefined'){
6187 var cellIndex = cell.dom.cellIndex;
6188 var rowIndex = this.getRowIndex(row);
6190 if(this.CellSelection){
6191 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6194 if(this.RowSelection){
6195 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6199 sort : function(e,el)
6201 var col = Roo.get(el);
6203 if(!col.hasClass('sortable')){
6207 var sort = col.attr('sort');
6210 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6214 this.store.sortInfo = {field : sort, direction : dir};
6217 Roo.log("calling footer first");
6218 this.footer.onClick('first');
6221 this.store.load({ params : { start : 0 } });
6225 renderHeader : function()
6233 this.totalWidth = 0;
6235 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6237 var config = cm.config[i];
6242 html: cm.getColumnHeader(i)
6247 if(typeof(config.sortable) != 'undefined' && config.sortable){
6249 c.html = '<i class="glyphicon"></i>' + c.html;
6252 if(typeof(config.lgHeader) != 'undefined'){
6253 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6256 if(typeof(config.mdHeader) != 'undefined'){
6257 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6260 if(typeof(config.smHeader) != 'undefined'){
6261 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6264 if(typeof(config.xsHeader) != 'undefined'){
6265 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6272 if(typeof(config.tooltip) != 'undefined'){
6273 c.tooltip = config.tooltip;
6276 if(typeof(config.colspan) != 'undefined'){
6277 c.colspan = config.colspan;
6280 if(typeof(config.hidden) != 'undefined' && config.hidden){
6281 c.style += ' display:none;';
6284 if(typeof(config.dataIndex) != 'undefined'){
6285 c.sort = config.dataIndex;
6290 if(typeof(config.align) != 'undefined' && config.align.length){
6291 c.style += ' text-align:' + config.align + ';';
6294 if(typeof(config.width) != 'undefined'){
6295 c.style += ' width:' + config.width + 'px;';
6296 this.totalWidth += config.width;
6298 this.totalWidth += 100; // assume minimum of 100 per column?
6301 if(typeof(config.cls) != 'undefined'){
6302 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6305 ['xs','sm','md','lg'].map(function(size){
6307 if(typeof(config[size]) == 'undefined'){
6311 if (!config[size]) { // 0 = hidden
6312 c.cls += ' hidden-' + size;
6316 c.cls += ' col-' + size + '-' + config[size];
6326 renderBody : function()
6336 colspan : this.cm.getColumnCount()
6346 renderFooter : function()
6356 colspan : this.cm.getColumnCount()
6370 // Roo.log('ds onload');
6375 var ds = this.store;
6377 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6378 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6379 if (_this.store.sortInfo) {
6381 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6382 e.select('i', true).addClass(['glyphicon-arrow-up']);
6385 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6386 e.select('i', true).addClass(['glyphicon-arrow-down']);
6391 var tbody = this.mainBody;
6393 if(ds.getCount() > 0){
6394 ds.data.each(function(d,rowIndex){
6395 var row = this.renderRow(cm, ds, rowIndex);
6397 tbody.createChild(row);
6401 if(row.cellObjects.length){
6402 Roo.each(row.cellObjects, function(r){
6403 _this.renderCellObject(r);
6410 Roo.each(this.el.select('tbody td', true).elements, function(e){
6411 e.on('mouseover', _this.onMouseover, _this);
6414 Roo.each(this.el.select('tbody td', true).elements, function(e){
6415 e.on('mouseout', _this.onMouseout, _this);
6417 this.fireEvent('rowsrendered', this);
6418 //if(this.loadMask){
6419 // this.maskEl.hide();
6426 onUpdate : function(ds,record)
6428 this.refreshRow(record);
6431 onRemove : function(ds, record, index, isUpdate){
6432 if(isUpdate !== true){
6433 this.fireEvent("beforerowremoved", this, index, record);
6435 var bt = this.mainBody.dom;
6437 var rows = this.el.select('tbody > tr', true).elements;
6439 if(typeof(rows[index]) != 'undefined'){
6440 bt.removeChild(rows[index].dom);
6443 // if(bt.rows[index]){
6444 // bt.removeChild(bt.rows[index]);
6447 if(isUpdate !== true){
6448 //this.stripeRows(index);
6449 //this.syncRowHeights(index, index);
6451 this.fireEvent("rowremoved", this, index, record);
6455 onAdd : function(ds, records, rowIndex)
6457 //Roo.log('on Add called');
6458 // - note this does not handle multiple adding very well..
6459 var bt = this.mainBody.dom;
6460 for (var i =0 ; i < records.length;i++) {
6461 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6462 //Roo.log(records[i]);
6463 //Roo.log(this.store.getAt(rowIndex+i));
6464 this.insertRow(this.store, rowIndex + i, false);
6471 refreshRow : function(record){
6472 var ds = this.store, index;
6473 if(typeof record == 'number'){
6475 record = ds.getAt(index);
6477 index = ds.indexOf(record);
6479 this.insertRow(ds, index, true);
6480 this.onRemove(ds, record, index+1, true);
6481 //this.syncRowHeights(index, index);
6483 this.fireEvent("rowupdated", this, index, record);
6486 insertRow : function(dm, rowIndex, isUpdate){
6489 this.fireEvent("beforerowsinserted", this, rowIndex);
6491 //var s = this.getScrollState();
6492 var row = this.renderRow(this.cm, this.store, rowIndex);
6493 // insert before rowIndex..
6494 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6498 if(row.cellObjects.length){
6499 Roo.each(row.cellObjects, function(r){
6500 _this.renderCellObject(r);
6505 this.fireEvent("rowsinserted", this, rowIndex);
6506 //this.syncRowHeights(firstRow, lastRow);
6507 //this.stripeRows(firstRow);
6514 getRowDom : function(rowIndex)
6516 var rows = this.el.select('tbody > tr', true).elements;
6518 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6521 // returns the object tree for a tr..
6524 renderRow : function(cm, ds, rowIndex)
6527 var d = ds.getAt(rowIndex);
6534 var cellObjects = [];
6536 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6537 var config = cm.config[i];
6539 var renderer = cm.getRenderer(i);
6543 if(typeof(renderer) !== 'undefined'){
6544 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6546 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6547 // and are rendered into the cells after the row is rendered - using the id for the element.
6549 if(typeof(value) === 'object'){
6559 rowIndex : rowIndex,
6564 this.fireEvent('rowclass', this, rowcfg);
6568 cls : rowcfg.rowClass,
6570 html: (typeof(value) === 'object') ? '' : value
6577 if(typeof(config.colspan) != 'undefined'){
6578 td.colspan = config.colspan;
6581 if(typeof(config.hidden) != 'undefined' && config.hidden){
6582 td.style += ' display:none;';
6585 if(typeof(config.align) != 'undefined' && config.align.length){
6586 td.style += ' text-align:' + config.align + ';';
6589 if(typeof(config.width) != 'undefined'){
6590 td.style += ' width:' + config.width + 'px;';
6593 if(typeof(config.cursor) != 'undefined'){
6594 td.style += ' cursor:' + config.cursor + ';';
6597 if(typeof(config.cls) != 'undefined'){
6598 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6601 ['xs','sm','md','lg'].map(function(size){
6603 if(typeof(config[size]) == 'undefined'){
6607 if (!config[size]) { // 0 = hidden
6608 td.cls += ' hidden-' + size;
6612 td.cls += ' col-' + size + '-' + config[size];
6620 row.cellObjects = cellObjects;
6628 onBeforeLoad : function()
6630 //Roo.log('ds onBeforeLoad');
6634 //if(this.loadMask){
6635 // this.maskEl.show();
6643 this.el.select('tbody', true).first().dom.innerHTML = '';
6646 * Show or hide a row.
6647 * @param {Number} rowIndex to show or hide
6648 * @param {Boolean} state hide
6650 setRowVisibility : function(rowIndex, state)
6652 var bt = this.mainBody.dom;
6654 var rows = this.el.select('tbody > tr', true).elements;
6656 if(typeof(rows[rowIndex]) == 'undefined'){
6659 rows[rowIndex].dom.style.display = state ? '' : 'none';
6663 getSelectionModel : function(){
6665 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6667 return this.selModel;
6670 * Render the Roo.bootstrap object from renderder
6672 renderCellObject : function(r)
6676 var t = r.cfg.render(r.container);
6679 Roo.each(r.cfg.cn, function(c){
6681 container: t.getChildContainer(),
6684 _this.renderCellObject(child);
6689 getRowIndex : function(row)
6693 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6704 * Returns the grid's underlying element = used by panel.Grid
6705 * @return {Element} The element
6707 getGridEl : function(){
6711 * Forces a resize - used by panel.Grid
6712 * @return {Element} The element
6714 autoSize : function()
6716 //var ctr = Roo.get(this.container.dom.parentElement);
6717 var ctr = Roo.get(this.el.dom);
6719 var thd = this.getGridEl().select('thead',true).first();
6720 var tbd = this.getGridEl().select('tbody', true).first();
6723 var cw = ctr.getWidth();
6727 tbd.setSize(ctr.getWidth(), ctr.getHeight() - thd.getHeight());
6728 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6731 cw = Math.max(cw, this.totalWidth);
6732 this.getGridEl().select('tr',true).setWidth(cw);
6733 // resize 'expandable coloumn?
6735 return; // we doe not have a view in this design..
6738 onBodyScroll: function()
6741 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6742 this.mainHead.setStyle({
6743 'position' : 'relative',
6744 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6761 * @class Roo.bootstrap.TableCell
6762 * @extends Roo.bootstrap.Component
6763 * Bootstrap TableCell class
6764 * @cfg {String} html cell contain text
6765 * @cfg {String} cls cell class
6766 * @cfg {String} tag cell tag (td|th) default td
6767 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6768 * @cfg {String} align Aligns the content in a cell
6769 * @cfg {String} axis Categorizes cells
6770 * @cfg {String} bgcolor Specifies the background color of a cell
6771 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6772 * @cfg {Number} colspan Specifies the number of columns a cell should span
6773 * @cfg {String} headers Specifies one or more header cells a cell is related to
6774 * @cfg {Number} height Sets the height of a cell
6775 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6776 * @cfg {Number} rowspan Sets the number of rows a cell should span
6777 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6778 * @cfg {String} valign Vertical aligns the content in a cell
6779 * @cfg {Number} width Specifies the width of a cell
6782 * Create a new TableCell
6783 * @param {Object} config The config object
6786 Roo.bootstrap.TableCell = function(config){
6787 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6790 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6810 getAutoCreate : function(){
6811 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6831 cfg.align=this.align
6837 cfg.bgcolor=this.bgcolor
6840 cfg.charoff=this.charoff
6843 cfg.colspan=this.colspan
6846 cfg.headers=this.headers
6849 cfg.height=this.height
6852 cfg.nowrap=this.nowrap
6855 cfg.rowspan=this.rowspan
6858 cfg.scope=this.scope
6861 cfg.valign=this.valign
6864 cfg.width=this.width
6883 * @class Roo.bootstrap.TableRow
6884 * @extends Roo.bootstrap.Component
6885 * Bootstrap TableRow class
6886 * @cfg {String} cls row class
6887 * @cfg {String} align Aligns the content in a table row
6888 * @cfg {String} bgcolor Specifies a background color for a table row
6889 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6890 * @cfg {String} valign Vertical aligns the content in a table row
6893 * Create a new TableRow
6894 * @param {Object} config The config object
6897 Roo.bootstrap.TableRow = function(config){
6898 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6901 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6909 getAutoCreate : function(){
6910 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6920 cfg.align = this.align;
6923 cfg.bgcolor = this.bgcolor;
6926 cfg.charoff = this.charoff;
6929 cfg.valign = this.valign;
6947 * @class Roo.bootstrap.TableBody
6948 * @extends Roo.bootstrap.Component
6949 * Bootstrap TableBody class
6950 * @cfg {String} cls element class
6951 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6952 * @cfg {String} align Aligns the content inside the element
6953 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6954 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6957 * Create a new TableBody
6958 * @param {Object} config The config object
6961 Roo.bootstrap.TableBody = function(config){
6962 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6965 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6973 getAutoCreate : function(){
6974 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6988 cfg.align = this.align;
6991 cfg.charoff = this.charoff;
6994 cfg.valign = this.valign;
7001 // initEvents : function()
7008 // this.store = Roo.factory(this.store, Roo.data);
7009 // this.store.on('load', this.onLoad, this);
7011 // this.store.load();
7015 // onLoad: function ()
7017 // this.fireEvent('load', this);
7027 * Ext JS Library 1.1.1
7028 * Copyright(c) 2006-2007, Ext JS, LLC.
7030 * Originally Released Under LGPL - original licence link has changed is not relivant.
7033 * <script type="text/javascript">
7036 // as we use this in bootstrap.
7037 Roo.namespace('Roo.form');
7039 * @class Roo.form.Action
7040 * Internal Class used to handle form actions
7042 * @param {Roo.form.BasicForm} el The form element or its id
7043 * @param {Object} config Configuration options
7048 // define the action interface
7049 Roo.form.Action = function(form, options){
7051 this.options = options || {};
7054 * Client Validation Failed
7057 Roo.form.Action.CLIENT_INVALID = 'client';
7059 * Server Validation Failed
7062 Roo.form.Action.SERVER_INVALID = 'server';
7064 * Connect to Server Failed
7067 Roo.form.Action.CONNECT_FAILURE = 'connect';
7069 * Reading Data from Server Failed
7072 Roo.form.Action.LOAD_FAILURE = 'load';
7074 Roo.form.Action.prototype = {
7076 failureType : undefined,
7077 response : undefined,
7081 run : function(options){
7086 success : function(response){
7091 handleResponse : function(response){
7095 // default connection failure
7096 failure : function(response){
7098 this.response = response;
7099 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7100 this.form.afterAction(this, false);
7103 processResponse : function(response){
7104 this.response = response;
7105 if(!response.responseText){
7108 this.result = this.handleResponse(response);
7112 // utility functions used internally
7113 getUrl : function(appendParams){
7114 var url = this.options.url || this.form.url || this.form.el.dom.action;
7116 var p = this.getParams();
7118 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7124 getMethod : function(){
7125 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7128 getParams : function(){
7129 var bp = this.form.baseParams;
7130 var p = this.options.params;
7132 if(typeof p == "object"){
7133 p = Roo.urlEncode(Roo.applyIf(p, bp));
7134 }else if(typeof p == 'string' && bp){
7135 p += '&' + Roo.urlEncode(bp);
7138 p = Roo.urlEncode(bp);
7143 createCallback : function(){
7145 success: this.success,
7146 failure: this.failure,
7148 timeout: (this.form.timeout*1000),
7149 upload: this.form.fileUpload ? this.success : undefined
7154 Roo.form.Action.Submit = function(form, options){
7155 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7158 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7161 haveProgress : false,
7162 uploadComplete : false,
7164 // uploadProgress indicator.
7165 uploadProgress : function()
7167 if (!this.form.progressUrl) {
7171 if (!this.haveProgress) {
7172 Roo.MessageBox.progress("Uploading", "Uploading");
7174 if (this.uploadComplete) {
7175 Roo.MessageBox.hide();
7179 this.haveProgress = true;
7181 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7183 var c = new Roo.data.Connection();
7185 url : this.form.progressUrl,
7190 success : function(req){
7191 //console.log(data);
7195 rdata = Roo.decode(req.responseText)
7197 Roo.log("Invalid data from server..");
7201 if (!rdata || !rdata.success) {
7203 Roo.MessageBox.alert(Roo.encode(rdata));
7206 var data = rdata.data;
7208 if (this.uploadComplete) {
7209 Roo.MessageBox.hide();
7214 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7215 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7218 this.uploadProgress.defer(2000,this);
7221 failure: function(data) {
7222 Roo.log('progress url failed ');
7233 // run get Values on the form, so it syncs any secondary forms.
7234 this.form.getValues();
7236 var o = this.options;
7237 var method = this.getMethod();
7238 var isPost = method == 'POST';
7239 if(o.clientValidation === false || this.form.isValid()){
7241 if (this.form.progressUrl) {
7242 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7243 (new Date() * 1) + '' + Math.random());
7248 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7249 form:this.form.el.dom,
7250 url:this.getUrl(!isPost),
7252 params:isPost ? this.getParams() : null,
7253 isUpload: this.form.fileUpload
7256 this.uploadProgress();
7258 }else if (o.clientValidation !== false){ // client validation failed
7259 this.failureType = Roo.form.Action.CLIENT_INVALID;
7260 this.form.afterAction(this, false);
7264 success : function(response)
7266 this.uploadComplete= true;
7267 if (this.haveProgress) {
7268 Roo.MessageBox.hide();
7272 var result = this.processResponse(response);
7273 if(result === true || result.success){
7274 this.form.afterAction(this, true);
7278 this.form.markInvalid(result.errors);
7279 this.failureType = Roo.form.Action.SERVER_INVALID;
7281 this.form.afterAction(this, false);
7283 failure : function(response)
7285 this.uploadComplete= true;
7286 if (this.haveProgress) {
7287 Roo.MessageBox.hide();
7290 this.response = response;
7291 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7292 this.form.afterAction(this, false);
7295 handleResponse : function(response){
7296 if(this.form.errorReader){
7297 var rs = this.form.errorReader.read(response);
7300 for(var i = 0, len = rs.records.length; i < len; i++) {
7301 var r = rs.records[i];
7305 if(errors.length < 1){
7309 success : rs.success,
7315 ret = Roo.decode(response.responseText);
7319 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7329 Roo.form.Action.Load = function(form, options){
7330 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7331 this.reader = this.form.reader;
7334 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7339 Roo.Ajax.request(Roo.apply(
7340 this.createCallback(), {
7341 method:this.getMethod(),
7342 url:this.getUrl(false),
7343 params:this.getParams()
7347 success : function(response){
7349 var result = this.processResponse(response);
7350 if(result === true || !result.success || !result.data){
7351 this.failureType = Roo.form.Action.LOAD_FAILURE;
7352 this.form.afterAction(this, false);
7355 this.form.clearInvalid();
7356 this.form.setValues(result.data);
7357 this.form.afterAction(this, true);
7360 handleResponse : function(response){
7361 if(this.form.reader){
7362 var rs = this.form.reader.read(response);
7363 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7365 success : rs.success,
7369 return Roo.decode(response.responseText);
7373 Roo.form.Action.ACTION_TYPES = {
7374 'load' : Roo.form.Action.Load,
7375 'submit' : Roo.form.Action.Submit
7384 * @class Roo.bootstrap.Form
7385 * @extends Roo.bootstrap.Component
7386 * Bootstrap Form class
7387 * @cfg {String} method GET | POST (default POST)
7388 * @cfg {String} labelAlign top | left (default top)
7389 * @cfg {String} align left | right - for navbars
7390 * @cfg {Boolean} loadMask load mask when submit (default true)
7395 * @param {Object} config The config object
7399 Roo.bootstrap.Form = function(config){
7400 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7403 * @event clientvalidation
7404 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7405 * @param {Form} this
7406 * @param {Boolean} valid true if the form has passed client-side validation
7408 clientvalidation: true,
7410 * @event beforeaction
7411 * Fires before any action is performed. Return false to cancel the action.
7412 * @param {Form} this
7413 * @param {Action} action The action to be performed
7417 * @event actionfailed
7418 * Fires when an action fails.
7419 * @param {Form} this
7420 * @param {Action} action The action that failed
7422 actionfailed : true,
7424 * @event actioncomplete
7425 * Fires when an action is completed.
7426 * @param {Form} this
7427 * @param {Action} action The action that completed
7429 actioncomplete : true
7434 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7437 * @cfg {String} method
7438 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7443 * The URL to use for form actions if one isn't supplied in the action options.
7446 * @cfg {Boolean} fileUpload
7447 * Set to true if this form is a file upload.
7451 * @cfg {Object} baseParams
7452 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7456 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7460 * @cfg {Sting} align (left|right) for navbar forms
7465 activeAction : null,
7468 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7469 * element by passing it or its id or mask the form itself by passing in true.
7472 waitMsgTarget : false,
7476 getAutoCreate : function(){
7480 method : this.method || 'POST',
7481 id : this.id || Roo.id(),
7484 if (this.parent().xtype.match(/^Nav/)) {
7485 cfg.cls = 'navbar-form navbar-' + this.align;
7489 if (this.labelAlign == 'left' ) {
7490 cfg.cls += ' form-horizontal';
7496 initEvents : function()
7498 this.el.on('submit', this.onSubmit, this);
7499 // this was added as random key presses on the form where triggering form submit.
7500 this.el.on('keypress', function(e) {
7501 if (e.getCharCode() != 13) {
7504 // we might need to allow it for textareas.. and some other items.
7505 // check e.getTarget().
7507 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7511 Roo.log("keypress blocked");
7519 onSubmit : function(e){
7524 * Returns true if client-side validation on the form is successful.
7527 isValid : function(){
7528 var items = this.getItems();
7530 items.each(function(f){
7539 * Returns true if any fields in this form have changed since their original load.
7542 isDirty : function(){
7544 var items = this.getItems();
7545 items.each(function(f){
7555 * Performs a predefined action (submit or load) or custom actions you define on this form.
7556 * @param {String} actionName The name of the action type
7557 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7558 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7559 * accept other config options):
7561 Property Type Description
7562 ---------------- --------------- ----------------------------------------------------------------------------------
7563 url String The url for the action (defaults to the form's url)
7564 method String The form method to use (defaults to the form's method, or POST if not defined)
7565 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7566 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7567 validate the form on the client (defaults to false)
7569 * @return {BasicForm} this
7571 doAction : function(action, options){
7572 if(typeof action == 'string'){
7573 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7575 if(this.fireEvent('beforeaction', this, action) !== false){
7576 this.beforeAction(action);
7577 action.run.defer(100, action);
7583 beforeAction : function(action){
7584 var o = action.options;
7587 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7589 // not really supported yet.. ??
7591 //if(this.waitMsgTarget === true){
7592 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7593 //}else if(this.waitMsgTarget){
7594 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7595 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7597 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7603 afterAction : function(action, success){
7604 this.activeAction = null;
7605 var o = action.options;
7607 //if(this.waitMsgTarget === true){
7609 //}else if(this.waitMsgTarget){
7610 // this.waitMsgTarget.unmask();
7612 // Roo.MessageBox.updateProgress(1);
7613 // Roo.MessageBox.hide();
7620 Roo.callback(o.success, o.scope, [this, action]);
7621 this.fireEvent('actioncomplete', this, action);
7625 // failure condition..
7626 // we have a scenario where updates need confirming.
7627 // eg. if a locking scenario exists..
7628 // we look for { errors : { needs_confirm : true }} in the response.
7630 (typeof(action.result) != 'undefined') &&
7631 (typeof(action.result.errors) != 'undefined') &&
7632 (typeof(action.result.errors.needs_confirm) != 'undefined')
7635 Roo.log("not supported yet");
7638 Roo.MessageBox.confirm(
7639 "Change requires confirmation",
7640 action.result.errorMsg,
7645 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7655 Roo.callback(o.failure, o.scope, [this, action]);
7656 // show an error message if no failed handler is set..
7657 if (!this.hasListener('actionfailed')) {
7658 Roo.log("need to add dialog support");
7660 Roo.MessageBox.alert("Error",
7661 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7662 action.result.errorMsg :
7663 "Saving Failed, please check your entries or try again"
7668 this.fireEvent('actionfailed', this, action);
7673 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7674 * @param {String} id The value to search for
7677 findField : function(id){
7678 var items = this.getItems();
7679 var field = items.get(id);
7681 items.each(function(f){
7682 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7689 return field || null;
7692 * Mark fields in this form invalid in bulk.
7693 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7694 * @return {BasicForm} this
7696 markInvalid : function(errors){
7697 if(errors instanceof Array){
7698 for(var i = 0, len = errors.length; i < len; i++){
7699 var fieldError = errors[i];
7700 var f = this.findField(fieldError.id);
7702 f.markInvalid(fieldError.msg);
7708 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7709 field.markInvalid(errors[id]);
7713 //Roo.each(this.childForms || [], function (f) {
7714 // f.markInvalid(errors);
7721 * Set values for fields in this form in bulk.
7722 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7723 * @return {BasicForm} this
7725 setValues : function(values){
7726 if(values instanceof Array){ // array of objects
7727 for(var i = 0, len = values.length; i < len; i++){
7729 var f = this.findField(v.id);
7731 f.setValue(v.value);
7732 if(this.trackResetOnLoad){
7733 f.originalValue = f.getValue();
7737 }else{ // object hash
7740 if(typeof values[id] != 'function' && (field = this.findField(id))){
7742 if (field.setFromData &&
7744 field.displayField &&
7745 // combos' with local stores can
7746 // be queried via setValue()
7747 // to set their value..
7748 (field.store && !field.store.isLocal)
7752 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7753 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7754 field.setFromData(sd);
7757 field.setValue(values[id]);
7761 if(this.trackResetOnLoad){
7762 field.originalValue = field.getValue();
7768 //Roo.each(this.childForms || [], function (f) {
7769 // f.setValues(values);
7776 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7777 * they are returned as an array.
7778 * @param {Boolean} asString
7781 getValues : function(asString){
7782 //if (this.childForms) {
7783 // copy values from the child forms
7784 // Roo.each(this.childForms, function (f) {
7785 // this.setValues(f.getValues());
7791 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7792 if(asString === true){
7795 return Roo.urlDecode(fs);
7799 * Returns the fields in this form as an object with key/value pairs.
7800 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7803 getFieldValues : function(with_hidden)
7805 var items = this.getItems();
7807 items.each(function(f){
7811 var v = f.getValue();
7812 if (f.inputType =='radio') {
7813 if (typeof(ret[f.getName()]) == 'undefined') {
7814 ret[f.getName()] = ''; // empty..
7817 if (!f.el.dom.checked) {
7825 // not sure if this supported any more..
7826 if ((typeof(v) == 'object') && f.getRawValue) {
7827 v = f.getRawValue() ; // dates..
7829 // combo boxes where name != hiddenName...
7830 if (f.name != f.getName()) {
7831 ret[f.name] = f.getRawValue();
7833 ret[f.getName()] = v;
7840 * Clears all invalid messages in this form.
7841 * @return {BasicForm} this
7843 clearInvalid : function(){
7844 var items = this.getItems();
7846 items.each(function(f){
7857 * @return {BasicForm} this
7860 var items = this.getItems();
7861 items.each(function(f){
7865 Roo.each(this.childForms || [], function (f) {
7872 getItems : function()
7874 var r=new Roo.util.MixedCollection(false, function(o){
7875 return o.id || (o.id = Roo.id());
7877 var iter = function(el) {
7884 Roo.each(el.items,function(e) {
7904 * Ext JS Library 1.1.1
7905 * Copyright(c) 2006-2007, Ext JS, LLC.
7907 * Originally Released Under LGPL - original licence link has changed is not relivant.
7910 * <script type="text/javascript">
7913 * @class Roo.form.VTypes
7914 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7917 Roo.form.VTypes = function(){
7918 // closure these in so they are only created once.
7919 var alpha = /^[a-zA-Z_]+$/;
7920 var alphanum = /^[a-zA-Z0-9_]+$/;
7921 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7922 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7924 // All these messages and functions are configurable
7927 * The function used to validate email addresses
7928 * @param {String} value The email address
7930 'email' : function(v){
7931 return email.test(v);
7934 * The error text to display when the email validation function returns false
7937 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7939 * The keystroke filter mask to be applied on email input
7942 'emailMask' : /[a-z0-9_\.\-@]/i,
7945 * The function used to validate URLs
7946 * @param {String} value The URL
7948 'url' : function(v){
7952 * The error text to display when the url validation function returns false
7955 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7958 * The function used to validate alpha values
7959 * @param {String} value The value
7961 'alpha' : function(v){
7962 return alpha.test(v);
7965 * The error text to display when the alpha validation function returns false
7968 'alphaText' : 'This field should only contain letters and _',
7970 * The keystroke filter mask to be applied on alpha input
7973 'alphaMask' : /[a-z_]/i,
7976 * The function used to validate alphanumeric values
7977 * @param {String} value The value
7979 'alphanum' : function(v){
7980 return alphanum.test(v);
7983 * The error text to display when the alphanumeric validation function returns false
7986 'alphanumText' : 'This field should only contain letters, numbers and _',
7988 * The keystroke filter mask to be applied on alphanumeric input
7991 'alphanumMask' : /[a-z0-9_]/i
8001 * @class Roo.bootstrap.Input
8002 * @extends Roo.bootstrap.Component
8003 * Bootstrap Input class
8004 * @cfg {Boolean} disabled is it disabled
8005 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8006 * @cfg {String} name name of the input
8007 * @cfg {string} fieldLabel - the label associated
8008 * @cfg {string} placeholder - placeholder to put in text.
8009 * @cfg {string} before - input group add on before
8010 * @cfg {string} after - input group add on after
8011 * @cfg {string} size - (lg|sm) or leave empty..
8012 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8013 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8014 * @cfg {Number} md colspan out of 12 for computer-sized screens
8015 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8016 * @cfg {string} value default value of the input
8017 * @cfg {Number} labelWidth set the width of label (0-12)
8018 * @cfg {String} labelAlign (top|left)
8019 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8020 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8021 * @cfg {String} indicatorpos (left|right) default left
8023 * @cfg {String} align (left|center|right) Default left
8024 * @cfg {Boolean} forceFeedback (true|false) Default false
8030 * Create a new Input
8031 * @param {Object} config The config object
8034 Roo.bootstrap.Input = function(config){
8035 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8040 * Fires when this field receives input focus.
8041 * @param {Roo.form.Field} this
8046 * Fires when this field loses input focus.
8047 * @param {Roo.form.Field} this
8052 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8053 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8054 * @param {Roo.form.Field} this
8055 * @param {Roo.EventObject} e The event object
8060 * Fires just before the field blurs if the field value has changed.
8061 * @param {Roo.form.Field} this
8062 * @param {Mixed} newValue The new value
8063 * @param {Mixed} oldValue The original value
8068 * Fires after the field has been marked as invalid.
8069 * @param {Roo.form.Field} this
8070 * @param {String} msg The validation message
8075 * Fires after the field has been validated with no errors.
8076 * @param {Roo.form.Field} this
8081 * Fires after the key up
8082 * @param {Roo.form.Field} this
8083 * @param {Roo.EventObject} e The event Object
8089 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8091 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8092 automatic validation (defaults to "keyup").
8094 validationEvent : "keyup",
8096 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8098 validateOnBlur : true,
8100 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8102 validationDelay : 250,
8104 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8106 focusClass : "x-form-focus", // not needed???
8110 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8112 invalidClass : "has-warning",
8115 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8117 validClass : "has-success",
8120 * @cfg {Boolean} hasFeedback (true|false) default true
8125 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8127 invalidFeedbackClass : "glyphicon-warning-sign",
8130 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8132 validFeedbackClass : "glyphicon-ok",
8135 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8137 selectOnFocus : false,
8140 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8144 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8149 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8151 disableKeyFilter : false,
8154 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8158 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8162 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8164 blankText : "This field is required",
8167 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8171 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8173 maxLength : Number.MAX_VALUE,
8175 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8177 minLengthText : "The minimum length for this field is {0}",
8179 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8181 maxLengthText : "The maximum length for this field is {0}",
8185 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8186 * If available, this function will be called only after the basic validators all return true, and will be passed the
8187 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8191 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8192 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8193 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8197 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8201 autocomplete: false,
8220 formatedValue : false,
8221 forceFeedback : false,
8223 indicatorpos : 'left',
8225 parentLabelAlign : function()
8228 while (parent.parent()) {
8229 parent = parent.parent();
8230 if (typeof(parent.labelAlign) !='undefined') {
8231 return parent.labelAlign;
8238 getAutoCreate : function()
8240 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8246 if(this.inputType != 'hidden'){
8247 cfg.cls = 'form-group' //input-group
8253 type : this.inputType,
8255 cls : 'form-control',
8256 placeholder : this.placeholder || '',
8257 autocomplete : this.autocomplete || 'new-password'
8261 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8264 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8265 input.maxLength = this.maxLength;
8268 if (this.disabled) {
8269 input.disabled=true;
8272 if (this.readOnly) {
8273 input.readonly=true;
8277 input.name = this.name;
8281 input.cls += ' input-' + this.size;
8285 ['xs','sm','md','lg'].map(function(size){
8286 if (settings[size]) {
8287 cfg.cls += ' col-' + size + '-' + settings[size];
8291 var inputblock = input;
8295 cls: 'glyphicon form-control-feedback'
8298 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8301 cls : 'has-feedback',
8309 if (this.before || this.after) {
8312 cls : 'input-group',
8316 if (this.before && typeof(this.before) == 'string') {
8318 inputblock.cn.push({
8320 cls : 'roo-input-before input-group-addon',
8324 if (this.before && typeof(this.before) == 'object') {
8325 this.before = Roo.factory(this.before);
8327 inputblock.cn.push({
8329 cls : 'roo-input-before input-group-' +
8330 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8334 inputblock.cn.push(input);
8336 if (this.after && typeof(this.after) == 'string') {
8337 inputblock.cn.push({
8339 cls : 'roo-input-after input-group-addon',
8343 if (this.after && typeof(this.after) == 'object') {
8344 this.after = Roo.factory(this.after);
8346 inputblock.cn.push({
8348 cls : 'roo-input-after input-group-' +
8349 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8353 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8354 inputblock.cls += ' has-feedback';
8355 inputblock.cn.push(feedback);
8359 if (align ==='left' && this.fieldLabel.length) {
8364 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8365 tooltip : 'This field is required'
8370 cls : 'control-label col-sm-' + this.labelWidth,
8371 html : this.fieldLabel
8375 cls : "col-sm-" + (12 - this.labelWidth),
8383 if(this.indicatorpos == 'right'){
8388 cls : 'control-label col-sm-' + this.labelWidth,
8389 html : this.fieldLabel
8394 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8395 tooltip : 'This field is required'
8398 cls : "col-sm-" + (12 - this.labelWidth),
8407 } else if ( this.fieldLabel.length) {
8412 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8413 tooltip : 'This field is required'
8417 //cls : 'input-group-addon',
8418 html : this.fieldLabel
8426 if(this.indicatorpos == 'right'){
8431 //cls : 'input-group-addon',
8432 html : this.fieldLabel
8437 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8438 tooltip : 'This field is required'
8458 if (this.parentType === 'Navbar' && this.parent().bar) {
8459 cfg.cls += ' navbar-form';
8462 if (this.parentType === 'NavGroup') {
8463 cfg.cls += ' navbar-form';
8471 * return the real input element.
8473 inputEl: function ()
8475 return this.el.select('input.form-control',true).first();
8478 tooltipEl : function()
8480 return this.inputEl();
8483 indicatorEl : function()
8485 var indicator = this.el.select('i.roo-required-indicator',true).first();
8495 setDisabled : function(v)
8497 var i = this.inputEl().dom;
8499 i.removeAttribute('disabled');
8503 i.setAttribute('disabled','true');
8505 initEvents : function()
8508 this.inputEl().on("keydown" , this.fireKey, this);
8509 this.inputEl().on("focus", this.onFocus, this);
8510 this.inputEl().on("blur", this.onBlur, this);
8512 this.inputEl().relayEvent('keyup', this);
8514 this.indicator = this.indicatorEl();
8517 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8518 this.indicator.hide();
8521 // reference to original value for reset
8522 this.originalValue = this.getValue();
8523 //Roo.form.TextField.superclass.initEvents.call(this);
8524 if(this.validationEvent == 'keyup'){
8525 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8526 this.inputEl().on('keyup', this.filterValidation, this);
8528 else if(this.validationEvent !== false){
8529 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8532 if(this.selectOnFocus){
8533 this.on("focus", this.preFocus, this);
8536 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8537 this.inputEl().on("keypress", this.filterKeys, this);
8540 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8541 this.el.on("click", this.autoSize, this);
8544 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8545 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8548 if (typeof(this.before) == 'object') {
8549 this.before.render(this.el.select('.roo-input-before',true).first());
8551 if (typeof(this.after) == 'object') {
8552 this.after.render(this.el.select('.roo-input-after',true).first());
8557 filterValidation : function(e){
8558 if(!e.isNavKeyPress()){
8559 this.validationTask.delay(this.validationDelay);
8563 * Validates the field value
8564 * @return {Boolean} True if the value is valid, else false
8566 validate : function(){
8567 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8568 if(this.disabled || this.validateValue(this.getRawValue())){
8579 * Validates a value according to the field's validation rules and marks the field as invalid
8580 * if the validation fails
8581 * @param {Mixed} value The value to validate
8582 * @return {Boolean} True if the value is valid, else false
8584 validateValue : function(value){
8585 if(value.length < 1) { // if it's blank
8586 if(this.allowBlank){
8592 if(value.length < this.minLength){
8595 if(value.length > this.maxLength){
8599 var vt = Roo.form.VTypes;
8600 if(!vt[this.vtype](value, this)){
8604 if(typeof this.validator == "function"){
8605 var msg = this.validator(value);
8611 if(this.regex && !this.regex.test(value)){
8621 fireKey : function(e){
8622 //Roo.log('field ' + e.getKey());
8623 if(e.isNavKeyPress()){
8624 this.fireEvent("specialkey", this, e);
8627 focus : function (selectText){
8629 this.inputEl().focus();
8630 if(selectText === true){
8631 this.inputEl().dom.select();
8637 onFocus : function(){
8638 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8639 // this.el.addClass(this.focusClass);
8642 this.hasFocus = true;
8643 this.startValue = this.getValue();
8644 this.fireEvent("focus", this);
8648 beforeBlur : Roo.emptyFn,
8652 onBlur : function(){
8654 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8655 //this.el.removeClass(this.focusClass);
8657 this.hasFocus = false;
8658 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8661 var v = this.getValue();
8662 if(String(v) !== String(this.startValue)){
8663 this.fireEvent('change', this, v, this.startValue);
8665 this.fireEvent("blur", this);
8669 * Resets the current field value to the originally loaded value and clears any validation messages
8672 this.setValue(this.originalValue);
8676 * Returns the name of the field
8677 * @return {Mixed} name The name field
8679 getName: function(){
8683 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8684 * @return {Mixed} value The field value
8686 getValue : function(){
8688 var v = this.inputEl().getValue();
8693 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8694 * @return {Mixed} value The field value
8696 getRawValue : function(){
8697 var v = this.inputEl().getValue();
8703 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8704 * @param {Mixed} value The value to set
8706 setRawValue : function(v){
8707 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8710 selectText : function(start, end){
8711 var v = this.getRawValue();
8713 start = start === undefined ? 0 : start;
8714 end = end === undefined ? v.length : end;
8715 var d = this.inputEl().dom;
8716 if(d.setSelectionRange){
8717 d.setSelectionRange(start, end);
8718 }else if(d.createTextRange){
8719 var range = d.createTextRange();
8720 range.moveStart("character", start);
8721 range.moveEnd("character", v.length-end);
8728 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8729 * @param {Mixed} value The value to set
8731 setValue : function(v){
8734 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8740 processValue : function(value){
8741 if(this.stripCharsRe){
8742 var newValue = value.replace(this.stripCharsRe, '');
8743 if(newValue !== value){
8744 this.setRawValue(newValue);
8751 preFocus : function(){
8753 if(this.selectOnFocus){
8754 this.inputEl().dom.select();
8757 filterKeys : function(e){
8759 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8762 var c = e.getCharCode(), cc = String.fromCharCode(c);
8763 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8766 if(!this.maskRe.test(cc)){
8771 * Clear any invalid styles/messages for this field
8773 clearInvalid : function(){
8775 if(!this.el || this.preventMark){ // not rendered
8780 this.indicator.hide();
8783 this.el.removeClass(this.invalidClass);
8785 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8787 var feedback = this.el.select('.form-control-feedback', true).first();
8790 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8795 this.fireEvent('valid', this);
8799 * Mark this field as valid
8801 markValid : function()
8803 if(!this.el || this.preventMark){ // not rendered
8807 this.el.removeClass([this.invalidClass, this.validClass]);
8809 var feedback = this.el.select('.form-control-feedback', true).first();
8812 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8815 if(this.disabled || this.allowBlank){
8820 this.indicator.hide();
8823 this.el.addClass(this.validClass);
8825 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8827 var feedback = this.el.select('.form-control-feedback', true).first();
8830 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8831 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8836 this.fireEvent('valid', this);
8840 * Mark this field as invalid
8841 * @param {String} msg The validation message
8843 markInvalid : function(msg)
8845 if(!this.el || this.preventMark){ // not rendered
8849 this.el.removeClass([this.invalidClass, this.validClass]);
8851 var feedback = this.el.select('.form-control-feedback', true).first();
8854 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8857 if(this.disabled || this.allowBlank){
8862 this.indicator.show();
8865 this.el.addClass(this.invalidClass);
8867 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8869 var feedback = this.el.select('.form-control-feedback', true).first();
8872 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8874 if(this.getValue().length || this.forceFeedback){
8875 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8882 this.fireEvent('invalid', this, msg);
8885 SafariOnKeyDown : function(event)
8887 // this is a workaround for a password hang bug on chrome/ webkit.
8889 var isSelectAll = false;
8891 if(this.inputEl().dom.selectionEnd > 0){
8892 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8894 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8895 event.preventDefault();
8900 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8902 event.preventDefault();
8903 // this is very hacky as keydown always get's upper case.
8905 var cc = String.fromCharCode(event.getCharCode());
8906 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8910 adjustWidth : function(tag, w){
8911 tag = tag.toLowerCase();
8912 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8913 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8917 if(tag == 'textarea'){
8920 }else if(Roo.isOpera){
8924 if(tag == 'textarea'){
8943 * @class Roo.bootstrap.TextArea
8944 * @extends Roo.bootstrap.Input
8945 * Bootstrap TextArea class
8946 * @cfg {Number} cols Specifies the visible width of a text area
8947 * @cfg {Number} rows Specifies the visible number of lines in a text area
8948 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8949 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8950 * @cfg {string} html text
8953 * Create a new TextArea
8954 * @param {Object} config The config object
8957 Roo.bootstrap.TextArea = function(config){
8958 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8962 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8972 getAutoCreate : function(){
8974 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8985 value : this.value || '',
8986 html: this.html || '',
8987 cls : 'form-control',
8988 placeholder : this.placeholder || ''
8992 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8993 input.maxLength = this.maxLength;
8997 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9001 input.cols = this.cols;
9004 if (this.readOnly) {
9005 input.readonly = true;
9009 input.name = this.name;
9013 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9017 ['xs','sm','md','lg'].map(function(size){
9018 if (settings[size]) {
9019 cfg.cls += ' col-' + size + '-' + settings[size];
9023 var inputblock = input;
9025 if(this.hasFeedback && !this.allowBlank){
9029 cls: 'glyphicon form-control-feedback'
9033 cls : 'has-feedback',
9042 if (this.before || this.after) {
9045 cls : 'input-group',
9049 inputblock.cn.push({
9051 cls : 'input-group-addon',
9056 inputblock.cn.push(input);
9058 if(this.hasFeedback && !this.allowBlank){
9059 inputblock.cls += ' has-feedback';
9060 inputblock.cn.push(feedback);
9064 inputblock.cn.push({
9066 cls : 'input-group-addon',
9073 if (align ==='left' && this.fieldLabel.length) {
9074 // Roo.log("left and has label");
9080 cls : 'control-label col-sm-' + this.labelWidth,
9081 html : this.fieldLabel
9085 cls : "col-sm-" + (12 - this.labelWidth),
9092 } else if ( this.fieldLabel.length) {
9093 // Roo.log(" label");
9098 //cls : 'input-group-addon',
9099 html : this.fieldLabel
9109 // Roo.log(" no label && no align");
9119 if (this.disabled) {
9120 input.disabled=true;
9127 * return the real textarea element.
9129 inputEl: function ()
9131 return this.el.select('textarea.form-control',true).first();
9135 * Clear any invalid styles/messages for this field
9137 clearInvalid : function()
9140 if(!this.el || this.preventMark){ // not rendered
9144 var label = this.el.select('label', true).first();
9145 var icon = this.el.select('i.fa-star', true).first();
9151 this.el.removeClass(this.invalidClass);
9153 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9155 var feedback = this.el.select('.form-control-feedback', true).first();
9158 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9163 this.fireEvent('valid', this);
9167 * Mark this field as valid
9169 markValid : function()
9171 if(!this.el || this.preventMark){ // not rendered
9175 this.el.removeClass([this.invalidClass, this.validClass]);
9177 var feedback = this.el.select('.form-control-feedback', true).first();
9180 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9183 if(this.disabled || this.allowBlank){
9187 var label = this.el.select('label', true).first();
9188 var icon = this.el.select('i.fa-star', true).first();
9194 this.el.addClass(this.validClass);
9196 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
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]);
9202 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9207 this.fireEvent('valid', this);
9211 * Mark this field as invalid
9212 * @param {String} msg The validation message
9214 markInvalid : function(msg)
9216 if(!this.el || this.preventMark){ // not rendered
9220 this.el.removeClass([this.invalidClass, this.validClass]);
9222 var feedback = this.el.select('.form-control-feedback', true).first();
9225 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9228 if(this.disabled || this.allowBlank){
9232 var label = this.el.select('label', true).first();
9233 var icon = this.el.select('i.fa-star', true).first();
9235 if(!this.getValue().length && label && !icon){
9236 this.el.createChild({
9238 cls : 'text-danger fa fa-lg fa-star',
9239 tooltip : 'This field is required',
9240 style : 'margin-right:5px;'
9244 this.el.addClass(this.invalidClass);
9246 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9248 var feedback = this.el.select('.form-control-feedback', true).first();
9251 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9253 if(this.getValue().length || this.forceFeedback){
9254 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9261 this.fireEvent('invalid', this, msg);
9269 * trigger field - base class for combo..
9274 * @class Roo.bootstrap.TriggerField
9275 * @extends Roo.bootstrap.Input
9276 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9277 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9278 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9279 * for which you can provide a custom implementation. For example:
9281 var trigger = new Roo.bootstrap.TriggerField();
9282 trigger.onTriggerClick = myTriggerFn;
9283 trigger.applyTo('my-field');
9286 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9287 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9288 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9289 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9290 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9293 * Create a new TriggerField.
9294 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9295 * to the base TextField)
9297 Roo.bootstrap.TriggerField = function(config){
9298 this.mimicing = false;
9299 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9302 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9304 * @cfg {String} triggerClass A CSS class to apply to the trigger
9307 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9312 * @cfg {Boolean} removable (true|false) special filter default false
9316 /** @cfg {Boolean} grow @hide */
9317 /** @cfg {Number} growMin @hide */
9318 /** @cfg {Number} growMax @hide */
9324 autoSize: Roo.emptyFn,
9331 actionMode : 'wrap',
9336 getAutoCreate : function(){
9338 var align = this.labelAlign || this.parentLabelAlign();
9343 cls: 'form-group' //input-group
9350 type : this.inputType,
9351 cls : 'form-control',
9352 autocomplete: 'new-password',
9353 placeholder : this.placeholder || ''
9357 input.name = this.name;
9360 input.cls += ' input-' + this.size;
9363 if (this.disabled) {
9364 input.disabled=true;
9367 var inputblock = input;
9369 if(this.hasFeedback && !this.allowBlank){
9373 cls: 'glyphicon form-control-feedback'
9376 if(this.removable && !this.editable && !this.tickable){
9378 cls : 'has-feedback',
9384 cls : 'roo-combo-removable-btn close'
9391 cls : 'has-feedback',
9400 if(this.removable && !this.editable && !this.tickable){
9402 cls : 'roo-removable',
9408 cls : 'roo-combo-removable-btn close'
9415 if (this.before || this.after) {
9418 cls : 'input-group',
9422 inputblock.cn.push({
9424 cls : 'input-group-addon',
9429 inputblock.cn.push(input);
9431 if(this.hasFeedback && !this.allowBlank){
9432 inputblock.cls += ' has-feedback';
9433 inputblock.cn.push(feedback);
9437 inputblock.cn.push({
9439 cls : 'input-group-addon',
9452 cls: 'form-hidden-field'
9466 cls: 'form-hidden-field'
9470 cls: 'roo-select2-choices',
9474 cls: 'roo-select2-search-field',
9487 cls: 'roo-select2-container input-group',
9492 // cls: 'typeahead typeahead-long dropdown-menu',
9493 // style: 'display:none'
9498 if(!this.multiple && this.showToggleBtn){
9504 if (this.caret != false) {
9507 cls: 'fa fa-' + this.caret
9514 cls : 'input-group-addon btn dropdown-toggle',
9519 cls: 'combobox-clear',
9533 combobox.cls += ' roo-select2-container-multi';
9536 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
9538 // Roo.log("left and has label");
9542 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9543 tooltip : 'This field is required'
9548 cls : 'control-label col-sm-' + this.labelWidth,
9549 html : this.fieldLabel
9553 cls : "col-sm-" + (12 - this.labelWidth),
9561 if(this.indicatorpos == 'right'){
9566 cls : 'control-label col-sm-' + this.labelWidth,
9567 html : this.fieldLabel
9572 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9573 tooltip : 'This field is required'
9576 cls : "col-sm-" + (12 - this.labelWidth),
9585 } else if ( this.fieldLabel.length) {
9586 // Roo.log(" label");
9590 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9591 tooltip : 'This field is required'
9595 //cls : 'input-group-addon',
9596 html : this.fieldLabel
9604 if(this.indicatorpos == 'right'){
9609 //cls : 'input-group-addon',
9610 html : this.fieldLabel
9615 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9616 tooltip : 'This field is required'
9627 // Roo.log(" no label && no align");
9634 ['xs','sm','md','lg'].map(function(size){
9635 if (settings[size]) {
9636 cfg.cls += ' col-' + size + '-' + settings[size];
9647 onResize : function(w, h){
9648 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9649 // if(typeof w == 'number'){
9650 // var x = w - this.trigger.getWidth();
9651 // this.inputEl().setWidth(this.adjustWidth('input', x));
9652 // this.trigger.setStyle('left', x+'px');
9657 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9660 getResizeEl : function(){
9661 return this.inputEl();
9665 getPositionEl : function(){
9666 return this.inputEl();
9670 alignErrorIcon : function(){
9671 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9675 initEvents : function(){
9679 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9680 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9681 if(!this.multiple && this.showToggleBtn){
9682 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9683 if(this.hideTrigger){
9684 this.trigger.setDisplayed(false);
9686 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9690 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9693 if(this.removable && !this.editable && !this.tickable){
9694 var close = this.closeTriggerEl();
9697 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9698 close.on('click', this.removeBtnClick, this, close);
9702 //this.trigger.addClassOnOver('x-form-trigger-over');
9703 //this.trigger.addClassOnClick('x-form-trigger-click');
9706 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9710 closeTriggerEl : function()
9712 var close = this.el.select('.roo-combo-removable-btn', true).first();
9713 return close ? close : false;
9716 removeBtnClick : function(e, h, el)
9720 if(this.fireEvent("remove", this) !== false){
9722 this.fireEvent("afterremove", this)
9726 createList : function()
9728 this.list = Roo.get(document.body).createChild({
9730 cls: 'typeahead typeahead-long dropdown-menu',
9731 style: 'display:none'
9734 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9739 initTrigger : function(){
9744 onDestroy : function(){
9746 this.trigger.removeAllListeners();
9747 // this.trigger.remove();
9750 // this.wrap.remove();
9752 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9756 onFocus : function(){
9757 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9760 this.wrap.addClass('x-trigger-wrap-focus');
9761 this.mimicing = true;
9762 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9763 if(this.monitorTab){
9764 this.el.on("keydown", this.checkTab, this);
9771 checkTab : function(e){
9772 if(e.getKey() == e.TAB){
9778 onBlur : function(){
9783 mimicBlur : function(e, t){
9785 if(!this.wrap.contains(t) && this.validateBlur()){
9792 triggerBlur : function(){
9793 this.mimicing = false;
9794 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9795 if(this.monitorTab){
9796 this.el.un("keydown", this.checkTab, this);
9798 //this.wrap.removeClass('x-trigger-wrap-focus');
9799 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9803 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9804 validateBlur : function(e, t){
9809 onDisable : function(){
9810 this.inputEl().dom.disabled = true;
9811 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9813 // this.wrap.addClass('x-item-disabled');
9818 onEnable : function(){
9819 this.inputEl().dom.disabled = false;
9820 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9822 // this.el.removeClass('x-item-disabled');
9827 onShow : function(){
9828 var ae = this.getActionEl();
9831 ae.dom.style.display = '';
9832 ae.dom.style.visibility = 'visible';
9838 onHide : function(){
9839 var ae = this.getActionEl();
9840 ae.dom.style.display = 'none';
9844 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9845 * by an implementing function.
9847 * @param {EventObject} e
9849 onTriggerClick : Roo.emptyFn
9853 * Ext JS Library 1.1.1
9854 * Copyright(c) 2006-2007, Ext JS, LLC.
9856 * Originally Released Under LGPL - original licence link has changed is not relivant.
9859 * <script type="text/javascript">
9864 * @class Roo.data.SortTypes
9866 * Defines the default sorting (casting?) comparison functions used when sorting data.
9868 Roo.data.SortTypes = {
9870 * Default sort that does nothing
9871 * @param {Mixed} s The value being converted
9872 * @return {Mixed} The comparison value
9879 * The regular expression used to strip tags
9883 stripTagsRE : /<\/?[^>]+>/gi,
9886 * Strips all HTML tags to sort on text only
9887 * @param {Mixed} s The value being converted
9888 * @return {String} The comparison value
9890 asText : function(s){
9891 return String(s).replace(this.stripTagsRE, "");
9895 * Strips all HTML tags to sort on text only - Case insensitive
9896 * @param {Mixed} s The value being converted
9897 * @return {String} The comparison value
9899 asUCText : function(s){
9900 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9904 * Case insensitive string
9905 * @param {Mixed} s The value being converted
9906 * @return {String} The comparison value
9908 asUCString : function(s) {
9909 return String(s).toUpperCase();
9914 * @param {Mixed} s The value being converted
9915 * @return {Number} The comparison value
9917 asDate : function(s) {
9921 if(s instanceof Date){
9924 return Date.parse(String(s));
9929 * @param {Mixed} s The value being converted
9930 * @return {Float} The comparison value
9932 asFloat : function(s) {
9933 var val = parseFloat(String(s).replace(/,/g, ""));
9942 * @param {Mixed} s The value being converted
9943 * @return {Number} The comparison value
9945 asInt : function(s) {
9946 var val = parseInt(String(s).replace(/,/g, ""));
9954 * Ext JS Library 1.1.1
9955 * Copyright(c) 2006-2007, Ext JS, LLC.
9957 * Originally Released Under LGPL - original licence link has changed is not relivant.
9960 * <script type="text/javascript">
9964 * @class Roo.data.Record
9965 * Instances of this class encapsulate both record <em>definition</em> information, and record
9966 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9967 * to access Records cached in an {@link Roo.data.Store} object.<br>
9969 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9970 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9973 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9975 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9976 * {@link #create}. The parameters are the same.
9977 * @param {Array} data An associative Array of data values keyed by the field name.
9978 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9979 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9980 * not specified an integer id is generated.
9982 Roo.data.Record = function(data, id){
9983 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9988 * Generate a constructor for a specific record layout.
9989 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9990 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9991 * Each field definition object may contain the following properties: <ul>
9992 * <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,
9993 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9994 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9995 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9996 * is being used, then this is a string containing the javascript expression to reference the data relative to
9997 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9998 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9999 * this may be omitted.</p></li>
10000 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10001 * <ul><li>auto (Default, implies no conversion)</li>
10006 * <li>date</li></ul></p></li>
10007 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10008 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10009 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10010 * by the Reader into an object that will be stored in the Record. It is passed the
10011 * following parameters:<ul>
10012 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10014 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10016 * <br>usage:<br><pre><code>
10017 var TopicRecord = Roo.data.Record.create(
10018 {name: 'title', mapping: 'topic_title'},
10019 {name: 'author', mapping: 'username'},
10020 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10021 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10022 {name: 'lastPoster', mapping: 'user2'},
10023 {name: 'excerpt', mapping: 'post_text'}
10026 var myNewRecord = new TopicRecord({
10027 title: 'Do my job please',
10030 lastPost: new Date(),
10031 lastPoster: 'Animal',
10032 excerpt: 'No way dude!'
10034 myStore.add(myNewRecord);
10039 Roo.data.Record.create = function(o){
10040 var f = function(){
10041 f.superclass.constructor.apply(this, arguments);
10043 Roo.extend(f, Roo.data.Record);
10044 var p = f.prototype;
10045 p.fields = new Roo.util.MixedCollection(false, function(field){
10048 for(var i = 0, len = o.length; i < len; i++){
10049 p.fields.add(new Roo.data.Field(o[i]));
10051 f.getField = function(name){
10052 return p.fields.get(name);
10057 Roo.data.Record.AUTO_ID = 1000;
10058 Roo.data.Record.EDIT = 'edit';
10059 Roo.data.Record.REJECT = 'reject';
10060 Roo.data.Record.COMMIT = 'commit';
10062 Roo.data.Record.prototype = {
10064 * Readonly flag - true if this record has been modified.
10073 join : function(store){
10074 this.store = store;
10078 * Set the named field to the specified value.
10079 * @param {String} name The name of the field to set.
10080 * @param {Object} value The value to set the field to.
10082 set : function(name, value){
10083 if(this.data[name] == value){
10087 if(!this.modified){
10088 this.modified = {};
10090 if(typeof this.modified[name] == 'undefined'){
10091 this.modified[name] = this.data[name];
10093 this.data[name] = value;
10094 if(!this.editing && this.store){
10095 this.store.afterEdit(this);
10100 * Get the value of the named field.
10101 * @param {String} name The name of the field to get the value of.
10102 * @return {Object} The value of the field.
10104 get : function(name){
10105 return this.data[name];
10109 beginEdit : function(){
10110 this.editing = true;
10111 this.modified = {};
10115 cancelEdit : function(){
10116 this.editing = false;
10117 delete this.modified;
10121 endEdit : function(){
10122 this.editing = false;
10123 if(this.dirty && this.store){
10124 this.store.afterEdit(this);
10129 * Usually called by the {@link Roo.data.Store} which owns the Record.
10130 * Rejects all changes made to the Record since either creation, or the last commit operation.
10131 * Modified fields are reverted to their original values.
10133 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10134 * of reject operations.
10136 reject : function(){
10137 var m = this.modified;
10139 if(typeof m[n] != "function"){
10140 this.data[n] = m[n];
10143 this.dirty = false;
10144 delete this.modified;
10145 this.editing = false;
10147 this.store.afterReject(this);
10152 * Usually called by the {@link Roo.data.Store} which owns the Record.
10153 * Commits all changes made to the Record since either creation, or the last commit operation.
10155 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10156 * of commit operations.
10158 commit : function(){
10159 this.dirty = false;
10160 delete this.modified;
10161 this.editing = false;
10163 this.store.afterCommit(this);
10168 hasError : function(){
10169 return this.error != null;
10173 clearError : function(){
10178 * Creates a copy of this record.
10179 * @param {String} id (optional) A new record id if you don't want to use this record's id
10182 copy : function(newId) {
10183 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10187 * Ext JS Library 1.1.1
10188 * Copyright(c) 2006-2007, Ext JS, LLC.
10190 * Originally Released Under LGPL - original licence link has changed is not relivant.
10193 * <script type="text/javascript">
10199 * @class Roo.data.Store
10200 * @extends Roo.util.Observable
10201 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10202 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10204 * 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
10205 * has no knowledge of the format of the data returned by the Proxy.<br>
10207 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10208 * instances from the data object. These records are cached and made available through accessor functions.
10210 * Creates a new Store.
10211 * @param {Object} config A config object containing the objects needed for the Store to access data,
10212 * and read the data into Records.
10214 Roo.data.Store = function(config){
10215 this.data = new Roo.util.MixedCollection(false);
10216 this.data.getKey = function(o){
10219 this.baseParams = {};
10221 this.paramNames = {
10226 "multisort" : "_multisort"
10229 if(config && config.data){
10230 this.inlineData = config.data;
10231 delete config.data;
10234 Roo.apply(this, config);
10236 if(this.reader){ // reader passed
10237 this.reader = Roo.factory(this.reader, Roo.data);
10238 this.reader.xmodule = this.xmodule || false;
10239 if(!this.recordType){
10240 this.recordType = this.reader.recordType;
10242 if(this.reader.onMetaChange){
10243 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10247 if(this.recordType){
10248 this.fields = this.recordType.prototype.fields;
10250 this.modified = [];
10254 * @event datachanged
10255 * Fires when the data cache has changed, and a widget which is using this Store
10256 * as a Record cache should refresh its view.
10257 * @param {Store} this
10259 datachanged : true,
10261 * @event metachange
10262 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10263 * @param {Store} this
10264 * @param {Object} meta The JSON metadata
10269 * Fires when Records have been added to the Store
10270 * @param {Store} this
10271 * @param {Roo.data.Record[]} records The array of Records added
10272 * @param {Number} index The index at which the record(s) were added
10277 * Fires when a Record has been removed from the Store
10278 * @param {Store} this
10279 * @param {Roo.data.Record} record The Record that was removed
10280 * @param {Number} index The index at which the record was removed
10285 * Fires when a Record has been updated
10286 * @param {Store} this
10287 * @param {Roo.data.Record} record The Record that was updated
10288 * @param {String} operation The update operation being performed. Value may be one of:
10290 Roo.data.Record.EDIT
10291 Roo.data.Record.REJECT
10292 Roo.data.Record.COMMIT
10298 * Fires when the data cache has been cleared.
10299 * @param {Store} this
10303 * @event beforeload
10304 * Fires before a request is made for a new data object. If the beforeload handler returns false
10305 * the load action will be canceled.
10306 * @param {Store} this
10307 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10311 * @event beforeloadadd
10312 * Fires after a new set of Records has been loaded.
10313 * @param {Store} this
10314 * @param {Roo.data.Record[]} records The Records that were loaded
10315 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10317 beforeloadadd : true,
10320 * Fires after a new set of Records has been loaded, before they are added to the store.
10321 * @param {Store} this
10322 * @param {Roo.data.Record[]} records The Records that were loaded
10323 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10324 * @params {Object} return from reader
10328 * @event loadexception
10329 * Fires if an exception occurs in the Proxy during loading.
10330 * Called with the signature of the Proxy's "loadexception" event.
10331 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10334 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10335 * @param {Object} load options
10336 * @param {Object} jsonData from your request (normally this contains the Exception)
10338 loadexception : true
10342 this.proxy = Roo.factory(this.proxy, Roo.data);
10343 this.proxy.xmodule = this.xmodule || false;
10344 this.relayEvents(this.proxy, ["loadexception"]);
10346 this.sortToggle = {};
10347 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10349 Roo.data.Store.superclass.constructor.call(this);
10351 if(this.inlineData){
10352 this.loadData(this.inlineData);
10353 delete this.inlineData;
10357 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10359 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10360 * without a remote query - used by combo/forms at present.
10364 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10367 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10370 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10371 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10374 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10375 * on any HTTP request
10378 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10381 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10385 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10386 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10388 remoteSort : false,
10391 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10392 * loaded or when a record is removed. (defaults to false).
10394 pruneModifiedRecords : false,
10397 lastOptions : null,
10400 * Add Records to the Store and fires the add event.
10401 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10403 add : function(records){
10404 records = [].concat(records);
10405 for(var i = 0, len = records.length; i < len; i++){
10406 records[i].join(this);
10408 var index = this.data.length;
10409 this.data.addAll(records);
10410 this.fireEvent("add", this, records, index);
10414 * Remove a Record from the Store and fires the remove event.
10415 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10417 remove : function(record){
10418 var index = this.data.indexOf(record);
10419 this.data.removeAt(index);
10420 if(this.pruneModifiedRecords){
10421 this.modified.remove(record);
10423 this.fireEvent("remove", this, record, index);
10427 * Remove all Records from the Store and fires the clear event.
10429 removeAll : function(){
10431 if(this.pruneModifiedRecords){
10432 this.modified = [];
10434 this.fireEvent("clear", this);
10438 * Inserts Records to the Store at the given index and fires the add event.
10439 * @param {Number} index The start index at which to insert the passed Records.
10440 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10442 insert : function(index, records){
10443 records = [].concat(records);
10444 for(var i = 0, len = records.length; i < len; i++){
10445 this.data.insert(index, records[i]);
10446 records[i].join(this);
10448 this.fireEvent("add", this, records, index);
10452 * Get the index within the cache of the passed Record.
10453 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10454 * @return {Number} The index of the passed Record. Returns -1 if not found.
10456 indexOf : function(record){
10457 return this.data.indexOf(record);
10461 * Get the index within the cache of the Record with the passed id.
10462 * @param {String} id The id of the Record to find.
10463 * @return {Number} The index of the Record. Returns -1 if not found.
10465 indexOfId : function(id){
10466 return this.data.indexOfKey(id);
10470 * Get the Record with the specified id.
10471 * @param {String} id The id of the Record to find.
10472 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10474 getById : function(id){
10475 return this.data.key(id);
10479 * Get the Record at the specified index.
10480 * @param {Number} index The index of the Record to find.
10481 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10483 getAt : function(index){
10484 return this.data.itemAt(index);
10488 * Returns a range of Records between specified indices.
10489 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10490 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10491 * @return {Roo.data.Record[]} An array of Records
10493 getRange : function(start, end){
10494 return this.data.getRange(start, end);
10498 storeOptions : function(o){
10499 o = Roo.apply({}, o);
10502 this.lastOptions = o;
10506 * Loads the Record cache from the configured Proxy using the configured Reader.
10508 * If using remote paging, then the first load call must specify the <em>start</em>
10509 * and <em>limit</em> properties in the options.params property to establish the initial
10510 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10512 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10513 * and this call will return before the new data has been loaded. Perform any post-processing
10514 * in a callback function, or in a "load" event handler.</strong>
10516 * @param {Object} options An object containing properties which control loading options:<ul>
10517 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10518 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10519 * passed the following arguments:<ul>
10520 * <li>r : Roo.data.Record[]</li>
10521 * <li>options: Options object from the load call</li>
10522 * <li>success: Boolean success indicator</li></ul></li>
10523 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10524 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10527 load : function(options){
10528 options = options || {};
10529 if(this.fireEvent("beforeload", this, options) !== false){
10530 this.storeOptions(options);
10531 var p = Roo.apply(options.params || {}, this.baseParams);
10532 // if meta was not loaded from remote source.. try requesting it.
10533 if (!this.reader.metaFromRemote) {
10534 p._requestMeta = 1;
10536 if(this.sortInfo && this.remoteSort){
10537 var pn = this.paramNames;
10538 p[pn["sort"]] = this.sortInfo.field;
10539 p[pn["dir"]] = this.sortInfo.direction;
10541 if (this.multiSort) {
10542 var pn = this.paramNames;
10543 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10546 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10551 * Reloads the Record cache from the configured Proxy using the configured Reader and
10552 * the options from the last load operation performed.
10553 * @param {Object} options (optional) An object containing properties which may override the options
10554 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10555 * the most recently used options are reused).
10557 reload : function(options){
10558 this.load(Roo.applyIf(options||{}, this.lastOptions));
10562 // Called as a callback by the Reader during a load operation.
10563 loadRecords : function(o, options, success){
10564 if(!o || success === false){
10565 if(success !== false){
10566 this.fireEvent("load", this, [], options, o);
10568 if(options.callback){
10569 options.callback.call(options.scope || this, [], options, false);
10573 // if data returned failure - throw an exception.
10574 if (o.success === false) {
10575 // show a message if no listener is registered.
10576 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10577 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10579 // loadmask wil be hooked into this..
10580 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10583 var r = o.records, t = o.totalRecords || r.length;
10585 this.fireEvent("beforeloadadd", this, r, options, o);
10587 if(!options || options.add !== true){
10588 if(this.pruneModifiedRecords){
10589 this.modified = [];
10591 for(var i = 0, len = r.length; i < len; i++){
10595 this.data = this.snapshot;
10596 delete this.snapshot;
10599 this.data.addAll(r);
10600 this.totalLength = t;
10602 this.fireEvent("datachanged", this);
10604 this.totalLength = Math.max(t, this.data.length+r.length);
10607 this.fireEvent("load", this, r, options, o);
10608 if(options.callback){
10609 options.callback.call(options.scope || this, r, options, true);
10615 * Loads data from a passed data block. A Reader which understands the format of the data
10616 * must have been configured in the constructor.
10617 * @param {Object} data The data block from which to read the Records. The format of the data expected
10618 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10619 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10621 loadData : function(o, append){
10622 var r = this.reader.readRecords(o);
10623 this.loadRecords(r, {add: append}, true);
10627 * Gets the number of cached records.
10629 * <em>If using paging, this may not be the total size of the dataset. If the data object
10630 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10631 * the data set size</em>
10633 getCount : function(){
10634 return this.data.length || 0;
10638 * Gets the total number of records in the dataset as returned by the server.
10640 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10641 * the dataset size</em>
10643 getTotalCount : function(){
10644 return this.totalLength || 0;
10648 * Returns the sort state of the Store as an object with two properties:
10650 field {String} The name of the field by which the Records are sorted
10651 direction {String} The sort order, "ASC" or "DESC"
10654 getSortState : function(){
10655 return this.sortInfo;
10659 applySort : function(){
10660 if(this.sortInfo && !this.remoteSort){
10661 var s = this.sortInfo, f = s.field;
10662 var st = this.fields.get(f).sortType;
10663 var fn = function(r1, r2){
10664 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10665 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10667 this.data.sort(s.direction, fn);
10668 if(this.snapshot && this.snapshot != this.data){
10669 this.snapshot.sort(s.direction, fn);
10675 * Sets the default sort column and order to be used by the next load operation.
10676 * @param {String} fieldName The name of the field to sort by.
10677 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10679 setDefaultSort : function(field, dir){
10680 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10684 * Sort the Records.
10685 * If remote sorting is used, the sort is performed on the server, and the cache is
10686 * reloaded. If local sorting is used, the cache is sorted internally.
10687 * @param {String} fieldName The name of the field to sort by.
10688 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10690 sort : function(fieldName, dir){
10691 var f = this.fields.get(fieldName);
10693 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10695 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10696 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10701 this.sortToggle[f.name] = dir;
10702 this.sortInfo = {field: f.name, direction: dir};
10703 if(!this.remoteSort){
10705 this.fireEvent("datachanged", this);
10707 this.load(this.lastOptions);
10712 * Calls the specified function for each of the Records in the cache.
10713 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10714 * Returning <em>false</em> aborts and exits the iteration.
10715 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10717 each : function(fn, scope){
10718 this.data.each(fn, scope);
10722 * Gets all records modified since the last commit. Modified records are persisted across load operations
10723 * (e.g., during paging).
10724 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10726 getModifiedRecords : function(){
10727 return this.modified;
10731 createFilterFn : function(property, value, anyMatch){
10732 if(!value.exec){ // not a regex
10733 value = String(value);
10734 if(value.length == 0){
10737 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10739 return function(r){
10740 return value.test(r.data[property]);
10745 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10746 * @param {String} property A field on your records
10747 * @param {Number} start The record index to start at (defaults to 0)
10748 * @param {Number} end The last record index to include (defaults to length - 1)
10749 * @return {Number} The sum
10751 sum : function(property, start, end){
10752 var rs = this.data.items, v = 0;
10753 start = start || 0;
10754 end = (end || end === 0) ? end : rs.length-1;
10756 for(var i = start; i <= end; i++){
10757 v += (rs[i].data[property] || 0);
10763 * Filter the records by a specified property.
10764 * @param {String} field A field on your records
10765 * @param {String/RegExp} value Either a string that the field
10766 * should start with or a RegExp to test against the field
10767 * @param {Boolean} anyMatch True to match any part not just the beginning
10769 filter : function(property, value, anyMatch){
10770 var fn = this.createFilterFn(property, value, anyMatch);
10771 return fn ? this.filterBy(fn) : this.clearFilter();
10775 * Filter by a function. The specified function will be called with each
10776 * record in this data source. If the function returns true the record is included,
10777 * otherwise it is filtered.
10778 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10779 * @param {Object} scope (optional) The scope of the function (defaults to this)
10781 filterBy : function(fn, scope){
10782 this.snapshot = this.snapshot || this.data;
10783 this.data = this.queryBy(fn, scope||this);
10784 this.fireEvent("datachanged", this);
10788 * Query the records by a specified property.
10789 * @param {String} field A field on your records
10790 * @param {String/RegExp} value Either a string that the field
10791 * should start with or a RegExp to test against the field
10792 * @param {Boolean} anyMatch True to match any part not just the beginning
10793 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10795 query : function(property, value, anyMatch){
10796 var fn = this.createFilterFn(property, value, anyMatch);
10797 return fn ? this.queryBy(fn) : this.data.clone();
10801 * Query by a function. The specified function will be called with each
10802 * record in this data source. If the function returns true the record is included
10804 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10805 * @param {Object} scope (optional) The scope of the function (defaults to this)
10806 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10808 queryBy : function(fn, scope){
10809 var data = this.snapshot || this.data;
10810 return data.filterBy(fn, scope||this);
10814 * Collects unique values for a particular dataIndex from this store.
10815 * @param {String} dataIndex The property to collect
10816 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10817 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10818 * @return {Array} An array of the unique values
10820 collect : function(dataIndex, allowNull, bypassFilter){
10821 var d = (bypassFilter === true && this.snapshot) ?
10822 this.snapshot.items : this.data.items;
10823 var v, sv, r = [], l = {};
10824 for(var i = 0, len = d.length; i < len; i++){
10825 v = d[i].data[dataIndex];
10827 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10836 * Revert to a view of the Record cache with no filtering applied.
10837 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10839 clearFilter : function(suppressEvent){
10840 if(this.snapshot && this.snapshot != this.data){
10841 this.data = this.snapshot;
10842 delete this.snapshot;
10843 if(suppressEvent !== true){
10844 this.fireEvent("datachanged", this);
10850 afterEdit : function(record){
10851 if(this.modified.indexOf(record) == -1){
10852 this.modified.push(record);
10854 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10858 afterReject : function(record){
10859 this.modified.remove(record);
10860 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10864 afterCommit : function(record){
10865 this.modified.remove(record);
10866 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10870 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10871 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10873 commitChanges : function(){
10874 var m = this.modified.slice(0);
10875 this.modified = [];
10876 for(var i = 0, len = m.length; i < len; i++){
10882 * Cancel outstanding changes on all changed records.
10884 rejectChanges : function(){
10885 var m = this.modified.slice(0);
10886 this.modified = [];
10887 for(var i = 0, len = m.length; i < len; i++){
10892 onMetaChange : function(meta, rtype, o){
10893 this.recordType = rtype;
10894 this.fields = rtype.prototype.fields;
10895 delete this.snapshot;
10896 this.sortInfo = meta.sortInfo || this.sortInfo;
10897 this.modified = [];
10898 this.fireEvent('metachange', this, this.reader.meta);
10901 moveIndex : function(data, type)
10903 var index = this.indexOf(data);
10905 var newIndex = index + type;
10909 this.insert(newIndex, data);
10914 * Ext JS Library 1.1.1
10915 * Copyright(c) 2006-2007, Ext JS, LLC.
10917 * Originally Released Under LGPL - original licence link has changed is not relivant.
10920 * <script type="text/javascript">
10924 * @class Roo.data.SimpleStore
10925 * @extends Roo.data.Store
10926 * Small helper class to make creating Stores from Array data easier.
10927 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10928 * @cfg {Array} fields An array of field definition objects, or field name strings.
10929 * @cfg {Array} data The multi-dimensional array of data
10931 * @param {Object} config
10933 Roo.data.SimpleStore = function(config){
10934 Roo.data.SimpleStore.superclass.constructor.call(this, {
10936 reader: new Roo.data.ArrayReader({
10939 Roo.data.Record.create(config.fields)
10941 proxy : new Roo.data.MemoryProxy(config.data)
10945 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10947 * Ext JS Library 1.1.1
10948 * Copyright(c) 2006-2007, Ext JS, LLC.
10950 * Originally Released Under LGPL - original licence link has changed is not relivant.
10953 * <script type="text/javascript">
10958 * @extends Roo.data.Store
10959 * @class Roo.data.JsonStore
10960 * Small helper class to make creating Stores for JSON data easier. <br/>
10962 var store = new Roo.data.JsonStore({
10963 url: 'get-images.php',
10965 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10968 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10969 * JsonReader and HttpProxy (unless inline data is provided).</b>
10970 * @cfg {Array} fields An array of field definition objects, or field name strings.
10972 * @param {Object} config
10974 Roo.data.JsonStore = function(c){
10975 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10976 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10977 reader: new Roo.data.JsonReader(c, c.fields)
10980 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10982 * Ext JS Library 1.1.1
10983 * Copyright(c) 2006-2007, Ext JS, LLC.
10985 * Originally Released Under LGPL - original licence link has changed is not relivant.
10988 * <script type="text/javascript">
10992 Roo.data.Field = function(config){
10993 if(typeof config == "string"){
10994 config = {name: config};
10996 Roo.apply(this, config);
10999 this.type = "auto";
11002 var st = Roo.data.SortTypes;
11003 // named sortTypes are supported, here we look them up
11004 if(typeof this.sortType == "string"){
11005 this.sortType = st[this.sortType];
11008 // set default sortType for strings and dates
11009 if(!this.sortType){
11012 this.sortType = st.asUCString;
11015 this.sortType = st.asDate;
11018 this.sortType = st.none;
11023 var stripRe = /[\$,%]/g;
11025 // prebuilt conversion function for this field, instead of
11026 // switching every time we're reading a value
11028 var cv, dateFormat = this.dateFormat;
11033 cv = function(v){ return v; };
11036 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11040 return v !== undefined && v !== null && v !== '' ?
11041 parseInt(String(v).replace(stripRe, ""), 10) : '';
11046 return v !== undefined && v !== null && v !== '' ?
11047 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11052 cv = function(v){ return v === true || v === "true" || v == 1; };
11059 if(v instanceof Date){
11063 if(dateFormat == "timestamp"){
11064 return new Date(v*1000);
11066 return Date.parseDate(v, dateFormat);
11068 var parsed = Date.parse(v);
11069 return parsed ? new Date(parsed) : null;
11078 Roo.data.Field.prototype = {
11086 * Ext JS Library 1.1.1
11087 * Copyright(c) 2006-2007, Ext JS, LLC.
11089 * Originally Released Under LGPL - original licence link has changed is not relivant.
11092 * <script type="text/javascript">
11095 // Base class for reading structured data from a data source. This class is intended to be
11096 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11099 * @class Roo.data.DataReader
11100 * Base class for reading structured data from a data source. This class is intended to be
11101 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11104 Roo.data.DataReader = function(meta, recordType){
11108 this.recordType = recordType instanceof Array ?
11109 Roo.data.Record.create(recordType) : recordType;
11112 Roo.data.DataReader.prototype = {
11114 * Create an empty record
11115 * @param {Object} data (optional) - overlay some values
11116 * @return {Roo.data.Record} record created.
11118 newRow : function(d) {
11120 this.recordType.prototype.fields.each(function(c) {
11122 case 'int' : da[c.name] = 0; break;
11123 case 'date' : da[c.name] = new Date(); break;
11124 case 'float' : da[c.name] = 0.0; break;
11125 case 'boolean' : da[c.name] = false; break;
11126 default : da[c.name] = ""; break;
11130 return new this.recordType(Roo.apply(da, d));
11135 * Ext JS Library 1.1.1
11136 * Copyright(c) 2006-2007, Ext JS, LLC.
11138 * Originally Released Under LGPL - original licence link has changed is not relivant.
11141 * <script type="text/javascript">
11145 * @class Roo.data.DataProxy
11146 * @extends Roo.data.Observable
11147 * This class is an abstract base class for implementations which provide retrieval of
11148 * unformatted data objects.<br>
11150 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11151 * (of the appropriate type which knows how to parse the data object) to provide a block of
11152 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11154 * Custom implementations must implement the load method as described in
11155 * {@link Roo.data.HttpProxy#load}.
11157 Roo.data.DataProxy = function(){
11160 * @event beforeload
11161 * Fires before a network request is made to retrieve a data object.
11162 * @param {Object} This DataProxy object.
11163 * @param {Object} params The params parameter to the load function.
11168 * Fires before the load method's callback is called.
11169 * @param {Object} This DataProxy object.
11170 * @param {Object} o The data object.
11171 * @param {Object} arg The callback argument object passed to the load function.
11175 * @event loadexception
11176 * Fires if an Exception occurs during data retrieval.
11177 * @param {Object} This DataProxy object.
11178 * @param {Object} o The data object.
11179 * @param {Object} arg The callback argument object passed to the load function.
11180 * @param {Object} e The Exception.
11182 loadexception : true
11184 Roo.data.DataProxy.superclass.constructor.call(this);
11187 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11190 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11194 * Ext JS Library 1.1.1
11195 * Copyright(c) 2006-2007, Ext JS, LLC.
11197 * Originally Released Under LGPL - original licence link has changed is not relivant.
11200 * <script type="text/javascript">
11203 * @class Roo.data.MemoryProxy
11204 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11205 * to the Reader when its load method is called.
11207 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11209 Roo.data.MemoryProxy = function(data){
11213 Roo.data.MemoryProxy.superclass.constructor.call(this);
11217 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11220 * Load data from the requested source (in this case an in-memory
11221 * data object passed to the constructor), read the data object into
11222 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11223 * process that block using the passed callback.
11224 * @param {Object} params This parameter is not used by the MemoryProxy class.
11225 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11226 * object into a block of Roo.data.Records.
11227 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11228 * The function must be passed <ul>
11229 * <li>The Record block object</li>
11230 * <li>The "arg" argument from the load function</li>
11231 * <li>A boolean success indicator</li>
11233 * @param {Object} scope The scope in which to call the callback
11234 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11236 load : function(params, reader, callback, scope, arg){
11237 params = params || {};
11240 result = reader.readRecords(this.data);
11242 this.fireEvent("loadexception", this, arg, null, e);
11243 callback.call(scope, null, arg, false);
11246 callback.call(scope, result, arg, true);
11250 update : function(params, records){
11255 * Ext JS Library 1.1.1
11256 * Copyright(c) 2006-2007, Ext JS, LLC.
11258 * Originally Released Under LGPL - original licence link has changed is not relivant.
11261 * <script type="text/javascript">
11264 * @class Roo.data.HttpProxy
11265 * @extends Roo.data.DataProxy
11266 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11267 * configured to reference a certain URL.<br><br>
11269 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11270 * from which the running page was served.<br><br>
11272 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11274 * Be aware that to enable the browser to parse an XML document, the server must set
11275 * the Content-Type header in the HTTP response to "text/xml".
11277 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11278 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11279 * will be used to make the request.
11281 Roo.data.HttpProxy = function(conn){
11282 Roo.data.HttpProxy.superclass.constructor.call(this);
11283 // is conn a conn config or a real conn?
11285 this.useAjax = !conn || !conn.events;
11289 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11290 // thse are take from connection...
11293 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11296 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11297 * extra parameters to each request made by this object. (defaults to undefined)
11300 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11301 * to each request made by this object. (defaults to undefined)
11304 * @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)
11307 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11310 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11316 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11320 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11321 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11322 * a finer-grained basis than the DataProxy events.
11324 getConnection : function(){
11325 return this.useAjax ? Roo.Ajax : this.conn;
11329 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11330 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11331 * process that block using the passed callback.
11332 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11333 * for the request to the remote server.
11334 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11335 * object into a block of Roo.data.Records.
11336 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11337 * The function must be passed <ul>
11338 * <li>The Record block object</li>
11339 * <li>The "arg" argument from the load function</li>
11340 * <li>A boolean success indicator</li>
11342 * @param {Object} scope The scope in which to call the callback
11343 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11345 load : function(params, reader, callback, scope, arg){
11346 if(this.fireEvent("beforeload", this, params) !== false){
11348 params : params || {},
11350 callback : callback,
11355 callback : this.loadResponse,
11359 Roo.applyIf(o, this.conn);
11360 if(this.activeRequest){
11361 Roo.Ajax.abort(this.activeRequest);
11363 this.activeRequest = Roo.Ajax.request(o);
11365 this.conn.request(o);
11368 callback.call(scope||this, null, arg, false);
11373 loadResponse : function(o, success, response){
11374 delete this.activeRequest;
11376 this.fireEvent("loadexception", this, o, response);
11377 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11382 result = o.reader.read(response);
11384 this.fireEvent("loadexception", this, o, response, e);
11385 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11389 this.fireEvent("load", this, o, o.request.arg);
11390 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11394 update : function(dataSet){
11399 updateResponse : function(dataSet){
11404 * Ext JS Library 1.1.1
11405 * Copyright(c) 2006-2007, Ext JS, LLC.
11407 * Originally Released Under LGPL - original licence link has changed is not relivant.
11410 * <script type="text/javascript">
11414 * @class Roo.data.ScriptTagProxy
11415 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11416 * other than the originating domain of the running page.<br><br>
11418 * <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
11419 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11421 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11422 * source code that is used as the source inside a <script> tag.<br><br>
11424 * In order for the browser to process the returned data, the server must wrap the data object
11425 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11426 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11427 * depending on whether the callback name was passed:
11430 boolean scriptTag = false;
11431 String cb = request.getParameter("callback");
11434 response.setContentType("text/javascript");
11436 response.setContentType("application/x-json");
11438 Writer out = response.getWriter();
11440 out.write(cb + "(");
11442 out.print(dataBlock.toJsonString());
11449 * @param {Object} config A configuration object.
11451 Roo.data.ScriptTagProxy = function(config){
11452 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11453 Roo.apply(this, config);
11454 this.head = document.getElementsByTagName("head")[0];
11457 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11459 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11461 * @cfg {String} url The URL from which to request the data object.
11464 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11468 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11469 * the server the name of the callback function set up by the load call to process the returned data object.
11470 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11471 * javascript output which calls this named function passing the data object as its only parameter.
11473 callbackParam : "callback",
11475 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11476 * name to the request.
11481 * Load data from the configured URL, read the data object into
11482 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11483 * process that block using the passed callback.
11484 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11485 * for the request to the remote server.
11486 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11487 * object into a block of Roo.data.Records.
11488 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11489 * The function must be passed <ul>
11490 * <li>The Record block object</li>
11491 * <li>The "arg" argument from the load function</li>
11492 * <li>A boolean success indicator</li>
11494 * @param {Object} scope The scope in which to call the callback
11495 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11497 load : function(params, reader, callback, scope, arg){
11498 if(this.fireEvent("beforeload", this, params) !== false){
11500 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11502 var url = this.url;
11503 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11505 url += "&_dc=" + (new Date().getTime());
11507 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11510 cb : "stcCallback"+transId,
11511 scriptId : "stcScript"+transId,
11515 callback : callback,
11521 window[trans.cb] = function(o){
11522 conn.handleResponse(o, trans);
11525 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11527 if(this.autoAbort !== false){
11531 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11533 var script = document.createElement("script");
11534 script.setAttribute("src", url);
11535 script.setAttribute("type", "text/javascript");
11536 script.setAttribute("id", trans.scriptId);
11537 this.head.appendChild(script);
11539 this.trans = trans;
11541 callback.call(scope||this, null, arg, false);
11546 isLoading : function(){
11547 return this.trans ? true : false;
11551 * Abort the current server request.
11553 abort : function(){
11554 if(this.isLoading()){
11555 this.destroyTrans(this.trans);
11560 destroyTrans : function(trans, isLoaded){
11561 this.head.removeChild(document.getElementById(trans.scriptId));
11562 clearTimeout(trans.timeoutId);
11564 window[trans.cb] = undefined;
11566 delete window[trans.cb];
11569 // if hasn't been loaded, wait for load to remove it to prevent script error
11570 window[trans.cb] = function(){
11571 window[trans.cb] = undefined;
11573 delete window[trans.cb];
11580 handleResponse : function(o, trans){
11581 this.trans = false;
11582 this.destroyTrans(trans, true);
11585 result = trans.reader.readRecords(o);
11587 this.fireEvent("loadexception", this, o, trans.arg, e);
11588 trans.callback.call(trans.scope||window, null, trans.arg, false);
11591 this.fireEvent("load", this, o, trans.arg);
11592 trans.callback.call(trans.scope||window, result, trans.arg, true);
11596 handleFailure : function(trans){
11597 this.trans = false;
11598 this.destroyTrans(trans, false);
11599 this.fireEvent("loadexception", this, null, trans.arg);
11600 trans.callback.call(trans.scope||window, null, trans.arg, false);
11604 * Ext JS Library 1.1.1
11605 * Copyright(c) 2006-2007, Ext JS, LLC.
11607 * Originally Released Under LGPL - original licence link has changed is not relivant.
11610 * <script type="text/javascript">
11614 * @class Roo.data.JsonReader
11615 * @extends Roo.data.DataReader
11616 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11617 * based on mappings in a provided Roo.data.Record constructor.
11619 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11620 * in the reply previously.
11625 var RecordDef = Roo.data.Record.create([
11626 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11627 {name: 'occupation'} // This field will use "occupation" as the mapping.
11629 var myReader = new Roo.data.JsonReader({
11630 totalProperty: "results", // The property which contains the total dataset size (optional)
11631 root: "rows", // The property which contains an Array of row objects
11632 id: "id" // The property within each row object that provides an ID for the record (optional)
11636 * This would consume a JSON file like this:
11638 { 'results': 2, 'rows': [
11639 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11640 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11643 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11644 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11645 * paged from the remote server.
11646 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11647 * @cfg {String} root name of the property which contains the Array of row objects.
11648 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11649 * @cfg {Array} fields Array of field definition objects
11651 * Create a new JsonReader
11652 * @param {Object} meta Metadata configuration options
11653 * @param {Object} recordType Either an Array of field definition objects,
11654 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11656 Roo.data.JsonReader = function(meta, recordType){
11659 // set some defaults:
11660 Roo.applyIf(meta, {
11661 totalProperty: 'total',
11662 successProperty : 'success',
11667 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11669 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11672 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11673 * Used by Store query builder to append _requestMeta to params.
11676 metaFromRemote : false,
11678 * This method is only used by a DataProxy which has retrieved data from a remote server.
11679 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11680 * @return {Object} data A data block which is used by an Roo.data.Store object as
11681 * a cache of Roo.data.Records.
11683 read : function(response){
11684 var json = response.responseText;
11686 var o = /* eval:var:o */ eval("("+json+")");
11688 throw {message: "JsonReader.read: Json object not found"};
11694 this.metaFromRemote = true;
11695 this.meta = o.metaData;
11696 this.recordType = Roo.data.Record.create(o.metaData.fields);
11697 this.onMetaChange(this.meta, this.recordType, o);
11699 return this.readRecords(o);
11702 // private function a store will implement
11703 onMetaChange : function(meta, recordType, o){
11710 simpleAccess: function(obj, subsc) {
11717 getJsonAccessor: function(){
11719 return function(expr) {
11721 return(re.test(expr))
11722 ? new Function("obj", "return obj." + expr)
11727 return Roo.emptyFn;
11732 * Create a data block containing Roo.data.Records from an XML document.
11733 * @param {Object} o An object which contains an Array of row objects in the property specified
11734 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11735 * which contains the total size of the dataset.
11736 * @return {Object} data A data block which is used by an Roo.data.Store object as
11737 * a cache of Roo.data.Records.
11739 readRecords : function(o){
11741 * After any data loads, the raw JSON data is available for further custom processing.
11745 var s = this.meta, Record = this.recordType,
11746 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11748 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11750 if(s.totalProperty) {
11751 this.getTotal = this.getJsonAccessor(s.totalProperty);
11753 if(s.successProperty) {
11754 this.getSuccess = this.getJsonAccessor(s.successProperty);
11756 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11758 var g = this.getJsonAccessor(s.id);
11759 this.getId = function(rec) {
11761 return (r === undefined || r === "") ? null : r;
11764 this.getId = function(){return null;};
11767 for(var jj = 0; jj < fl; jj++){
11769 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11770 this.ef[jj] = this.getJsonAccessor(map);
11774 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11775 if(s.totalProperty){
11776 var vt = parseInt(this.getTotal(o), 10);
11781 if(s.successProperty){
11782 var vs = this.getSuccess(o);
11783 if(vs === false || vs === 'false'){
11788 for(var i = 0; i < c; i++){
11791 var id = this.getId(n);
11792 for(var j = 0; j < fl; j++){
11794 var v = this.ef[j](n);
11796 Roo.log('missing convert for ' + f.name);
11800 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11802 var record = new Record(values, id);
11804 records[i] = record;
11810 totalRecords : totalRecords
11815 * Ext JS Library 1.1.1
11816 * Copyright(c) 2006-2007, Ext JS, LLC.
11818 * Originally Released Under LGPL - original licence link has changed is not relivant.
11821 * <script type="text/javascript">
11825 * @class Roo.data.ArrayReader
11826 * @extends Roo.data.DataReader
11827 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11828 * Each element of that Array represents a row of data fields. The
11829 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11830 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11834 var RecordDef = Roo.data.Record.create([
11835 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11836 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11838 var myReader = new Roo.data.ArrayReader({
11839 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11843 * This would consume an Array like this:
11845 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11847 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11849 * Create a new JsonReader
11850 * @param {Object} meta Metadata configuration options.
11851 * @param {Object} recordType Either an Array of field definition objects
11852 * as specified to {@link Roo.data.Record#create},
11853 * or an {@link Roo.data.Record} object
11854 * created using {@link Roo.data.Record#create}.
11856 Roo.data.ArrayReader = function(meta, recordType){
11857 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11860 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11862 * Create a data block containing Roo.data.Records from an XML document.
11863 * @param {Object} o An Array of row objects which represents the dataset.
11864 * @return {Object} data A data block which is used by an Roo.data.Store object as
11865 * a cache of Roo.data.Records.
11867 readRecords : function(o){
11868 var sid = this.meta ? this.meta.id : null;
11869 var recordType = this.recordType, fields = recordType.prototype.fields;
11872 for(var i = 0; i < root.length; i++){
11875 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11876 for(var j = 0, jlen = fields.length; j < jlen; j++){
11877 var f = fields.items[j];
11878 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11879 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11881 values[f.name] = v;
11883 var record = new recordType(values, id);
11885 records[records.length] = record;
11889 totalRecords : records.length
11898 * @class Roo.bootstrap.ComboBox
11899 * @extends Roo.bootstrap.TriggerField
11900 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11901 * @cfg {Boolean} append (true|false) default false
11902 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11903 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11904 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11905 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11906 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11907 * @cfg {Boolean} animate default true
11908 * @cfg {Boolean} emptyResultText only for touch device
11909 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11911 * Create a new ComboBox.
11912 * @param {Object} config Configuration options
11914 Roo.bootstrap.ComboBox = function(config){
11915 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11919 * Fires when the dropdown list is expanded
11920 * @param {Roo.bootstrap.ComboBox} combo This combo box
11925 * Fires when the dropdown list is collapsed
11926 * @param {Roo.bootstrap.ComboBox} combo This combo box
11930 * @event beforeselect
11931 * Fires before a list item is selected. Return false to cancel the selection.
11932 * @param {Roo.bootstrap.ComboBox} combo This combo box
11933 * @param {Roo.data.Record} record The data record returned from the underlying store
11934 * @param {Number} index The index of the selected item in the dropdown list
11936 'beforeselect' : true,
11939 * Fires when a list item is selected
11940 * @param {Roo.bootstrap.ComboBox} combo This combo box
11941 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11942 * @param {Number} index The index of the selected item in the dropdown list
11946 * @event beforequery
11947 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11948 * The event object passed has these properties:
11949 * @param {Roo.bootstrap.ComboBox} combo This combo box
11950 * @param {String} query The query
11951 * @param {Boolean} forceAll true to force "all" query
11952 * @param {Boolean} cancel true to cancel the query
11953 * @param {Object} e The query event object
11955 'beforequery': true,
11958 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11959 * @param {Roo.bootstrap.ComboBox} combo This combo box
11964 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11965 * @param {Roo.bootstrap.ComboBox} combo This combo box
11966 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11971 * Fires when the remove value from the combobox array
11972 * @param {Roo.bootstrap.ComboBox} combo This combo box
11976 * @event afterremove
11977 * Fires when the remove value from the combobox array
11978 * @param {Roo.bootstrap.ComboBox} combo This combo box
11980 'afterremove' : true,
11982 * @event specialfilter
11983 * Fires when specialfilter
11984 * @param {Roo.bootstrap.ComboBox} combo This combo box
11986 'specialfilter' : true,
11989 * Fires when tick the element
11990 * @param {Roo.bootstrap.ComboBox} combo This combo box
11994 * @event touchviewdisplay
11995 * Fires when touch view require special display (default is using displayField)
11996 * @param {Roo.bootstrap.ComboBox} combo This combo box
11997 * @param {Object} cfg set html .
11999 'touchviewdisplay' : true
12004 this.tickItems = [];
12006 this.selectedIndex = -1;
12007 if(this.mode == 'local'){
12008 if(config.queryDelay === undefined){
12009 this.queryDelay = 10;
12011 if(config.minChars === undefined){
12017 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12020 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12021 * rendering into an Roo.Editor, defaults to false)
12024 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12025 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12028 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12031 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12032 * the dropdown list (defaults to undefined, with no header element)
12036 * @cfg {String/Roo.Template} tpl The template to use to render the output
12040 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12042 listWidth: undefined,
12044 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12045 * mode = 'remote' or 'text' if mode = 'local')
12047 displayField: undefined,
12050 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12051 * mode = 'remote' or 'value' if mode = 'local').
12052 * Note: use of a valueField requires the user make a selection
12053 * in order for a value to be mapped.
12055 valueField: undefined,
12057 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12062 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12063 * field's data value (defaults to the underlying DOM element's name)
12065 hiddenName: undefined,
12067 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12071 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12073 selectedClass: 'active',
12076 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12080 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12081 * anchor positions (defaults to 'tl-bl')
12083 listAlign: 'tl-bl?',
12085 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12089 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12090 * query specified by the allQuery config option (defaults to 'query')
12092 triggerAction: 'query',
12094 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12095 * (defaults to 4, does not apply if editable = false)
12099 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12100 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12104 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12105 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12109 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12110 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12114 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12115 * when editable = true (defaults to false)
12117 selectOnFocus:false,
12119 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12121 queryParam: 'query',
12123 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12124 * when mode = 'remote' (defaults to 'Loading...')
12126 loadingText: 'Loading...',
12128 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12132 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12136 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12137 * traditional select (defaults to true)
12141 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12145 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12149 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12150 * listWidth has a higher value)
12154 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12155 * allow the user to set arbitrary text into the field (defaults to false)
12157 forceSelection:false,
12159 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12160 * if typeAhead = true (defaults to 250)
12162 typeAheadDelay : 250,
12164 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12165 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12167 valueNotFoundText : undefined,
12169 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12171 blockFocus : false,
12174 * @cfg {Boolean} disableClear Disable showing of clear button.
12176 disableClear : false,
12178 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12180 alwaysQuery : false,
12183 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12188 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12190 invalidClass : "has-warning",
12193 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12195 validClass : "has-success",
12198 * @cfg {Boolean} specialFilter (true|false) special filter default false
12200 specialFilter : false,
12203 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12205 mobileTouchView : true,
12217 btnPosition : 'right',
12218 triggerList : true,
12219 showToggleBtn : true,
12221 emptyResultText: 'Empty',
12222 triggerText : 'Select',
12224 // element that contains real text value.. (when hidden is used..)
12226 getAutoCreate : function()
12234 if(Roo.isTouch && this.mobileTouchView){
12235 cfg = this.getAutoCreateTouchView();
12242 if(!this.tickable){
12243 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12248 * ComboBox with tickable selections
12251 var align = this.labelAlign || this.parentLabelAlign();
12254 cls : 'form-group roo-combobox-tickable' //input-group
12259 cls : 'tickable-buttons',
12264 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12265 html : this.triggerText
12271 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12278 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12285 buttons.cn.unshift({
12287 cls: 'roo-select2-search-field-input'
12293 Roo.each(buttons.cn, function(c){
12295 c.cls += ' btn-' + _this.size;
12298 if (_this.disabled) {
12309 cls: 'form-hidden-field'
12313 cls: 'roo-select2-choices',
12317 cls: 'roo-select2-search-field',
12329 cls: 'roo-select2-container input-group roo-select2-container-multi',
12334 // cls: 'typeahead typeahead-long dropdown-menu',
12335 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12340 if(this.hasFeedback && !this.allowBlank){
12344 cls: 'glyphicon form-control-feedback'
12347 combobox.cn.push(feedback);
12350 if (align ==='left' && this.fieldLabel.length && this.labelWidth) {
12352 // Roo.log("left and has label");
12356 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12357 tooltip : 'This field is required'
12362 cls : 'control-label col-sm-' + this.labelWidth,
12363 html : this.fieldLabel
12367 cls : "col-sm-" + (12 - this.labelWidth),
12375 if(this.indicatorpos == 'right'){
12381 cls : 'control-label col-sm-' + this.labelWidth,
12382 html : this.fieldLabel
12387 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12388 tooltip : 'This field is required'
12391 cls : "col-sm-" + (12 - this.labelWidth),
12402 } else if ( this.fieldLabel.length) {
12403 // Roo.log(" label");
12407 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12408 tooltip : 'This field is required'
12412 //cls : 'input-group-addon',
12413 html : this.fieldLabel
12421 if(this.indicatorpos == 'right'){
12426 //cls : 'input-group-addon',
12427 html : this.fieldLabel
12433 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12434 tooltip : 'This field is required'
12445 // Roo.log(" no label && no align");
12452 ['xs','sm','md','lg'].map(function(size){
12453 if (settings[size]) {
12454 cfg.cls += ' col-' + size + '-' + settings[size];
12462 _initEventsCalled : false,
12465 initEvents: function()
12468 if (this._initEventsCalled) { // as we call render... prevent looping...
12471 this._initEventsCalled = true;
12474 throw "can not find store for combo";
12477 this.store = Roo.factory(this.store, Roo.data);
12479 // if we are building from html. then this element is so complex, that we can not really
12480 // use the rendered HTML.
12481 // so we have to trash and replace the previous code.
12482 if (Roo.XComponent.build_from_html) {
12484 // remove this element....
12485 var e = this.el.dom, k=0;
12486 while (e ) { e = e.previousSibling; ++k;}
12491 this.rendered = false;
12493 this.render(this.parent().getChildContainer(true), k);
12504 if(Roo.isTouch && this.mobileTouchView){
12505 this.initTouchView();
12510 this.initTickableEvents();
12514 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12516 if(this.hiddenName){
12518 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12520 this.hiddenField.dom.value =
12521 this.hiddenValue !== undefined ? this.hiddenValue :
12522 this.value !== undefined ? this.value : '';
12524 // prevent input submission
12525 this.el.dom.removeAttribute('name');
12526 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12531 // this.el.dom.setAttribute('autocomplete', 'off');
12534 var cls = 'x-combo-list';
12536 //this.list = new Roo.Layer({
12537 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12543 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12544 _this.list.setWidth(lw);
12547 this.list.on('mouseover', this.onViewOver, this);
12548 this.list.on('mousemove', this.onViewMove, this);
12550 this.list.on('scroll', this.onViewScroll, this);
12553 this.list.swallowEvent('mousewheel');
12554 this.assetHeight = 0;
12557 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12558 this.assetHeight += this.header.getHeight();
12561 this.innerList = this.list.createChild({cls:cls+'-inner'});
12562 this.innerList.on('mouseover', this.onViewOver, this);
12563 this.innerList.on('mousemove', this.onViewMove, this);
12564 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12566 if(this.allowBlank && !this.pageSize && !this.disableClear){
12567 this.footer = this.list.createChild({cls:cls+'-ft'});
12568 this.pageTb = new Roo.Toolbar(this.footer);
12572 this.footer = this.list.createChild({cls:cls+'-ft'});
12573 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12574 {pageSize: this.pageSize});
12578 if (this.pageTb && this.allowBlank && !this.disableClear) {
12580 this.pageTb.add(new Roo.Toolbar.Fill(), {
12581 cls: 'x-btn-icon x-btn-clear',
12583 handler: function()
12586 _this.clearValue();
12587 _this.onSelect(false, -1);
12592 this.assetHeight += this.footer.getHeight();
12597 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12600 this.view = new Roo.View(this.list, this.tpl, {
12601 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12603 //this.view.wrapEl.setDisplayed(false);
12604 this.view.on('click', this.onViewClick, this);
12608 this.store.on('beforeload', this.onBeforeLoad, this);
12609 this.store.on('load', this.onLoad, this);
12610 this.store.on('loadexception', this.onLoadException, this);
12612 if(this.resizable){
12613 this.resizer = new Roo.Resizable(this.list, {
12614 pinned:true, handles:'se'
12616 this.resizer.on('resize', function(r, w, h){
12617 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12618 this.listWidth = w;
12619 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12620 this.restrictHeight();
12622 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12625 if(!this.editable){
12626 this.editable = true;
12627 this.setEditable(false);
12632 if (typeof(this.events.add.listeners) != 'undefined') {
12634 this.addicon = this.wrap.createChild(
12635 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12637 this.addicon.on('click', function(e) {
12638 this.fireEvent('add', this);
12641 if (typeof(this.events.edit.listeners) != 'undefined') {
12643 this.editicon = this.wrap.createChild(
12644 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12645 if (this.addicon) {
12646 this.editicon.setStyle('margin-left', '40px');
12648 this.editicon.on('click', function(e) {
12650 // we fire even if inothing is selected..
12651 this.fireEvent('edit', this, this.lastData );
12657 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12658 "up" : function(e){
12659 this.inKeyMode = true;
12663 "down" : function(e){
12664 if(!this.isExpanded()){
12665 this.onTriggerClick();
12667 this.inKeyMode = true;
12672 "enter" : function(e){
12673 // this.onViewClick();
12677 if(this.fireEvent("specialkey", this, e)){
12678 this.onViewClick(false);
12684 "esc" : function(e){
12688 "tab" : function(e){
12691 if(this.fireEvent("specialkey", this, e)){
12692 this.onViewClick(false);
12700 doRelay : function(foo, bar, hname){
12701 if(hname == 'down' || this.scope.isExpanded()){
12702 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12711 this.queryDelay = Math.max(this.queryDelay || 10,
12712 this.mode == 'local' ? 10 : 250);
12715 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12717 if(this.typeAhead){
12718 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12720 if(this.editable !== false){
12721 this.inputEl().on("keyup", this.onKeyUp, this);
12723 if(this.forceSelection){
12724 this.inputEl().on('blur', this.doForce, this);
12728 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12729 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12733 initTickableEvents: function()
12737 if(this.hiddenName){
12739 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12741 this.hiddenField.dom.value =
12742 this.hiddenValue !== undefined ? this.hiddenValue :
12743 this.value !== undefined ? this.value : '';
12745 // prevent input submission
12746 this.el.dom.removeAttribute('name');
12747 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12752 // this.list = this.el.select('ul.dropdown-menu',true).first();
12754 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12755 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12756 if(this.triggerList){
12757 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12760 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12761 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12763 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12764 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12766 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12767 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12769 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12770 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12771 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12774 this.cancelBtn.hide();
12779 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12780 _this.list.setWidth(lw);
12783 this.list.on('mouseover', this.onViewOver, this);
12784 this.list.on('mousemove', this.onViewMove, this);
12786 this.list.on('scroll', this.onViewScroll, this);
12789 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>';
12792 this.view = new Roo.View(this.list, this.tpl, {
12793 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12796 //this.view.wrapEl.setDisplayed(false);
12797 this.view.on('click', this.onViewClick, this);
12801 this.store.on('beforeload', this.onBeforeLoad, this);
12802 this.store.on('load', this.onLoad, this);
12803 this.store.on('loadexception', this.onLoadException, this);
12806 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12807 "up" : function(e){
12808 this.inKeyMode = true;
12812 "down" : function(e){
12813 this.inKeyMode = true;
12817 "enter" : function(e){
12818 if(this.fireEvent("specialkey", this, e)){
12819 this.onViewClick(false);
12825 "esc" : function(e){
12826 this.onTickableFooterButtonClick(e, false, false);
12829 "tab" : function(e){
12830 this.fireEvent("specialkey", this, e);
12832 this.onTickableFooterButtonClick(e, false, false);
12839 doRelay : function(e, fn, key){
12840 if(this.scope.isExpanded()){
12841 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12850 this.queryDelay = Math.max(this.queryDelay || 10,
12851 this.mode == 'local' ? 10 : 250);
12854 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12856 if(this.typeAhead){
12857 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12860 if(this.editable !== false){
12861 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12866 onDestroy : function(){
12868 this.view.setStore(null);
12869 this.view.el.removeAllListeners();
12870 this.view.el.remove();
12871 this.view.purgeListeners();
12874 this.list.dom.innerHTML = '';
12878 this.store.un('beforeload', this.onBeforeLoad, this);
12879 this.store.un('load', this.onLoad, this);
12880 this.store.un('loadexception', this.onLoadException, this);
12882 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12886 fireKey : function(e){
12887 if(e.isNavKeyPress() && !this.list.isVisible()){
12888 this.fireEvent("specialkey", this, e);
12893 onResize: function(w, h){
12894 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12896 // if(typeof w != 'number'){
12897 // // we do not handle it!?!?
12900 // var tw = this.trigger.getWidth();
12901 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12902 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12904 // this.inputEl().setWidth( this.adjustWidth('input', x));
12906 // //this.trigger.setStyle('left', x+'px');
12908 // if(this.list && this.listWidth === undefined){
12909 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12910 // this.list.setWidth(lw);
12911 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12919 * Allow or prevent the user from directly editing the field text. If false is passed,
12920 * the user will only be able to select from the items defined in the dropdown list. This method
12921 * is the runtime equivalent of setting the 'editable' config option at config time.
12922 * @param {Boolean} value True to allow the user to directly edit the field text
12924 setEditable : function(value){
12925 if(value == this.editable){
12928 this.editable = value;
12930 this.inputEl().dom.setAttribute('readOnly', true);
12931 this.inputEl().on('mousedown', this.onTriggerClick, this);
12932 this.inputEl().addClass('x-combo-noedit');
12934 this.inputEl().dom.setAttribute('readOnly', false);
12935 this.inputEl().un('mousedown', this.onTriggerClick, this);
12936 this.inputEl().removeClass('x-combo-noedit');
12942 onBeforeLoad : function(combo,opts){
12943 if(!this.hasFocus){
12947 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12949 this.restrictHeight();
12950 this.selectedIndex = -1;
12954 onLoad : function(){
12956 this.hasQuery = false;
12958 if(!this.hasFocus){
12962 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12963 this.loading.hide();
12966 if(this.store.getCount() > 0){
12968 this.restrictHeight();
12969 if(this.lastQuery == this.allQuery){
12970 if(this.editable && !this.tickable){
12971 this.inputEl().dom.select();
12975 !this.selectByValue(this.value, true) &&
12978 !this.store.lastOptions ||
12979 typeof(this.store.lastOptions.add) == 'undefined' ||
12980 this.store.lastOptions.add != true
12983 this.select(0, true);
12986 if(this.autoFocus){
12989 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12990 this.taTask.delay(this.typeAheadDelay);
12994 this.onEmptyResults();
13000 onLoadException : function()
13002 this.hasQuery = false;
13004 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13005 this.loading.hide();
13008 if(this.tickable && this.editable){
13013 // only causes errors at present
13014 //Roo.log(this.store.reader.jsonData);
13015 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13017 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13023 onTypeAhead : function(){
13024 if(this.store.getCount() > 0){
13025 var r = this.store.getAt(0);
13026 var newValue = r.data[this.displayField];
13027 var len = newValue.length;
13028 var selStart = this.getRawValue().length;
13030 if(selStart != len){
13031 this.setRawValue(newValue);
13032 this.selectText(selStart, newValue.length);
13038 onSelect : function(record, index){
13040 if(this.fireEvent('beforeselect', this, record, index) !== false){
13042 this.setFromData(index > -1 ? record.data : false);
13045 this.fireEvent('select', this, record, index);
13050 * Returns the currently selected field value or empty string if no value is set.
13051 * @return {String} value The selected value
13053 getValue : function(){
13056 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13059 if(this.valueField){
13060 return typeof this.value != 'undefined' ? this.value : '';
13062 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13067 * Clears any text/value currently set in the field
13069 clearValue : function(){
13070 if(this.hiddenField){
13071 this.hiddenField.dom.value = '';
13074 this.setRawValue('');
13075 this.lastSelectionText = '';
13076 this.lastData = false;
13078 var close = this.closeTriggerEl();
13089 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13090 * will be displayed in the field. If the value does not match the data value of an existing item,
13091 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13092 * Otherwise the field will be blank (although the value will still be set).
13093 * @param {String} value The value to match
13095 setValue : function(v){
13102 if(this.valueField){
13103 var r = this.findRecord(this.valueField, v);
13105 text = r.data[this.displayField];
13106 }else if(this.valueNotFoundText !== undefined){
13107 text = this.valueNotFoundText;
13110 this.lastSelectionText = text;
13111 if(this.hiddenField){
13112 this.hiddenField.dom.value = v;
13114 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13117 var close = this.closeTriggerEl();
13120 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13126 * @property {Object} the last set data for the element
13131 * Sets the value of the field based on a object which is related to the record format for the store.
13132 * @param {Object} value the value to set as. or false on reset?
13134 setFromData : function(o){
13141 var dv = ''; // display value
13142 var vv = ''; // value value..
13144 if (this.displayField) {
13145 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13147 // this is an error condition!!!
13148 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13151 if(this.valueField){
13152 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13155 var close = this.closeTriggerEl();
13158 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13161 if(this.hiddenField){
13162 this.hiddenField.dom.value = vv;
13164 this.lastSelectionText = dv;
13165 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13169 // no hidden field.. - we store the value in 'value', but still display
13170 // display field!!!!
13171 this.lastSelectionText = dv;
13172 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13179 reset : function(){
13180 // overridden so that last data is reset..
13187 this.setValue(this.originalValue);
13188 //this.clearInvalid();
13189 this.lastData = false;
13191 this.view.clearSelections();
13197 findRecord : function(prop, value){
13199 if(this.store.getCount() > 0){
13200 this.store.each(function(r){
13201 if(r.data[prop] == value){
13211 getName: function()
13213 // returns hidden if it's set..
13214 if (!this.rendered) {return ''};
13215 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13219 onViewMove : function(e, t){
13220 this.inKeyMode = false;
13224 onViewOver : function(e, t){
13225 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13228 var item = this.view.findItemFromChild(t);
13231 var index = this.view.indexOf(item);
13232 this.select(index, false);
13237 onViewClick : function(view, doFocus, el, e)
13239 var index = this.view.getSelectedIndexes()[0];
13241 var r = this.store.getAt(index);
13245 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13252 Roo.each(this.tickItems, function(v,k){
13254 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13256 _this.tickItems.splice(k, 1);
13258 if(typeof(e) == 'undefined' && view == false){
13259 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13271 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13272 this.tickItems.push(r.data);
13275 if(typeof(e) == 'undefined' && view == false){
13276 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13283 this.onSelect(r, index);
13285 if(doFocus !== false && !this.blockFocus){
13286 this.inputEl().focus();
13291 restrictHeight : function(){
13292 //this.innerList.dom.style.height = '';
13293 //var inner = this.innerList.dom;
13294 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13295 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13296 //this.list.beginUpdate();
13297 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13298 this.list.alignTo(this.inputEl(), this.listAlign);
13299 this.list.alignTo(this.inputEl(), this.listAlign);
13300 //this.list.endUpdate();
13304 onEmptyResults : function(){
13306 if(this.tickable && this.editable){
13307 this.restrictHeight();
13315 * Returns true if the dropdown list is expanded, else false.
13317 isExpanded : function(){
13318 return this.list.isVisible();
13322 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13323 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13324 * @param {String} value The data value of the item to select
13325 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13326 * selected item if it is not currently in view (defaults to true)
13327 * @return {Boolean} True if the value matched an item in the list, else false
13329 selectByValue : function(v, scrollIntoView){
13330 if(v !== undefined && v !== null){
13331 var r = this.findRecord(this.valueField || this.displayField, v);
13333 this.select(this.store.indexOf(r), scrollIntoView);
13341 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13342 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13343 * @param {Number} index The zero-based index of the list item to select
13344 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13345 * selected item if it is not currently in view (defaults to true)
13347 select : function(index, scrollIntoView){
13348 this.selectedIndex = index;
13349 this.view.select(index);
13350 if(scrollIntoView !== false){
13351 var el = this.view.getNode(index);
13353 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13356 this.list.scrollChildIntoView(el, false);
13362 selectNext : function(){
13363 var ct = this.store.getCount();
13365 if(this.selectedIndex == -1){
13367 }else if(this.selectedIndex < ct-1){
13368 this.select(this.selectedIndex+1);
13374 selectPrev : function(){
13375 var ct = this.store.getCount();
13377 if(this.selectedIndex == -1){
13379 }else if(this.selectedIndex != 0){
13380 this.select(this.selectedIndex-1);
13386 onKeyUp : function(e){
13387 if(this.editable !== false && !e.isSpecialKey()){
13388 this.lastKey = e.getKey();
13389 this.dqTask.delay(this.queryDelay);
13394 validateBlur : function(){
13395 return !this.list || !this.list.isVisible();
13399 initQuery : function(){
13401 var v = this.getRawValue();
13403 if(this.tickable && this.editable){
13404 v = this.tickableInputEl().getValue();
13411 doForce : function(){
13412 if(this.inputEl().dom.value.length > 0){
13413 this.inputEl().dom.value =
13414 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13420 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13421 * query allowing the query action to be canceled if needed.
13422 * @param {String} query The SQL query to execute
13423 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13424 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13425 * saved in the current store (defaults to false)
13427 doQuery : function(q, forceAll){
13429 if(q === undefined || q === null){
13434 forceAll: forceAll,
13438 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13443 forceAll = qe.forceAll;
13444 if(forceAll === true || (q.length >= this.minChars)){
13446 this.hasQuery = true;
13448 if(this.lastQuery != q || this.alwaysQuery){
13449 this.lastQuery = q;
13450 if(this.mode == 'local'){
13451 this.selectedIndex = -1;
13453 this.store.clearFilter();
13456 if(this.specialFilter){
13457 this.fireEvent('specialfilter', this);
13462 this.store.filter(this.displayField, q);
13465 this.store.fireEvent("datachanged", this.store);
13472 this.store.baseParams[this.queryParam] = q;
13474 var options = {params : this.getParams(q)};
13477 options.add = true;
13478 options.params.start = this.page * this.pageSize;
13481 this.store.load(options);
13484 * this code will make the page width larger, at the beginning, the list not align correctly,
13485 * we should expand the list on onLoad
13486 * so command out it
13491 this.selectedIndex = -1;
13496 this.loadNext = false;
13500 getParams : function(q){
13502 //p[this.queryParam] = q;
13506 p.limit = this.pageSize;
13512 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13514 collapse : function(){
13515 if(!this.isExpanded()){
13522 this.hasFocus = false;
13524 this.cancelBtn.hide();
13525 this.trigger.show();
13528 this.tickableInputEl().dom.value = '';
13529 this.tickableInputEl().blur();
13534 Roo.get(document).un('mousedown', this.collapseIf, this);
13535 Roo.get(document).un('mousewheel', this.collapseIf, this);
13536 if (!this.editable) {
13537 Roo.get(document).un('keydown', this.listKeyPress, this);
13539 this.fireEvent('collapse', this);
13545 collapseIf : function(e){
13546 var in_combo = e.within(this.el);
13547 var in_list = e.within(this.list);
13548 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13550 if (in_combo || in_list || is_list) {
13551 //e.stopPropagation();
13556 this.onTickableFooterButtonClick(e, false, false);
13564 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13566 expand : function(){
13568 if(this.isExpanded() || !this.hasFocus){
13572 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13573 this.list.setWidth(lw);
13580 this.restrictHeight();
13584 this.tickItems = Roo.apply([], this.item);
13587 this.cancelBtn.show();
13588 this.trigger.hide();
13591 this.tickableInputEl().focus();
13596 Roo.get(document).on('mousedown', this.collapseIf, this);
13597 Roo.get(document).on('mousewheel', this.collapseIf, this);
13598 if (!this.editable) {
13599 Roo.get(document).on('keydown', this.listKeyPress, this);
13602 this.fireEvent('expand', this);
13606 // Implements the default empty TriggerField.onTriggerClick function
13607 onTriggerClick : function(e)
13609 Roo.log('trigger click');
13611 if(this.disabled || !this.triggerList){
13616 this.loadNext = false;
13618 if(this.isExpanded()){
13620 if (!this.blockFocus) {
13621 this.inputEl().focus();
13625 this.hasFocus = true;
13626 if(this.triggerAction == 'all') {
13627 this.doQuery(this.allQuery, true);
13629 this.doQuery(this.getRawValue());
13631 if (!this.blockFocus) {
13632 this.inputEl().focus();
13637 onTickableTriggerClick : function(e)
13644 this.loadNext = false;
13645 this.hasFocus = true;
13647 if(this.triggerAction == 'all') {
13648 this.doQuery(this.allQuery, true);
13650 this.doQuery(this.getRawValue());
13654 onSearchFieldClick : function(e)
13656 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13657 this.onTickableFooterButtonClick(e, false, false);
13661 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13666 this.loadNext = false;
13667 this.hasFocus = true;
13669 if(this.triggerAction == 'all') {
13670 this.doQuery(this.allQuery, true);
13672 this.doQuery(this.getRawValue());
13676 listKeyPress : function(e)
13678 //Roo.log('listkeypress');
13679 // scroll to first matching element based on key pres..
13680 if (e.isSpecialKey()) {
13683 var k = String.fromCharCode(e.getKey()).toUpperCase();
13686 var csel = this.view.getSelectedNodes();
13687 var cselitem = false;
13689 var ix = this.view.indexOf(csel[0]);
13690 cselitem = this.store.getAt(ix);
13691 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13697 this.store.each(function(v) {
13699 // start at existing selection.
13700 if (cselitem.id == v.id) {
13706 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13707 match = this.store.indexOf(v);
13713 if (match === false) {
13714 return true; // no more action?
13717 this.view.select(match);
13718 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13719 sn.scrollIntoView(sn.dom.parentNode, false);
13722 onViewScroll : function(e, t){
13724 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){
13728 this.hasQuery = true;
13730 this.loading = this.list.select('.loading', true).first();
13732 if(this.loading === null){
13733 this.list.createChild({
13735 cls: 'loading roo-select2-more-results roo-select2-active',
13736 html: 'Loading more results...'
13739 this.loading = this.list.select('.loading', true).first();
13741 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13743 this.loading.hide();
13746 this.loading.show();
13751 this.loadNext = true;
13753 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13758 addItem : function(o)
13760 var dv = ''; // display value
13762 if (this.displayField) {
13763 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13765 // this is an error condition!!!
13766 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13773 var choice = this.choices.createChild({
13775 cls: 'roo-select2-search-choice',
13784 cls: 'roo-select2-search-choice-close',
13789 }, this.searchField);
13791 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13793 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13801 this.inputEl().dom.value = '';
13806 onRemoveItem : function(e, _self, o)
13808 e.preventDefault();
13810 this.lastItem = Roo.apply([], this.item);
13812 var index = this.item.indexOf(o.data) * 1;
13815 Roo.log('not this item?!');
13819 this.item.splice(index, 1);
13824 this.fireEvent('remove', this, e);
13830 syncValue : function()
13832 if(!this.item.length){
13839 Roo.each(this.item, function(i){
13840 if(_this.valueField){
13841 value.push(i[_this.valueField]);
13848 this.value = value.join(',');
13850 if(this.hiddenField){
13851 this.hiddenField.dom.value = this.value;
13854 this.store.fireEvent("datachanged", this.store);
13859 clearItem : function()
13861 if(!this.multiple){
13867 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13875 if(this.tickable && !Roo.isTouch){
13876 this.view.refresh();
13880 inputEl: function ()
13882 if(Roo.isTouch && this.mobileTouchView){
13883 return this.el.select('input.form-control',true).first();
13887 return this.searchField;
13890 return this.el.select('input.form-control',true).first();
13894 onTickableFooterButtonClick : function(e, btn, el)
13896 e.preventDefault();
13898 this.lastItem = Roo.apply([], this.item);
13900 if(btn && btn.name == 'cancel'){
13901 this.tickItems = Roo.apply([], this.item);
13910 Roo.each(this.tickItems, function(o){
13918 validate : function()
13920 var v = this.getRawValue();
13923 v = this.getValue();
13926 if(this.disabled || this.allowBlank || v.length){
13931 this.markInvalid();
13935 tickableInputEl : function()
13937 if(!this.tickable || !this.editable){
13938 return this.inputEl();
13941 return this.inputEl().select('.roo-select2-search-field-input', true).first();
13945 getAutoCreateTouchView : function()
13950 cls: 'form-group' //input-group
13956 type : this.inputType,
13957 cls : 'form-control x-combo-noedit',
13958 autocomplete: 'new-password',
13959 placeholder : this.placeholder || '',
13964 input.name = this.name;
13968 input.cls += ' input-' + this.size;
13971 if (this.disabled) {
13972 input.disabled = true;
13983 inputblock.cls += ' input-group';
13985 inputblock.cn.unshift({
13987 cls : 'input-group-addon',
13992 if(this.removable && !this.multiple){
13993 inputblock.cls += ' roo-removable';
13995 inputblock.cn.push({
13998 cls : 'roo-combo-removable-btn close'
14002 if(this.hasFeedback && !this.allowBlank){
14004 inputblock.cls += ' has-feedback';
14006 inputblock.cn.push({
14008 cls: 'glyphicon form-control-feedback'
14015 inputblock.cls += (this.before) ? '' : ' input-group';
14017 inputblock.cn.push({
14019 cls : 'input-group-addon',
14030 cls: 'form-hidden-field'
14044 cls: 'form-hidden-field'
14048 cls: 'roo-select2-choices',
14052 cls: 'roo-select2-search-field',
14065 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14071 if(!this.multiple && this.showToggleBtn){
14078 if (this.caret != false) {
14081 cls: 'fa fa-' + this.caret
14088 cls : 'input-group-addon btn dropdown-toggle',
14093 cls: 'combobox-clear',
14107 combobox.cls += ' roo-select2-container-multi';
14110 var align = this.labelAlign || this.parentLabelAlign();
14114 if(this.fieldLabel.length && this.labelWidth){
14116 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
14117 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
14122 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14123 tooltip : 'This field is required'
14127 cls : 'control-label ' + lw,
14128 html : this.fieldLabel
14139 if(this.indicatorpos == 'right'){
14143 cls : 'control-label ' + lw,
14144 html : this.fieldLabel
14149 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14150 tooltip : 'This field is required'
14162 var settings = this;
14164 ['xs','sm','md','lg'].map(function(size){
14165 if (settings[size]) {
14166 cfg.cls += ' col-' + size + '-' + settings[size];
14173 initTouchView : function()
14175 this.renderTouchView();
14177 this.touchViewEl.on('scroll', function(){
14178 this.el.dom.scrollTop = 0;
14181 this.originalValue = this.getValue();
14183 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14185 this.inputEl().on("click", this.showTouchView, this);
14186 this.triggerEl.on("click", this.showTouchView, this);
14188 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14189 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14191 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14193 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14194 this.store.on('load', this.onTouchViewLoad, this);
14195 this.store.on('loadexception', this.onTouchViewLoadException, this);
14197 if(this.hiddenName){
14199 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14201 this.hiddenField.dom.value =
14202 this.hiddenValue !== undefined ? this.hiddenValue :
14203 this.value !== undefined ? this.value : '';
14205 this.el.dom.removeAttribute('name');
14206 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14210 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14211 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14214 if(this.removable && !this.multiple){
14215 var close = this.closeTriggerEl();
14217 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14218 close.on('click', this.removeBtnClick, this, close);
14222 * fix the bug in Safari iOS8
14224 this.inputEl().on("focus", function(e){
14225 document.activeElement.blur();
14233 renderTouchView : function()
14235 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14236 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14238 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14239 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14241 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14242 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14243 this.touchViewBodyEl.setStyle('overflow', 'auto');
14245 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14246 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14248 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14249 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14253 showTouchView : function()
14259 this.touchViewHeaderEl.hide();
14261 if(this.modalTitle.length){
14262 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14263 this.touchViewHeaderEl.show();
14266 this.touchViewEl.show();
14268 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14269 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14270 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14272 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14274 if(this.modalTitle.length){
14275 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14278 this.touchViewBodyEl.setHeight(bodyHeight);
14282 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14284 this.touchViewEl.addClass('in');
14287 this.doTouchViewQuery();
14291 hideTouchView : function()
14293 this.touchViewEl.removeClass('in');
14297 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14299 this.touchViewEl.setStyle('display', 'none');
14304 setTouchViewValue : function()
14311 Roo.each(this.tickItems, function(o){
14316 this.hideTouchView();
14319 doTouchViewQuery : function()
14328 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14332 if(!this.alwaysQuery || this.mode == 'local'){
14333 this.onTouchViewLoad();
14340 onTouchViewBeforeLoad : function(combo,opts)
14346 onTouchViewLoad : function()
14348 if(this.store.getCount() < 1){
14349 this.onTouchViewEmptyResults();
14353 this.clearTouchView();
14355 var rawValue = this.getRawValue();
14357 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14359 this.tickItems = [];
14361 this.store.data.each(function(d, rowIndex){
14362 var row = this.touchViewListGroup.createChild(template);
14364 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14365 row.addClass(d.data.cls);
14368 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14371 html : d.data[this.displayField]
14374 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14375 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14378 row.removeClass('selected');
14379 if(!this.multiple && this.valueField &&
14380 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14383 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14384 row.addClass('selected');
14387 if(this.multiple && this.valueField &&
14388 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14392 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14393 this.tickItems.push(d.data);
14396 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14400 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14402 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14404 if(this.modalTitle.length){
14405 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14408 var listHeight = this.touchViewListGroup.getHeight();
14412 if(firstChecked && listHeight > bodyHeight){
14413 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14418 onTouchViewLoadException : function()
14420 this.hideTouchView();
14423 onTouchViewEmptyResults : function()
14425 this.clearTouchView();
14427 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14429 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14433 clearTouchView : function()
14435 this.touchViewListGroup.dom.innerHTML = '';
14438 onTouchViewClick : function(e, el, o)
14440 e.preventDefault();
14443 var rowIndex = o.rowIndex;
14445 var r = this.store.getAt(rowIndex);
14447 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14449 if(!this.multiple){
14450 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14451 c.dom.removeAttribute('checked');
14454 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14456 this.setFromData(r.data);
14458 var close = this.closeTriggerEl();
14464 this.hideTouchView();
14466 this.fireEvent('select', this, r, rowIndex);
14471 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14472 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14473 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14477 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14478 this.addItem(r.data);
14479 this.tickItems.push(r.data);
14485 * @cfg {Boolean} grow
14489 * @cfg {Number} growMin
14493 * @cfg {Number} growMax
14502 Roo.apply(Roo.bootstrap.ComboBox, {
14506 cls: 'modal-header',
14528 cls: 'list-group-item',
14532 cls: 'roo-combobox-list-group-item-value'
14536 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14550 listItemCheckbox : {
14552 cls: 'list-group-item',
14556 cls: 'roo-combobox-list-group-item-value'
14560 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14576 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14581 cls: 'modal-footer',
14589 cls: 'col-xs-6 text-left',
14592 cls: 'btn btn-danger roo-touch-view-cancel',
14598 cls: 'col-xs-6 text-right',
14601 cls: 'btn btn-success roo-touch-view-ok',
14612 Roo.apply(Roo.bootstrap.ComboBox, {
14614 touchViewTemplate : {
14616 cls: 'modal fade roo-combobox-touch-view',
14620 cls: 'modal-dialog',
14621 style : 'position:fixed', // we have to fix position....
14625 cls: 'modal-content',
14627 Roo.bootstrap.ComboBox.header,
14628 Roo.bootstrap.ComboBox.body,
14629 Roo.bootstrap.ComboBox.footer
14638 * Ext JS Library 1.1.1
14639 * Copyright(c) 2006-2007, Ext JS, LLC.
14641 * Originally Released Under LGPL - original licence link has changed is not relivant.
14644 * <script type="text/javascript">
14649 * @extends Roo.util.Observable
14650 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14651 * This class also supports single and multi selection modes. <br>
14652 * Create a data model bound view:
14654 var store = new Roo.data.Store(...);
14656 var view = new Roo.View({
14658 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14660 singleSelect: true,
14661 selectedClass: "ydataview-selected",
14665 // listen for node click?
14666 view.on("click", function(vw, index, node, e){
14667 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14671 dataModel.load("foobar.xml");
14673 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14675 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14676 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14678 * Note: old style constructor is still suported (container, template, config)
14681 * Create a new View
14682 * @param {Object} config The config object
14685 Roo.View = function(config, depreciated_tpl, depreciated_config){
14687 this.parent = false;
14689 if (typeof(depreciated_tpl) == 'undefined') {
14690 // new way.. - universal constructor.
14691 Roo.apply(this, config);
14692 this.el = Roo.get(this.el);
14695 this.el = Roo.get(config);
14696 this.tpl = depreciated_tpl;
14697 Roo.apply(this, depreciated_config);
14699 this.wrapEl = this.el.wrap().wrap();
14700 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14703 if(typeof(this.tpl) == "string"){
14704 this.tpl = new Roo.Template(this.tpl);
14706 // support xtype ctors..
14707 this.tpl = new Roo.factory(this.tpl, Roo);
14711 this.tpl.compile();
14716 * @event beforeclick
14717 * Fires before a click is processed. Returns false to cancel the default action.
14718 * @param {Roo.View} this
14719 * @param {Number} index The index of the target node
14720 * @param {HTMLElement} node The target node
14721 * @param {Roo.EventObject} e The raw event object
14723 "beforeclick" : true,
14726 * Fires when a template node is clicked.
14727 * @param {Roo.View} this
14728 * @param {Number} index The index of the target node
14729 * @param {HTMLElement} node The target node
14730 * @param {Roo.EventObject} e The raw event object
14735 * Fires when a template node is double clicked.
14736 * @param {Roo.View} this
14737 * @param {Number} index The index of the target node
14738 * @param {HTMLElement} node The target node
14739 * @param {Roo.EventObject} e The raw event object
14743 * @event contextmenu
14744 * Fires when a template node is right clicked.
14745 * @param {Roo.View} this
14746 * @param {Number} index The index of the target node
14747 * @param {HTMLElement} node The target node
14748 * @param {Roo.EventObject} e The raw event object
14750 "contextmenu" : true,
14752 * @event selectionchange
14753 * Fires when the selected nodes change.
14754 * @param {Roo.View} this
14755 * @param {Array} selections Array of the selected nodes
14757 "selectionchange" : true,
14760 * @event beforeselect
14761 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14762 * @param {Roo.View} this
14763 * @param {HTMLElement} node The node to be selected
14764 * @param {Array} selections Array of currently selected nodes
14766 "beforeselect" : true,
14768 * @event preparedata
14769 * Fires on every row to render, to allow you to change the data.
14770 * @param {Roo.View} this
14771 * @param {Object} data to be rendered (change this)
14773 "preparedata" : true
14781 "click": this.onClick,
14782 "dblclick": this.onDblClick,
14783 "contextmenu": this.onContextMenu,
14787 this.selections = [];
14789 this.cmp = new Roo.CompositeElementLite([]);
14791 this.store = Roo.factory(this.store, Roo.data);
14792 this.setStore(this.store, true);
14795 if ( this.footer && this.footer.xtype) {
14797 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14799 this.footer.dataSource = this.store;
14800 this.footer.container = fctr;
14801 this.footer = Roo.factory(this.footer, Roo);
14802 fctr.insertFirst(this.el);
14804 // this is a bit insane - as the paging toolbar seems to detach the el..
14805 // dom.parentNode.parentNode.parentNode
14806 // they get detached?
14810 Roo.View.superclass.constructor.call(this);
14815 Roo.extend(Roo.View, Roo.util.Observable, {
14818 * @cfg {Roo.data.Store} store Data store to load data from.
14823 * @cfg {String|Roo.Element} el The container element.
14828 * @cfg {String|Roo.Template} tpl The template used by this View
14832 * @cfg {String} dataName the named area of the template to use as the data area
14833 * Works with domtemplates roo-name="name"
14837 * @cfg {String} selectedClass The css class to add to selected nodes
14839 selectedClass : "x-view-selected",
14841 * @cfg {String} emptyText The empty text to show when nothing is loaded.
14846 * @cfg {String} text to display on mask (default Loading)
14850 * @cfg {Boolean} multiSelect Allow multiple selection
14852 multiSelect : false,
14854 * @cfg {Boolean} singleSelect Allow single selection
14856 singleSelect: false,
14859 * @cfg {Boolean} toggleSelect - selecting
14861 toggleSelect : false,
14864 * @cfg {Boolean} tickable - selecting
14869 * Returns the element this view is bound to.
14870 * @return {Roo.Element}
14872 getEl : function(){
14873 return this.wrapEl;
14879 * Refreshes the view. - called by datachanged on the store. - do not call directly.
14881 refresh : function(){
14882 //Roo.log('refresh');
14885 // if we are using something like 'domtemplate', then
14886 // the what gets used is:
14887 // t.applySubtemplate(NAME, data, wrapping data..)
14888 // the outer template then get' applied with
14889 // the store 'extra data'
14890 // and the body get's added to the
14891 // roo-name="data" node?
14892 // <span class='roo-tpl-{name}'></span> ?????
14896 this.clearSelections();
14897 this.el.update("");
14899 var records = this.store.getRange();
14900 if(records.length < 1) {
14902 // is this valid?? = should it render a template??
14904 this.el.update(this.emptyText);
14908 if (this.dataName) {
14909 this.el.update(t.apply(this.store.meta)); //????
14910 el = this.el.child('.roo-tpl-' + this.dataName);
14913 for(var i = 0, len = records.length; i < len; i++){
14914 var data = this.prepareData(records[i].data, i, records[i]);
14915 this.fireEvent("preparedata", this, data, i, records[i]);
14917 var d = Roo.apply({}, data);
14920 Roo.apply(d, {'roo-id' : Roo.id()});
14924 Roo.each(this.parent.item, function(item){
14925 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
14928 Roo.apply(d, {'roo-data-checked' : 'checked'});
14932 html[html.length] = Roo.util.Format.trim(
14934 t.applySubtemplate(this.dataName, d, this.store.meta) :
14941 el.update(html.join(""));
14942 this.nodes = el.dom.childNodes;
14943 this.updateIndexes(0);
14948 * Function to override to reformat the data that is sent to
14949 * the template for each node.
14950 * DEPRICATED - use the preparedata event handler.
14951 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
14952 * a JSON object for an UpdateManager bound view).
14954 prepareData : function(data, index, record)
14956 this.fireEvent("preparedata", this, data, index, record);
14960 onUpdate : function(ds, record){
14961 // Roo.log('on update');
14962 this.clearSelections();
14963 var index = this.store.indexOf(record);
14964 var n = this.nodes[index];
14965 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
14966 n.parentNode.removeChild(n);
14967 this.updateIndexes(index, index);
14973 onAdd : function(ds, records, index)
14975 //Roo.log(['on Add', ds, records, index] );
14976 this.clearSelections();
14977 if(this.nodes.length == 0){
14981 var n = this.nodes[index];
14982 for(var i = 0, len = records.length; i < len; i++){
14983 var d = this.prepareData(records[i].data, i, records[i]);
14985 this.tpl.insertBefore(n, d);
14988 this.tpl.append(this.el, d);
14991 this.updateIndexes(index);
14994 onRemove : function(ds, record, index){
14995 // Roo.log('onRemove');
14996 this.clearSelections();
14997 var el = this.dataName ?
14998 this.el.child('.roo-tpl-' + this.dataName) :
15001 el.dom.removeChild(this.nodes[index]);
15002 this.updateIndexes(index);
15006 * Refresh an individual node.
15007 * @param {Number} index
15009 refreshNode : function(index){
15010 this.onUpdate(this.store, this.store.getAt(index));
15013 updateIndexes : function(startIndex, endIndex){
15014 var ns = this.nodes;
15015 startIndex = startIndex || 0;
15016 endIndex = endIndex || ns.length - 1;
15017 for(var i = startIndex; i <= endIndex; i++){
15018 ns[i].nodeIndex = i;
15023 * Changes the data store this view uses and refresh the view.
15024 * @param {Store} store
15026 setStore : function(store, initial){
15027 if(!initial && this.store){
15028 this.store.un("datachanged", this.refresh);
15029 this.store.un("add", this.onAdd);
15030 this.store.un("remove", this.onRemove);
15031 this.store.un("update", this.onUpdate);
15032 this.store.un("clear", this.refresh);
15033 this.store.un("beforeload", this.onBeforeLoad);
15034 this.store.un("load", this.onLoad);
15035 this.store.un("loadexception", this.onLoad);
15039 store.on("datachanged", this.refresh, this);
15040 store.on("add", this.onAdd, this);
15041 store.on("remove", this.onRemove, this);
15042 store.on("update", this.onUpdate, this);
15043 store.on("clear", this.refresh, this);
15044 store.on("beforeload", this.onBeforeLoad, this);
15045 store.on("load", this.onLoad, this);
15046 store.on("loadexception", this.onLoad, this);
15054 * onbeforeLoad - masks the loading area.
15057 onBeforeLoad : function(store,opts)
15059 //Roo.log('onBeforeLoad');
15061 this.el.update("");
15063 this.el.mask(this.mask ? this.mask : "Loading" );
15065 onLoad : function ()
15072 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15073 * @param {HTMLElement} node
15074 * @return {HTMLElement} The template node
15076 findItemFromChild : function(node){
15077 var el = this.dataName ?
15078 this.el.child('.roo-tpl-' + this.dataName,true) :
15081 if(!node || node.parentNode == el){
15084 var p = node.parentNode;
15085 while(p && p != el){
15086 if(p.parentNode == el){
15095 onClick : function(e){
15096 var item = this.findItemFromChild(e.getTarget());
15098 var index = this.indexOf(item);
15099 if(this.onItemClick(item, index, e) !== false){
15100 this.fireEvent("click", this, index, item, e);
15103 this.clearSelections();
15108 onContextMenu : function(e){
15109 var item = this.findItemFromChild(e.getTarget());
15111 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15116 onDblClick : function(e){
15117 var item = this.findItemFromChild(e.getTarget());
15119 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15123 onItemClick : function(item, index, e)
15125 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15128 if (this.toggleSelect) {
15129 var m = this.isSelected(item) ? 'unselect' : 'select';
15132 _t[m](item, true, false);
15135 if(this.multiSelect || this.singleSelect){
15136 if(this.multiSelect && e.shiftKey && this.lastSelection){
15137 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15139 this.select(item, this.multiSelect && e.ctrlKey);
15140 this.lastSelection = item;
15143 if(!this.tickable){
15144 e.preventDefault();
15152 * Get the number of selected nodes.
15155 getSelectionCount : function(){
15156 return this.selections.length;
15160 * Get the currently selected nodes.
15161 * @return {Array} An array of HTMLElements
15163 getSelectedNodes : function(){
15164 return this.selections;
15168 * Get the indexes of the selected nodes.
15171 getSelectedIndexes : function(){
15172 var indexes = [], s = this.selections;
15173 for(var i = 0, len = s.length; i < len; i++){
15174 indexes.push(s[i].nodeIndex);
15180 * Clear all selections
15181 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15183 clearSelections : function(suppressEvent){
15184 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15185 this.cmp.elements = this.selections;
15186 this.cmp.removeClass(this.selectedClass);
15187 this.selections = [];
15188 if(!suppressEvent){
15189 this.fireEvent("selectionchange", this, this.selections);
15195 * Returns true if the passed node is selected
15196 * @param {HTMLElement/Number} node The node or node index
15197 * @return {Boolean}
15199 isSelected : function(node){
15200 var s = this.selections;
15204 node = this.getNode(node);
15205 return s.indexOf(node) !== -1;
15210 * @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
15211 * @param {Boolean} keepExisting (optional) true to keep existing selections
15212 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15214 select : function(nodeInfo, keepExisting, suppressEvent){
15215 if(nodeInfo instanceof Array){
15217 this.clearSelections(true);
15219 for(var i = 0, len = nodeInfo.length; i < len; i++){
15220 this.select(nodeInfo[i], true, true);
15224 var node = this.getNode(nodeInfo);
15225 if(!node || this.isSelected(node)){
15226 return; // already selected.
15229 this.clearSelections(true);
15232 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15233 Roo.fly(node).addClass(this.selectedClass);
15234 this.selections.push(node);
15235 if(!suppressEvent){
15236 this.fireEvent("selectionchange", this, this.selections);
15244 * @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
15245 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15246 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15248 unselect : function(nodeInfo, keepExisting, suppressEvent)
15250 if(nodeInfo instanceof Array){
15251 Roo.each(this.selections, function(s) {
15252 this.unselect(s, nodeInfo);
15256 var node = this.getNode(nodeInfo);
15257 if(!node || !this.isSelected(node)){
15258 //Roo.log("not selected");
15259 return; // not selected.
15263 Roo.each(this.selections, function(s) {
15265 Roo.fly(node).removeClass(this.selectedClass);
15272 this.selections= ns;
15273 this.fireEvent("selectionchange", this, this.selections);
15277 * Gets a template node.
15278 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15279 * @return {HTMLElement} The node or null if it wasn't found
15281 getNode : function(nodeInfo){
15282 if(typeof nodeInfo == "string"){
15283 return document.getElementById(nodeInfo);
15284 }else if(typeof nodeInfo == "number"){
15285 return this.nodes[nodeInfo];
15291 * Gets a range template nodes.
15292 * @param {Number} startIndex
15293 * @param {Number} endIndex
15294 * @return {Array} An array of nodes
15296 getNodes : function(start, end){
15297 var ns = this.nodes;
15298 start = start || 0;
15299 end = typeof end == "undefined" ? ns.length - 1 : end;
15302 for(var i = start; i <= end; i++){
15306 for(var i = start; i >= end; i--){
15314 * Finds the index of the passed node
15315 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15316 * @return {Number} The index of the node or -1
15318 indexOf : function(node){
15319 node = this.getNode(node);
15320 if(typeof node.nodeIndex == "number"){
15321 return node.nodeIndex;
15323 var ns = this.nodes;
15324 for(var i = 0, len = ns.length; i < len; i++){
15335 * based on jquery fullcalendar
15339 Roo.bootstrap = Roo.bootstrap || {};
15341 * @class Roo.bootstrap.Calendar
15342 * @extends Roo.bootstrap.Component
15343 * Bootstrap Calendar class
15344 * @cfg {Boolean} loadMask (true|false) default false
15345 * @cfg {Object} header generate the user specific header of the calendar, default false
15348 * Create a new Container
15349 * @param {Object} config The config object
15354 Roo.bootstrap.Calendar = function(config){
15355 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15359 * Fires when a date is selected
15360 * @param {DatePicker} this
15361 * @param {Date} date The selected date
15365 * @event monthchange
15366 * Fires when the displayed month changes
15367 * @param {DatePicker} this
15368 * @param {Date} date The selected month
15370 'monthchange': true,
15372 * @event evententer
15373 * Fires when mouse over an event
15374 * @param {Calendar} this
15375 * @param {event} Event
15377 'evententer': true,
15379 * @event eventleave
15380 * Fires when the mouse leaves an
15381 * @param {Calendar} this
15384 'eventleave': true,
15386 * @event eventclick
15387 * Fires when the mouse click an
15388 * @param {Calendar} this
15397 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15400 * @cfg {Number} startDay
15401 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15409 getAutoCreate : function(){
15412 var fc_button = function(name, corner, style, content ) {
15413 return Roo.apply({},{
15415 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15417 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15420 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15431 style : 'width:100%',
15438 cls : 'fc-header-left',
15440 fc_button('prev', 'left', 'arrow', '‹' ),
15441 fc_button('next', 'right', 'arrow', '›' ),
15442 { tag: 'span', cls: 'fc-header-space' },
15443 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15451 cls : 'fc-header-center',
15455 cls: 'fc-header-title',
15458 html : 'month / year'
15466 cls : 'fc-header-right',
15468 /* fc_button('month', 'left', '', 'month' ),
15469 fc_button('week', '', '', 'week' ),
15470 fc_button('day', 'right', '', 'day' )
15482 header = this.header;
15485 var cal_heads = function() {
15487 // fixme - handle this.
15489 for (var i =0; i < Date.dayNames.length; i++) {
15490 var d = Date.dayNames[i];
15493 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15494 html : d.substring(0,3)
15498 ret[0].cls += ' fc-first';
15499 ret[6].cls += ' fc-last';
15502 var cal_cell = function(n) {
15505 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15510 cls: 'fc-day-number',
15514 cls: 'fc-day-content',
15518 style: 'position: relative;' // height: 17px;
15530 var cal_rows = function() {
15533 for (var r = 0; r < 6; r++) {
15540 for (var i =0; i < Date.dayNames.length; i++) {
15541 var d = Date.dayNames[i];
15542 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15545 row.cn[0].cls+=' fc-first';
15546 row.cn[0].cn[0].style = 'min-height:90px';
15547 row.cn[6].cls+=' fc-last';
15551 ret[0].cls += ' fc-first';
15552 ret[4].cls += ' fc-prev-last';
15553 ret[5].cls += ' fc-last';
15560 cls: 'fc-border-separate',
15561 style : 'width:100%',
15569 cls : 'fc-first fc-last',
15587 cls : 'fc-content',
15588 style : "position: relative;",
15591 cls : 'fc-view fc-view-month fc-grid',
15592 style : 'position: relative',
15593 unselectable : 'on',
15596 cls : 'fc-event-container',
15597 style : 'position:absolute;z-index:8;top:0;left:0;'
15615 initEvents : function()
15618 throw "can not find store for calendar";
15624 style: "text-align:center",
15628 style: "background-color:white;width:50%;margin:250 auto",
15632 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15643 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15645 var size = this.el.select('.fc-content', true).first().getSize();
15646 this.maskEl.setSize(size.width, size.height);
15647 this.maskEl.enableDisplayMode("block");
15648 if(!this.loadMask){
15649 this.maskEl.hide();
15652 this.store = Roo.factory(this.store, Roo.data);
15653 this.store.on('load', this.onLoad, this);
15654 this.store.on('beforeload', this.onBeforeLoad, this);
15658 this.cells = this.el.select('.fc-day',true);
15659 //Roo.log(this.cells);
15660 this.textNodes = this.el.query('.fc-day-number');
15661 this.cells.addClassOnOver('fc-state-hover');
15663 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15664 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15665 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15666 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15668 this.on('monthchange', this.onMonthChange, this);
15670 this.update(new Date().clearTime());
15673 resize : function() {
15674 var sz = this.el.getSize();
15676 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15677 this.el.select('.fc-day-content div',true).setHeight(34);
15682 showPrevMonth : function(e){
15683 this.update(this.activeDate.add("mo", -1));
15685 showToday : function(e){
15686 this.update(new Date().clearTime());
15689 showNextMonth : function(e){
15690 this.update(this.activeDate.add("mo", 1));
15694 showPrevYear : function(){
15695 this.update(this.activeDate.add("y", -1));
15699 showNextYear : function(){
15700 this.update(this.activeDate.add("y", 1));
15705 update : function(date)
15707 var vd = this.activeDate;
15708 this.activeDate = date;
15709 // if(vd && this.el){
15710 // var t = date.getTime();
15711 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15712 // Roo.log('using add remove');
15714 // this.fireEvent('monthchange', this, date);
15716 // this.cells.removeClass("fc-state-highlight");
15717 // this.cells.each(function(c){
15718 // if(c.dateValue == t){
15719 // c.addClass("fc-state-highlight");
15720 // setTimeout(function(){
15721 // try{c.dom.firstChild.focus();}catch(e){}
15731 var days = date.getDaysInMonth();
15733 var firstOfMonth = date.getFirstDateOfMonth();
15734 var startingPos = firstOfMonth.getDay()-this.startDay;
15736 if(startingPos < this.startDay){
15740 var pm = date.add(Date.MONTH, -1);
15741 var prevStart = pm.getDaysInMonth()-startingPos;
15743 this.cells = this.el.select('.fc-day',true);
15744 this.textNodes = this.el.query('.fc-day-number');
15745 this.cells.addClassOnOver('fc-state-hover');
15747 var cells = this.cells.elements;
15748 var textEls = this.textNodes;
15750 Roo.each(cells, function(cell){
15751 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15754 days += startingPos;
15756 // convert everything to numbers so it's fast
15757 var day = 86400000;
15758 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15761 //Roo.log(prevStart);
15763 var today = new Date().clearTime().getTime();
15764 var sel = date.clearTime().getTime();
15765 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15766 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15767 var ddMatch = this.disabledDatesRE;
15768 var ddText = this.disabledDatesText;
15769 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15770 var ddaysText = this.disabledDaysText;
15771 var format = this.format;
15773 var setCellClass = function(cal, cell){
15777 //Roo.log('set Cell Class');
15779 var t = d.getTime();
15783 cell.dateValue = t;
15785 cell.className += " fc-today";
15786 cell.className += " fc-state-highlight";
15787 cell.title = cal.todayText;
15790 // disable highlight in other month..
15791 //cell.className += " fc-state-highlight";
15796 cell.className = " fc-state-disabled";
15797 cell.title = cal.minText;
15801 cell.className = " fc-state-disabled";
15802 cell.title = cal.maxText;
15806 if(ddays.indexOf(d.getDay()) != -1){
15807 cell.title = ddaysText;
15808 cell.className = " fc-state-disabled";
15811 if(ddMatch && format){
15812 var fvalue = d.dateFormat(format);
15813 if(ddMatch.test(fvalue)){
15814 cell.title = ddText.replace("%0", fvalue);
15815 cell.className = " fc-state-disabled";
15819 if (!cell.initialClassName) {
15820 cell.initialClassName = cell.dom.className;
15823 cell.dom.className = cell.initialClassName + ' ' + cell.className;
15828 for(; i < startingPos; i++) {
15829 textEls[i].innerHTML = (++prevStart);
15830 d.setDate(d.getDate()+1);
15832 cells[i].className = "fc-past fc-other-month";
15833 setCellClass(this, cells[i]);
15838 for(; i < days; i++){
15839 intDay = i - startingPos + 1;
15840 textEls[i].innerHTML = (intDay);
15841 d.setDate(d.getDate()+1);
15843 cells[i].className = ''; // "x-date-active";
15844 setCellClass(this, cells[i]);
15848 for(; i < 42; i++) {
15849 textEls[i].innerHTML = (++extraDays);
15850 d.setDate(d.getDate()+1);
15852 cells[i].className = "fc-future fc-other-month";
15853 setCellClass(this, cells[i]);
15856 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
15858 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
15860 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
15861 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
15863 if(totalRows != 6){
15864 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
15865 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
15868 this.fireEvent('monthchange', this, date);
15872 if(!this.internalRender){
15873 var main = this.el.dom.firstChild;
15874 var w = main.offsetWidth;
15875 this.el.setWidth(w + this.el.getBorderWidth("lr"));
15876 Roo.fly(main).setWidth(w);
15877 this.internalRender = true;
15878 // opera does not respect the auto grow header center column
15879 // then, after it gets a width opera refuses to recalculate
15880 // without a second pass
15881 if(Roo.isOpera && !this.secondPass){
15882 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
15883 this.secondPass = true;
15884 this.update.defer(10, this, [date]);
15891 findCell : function(dt) {
15892 dt = dt.clearTime().getTime();
15894 this.cells.each(function(c){
15895 //Roo.log("check " +c.dateValue + '?=' + dt);
15896 if(c.dateValue == dt){
15906 findCells : function(ev) {
15907 var s = ev.start.clone().clearTime().getTime();
15909 var e= ev.end.clone().clearTime().getTime();
15912 this.cells.each(function(c){
15913 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
15915 if(c.dateValue > e){
15918 if(c.dateValue < s){
15927 // findBestRow: function(cells)
15931 // for (var i =0 ; i < cells.length;i++) {
15932 // ret = Math.max(cells[i].rows || 0,ret);
15939 addItem : function(ev)
15941 // look for vertical location slot in
15942 var cells = this.findCells(ev);
15944 // ev.row = this.findBestRow(cells);
15946 // work out the location.
15950 for(var i =0; i < cells.length; i++) {
15952 cells[i].row = cells[0].row;
15955 cells[i].row = cells[i].row + 1;
15965 if (crow.start.getY() == cells[i].getY()) {
15967 crow.end = cells[i];
15984 cells[0].events.push(ev);
15986 this.calevents.push(ev);
15989 clearEvents: function() {
15991 if(!this.calevents){
15995 Roo.each(this.cells.elements, function(c){
16001 Roo.each(this.calevents, function(e) {
16002 Roo.each(e.els, function(el) {
16003 el.un('mouseenter' ,this.onEventEnter, this);
16004 el.un('mouseleave' ,this.onEventLeave, this);
16009 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16015 renderEvents: function()
16019 this.cells.each(function(c) {
16028 if(c.row != c.events.length){
16029 r = 4 - (4 - (c.row - c.events.length));
16032 c.events = ev.slice(0, r);
16033 c.more = ev.slice(r);
16035 if(c.more.length && c.more.length == 1){
16036 c.events.push(c.more.pop());
16039 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16043 this.cells.each(function(c) {
16045 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16048 for (var e = 0; e < c.events.length; e++){
16049 var ev = c.events[e];
16050 var rows = ev.rows;
16052 for(var i = 0; i < rows.length; i++) {
16054 // how many rows should it span..
16057 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16058 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16060 unselectable : "on",
16063 cls: 'fc-event-inner',
16067 // cls: 'fc-event-time',
16068 // html : cells.length > 1 ? '' : ev.time
16072 cls: 'fc-event-title',
16073 html : String.format('{0}', ev.title)
16080 cls: 'ui-resizable-handle ui-resizable-e',
16081 html : '  '
16088 cfg.cls += ' fc-event-start';
16090 if ((i+1) == rows.length) {
16091 cfg.cls += ' fc-event-end';
16094 var ctr = _this.el.select('.fc-event-container',true).first();
16095 var cg = ctr.createChild(cfg);
16097 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16098 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16100 var r = (c.more.length) ? 1 : 0;
16101 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16102 cg.setWidth(ebox.right - sbox.x -2);
16104 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16105 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16106 cg.on('click', _this.onEventClick, _this, ev);
16117 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16118 style : 'position: absolute',
16119 unselectable : "on",
16122 cls: 'fc-event-inner',
16126 cls: 'fc-event-title',
16134 cls: 'ui-resizable-handle ui-resizable-e',
16135 html : '  '
16141 var ctr = _this.el.select('.fc-event-container',true).first();
16142 var cg = ctr.createChild(cfg);
16144 var sbox = c.select('.fc-day-content',true).first().getBox();
16145 var ebox = c.select('.fc-day-content',true).first().getBox();
16147 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16148 cg.setWidth(ebox.right - sbox.x -2);
16150 cg.on('click', _this.onMoreEventClick, _this, c.more);
16160 onEventEnter: function (e, el,event,d) {
16161 this.fireEvent('evententer', this, el, event);
16164 onEventLeave: function (e, el,event,d) {
16165 this.fireEvent('eventleave', this, el, event);
16168 onEventClick: function (e, el,event,d) {
16169 this.fireEvent('eventclick', this, el, event);
16172 onMonthChange: function () {
16176 onMoreEventClick: function(e, el, more)
16180 this.calpopover.placement = 'right';
16181 this.calpopover.setTitle('More');
16183 this.calpopover.setContent('');
16185 var ctr = this.calpopover.el.select('.popover-content', true).first();
16187 Roo.each(more, function(m){
16189 cls : 'fc-event-hori fc-event-draggable',
16192 var cg = ctr.createChild(cfg);
16194 cg.on('click', _this.onEventClick, _this, m);
16197 this.calpopover.show(el);
16202 onLoad: function ()
16204 this.calevents = [];
16207 if(this.store.getCount() > 0){
16208 this.store.data.each(function(d){
16211 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16212 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16213 time : d.data.start_time,
16214 title : d.data.title,
16215 description : d.data.description,
16216 venue : d.data.venue
16221 this.renderEvents();
16223 if(this.calevents.length && this.loadMask){
16224 this.maskEl.hide();
16228 onBeforeLoad: function()
16230 this.clearEvents();
16232 this.maskEl.show();
16246 * @class Roo.bootstrap.Popover
16247 * @extends Roo.bootstrap.Component
16248 * Bootstrap Popover class
16249 * @cfg {String} html contents of the popover (or false to use children..)
16250 * @cfg {String} title of popover (or false to hide)
16251 * @cfg {String} placement how it is placed
16252 * @cfg {String} trigger click || hover (or false to trigger manually)
16253 * @cfg {String} over what (parent or false to trigger manually.)
16254 * @cfg {Number} delay - delay before showing
16257 * Create a new Popover
16258 * @param {Object} config The config object
16261 Roo.bootstrap.Popover = function(config){
16262 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16268 * After the popover show
16270 * @param {Roo.bootstrap.Popover} this
16275 * After the popover hide
16277 * @param {Roo.bootstrap.Popover} this
16283 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16285 title: 'Fill in a title',
16288 placement : 'right',
16289 trigger : 'hover', // hover
16295 can_build_overlaid : false,
16297 getChildContainer : function()
16299 return this.el.select('.popover-content',true).first();
16302 getAutoCreate : function(){
16305 cls : 'popover roo-dynamic',
16306 style: 'display:block',
16312 cls : 'popover-inner',
16316 cls: 'popover-title',
16320 cls : 'popover-content',
16331 setTitle: function(str)
16334 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16336 setContent: function(str)
16339 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16341 // as it get's added to the bottom of the page.
16342 onRender : function(ct, position)
16344 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16346 var cfg = Roo.apply({}, this.getAutoCreate());
16350 cfg.cls += ' ' + this.cls;
16353 cfg.style = this.style;
16355 //Roo.log("adding to ");
16356 this.el = Roo.get(document.body).createChild(cfg, position);
16357 // Roo.log(this.el);
16362 initEvents : function()
16364 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16365 this.el.enableDisplayMode('block');
16367 if (this.over === false) {
16370 if (this.triggers === false) {
16373 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16374 var triggers = this.trigger ? this.trigger.split(' ') : [];
16375 Roo.each(triggers, function(trigger) {
16377 if (trigger == 'click') {
16378 on_el.on('click', this.toggle, this);
16379 } else if (trigger != 'manual') {
16380 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16381 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16383 on_el.on(eventIn ,this.enter, this);
16384 on_el.on(eventOut, this.leave, this);
16395 toggle : function () {
16396 this.hoverState == 'in' ? this.leave() : this.enter();
16399 enter : function () {
16401 clearTimeout(this.timeout);
16403 this.hoverState = 'in';
16405 if (!this.delay || !this.delay.show) {
16410 this.timeout = setTimeout(function () {
16411 if (_t.hoverState == 'in') {
16414 }, this.delay.show)
16417 leave : function() {
16418 clearTimeout(this.timeout);
16420 this.hoverState = 'out';
16422 if (!this.delay || !this.delay.hide) {
16427 this.timeout = setTimeout(function () {
16428 if (_t.hoverState == 'out') {
16431 }, this.delay.hide)
16434 show : function (on_el)
16437 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16441 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16442 if (this.html !== false) {
16443 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16445 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16446 if (!this.title.length) {
16447 this.el.select('.popover-title',true).hide();
16450 var placement = typeof this.placement == 'function' ?
16451 this.placement.call(this, this.el, on_el) :
16454 var autoToken = /\s?auto?\s?/i;
16455 var autoPlace = autoToken.test(placement);
16457 placement = placement.replace(autoToken, '') || 'top';
16461 //this.el.setXY([0,0]);
16463 this.el.dom.style.display='block';
16464 this.el.addClass(placement);
16466 //this.el.appendTo(on_el);
16468 var p = this.getPosition();
16469 var box = this.el.getBox();
16474 var align = Roo.bootstrap.Popover.alignment[placement];
16475 this.el.alignTo(on_el, align[0],align[1]);
16476 //var arrow = this.el.select('.arrow',true).first();
16477 //arrow.set(align[2],
16479 this.el.addClass('in');
16482 if (this.el.hasClass('fade')) {
16486 this.hoverState = 'in';
16488 this.fireEvent('show', this);
16493 this.el.setXY([0,0]);
16494 this.el.removeClass('in');
16496 this.hoverState = null;
16498 this.fireEvent('hide', this);
16503 Roo.bootstrap.Popover.alignment = {
16504 'left' : ['r-l', [-10,0], 'right'],
16505 'right' : ['l-r', [10,0], 'left'],
16506 'bottom' : ['t-b', [0,10], 'top'],
16507 'top' : [ 'b-t', [0,-10], 'bottom']
16518 * @class Roo.bootstrap.Progress
16519 * @extends Roo.bootstrap.Component
16520 * Bootstrap Progress class
16521 * @cfg {Boolean} striped striped of the progress bar
16522 * @cfg {Boolean} active animated of the progress bar
16526 * Create a new Progress
16527 * @param {Object} config The config object
16530 Roo.bootstrap.Progress = function(config){
16531 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16534 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16539 getAutoCreate : function(){
16547 cfg.cls += ' progress-striped';
16551 cfg.cls += ' active';
16570 * @class Roo.bootstrap.ProgressBar
16571 * @extends Roo.bootstrap.Component
16572 * Bootstrap ProgressBar class
16573 * @cfg {Number} aria_valuenow aria-value now
16574 * @cfg {Number} aria_valuemin aria-value min
16575 * @cfg {Number} aria_valuemax aria-value max
16576 * @cfg {String} label label for the progress bar
16577 * @cfg {String} panel (success | info | warning | danger )
16578 * @cfg {String} role role of the progress bar
16579 * @cfg {String} sr_only text
16583 * Create a new ProgressBar
16584 * @param {Object} config The config object
16587 Roo.bootstrap.ProgressBar = function(config){
16588 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16591 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16595 aria_valuemax : 100,
16601 getAutoCreate : function()
16606 cls: 'progress-bar',
16607 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16619 cfg.role = this.role;
16622 if(this.aria_valuenow){
16623 cfg['aria-valuenow'] = this.aria_valuenow;
16626 if(this.aria_valuemin){
16627 cfg['aria-valuemin'] = this.aria_valuemin;
16630 if(this.aria_valuemax){
16631 cfg['aria-valuemax'] = this.aria_valuemax;
16634 if(this.label && !this.sr_only){
16635 cfg.html = this.label;
16639 cfg.cls += ' progress-bar-' + this.panel;
16645 update : function(aria_valuenow)
16647 this.aria_valuenow = aria_valuenow;
16649 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16664 * @class Roo.bootstrap.TabGroup
16665 * @extends Roo.bootstrap.Column
16666 * Bootstrap Column class
16667 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16668 * @cfg {Boolean} carousel true to make the group behave like a carousel
16669 * @cfg {Boolean} bullets show bullets for the panels
16670 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16671 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16672 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16673 * @cfg {Boolean} showarrow (true|false) show arrow default true
16676 * Create a new TabGroup
16677 * @param {Object} config The config object
16680 Roo.bootstrap.TabGroup = function(config){
16681 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16683 this.navId = Roo.id();
16686 Roo.bootstrap.TabGroup.register(this);
16690 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16693 transition : false,
16698 slideOnTouch : false,
16701 getAutoCreate : function()
16703 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16705 cfg.cls += ' tab-content';
16707 if (this.carousel) {
16708 cfg.cls += ' carousel slide';
16711 cls : 'carousel-inner',
16715 if(this.bullets && !Roo.isTouch){
16718 cls : 'carousel-bullets',
16722 if(this.bullets_cls){
16723 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16730 cfg.cn[0].cn.push(bullets);
16733 if(this.showarrow){
16734 cfg.cn[0].cn.push({
16736 class : 'carousel-arrow',
16740 class : 'carousel-prev',
16744 class : 'fa fa-chevron-left'
16750 class : 'carousel-next',
16754 class : 'fa fa-chevron-right'
16767 initEvents: function()
16769 if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
16770 this.el.on("touchstart", this.onTouchStart, this);
16773 if(this.autoslide){
16776 this.slideFn = window.setInterval(function() {
16777 _this.showPanelNext();
16781 if(this.showarrow){
16782 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
16783 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
16789 onTouchStart : function(e, el, o)
16791 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16795 this.showPanelNext();
16798 getChildContainer : function()
16800 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
16804 * register a Navigation item
16805 * @param {Roo.bootstrap.NavItem} the navitem to add
16807 register : function(item)
16809 this.tabs.push( item);
16810 item.navId = this.navId; // not really needed..
16815 getActivePanel : function()
16818 Roo.each(this.tabs, function(t) {
16828 getPanelByName : function(n)
16831 Roo.each(this.tabs, function(t) {
16832 if (t.tabId == n) {
16840 indexOfPanel : function(p)
16843 Roo.each(this.tabs, function(t,i) {
16844 if (t.tabId == p.tabId) {
16853 * show a specific panel
16854 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
16855 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
16857 showPanel : function (pan)
16859 if(this.transition || typeof(pan) == 'undefined'){
16860 Roo.log("waiting for the transitionend");
16864 if (typeof(pan) == 'number') {
16865 pan = this.tabs[pan];
16868 if (typeof(pan) == 'string') {
16869 pan = this.getPanelByName(pan);
16872 var cur = this.getActivePanel();
16875 Roo.log('pan or acitve pan is undefined');
16879 if (pan.tabId == this.getActivePanel().tabId) {
16883 if (false === cur.fireEvent('beforedeactivate')) {
16887 if(this.bullets > 0 && !Roo.isTouch){
16888 this.setActiveBullet(this.indexOfPanel(pan));
16891 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
16893 this.transition = true;
16894 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
16895 var lr = dir == 'next' ? 'left' : 'right';
16896 pan.el.addClass(dir); // or prev
16897 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
16898 cur.el.addClass(lr); // or right
16899 pan.el.addClass(lr);
16902 cur.el.on('transitionend', function() {
16903 Roo.log("trans end?");
16905 pan.el.removeClass([lr,dir]);
16906 pan.setActive(true);
16908 cur.el.removeClass([lr]);
16909 cur.setActive(false);
16911 _this.transition = false;
16913 }, this, { single: true } );
16918 cur.setActive(false);
16919 pan.setActive(true);
16924 showPanelNext : function()
16926 var i = this.indexOfPanel(this.getActivePanel());
16928 if (i >= this.tabs.length - 1 && !this.autoslide) {
16932 if (i >= this.tabs.length - 1 && this.autoslide) {
16936 this.showPanel(this.tabs[i+1]);
16939 showPanelPrev : function()
16941 var i = this.indexOfPanel(this.getActivePanel());
16943 if (i < 1 && !this.autoslide) {
16947 if (i < 1 && this.autoslide) {
16948 i = this.tabs.length;
16951 this.showPanel(this.tabs[i-1]);
16955 addBullet: function()
16957 if(!this.bullets || Roo.isTouch){
16960 var ctr = this.el.select('.carousel-bullets',true).first();
16961 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
16962 var bullet = ctr.createChild({
16963 cls : 'bullet bullet-' + i
16964 },ctr.dom.lastChild);
16969 bullet.on('click', (function(e, el, o, ii, t){
16971 e.preventDefault();
16973 this.showPanel(ii);
16975 if(this.autoslide && this.slideFn){
16976 clearInterval(this.slideFn);
16977 this.slideFn = window.setInterval(function() {
16978 _this.showPanelNext();
16982 }).createDelegate(this, [i, bullet], true));
16987 setActiveBullet : function(i)
16993 Roo.each(this.el.select('.bullet', true).elements, function(el){
16994 el.removeClass('selected');
16997 var bullet = this.el.select('.bullet-' + i, true).first();
17003 bullet.addClass('selected');
17014 Roo.apply(Roo.bootstrap.TabGroup, {
17018 * register a Navigation Group
17019 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17021 register : function(navgrp)
17023 this.groups[navgrp.navId] = navgrp;
17027 * fetch a Navigation Group based on the navigation ID
17028 * if one does not exist , it will get created.
17029 * @param {string} the navgroup to add
17030 * @returns {Roo.bootstrap.NavGroup} the navgroup
17032 get: function(navId) {
17033 if (typeof(this.groups[navId]) == 'undefined') {
17034 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17036 return this.groups[navId] ;
17051 * @class Roo.bootstrap.TabPanel
17052 * @extends Roo.bootstrap.Component
17053 * Bootstrap TabPanel class
17054 * @cfg {Boolean} active panel active
17055 * @cfg {String} html panel content
17056 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17057 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17058 * @cfg {String} href click to link..
17062 * Create a new TabPanel
17063 * @param {Object} config The config object
17066 Roo.bootstrap.TabPanel = function(config){
17067 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17071 * Fires when the active status changes
17072 * @param {Roo.bootstrap.TabPanel} this
17073 * @param {Boolean} state the new state
17078 * @event beforedeactivate
17079 * Fires before a tab is de-activated - can be used to do validation on a form.
17080 * @param {Roo.bootstrap.TabPanel} this
17081 * @return {Boolean} false if there is an error
17084 'beforedeactivate': true
17087 this.tabId = this.tabId || Roo.id();
17091 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17099 getAutoCreate : function(){
17102 // item is needed for carousel - not sure if it has any effect otherwise
17103 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17104 html: this.html || ''
17108 cfg.cls += ' active';
17112 cfg.tabId = this.tabId;
17119 initEvents: function()
17121 var p = this.parent();
17122 this.navId = this.navId || p.navId;
17124 if (typeof(this.navId) != 'undefined') {
17125 // not really needed.. but just in case.. parent should be a NavGroup.
17126 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17130 var i = tg.tabs.length - 1;
17132 if(this.active && tg.bullets > 0 && i < tg.bullets){
17133 tg.setActiveBullet(i);
17137 if(this.href.length){
17138 this.el.on('click', this.onClick, this);
17143 onRender : function(ct, position)
17145 // Roo.log("Call onRender: " + this.xtype);
17147 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17155 setActive: function(state)
17157 Roo.log("panel - set active " + this.tabId + "=" + state);
17159 this.active = state;
17161 this.el.removeClass('active');
17163 } else if (!this.el.hasClass('active')) {
17164 this.el.addClass('active');
17167 this.fireEvent('changed', this, state);
17170 onClick: function(e)
17172 e.preventDefault();
17174 window.location.href = this.href;
17191 * @class Roo.bootstrap.DateField
17192 * @extends Roo.bootstrap.Input
17193 * Bootstrap DateField class
17194 * @cfg {Number} weekStart default 0
17195 * @cfg {String} viewMode default empty, (months|years)
17196 * @cfg {String} minViewMode default empty, (months|years)
17197 * @cfg {Number} startDate default -Infinity
17198 * @cfg {Number} endDate default Infinity
17199 * @cfg {Boolean} todayHighlight default false
17200 * @cfg {Boolean} todayBtn default false
17201 * @cfg {Boolean} calendarWeeks default false
17202 * @cfg {Object} daysOfWeekDisabled default empty
17203 * @cfg {Boolean} singleMode default false (true | false)
17205 * @cfg {Boolean} keyboardNavigation default true
17206 * @cfg {String} language default en
17209 * Create a new DateField
17210 * @param {Object} config The config object
17213 Roo.bootstrap.DateField = function(config){
17214 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17218 * Fires when this field show.
17219 * @param {Roo.bootstrap.DateField} this
17220 * @param {Mixed} date The date value
17225 * Fires when this field hide.
17226 * @param {Roo.bootstrap.DateField} this
17227 * @param {Mixed} date The date value
17232 * Fires when select a date.
17233 * @param {Roo.bootstrap.DateField} this
17234 * @param {Mixed} date The date value
17238 * @event beforeselect
17239 * Fires when before select a date.
17240 * @param {Roo.bootstrap.DateField} this
17241 * @param {Mixed} date The date value
17243 beforeselect : true
17247 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17250 * @cfg {String} format
17251 * The default date format string which can be overriden for localization support. The format must be
17252 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17256 * @cfg {String} altFormats
17257 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17258 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17260 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17268 todayHighlight : false,
17274 keyboardNavigation: true,
17276 calendarWeeks: false,
17278 startDate: -Infinity,
17282 daysOfWeekDisabled: [],
17286 singleMode : false,
17288 UTCDate: function()
17290 return new Date(Date.UTC.apply(Date, arguments));
17293 UTCToday: function()
17295 var today = new Date();
17296 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
17299 getDate: function() {
17300 var d = this.getUTCDate();
17301 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
17304 getUTCDate: function() {
17308 setDate: function(d) {
17309 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
17312 setUTCDate: function(d) {
17314 this.setValue(this.formatDate(this.date));
17317 onRender: function(ct, position)
17320 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
17322 this.language = this.language || 'en';
17323 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
17324 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
17326 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
17327 this.format = this.format || 'm/d/y';
17328 this.isInline = false;
17329 this.isInput = true;
17330 this.component = this.el.select('.add-on', true).first() || false;
17331 this.component = (this.component && this.component.length === 0) ? false : this.component;
17332 this.hasInput = this.component && this.inputEL().length;
17334 if (typeof(this.minViewMode === 'string')) {
17335 switch (this.minViewMode) {
17337 this.minViewMode = 1;
17340 this.minViewMode = 2;
17343 this.minViewMode = 0;
17348 if (typeof(this.viewMode === 'string')) {
17349 switch (this.viewMode) {
17362 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17364 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17366 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17368 this.picker().on('mousedown', this.onMousedown, this);
17369 this.picker().on('click', this.onClick, this);
17371 this.picker().addClass('datepicker-dropdown');
17373 this.startViewMode = this.viewMode;
17375 if(this.singleMode){
17376 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17377 v.setVisibilityMode(Roo.Element.DISPLAY);
17381 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17382 v.setStyle('width', '189px');
17386 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17387 if(!this.calendarWeeks){
17392 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17393 v.attr('colspan', function(i, val){
17394 return parseInt(val) + 1;
17399 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17401 this.setStartDate(this.startDate);
17402 this.setEndDate(this.endDate);
17404 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17411 if(this.isInline) {
17416 picker : function()
17418 return this.pickerEl;
17419 // return this.el.select('.datepicker', true).first();
17422 fillDow: function()
17424 var dowCnt = this.weekStart;
17433 if(this.calendarWeeks){
17441 while (dowCnt < this.weekStart + 7) {
17445 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17449 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17452 fillMonths: function()
17455 var months = this.picker().select('>.datepicker-months td', true).first();
17457 months.dom.innerHTML = '';
17463 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17466 months.createChild(month);
17473 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;
17475 if (this.date < this.startDate) {
17476 this.viewDate = new Date(this.startDate);
17477 } else if (this.date > this.endDate) {
17478 this.viewDate = new Date(this.endDate);
17480 this.viewDate = new Date(this.date);
17488 var d = new Date(this.viewDate),
17489 year = d.getUTCFullYear(),
17490 month = d.getUTCMonth(),
17491 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17492 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17493 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17494 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17495 currentDate = this.date && this.date.valueOf(),
17496 today = this.UTCToday();
17498 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17500 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17502 // this.picker.select('>tfoot th.today').
17503 // .text(dates[this.language].today)
17504 // .toggle(this.todayBtn !== false);
17506 this.updateNavArrows();
17509 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17511 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17513 prevMonth.setUTCDate(day);
17515 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17517 var nextMonth = new Date(prevMonth);
17519 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17521 nextMonth = nextMonth.valueOf();
17523 var fillMonths = false;
17525 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17527 while(prevMonth.valueOf() < nextMonth) {
17530 if (prevMonth.getUTCDay() === this.weekStart) {
17532 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17540 if(this.calendarWeeks){
17541 // ISO 8601: First week contains first thursday.
17542 // ISO also states week starts on Monday, but we can be more abstract here.
17544 // Start of current week: based on weekstart/current date
17545 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17546 // Thursday of this week
17547 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17548 // First Thursday of year, year from thursday
17549 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17550 // Calendar week: ms between thursdays, div ms per day, div 7 days
17551 calWeek = (th - yth) / 864e5 / 7 + 1;
17553 fillMonths.cn.push({
17561 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17563 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17566 if (this.todayHighlight &&
17567 prevMonth.getUTCFullYear() == today.getFullYear() &&
17568 prevMonth.getUTCMonth() == today.getMonth() &&
17569 prevMonth.getUTCDate() == today.getDate()) {
17570 clsName += ' today';
17573 if (currentDate && prevMonth.valueOf() === currentDate) {
17574 clsName += ' active';
17577 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17578 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17579 clsName += ' disabled';
17582 fillMonths.cn.push({
17584 cls: 'day ' + clsName,
17585 html: prevMonth.getDate()
17588 prevMonth.setDate(prevMonth.getDate()+1);
17591 var currentYear = this.date && this.date.getUTCFullYear();
17592 var currentMonth = this.date && this.date.getUTCMonth();
17594 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17596 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17597 v.removeClass('active');
17599 if(currentYear === year && k === currentMonth){
17600 v.addClass('active');
17603 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17604 v.addClass('disabled');
17610 year = parseInt(year/10, 10) * 10;
17612 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17614 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17617 for (var i = -1; i < 11; i++) {
17618 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17620 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17628 showMode: function(dir)
17631 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17634 Roo.each(this.picker().select('>div',true).elements, function(v){
17635 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17638 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17643 if(this.isInline) {
17647 this.picker().removeClass(['bottom', 'top']);
17649 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17651 * place to the top of element!
17655 this.picker().addClass('top');
17656 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17661 this.picker().addClass('bottom');
17663 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17666 parseDate : function(value)
17668 if(!value || value instanceof Date){
17671 var v = Date.parseDate(value, this.format);
17672 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17673 v = Date.parseDate(value, 'Y-m-d');
17675 if(!v && this.altFormats){
17676 if(!this.altFormatsArray){
17677 this.altFormatsArray = this.altFormats.split("|");
17679 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17680 v = Date.parseDate(value, this.altFormatsArray[i]);
17686 formatDate : function(date, fmt)
17688 return (!date || !(date instanceof Date)) ?
17689 date : date.dateFormat(fmt || this.format);
17692 onFocus : function()
17694 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17698 onBlur : function()
17700 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17702 var d = this.inputEl().getValue();
17711 this.picker().show();
17715 this.fireEvent('show', this, this.date);
17720 if(this.isInline) {
17723 this.picker().hide();
17724 this.viewMode = this.startViewMode;
17727 this.fireEvent('hide', this, this.date);
17731 onMousedown: function(e)
17733 e.stopPropagation();
17734 e.preventDefault();
17739 Roo.bootstrap.DateField.superclass.keyup.call(this);
17743 setValue: function(v)
17745 if(this.fireEvent('beforeselect', this, v) !== false){
17746 var d = new Date(this.parseDate(v) ).clearTime();
17748 if(isNaN(d.getTime())){
17749 this.date = this.viewDate = '';
17750 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17754 v = this.formatDate(d);
17756 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17758 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17762 this.fireEvent('select', this, this.date);
17766 getValue: function()
17768 return this.formatDate(this.date);
17771 fireKey: function(e)
17773 if (!this.picker().isVisible()){
17774 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17780 var dateChanged = false,
17782 newDate, newViewDate;
17787 e.preventDefault();
17791 if (!this.keyboardNavigation) {
17794 dir = e.keyCode == 37 ? -1 : 1;
17797 newDate = this.moveYear(this.date, dir);
17798 newViewDate = this.moveYear(this.viewDate, dir);
17799 } else if (e.shiftKey){
17800 newDate = this.moveMonth(this.date, dir);
17801 newViewDate = this.moveMonth(this.viewDate, dir);
17803 newDate = new Date(this.date);
17804 newDate.setUTCDate(this.date.getUTCDate() + dir);
17805 newViewDate = new Date(this.viewDate);
17806 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
17808 if (this.dateWithinRange(newDate)){
17809 this.date = newDate;
17810 this.viewDate = newViewDate;
17811 this.setValue(this.formatDate(this.date));
17813 e.preventDefault();
17814 dateChanged = true;
17819 if (!this.keyboardNavigation) {
17822 dir = e.keyCode == 38 ? -1 : 1;
17824 newDate = this.moveYear(this.date, dir);
17825 newViewDate = this.moveYear(this.viewDate, dir);
17826 } else if (e.shiftKey){
17827 newDate = this.moveMonth(this.date, dir);
17828 newViewDate = this.moveMonth(this.viewDate, dir);
17830 newDate = new Date(this.date);
17831 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
17832 newViewDate = new Date(this.viewDate);
17833 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
17835 if (this.dateWithinRange(newDate)){
17836 this.date = newDate;
17837 this.viewDate = newViewDate;
17838 this.setValue(this.formatDate(this.date));
17840 e.preventDefault();
17841 dateChanged = true;
17845 this.setValue(this.formatDate(this.date));
17847 e.preventDefault();
17850 this.setValue(this.formatDate(this.date));
17864 onClick: function(e)
17866 e.stopPropagation();
17867 e.preventDefault();
17869 var target = e.getTarget();
17871 if(target.nodeName.toLowerCase() === 'i'){
17872 target = Roo.get(target).dom.parentNode;
17875 var nodeName = target.nodeName;
17876 var className = target.className;
17877 var html = target.innerHTML;
17878 //Roo.log(nodeName);
17880 switch(nodeName.toLowerCase()) {
17882 switch(className) {
17888 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
17889 switch(this.viewMode){
17891 this.viewDate = this.moveMonth(this.viewDate, dir);
17895 this.viewDate = this.moveYear(this.viewDate, dir);
17901 var date = new Date();
17902 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
17904 this.setValue(this.formatDate(this.date));
17911 if (className.indexOf('disabled') < 0) {
17912 this.viewDate.setUTCDate(1);
17913 if (className.indexOf('month') > -1) {
17914 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
17916 var year = parseInt(html, 10) || 0;
17917 this.viewDate.setUTCFullYear(year);
17921 if(this.singleMode){
17922 this.setValue(this.formatDate(this.viewDate));
17933 //Roo.log(className);
17934 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
17935 var day = parseInt(html, 10) || 1;
17936 var year = this.viewDate.getUTCFullYear(),
17937 month = this.viewDate.getUTCMonth();
17939 if (className.indexOf('old') > -1) {
17946 } else if (className.indexOf('new') > -1) {
17954 //Roo.log([year,month,day]);
17955 this.date = this.UTCDate(year, month, day,0,0,0,0);
17956 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
17958 //Roo.log(this.formatDate(this.date));
17959 this.setValue(this.formatDate(this.date));
17966 setStartDate: function(startDate)
17968 this.startDate = startDate || -Infinity;
17969 if (this.startDate !== -Infinity) {
17970 this.startDate = this.parseDate(this.startDate);
17973 this.updateNavArrows();
17976 setEndDate: function(endDate)
17978 this.endDate = endDate || Infinity;
17979 if (this.endDate !== Infinity) {
17980 this.endDate = this.parseDate(this.endDate);
17983 this.updateNavArrows();
17986 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
17988 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
17989 if (typeof(this.daysOfWeekDisabled) !== 'object') {
17990 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
17992 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
17993 return parseInt(d, 10);
17996 this.updateNavArrows();
17999 updateNavArrows: function()
18001 if(this.singleMode){
18005 var d = new Date(this.viewDate),
18006 year = d.getUTCFullYear(),
18007 month = d.getUTCMonth();
18009 Roo.each(this.picker().select('.prev', true).elements, function(v){
18011 switch (this.viewMode) {
18014 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18020 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18027 Roo.each(this.picker().select('.next', true).elements, function(v){
18029 switch (this.viewMode) {
18032 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18038 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18046 moveMonth: function(date, dir)
18051 var new_date = new Date(date.valueOf()),
18052 day = new_date.getUTCDate(),
18053 month = new_date.getUTCMonth(),
18054 mag = Math.abs(dir),
18056 dir = dir > 0 ? 1 : -1;
18059 // If going back one month, make sure month is not current month
18060 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18062 return new_date.getUTCMonth() == month;
18064 // If going forward one month, make sure month is as expected
18065 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18067 return new_date.getUTCMonth() != new_month;
18069 new_month = month + dir;
18070 new_date.setUTCMonth(new_month);
18071 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18072 if (new_month < 0 || new_month > 11) {
18073 new_month = (new_month + 12) % 12;
18076 // For magnitudes >1, move one month at a time...
18077 for (var i=0; i<mag; i++) {
18078 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18079 new_date = this.moveMonth(new_date, dir);
18081 // ...then reset the day, keeping it in the new month
18082 new_month = new_date.getUTCMonth();
18083 new_date.setUTCDate(day);
18085 return new_month != new_date.getUTCMonth();
18088 // Common date-resetting loop -- if date is beyond end of month, make it
18091 new_date.setUTCDate(--day);
18092 new_date.setUTCMonth(new_month);
18097 moveYear: function(date, dir)
18099 return this.moveMonth(date, dir*12);
18102 dateWithinRange: function(date)
18104 return date >= this.startDate && date <= this.endDate;
18110 this.picker().remove();
18115 Roo.apply(Roo.bootstrap.DateField, {
18126 html: '<i class="fa fa-arrow-left"/>'
18136 html: '<i class="fa fa-arrow-right"/>'
18178 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18179 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18180 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18181 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18182 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18195 navFnc: 'FullYear',
18200 navFnc: 'FullYear',
18205 Roo.apply(Roo.bootstrap.DateField, {
18209 cls: 'datepicker dropdown-menu roo-dynamic',
18213 cls: 'datepicker-days',
18217 cls: 'table-condensed',
18219 Roo.bootstrap.DateField.head,
18223 Roo.bootstrap.DateField.footer
18230 cls: 'datepicker-months',
18234 cls: 'table-condensed',
18236 Roo.bootstrap.DateField.head,
18237 Roo.bootstrap.DateField.content,
18238 Roo.bootstrap.DateField.footer
18245 cls: 'datepicker-years',
18249 cls: 'table-condensed',
18251 Roo.bootstrap.DateField.head,
18252 Roo.bootstrap.DateField.content,
18253 Roo.bootstrap.DateField.footer
18272 * @class Roo.bootstrap.TimeField
18273 * @extends Roo.bootstrap.Input
18274 * Bootstrap DateField class
18278 * Create a new TimeField
18279 * @param {Object} config The config object
18282 Roo.bootstrap.TimeField = function(config){
18283 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
18287 * Fires when this field show.
18288 * @param {Roo.bootstrap.DateField} thisthis
18289 * @param {Mixed} date The date value
18294 * Fires when this field hide.
18295 * @param {Roo.bootstrap.DateField} this
18296 * @param {Mixed} date The date value
18301 * Fires when select a date.
18302 * @param {Roo.bootstrap.DateField} this
18303 * @param {Mixed} date The date value
18309 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
18312 * @cfg {String} format
18313 * The default time format string which can be overriden for localization support. The format must be
18314 * valid according to {@link Date#parseDate} (defaults to 'H:i').
18318 onRender: function(ct, position)
18321 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
18323 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
18325 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18327 this.pop = this.picker().select('>.datepicker-time',true).first();
18328 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18330 this.picker().on('mousedown', this.onMousedown, this);
18331 this.picker().on('click', this.onClick, this);
18333 this.picker().addClass('datepicker-dropdown');
18338 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
18339 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
18340 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
18341 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
18342 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
18343 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
18347 fireKey: function(e){
18348 if (!this.picker().isVisible()){
18349 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18355 e.preventDefault();
18363 this.onTogglePeriod();
18366 this.onIncrementMinutes();
18369 this.onDecrementMinutes();
18378 onClick: function(e) {
18379 e.stopPropagation();
18380 e.preventDefault();
18383 picker : function()
18385 return this.el.select('.datepicker', true).first();
18388 fillTime: function()
18390 var time = this.pop.select('tbody', true).first();
18392 time.dom.innerHTML = '';
18407 cls: 'hours-up glyphicon glyphicon-chevron-up'
18427 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18448 cls: 'timepicker-hour',
18463 cls: 'timepicker-minute',
18478 cls: 'btn btn-primary period',
18500 cls: 'hours-down glyphicon glyphicon-chevron-down'
18520 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18538 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18545 var hours = this.time.getHours();
18546 var minutes = this.time.getMinutes();
18559 hours = hours - 12;
18563 hours = '0' + hours;
18567 minutes = '0' + minutes;
18570 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18571 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18572 this.pop.select('button', true).first().dom.innerHTML = period;
18578 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18580 var cls = ['bottom'];
18582 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18589 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18594 this.picker().addClass(cls.join('-'));
18598 Roo.each(cls, function(c){
18600 _this.picker().setTop(_this.inputEl().getHeight());
18604 _this.picker().setTop(0 - _this.picker().getHeight());
18609 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18613 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18620 onFocus : function()
18622 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18626 onBlur : function()
18628 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18634 this.picker().show();
18639 this.fireEvent('show', this, this.date);
18644 this.picker().hide();
18647 this.fireEvent('hide', this, this.date);
18650 setTime : function()
18653 this.setValue(this.time.format(this.format));
18655 this.fireEvent('select', this, this.date);
18660 onMousedown: function(e){
18661 e.stopPropagation();
18662 e.preventDefault();
18665 onIncrementHours: function()
18667 Roo.log('onIncrementHours');
18668 this.time = this.time.add(Date.HOUR, 1);
18673 onDecrementHours: function()
18675 Roo.log('onDecrementHours');
18676 this.time = this.time.add(Date.HOUR, -1);
18680 onIncrementMinutes: function()
18682 Roo.log('onIncrementMinutes');
18683 this.time = this.time.add(Date.MINUTE, 1);
18687 onDecrementMinutes: function()
18689 Roo.log('onDecrementMinutes');
18690 this.time = this.time.add(Date.MINUTE, -1);
18694 onTogglePeriod: function()
18696 Roo.log('onTogglePeriod');
18697 this.time = this.time.add(Date.HOUR, 12);
18704 Roo.apply(Roo.bootstrap.TimeField, {
18734 cls: 'btn btn-info ok',
18746 Roo.apply(Roo.bootstrap.TimeField, {
18750 cls: 'datepicker dropdown-menu',
18754 cls: 'datepicker-time',
18758 cls: 'table-condensed',
18760 Roo.bootstrap.TimeField.content,
18761 Roo.bootstrap.TimeField.footer
18780 * @class Roo.bootstrap.MonthField
18781 * @extends Roo.bootstrap.Input
18782 * Bootstrap MonthField class
18784 * @cfg {String} language default en
18787 * Create a new MonthField
18788 * @param {Object} config The config object
18791 Roo.bootstrap.MonthField = function(config){
18792 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
18797 * Fires when this field show.
18798 * @param {Roo.bootstrap.MonthField} this
18799 * @param {Mixed} date The date value
18804 * Fires when this field hide.
18805 * @param {Roo.bootstrap.MonthField} this
18806 * @param {Mixed} date The date value
18811 * Fires when select a date.
18812 * @param {Roo.bootstrap.MonthField} this
18813 * @param {String} oldvalue The old value
18814 * @param {String} newvalue The new value
18820 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
18822 onRender: function(ct, position)
18825 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
18827 this.language = this.language || 'en';
18828 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
18829 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
18831 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
18832 this.isInline = false;
18833 this.isInput = true;
18834 this.component = this.el.select('.add-on', true).first() || false;
18835 this.component = (this.component && this.component.length === 0) ? false : this.component;
18836 this.hasInput = this.component && this.inputEL().length;
18838 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
18840 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18842 this.picker().on('mousedown', this.onMousedown, this);
18843 this.picker().on('click', this.onClick, this);
18845 this.picker().addClass('datepicker-dropdown');
18847 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18848 v.setStyle('width', '189px');
18855 if(this.isInline) {
18861 setValue: function(v, suppressEvent)
18863 var o = this.getValue();
18865 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
18869 if(suppressEvent !== true){
18870 this.fireEvent('select', this, o, v);
18875 getValue: function()
18880 onClick: function(e)
18882 e.stopPropagation();
18883 e.preventDefault();
18885 var target = e.getTarget();
18887 if(target.nodeName.toLowerCase() === 'i'){
18888 target = Roo.get(target).dom.parentNode;
18891 var nodeName = target.nodeName;
18892 var className = target.className;
18893 var html = target.innerHTML;
18895 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
18899 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
18901 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18907 picker : function()
18909 return this.pickerEl;
18912 fillMonths: function()
18915 var months = this.picker().select('>.datepicker-months td', true).first();
18917 months.dom.innerHTML = '';
18923 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
18926 months.createChild(month);
18935 if(typeof(this.vIndex) == 'undefined' && this.value.length){
18936 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
18939 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
18940 e.removeClass('active');
18942 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
18943 e.addClass('active');
18950 if(this.isInline) {
18954 this.picker().removeClass(['bottom', 'top']);
18956 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18958 * place to the top of element!
18962 this.picker().addClass('top');
18963 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18968 this.picker().addClass('bottom');
18970 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18973 onFocus : function()
18975 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
18979 onBlur : function()
18981 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
18983 var d = this.inputEl().getValue();
18992 this.picker().show();
18993 this.picker().select('>.datepicker-months', true).first().show();
18997 this.fireEvent('show', this, this.date);
19002 if(this.isInline) {
19005 this.picker().hide();
19006 this.fireEvent('hide', this, this.date);
19010 onMousedown: function(e)
19012 e.stopPropagation();
19013 e.preventDefault();
19018 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19022 fireKey: function(e)
19024 if (!this.picker().isVisible()){
19025 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19036 e.preventDefault();
19040 dir = e.keyCode == 37 ? -1 : 1;
19042 this.vIndex = this.vIndex + dir;
19044 if(this.vIndex < 0){
19048 if(this.vIndex > 11){
19052 if(isNaN(this.vIndex)){
19056 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19062 dir = e.keyCode == 38 ? -1 : 1;
19064 this.vIndex = this.vIndex + dir * 4;
19066 if(this.vIndex < 0){
19070 if(this.vIndex > 11){
19074 if(isNaN(this.vIndex)){
19078 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19083 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19084 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19088 e.preventDefault();
19091 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19092 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19108 this.picker().remove();
19113 Roo.apply(Roo.bootstrap.MonthField, {
19132 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19133 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19138 Roo.apply(Roo.bootstrap.MonthField, {
19142 cls: 'datepicker dropdown-menu roo-dynamic',
19146 cls: 'datepicker-months',
19150 cls: 'table-condensed',
19152 Roo.bootstrap.DateField.content
19172 * @class Roo.bootstrap.CheckBox
19173 * @extends Roo.bootstrap.Input
19174 * Bootstrap CheckBox class
19176 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19177 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19178 * @cfg {String} boxLabel The text that appears beside the checkbox
19179 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19180 * @cfg {Boolean} checked initnal the element
19181 * @cfg {Boolean} inline inline the element (default false)
19182 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19185 * Create a new CheckBox
19186 * @param {Object} config The config object
19189 Roo.bootstrap.CheckBox = function(config){
19190 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19195 * Fires when the element is checked or unchecked.
19196 * @param {Roo.bootstrap.CheckBox} this This input
19197 * @param {Boolean} checked The new checked value
19204 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19206 inputType: 'checkbox',
19214 getAutoCreate : function()
19216 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19222 cfg.cls = 'form-group ' + this.inputType; //input-group
19225 cfg.cls += ' ' + this.inputType + '-inline';
19231 type : this.inputType,
19232 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
19233 cls : 'roo-' + this.inputType, //'form-box',
19234 placeholder : this.placeholder || ''
19238 if (this.weight) { // Validity check?
19239 cfg.cls += " " + this.inputType + "-" + this.weight;
19242 if (this.disabled) {
19243 input.disabled=true;
19247 input.checked = this.checked;
19251 input.name = this.name;
19255 input.cls += ' input-' + this.size;
19260 ['xs','sm','md','lg'].map(function(size){
19261 if (settings[size]) {
19262 cfg.cls += ' col-' + size + '-' + settings[size];
19266 var inputblock = input;
19268 if (this.before || this.after) {
19271 cls : 'input-group',
19276 inputblock.cn.push({
19278 cls : 'input-group-addon',
19283 inputblock.cn.push(input);
19286 inputblock.cn.push({
19288 cls : 'input-group-addon',
19295 if (align ==='left' && this.fieldLabel.length) {
19296 // Roo.log("left and has label");
19302 cls : 'control-label col-md-' + this.labelWidth,
19303 html : this.fieldLabel
19307 cls : "col-md-" + (12 - this.labelWidth),
19314 } else if ( this.fieldLabel.length) {
19315 // Roo.log(" label");
19319 tag: this.boxLabel ? 'span' : 'label',
19321 cls: 'control-label box-input-label',
19322 //cls : 'input-group-addon',
19323 html : this.fieldLabel
19333 // Roo.log(" no label && no align");
19334 cfg.cn = [ inputblock ] ;
19340 var boxLabelCfg = {
19342 //'for': id, // box label is handled by onclick - so no for...
19344 html: this.boxLabel
19348 boxLabelCfg.tooltip = this.tooltip;
19351 cfg.cn.push(boxLabelCfg);
19361 * return the real input element.
19363 inputEl: function ()
19365 return this.el.select('input.roo-' + this.inputType,true).first();
19368 labelEl: function()
19370 return this.el.select('label.control-label',true).first();
19372 /* depricated... */
19376 return this.labelEl();
19379 boxLabelEl: function()
19381 return this.el.select('label.box-label',true).first();
19384 initEvents : function()
19386 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19388 this.inputEl().on('click', this.onClick, this);
19390 if (this.boxLabel) {
19391 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19394 this.startValue = this.getValue();
19397 Roo.bootstrap.CheckBox.register(this);
19401 onClick : function()
19403 this.setChecked(!this.checked);
19406 setChecked : function(state,suppressEvent)
19408 this.startValue = this.getValue();
19410 if(this.inputType == 'radio'){
19412 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19413 e.dom.checked = false;
19416 this.inputEl().dom.checked = true;
19418 this.inputEl().dom.value = this.inputValue;
19420 if(suppressEvent !== true){
19421 this.fireEvent('check', this, true);
19429 this.checked = state;
19431 this.inputEl().dom.checked = state;
19433 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19435 if(suppressEvent !== true){
19436 this.fireEvent('check', this, state);
19442 getValue : function()
19444 if(this.inputType == 'radio'){
19445 return this.getGroupValue();
19448 return this.inputEl().getValue();
19452 getGroupValue : function()
19454 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19458 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19461 setValue : function(v,suppressEvent)
19463 if(this.inputType == 'radio'){
19464 this.setGroupValue(v, suppressEvent);
19468 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19473 setGroupValue : function(v, suppressEvent)
19475 this.startValue = this.getValue();
19477 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19478 e.dom.checked = false;
19480 if(e.dom.value == v){
19481 e.dom.checked = true;
19485 if(suppressEvent !== true){
19486 this.fireEvent('check', this, true);
19494 validate : function()
19498 (this.inputType == 'radio' && this.validateRadio()) ||
19499 (this.inputType == 'checkbox' && this.validateCheckbox())
19505 this.markInvalid();
19509 validateRadio : function()
19513 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19514 if(!e.dom.checked){
19526 validateCheckbox : function()
19529 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19532 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19540 for(var i in group){
19545 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19552 * Mark this field as valid
19554 markValid : function()
19556 if(this.allowBlank){
19562 this.fireEvent('valid', this);
19564 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19567 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19574 if(this.inputType == 'radio'){
19575 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19576 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19577 e.findParent('.form-group', false, true).addClass(_this.validClass);
19584 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19585 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19589 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19595 for(var i in group){
19596 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19597 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19602 * Mark this field as invalid
19603 * @param {String} msg The validation message
19605 markInvalid : function(msg)
19607 if(this.allowBlank){
19613 this.fireEvent('invalid', this, msg);
19615 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19618 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19622 label.markInvalid();
19625 if(this.inputType == 'radio'){
19626 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19627 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19628 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19635 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19636 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19640 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19646 for(var i in group){
19647 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19648 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19655 Roo.apply(Roo.bootstrap.CheckBox, {
19660 * register a CheckBox Group
19661 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19663 register : function(checkbox)
19665 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19666 this.groups[checkbox.groupId] = {};
19669 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19673 this.groups[checkbox.groupId][checkbox.name] = checkbox;
19677 * fetch a CheckBox Group based on the group ID
19678 * @param {string} the group ID
19679 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
19681 get: function(groupId) {
19682 if (typeof(this.groups[groupId]) == 'undefined') {
19686 return this.groups[groupId] ;
19698 *<div class="radio">
19700 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
19701 Option one is this and that—be sure to include why it's great
19708 *<label class="radio-inline">fieldLabel</label>
19709 *<label class="radio-inline">
19710 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
19718 * @class Roo.bootstrap.Radio
19719 * @extends Roo.bootstrap.CheckBox
19720 * Bootstrap Radio class
19723 * Create a new Radio
19724 * @param {Object} config The config object
19727 Roo.bootstrap.Radio = function(config){
19728 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
19732 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
19734 inputType: 'radio',
19738 getAutoCreate : function()
19740 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19741 align = align || 'left'; // default...
19748 tag : this.inline ? 'span' : 'div',
19753 var inline = this.inline ? ' radio-inline' : '';
19757 // does not need for, as we wrap the input with it..
19759 cls : 'control-label box-label' + inline,
19762 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
19766 //cls : 'control-label' + inline,
19767 html : this.fieldLabel,
19768 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
19777 type : this.inputType,
19778 //value : (!this.checked) ? this.valueOff : this.inputValue,
19779 value : this.inputValue,
19781 placeholder : this.placeholder || '' // ?? needed????
19784 if (this.weight) { // Validity check?
19785 input.cls += " radio-" + this.weight;
19787 if (this.disabled) {
19788 input.disabled=true;
19792 input.checked = this.checked;
19796 input.name = this.name;
19800 input.cls += ' input-' + this.size;
19803 //?? can span's inline have a width??
19806 ['xs','sm','md','lg'].map(function(size){
19807 if (settings[size]) {
19808 cfg.cls += ' col-' + size + '-' + settings[size];
19812 var inputblock = input;
19814 if (this.before || this.after) {
19817 cls : 'input-group',
19822 inputblock.cn.push({
19824 cls : 'input-group-addon',
19828 inputblock.cn.push(input);
19830 inputblock.cn.push({
19832 cls : 'input-group-addon',
19840 if (this.fieldLabel && this.fieldLabel.length) {
19841 cfg.cn.push(fieldLabel);
19844 // normal bootstrap puts the input inside the label.
19845 // however with our styled version - it has to go after the input.
19847 //lbl.cn.push(inputblock);
19851 cls: 'radio' + inline,
19858 cfg.cn.push( lblwrap);
19863 html: this.boxLabel
19872 initEvents : function()
19874 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19876 this.inputEl().on('click', this.onClick, this);
19877 if (this.boxLabel) {
19878 //Roo.log('find label');
19879 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
19884 inputEl: function ()
19886 return this.el.select('input.roo-radio',true).first();
19888 onClick : function()
19891 this.setChecked(true);
19894 setChecked : function(state,suppressEvent)
19897 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19898 v.dom.checked = false;
19901 Roo.log(this.inputEl().dom);
19902 this.checked = state;
19903 this.inputEl().dom.checked = state;
19905 if(suppressEvent !== true){
19906 this.fireEvent('check', this, state);
19909 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19913 getGroupValue : function()
19916 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19917 if(v.dom.checked == true){
19918 value = v.dom.value;
19926 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19927 * @return {Mixed} value The field value
19929 getValue : function(){
19930 return this.getGroupValue();
19936 //<script type="text/javascript">
19939 * Based Ext JS Library 1.1.1
19940 * Copyright(c) 2006-2007, Ext JS, LLC.
19946 * @class Roo.HtmlEditorCore
19947 * @extends Roo.Component
19948 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
19950 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
19953 Roo.HtmlEditorCore = function(config){
19956 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
19961 * @event initialize
19962 * Fires when the editor is fully initialized (including the iframe)
19963 * @param {Roo.HtmlEditorCore} this
19968 * Fires when the editor is first receives the focus. Any insertion must wait
19969 * until after this event.
19970 * @param {Roo.HtmlEditorCore} this
19974 * @event beforesync
19975 * Fires before the textarea is updated with content from the editor iframe. Return false
19976 * to cancel the sync.
19977 * @param {Roo.HtmlEditorCore} this
19978 * @param {String} html
19982 * @event beforepush
19983 * Fires before the iframe editor is updated with content from the textarea. Return false
19984 * to cancel the push.
19985 * @param {Roo.HtmlEditorCore} this
19986 * @param {String} html
19991 * Fires when the textarea is updated with content from the editor iframe.
19992 * @param {Roo.HtmlEditorCore} this
19993 * @param {String} html
19998 * Fires when the iframe editor is updated with content from the textarea.
19999 * @param {Roo.HtmlEditorCore} this
20000 * @param {String} html
20005 * @event editorevent
20006 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20007 * @param {Roo.HtmlEditorCore} this
20013 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20015 // defaults : white / black...
20016 this.applyBlacklists();
20023 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20027 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20033 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20038 * @cfg {Number} height (in pixels)
20042 * @cfg {Number} width (in pixels)
20047 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20050 stylesheets: false,
20055 // private properties
20056 validationEvent : false,
20058 initialized : false,
20060 sourceEditMode : false,
20061 onFocus : Roo.emptyFn,
20063 hideMode:'offsets',
20067 // blacklist + whitelisted elements..
20074 * Protected method that will not generally be called directly. It
20075 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20076 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20078 getDocMarkup : function(){
20082 // inherit styels from page...??
20083 if (this.stylesheets === false) {
20085 Roo.get(document.head).select('style').each(function(node) {
20086 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20089 Roo.get(document.head).select('link').each(function(node) {
20090 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20093 } else if (!this.stylesheets.length) {
20095 st = '<style type="text/css">' +
20096 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20102 st += '<style type="text/css">' +
20103 'IMG { cursor: pointer } ' +
20107 return '<html><head>' + st +
20108 //<style type="text/css">' +
20109 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20111 ' </head><body class="roo-htmleditor-body"></body></html>';
20115 onRender : function(ct, position)
20118 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20119 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20122 this.el.dom.style.border = '0 none';
20123 this.el.dom.setAttribute('tabIndex', -1);
20124 this.el.addClass('x-hidden hide');
20128 if(Roo.isIE){ // fix IE 1px bogus margin
20129 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20133 this.frameId = Roo.id();
20137 var iframe = this.owner.wrap.createChild({
20139 cls: 'form-control', // bootstrap..
20141 name: this.frameId,
20142 frameBorder : 'no',
20143 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20148 this.iframe = iframe.dom;
20150 this.assignDocWin();
20152 this.doc.designMode = 'on';
20155 this.doc.write(this.getDocMarkup());
20159 var task = { // must defer to wait for browser to be ready
20161 //console.log("run task?" + this.doc.readyState);
20162 this.assignDocWin();
20163 if(this.doc.body || this.doc.readyState == 'complete'){
20165 this.doc.designMode="on";
20169 Roo.TaskMgr.stop(task);
20170 this.initEditor.defer(10, this);
20177 Roo.TaskMgr.start(task);
20182 onResize : function(w, h)
20184 Roo.log('resize: ' +w + ',' + h );
20185 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20189 if(typeof w == 'number'){
20191 this.iframe.style.width = w + 'px';
20193 if(typeof h == 'number'){
20195 this.iframe.style.height = h + 'px';
20197 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20204 * Toggles the editor between standard and source edit mode.
20205 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20207 toggleSourceEdit : function(sourceEditMode){
20209 this.sourceEditMode = sourceEditMode === true;
20211 if(this.sourceEditMode){
20213 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20216 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20217 //this.iframe.className = '';
20220 //this.setSize(this.owner.wrap.getSize());
20221 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20228 * Protected method that will not generally be called directly. If you need/want
20229 * custom HTML cleanup, this is the method you should override.
20230 * @param {String} html The HTML to be cleaned
20231 * return {String} The cleaned HTML
20233 cleanHtml : function(html){
20234 html = String(html);
20235 if(html.length > 5){
20236 if(Roo.isSafari){ // strip safari nonsense
20237 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20240 if(html == ' '){
20247 * HTML Editor -> Textarea
20248 * Protected method that will not generally be called directly. Syncs the contents
20249 * of the editor iframe with the textarea.
20251 syncValue : function(){
20252 if(this.initialized){
20253 var bd = (this.doc.body || this.doc.documentElement);
20254 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20255 var html = bd.innerHTML;
20257 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20258 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20260 html = '<div style="'+m[0]+'">' + html + '</div>';
20263 html = this.cleanHtml(html);
20264 // fix up the special chars.. normaly like back quotes in word...
20265 // however we do not want to do this with chinese..
20266 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20267 var cc = b.charCodeAt();
20269 (cc >= 0x4E00 && cc < 0xA000 ) ||
20270 (cc >= 0x3400 && cc < 0x4E00 ) ||
20271 (cc >= 0xf900 && cc < 0xfb00 )
20277 if(this.owner.fireEvent('beforesync', this, html) !== false){
20278 this.el.dom.value = html;
20279 this.owner.fireEvent('sync', this, html);
20285 * Protected method that will not generally be called directly. Pushes the value of the textarea
20286 * into the iframe editor.
20288 pushValue : function(){
20289 if(this.initialized){
20290 var v = this.el.dom.value.trim();
20292 // if(v.length < 1){
20296 if(this.owner.fireEvent('beforepush', this, v) !== false){
20297 var d = (this.doc.body || this.doc.documentElement);
20299 this.cleanUpPaste();
20300 this.el.dom.value = d.innerHTML;
20301 this.owner.fireEvent('push', this, v);
20307 deferFocus : function(){
20308 this.focus.defer(10, this);
20312 focus : function(){
20313 if(this.win && !this.sourceEditMode){
20320 assignDocWin: function()
20322 var iframe = this.iframe;
20325 this.doc = iframe.contentWindow.document;
20326 this.win = iframe.contentWindow;
20328 // if (!Roo.get(this.frameId)) {
20331 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20332 // this.win = Roo.get(this.frameId).dom.contentWindow;
20334 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
20338 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
20339 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
20344 initEditor : function(){
20345 //console.log("INIT EDITOR");
20346 this.assignDocWin();
20350 this.doc.designMode="on";
20352 this.doc.write(this.getDocMarkup());
20355 var dbody = (this.doc.body || this.doc.documentElement);
20356 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20357 // this copies styles from the containing element into thsi one..
20358 // not sure why we need all of this..
20359 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20361 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20362 //ss['background-attachment'] = 'fixed'; // w3c
20363 dbody.bgProperties = 'fixed'; // ie
20364 //Roo.DomHelper.applyStyles(dbody, ss);
20365 Roo.EventManager.on(this.doc, {
20366 //'mousedown': this.onEditorEvent,
20367 'mouseup': this.onEditorEvent,
20368 'dblclick': this.onEditorEvent,
20369 'click': this.onEditorEvent,
20370 'keyup': this.onEditorEvent,
20375 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20377 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20378 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20380 this.initialized = true;
20382 this.owner.fireEvent('initialize', this);
20387 onDestroy : function(){
20393 //for (var i =0; i < this.toolbars.length;i++) {
20394 // // fixme - ask toolbars for heights?
20395 // this.toolbars[i].onDestroy();
20398 //this.wrap.dom.innerHTML = '';
20399 //this.wrap.remove();
20404 onFirstFocus : function(){
20406 this.assignDocWin();
20409 this.activated = true;
20412 if(Roo.isGecko){ // prevent silly gecko errors
20414 var s = this.win.getSelection();
20415 if(!s.focusNode || s.focusNode.nodeType != 3){
20416 var r = s.getRangeAt(0);
20417 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20422 this.execCmd('useCSS', true);
20423 this.execCmd('styleWithCSS', false);
20426 this.owner.fireEvent('activate', this);
20430 adjustFont: function(btn){
20431 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20432 //if(Roo.isSafari){ // safari
20435 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20436 if(Roo.isSafari){ // safari
20437 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20438 v = (v < 10) ? 10 : v;
20439 v = (v > 48) ? 48 : v;
20440 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20445 v = Math.max(1, v+adjust);
20447 this.execCmd('FontSize', v );
20450 onEditorEvent : function(e)
20452 this.owner.fireEvent('editorevent', this, e);
20453 // this.updateToolbar();
20454 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20457 insertTag : function(tg)
20459 // could be a bit smarter... -> wrap the current selected tRoo..
20460 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20462 range = this.createRange(this.getSelection());
20463 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20464 wrappingNode.appendChild(range.extractContents());
20465 range.insertNode(wrappingNode);
20472 this.execCmd("formatblock", tg);
20476 insertText : function(txt)
20480 var range = this.createRange();
20481 range.deleteContents();
20482 //alert(Sender.getAttribute('label'));
20484 range.insertNode(this.doc.createTextNode(txt));
20490 * Executes a Midas editor command on the editor document and performs necessary focus and
20491 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20492 * @param {String} cmd The Midas command
20493 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20495 relayCmd : function(cmd, value){
20497 this.execCmd(cmd, value);
20498 this.owner.fireEvent('editorevent', this);
20499 //this.updateToolbar();
20500 this.owner.deferFocus();
20504 * Executes a Midas editor command directly on the editor document.
20505 * For visual commands, you should use {@link #relayCmd} instead.
20506 * <b>This should only be called after the editor is initialized.</b>
20507 * @param {String} cmd The Midas command
20508 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20510 execCmd : function(cmd, value){
20511 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20518 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20520 * @param {String} text | dom node..
20522 insertAtCursor : function(text)
20527 if(!this.activated){
20533 var r = this.doc.selection.createRange();
20544 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20548 // from jquery ui (MIT licenced)
20550 var win = this.win;
20552 if (win.getSelection && win.getSelection().getRangeAt) {
20553 range = win.getSelection().getRangeAt(0);
20554 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20555 range.insertNode(node);
20556 } else if (win.document.selection && win.document.selection.createRange) {
20557 // no firefox support
20558 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20559 win.document.selection.createRange().pasteHTML(txt);
20561 // no firefox support
20562 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20563 this.execCmd('InsertHTML', txt);
20572 mozKeyPress : function(e){
20574 var c = e.getCharCode(), cmd;
20577 c = String.fromCharCode(c).toLowerCase();
20591 this.cleanUpPaste.defer(100, this);
20599 e.preventDefault();
20607 fixKeys : function(){ // load time branching for fastest keydown performance
20609 return function(e){
20610 var k = e.getKey(), r;
20613 r = this.doc.selection.createRange();
20616 r.pasteHTML('    ');
20623 r = this.doc.selection.createRange();
20625 var target = r.parentElement();
20626 if(!target || target.tagName.toLowerCase() != 'li'){
20628 r.pasteHTML('<br />');
20634 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20635 this.cleanUpPaste.defer(100, this);
20641 }else if(Roo.isOpera){
20642 return function(e){
20643 var k = e.getKey();
20647 this.execCmd('InsertHTML','    ');
20650 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20651 this.cleanUpPaste.defer(100, this);
20656 }else if(Roo.isSafari){
20657 return function(e){
20658 var k = e.getKey();
20662 this.execCmd('InsertText','\t');
20666 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20667 this.cleanUpPaste.defer(100, this);
20675 getAllAncestors: function()
20677 var p = this.getSelectedNode();
20680 a.push(p); // push blank onto stack..
20681 p = this.getParentElement();
20685 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
20689 a.push(this.doc.body);
20693 lastSelNode : false,
20696 getSelection : function()
20698 this.assignDocWin();
20699 return Roo.isIE ? this.doc.selection : this.win.getSelection();
20702 getSelectedNode: function()
20704 // this may only work on Gecko!!!
20706 // should we cache this!!!!
20711 var range = this.createRange(this.getSelection()).cloneRange();
20714 var parent = range.parentElement();
20716 var testRange = range.duplicate();
20717 testRange.moveToElementText(parent);
20718 if (testRange.inRange(range)) {
20721 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
20724 parent = parent.parentElement;
20729 // is ancestor a text element.
20730 var ac = range.commonAncestorContainer;
20731 if (ac.nodeType == 3) {
20732 ac = ac.parentNode;
20735 var ar = ac.childNodes;
20738 var other_nodes = [];
20739 var has_other_nodes = false;
20740 for (var i=0;i<ar.length;i++) {
20741 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
20744 // fullly contained node.
20746 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
20751 // probably selected..
20752 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
20753 other_nodes.push(ar[i]);
20757 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
20762 has_other_nodes = true;
20764 if (!nodes.length && other_nodes.length) {
20765 nodes= other_nodes;
20767 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
20773 createRange: function(sel)
20775 // this has strange effects when using with
20776 // top toolbar - not sure if it's a great idea.
20777 //this.editor.contentWindow.focus();
20778 if (typeof sel != "undefined") {
20780 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
20782 return this.doc.createRange();
20785 return this.doc.createRange();
20788 getParentElement: function()
20791 this.assignDocWin();
20792 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
20794 var range = this.createRange(sel);
20797 var p = range.commonAncestorContainer;
20798 while (p.nodeType == 3) { // text node
20809 * Range intersection.. the hard stuff...
20813 * [ -- selected range --- ]
20817 * if end is before start or hits it. fail.
20818 * if start is after end or hits it fail.
20820 * if either hits (but other is outside. - then it's not
20826 // @see http://www.thismuchiknow.co.uk/?p=64.
20827 rangeIntersectsNode : function(range, node)
20829 var nodeRange = node.ownerDocument.createRange();
20831 nodeRange.selectNode(node);
20833 nodeRange.selectNodeContents(node);
20836 var rangeStartRange = range.cloneRange();
20837 rangeStartRange.collapse(true);
20839 var rangeEndRange = range.cloneRange();
20840 rangeEndRange.collapse(false);
20842 var nodeStartRange = nodeRange.cloneRange();
20843 nodeStartRange.collapse(true);
20845 var nodeEndRange = nodeRange.cloneRange();
20846 nodeEndRange.collapse(false);
20848 return rangeStartRange.compareBoundaryPoints(
20849 Range.START_TO_START, nodeEndRange) == -1 &&
20850 rangeEndRange.compareBoundaryPoints(
20851 Range.START_TO_START, nodeStartRange) == 1;
20855 rangeCompareNode : function(range, node)
20857 var nodeRange = node.ownerDocument.createRange();
20859 nodeRange.selectNode(node);
20861 nodeRange.selectNodeContents(node);
20865 range.collapse(true);
20867 nodeRange.collapse(true);
20869 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
20870 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
20872 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
20874 var nodeIsBefore = ss == 1;
20875 var nodeIsAfter = ee == -1;
20877 if (nodeIsBefore && nodeIsAfter) {
20880 if (!nodeIsBefore && nodeIsAfter) {
20881 return 1; //right trailed.
20884 if (nodeIsBefore && !nodeIsAfter) {
20885 return 2; // left trailed.
20891 // private? - in a new class?
20892 cleanUpPaste : function()
20894 // cleans up the whole document..
20895 Roo.log('cleanuppaste');
20897 this.cleanUpChildren(this.doc.body);
20898 var clean = this.cleanWordChars(this.doc.body.innerHTML);
20899 if (clean != this.doc.body.innerHTML) {
20900 this.doc.body.innerHTML = clean;
20905 cleanWordChars : function(input) {// change the chars to hex code
20906 var he = Roo.HtmlEditorCore;
20908 var output = input;
20909 Roo.each(he.swapCodes, function(sw) {
20910 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
20912 output = output.replace(swapper, sw[1]);
20919 cleanUpChildren : function (n)
20921 if (!n.childNodes.length) {
20924 for (var i = n.childNodes.length-1; i > -1 ; i--) {
20925 this.cleanUpChild(n.childNodes[i]);
20932 cleanUpChild : function (node)
20935 //console.log(node);
20936 if (node.nodeName == "#text") {
20937 // clean up silly Windows -- stuff?
20940 if (node.nodeName == "#comment") {
20941 node.parentNode.removeChild(node);
20942 // clean up silly Windows -- stuff?
20945 var lcname = node.tagName.toLowerCase();
20946 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
20947 // whitelist of tags..
20949 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
20951 node.parentNode.removeChild(node);
20956 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
20958 // remove <a name=....> as rendering on yahoo mailer is borked with this.
20959 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
20961 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
20962 // remove_keep_children = true;
20965 if (remove_keep_children) {
20966 this.cleanUpChildren(node);
20967 // inserts everything just before this node...
20968 while (node.childNodes.length) {
20969 var cn = node.childNodes[0];
20970 node.removeChild(cn);
20971 node.parentNode.insertBefore(cn, node);
20973 node.parentNode.removeChild(node);
20977 if (!node.attributes || !node.attributes.length) {
20978 this.cleanUpChildren(node);
20982 function cleanAttr(n,v)
20985 if (v.match(/^\./) || v.match(/^\//)) {
20988 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
20991 if (v.match(/^#/)) {
20994 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
20995 node.removeAttribute(n);
20999 var cwhite = this.cwhite;
21000 var cblack = this.cblack;
21002 function cleanStyle(n,v)
21004 if (v.match(/expression/)) { //XSS?? should we even bother..
21005 node.removeAttribute(n);
21009 var parts = v.split(/;/);
21012 Roo.each(parts, function(p) {
21013 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21017 var l = p.split(':').shift().replace(/\s+/g,'');
21018 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21020 if ( cwhite.length && cblack.indexOf(l) > -1) {
21021 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21022 //node.removeAttribute(n);
21026 // only allow 'c whitelisted system attributes'
21027 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21028 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21029 //node.removeAttribute(n);
21039 if (clean.length) {
21040 node.setAttribute(n, clean.join(';'));
21042 node.removeAttribute(n);
21048 for (var i = node.attributes.length-1; i > -1 ; i--) {
21049 var a = node.attributes[i];
21052 if (a.name.toLowerCase().substr(0,2)=='on') {
21053 node.removeAttribute(a.name);
21056 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21057 node.removeAttribute(a.name);
21060 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21061 cleanAttr(a.name,a.value); // fixme..
21064 if (a.name == 'style') {
21065 cleanStyle(a.name,a.value);
21068 /// clean up MS crap..
21069 // tecnically this should be a list of valid class'es..
21072 if (a.name == 'class') {
21073 if (a.value.match(/^Mso/)) {
21074 node.className = '';
21077 if (a.value.match(/body/)) {
21078 node.className = '';
21089 this.cleanUpChildren(node);
21095 * Clean up MS wordisms...
21097 cleanWord : function(node)
21102 this.cleanWord(this.doc.body);
21105 if (node.nodeName == "#text") {
21106 // clean up silly Windows -- stuff?
21109 if (node.nodeName == "#comment") {
21110 node.parentNode.removeChild(node);
21111 // clean up silly Windows -- stuff?
21115 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21116 node.parentNode.removeChild(node);
21120 // remove - but keep children..
21121 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21122 while (node.childNodes.length) {
21123 var cn = node.childNodes[0];
21124 node.removeChild(cn);
21125 node.parentNode.insertBefore(cn, node);
21127 node.parentNode.removeChild(node);
21128 this.iterateChildren(node, this.cleanWord);
21132 if (node.className.length) {
21134 var cn = node.className.split(/\W+/);
21136 Roo.each(cn, function(cls) {
21137 if (cls.match(/Mso[a-zA-Z]+/)) {
21142 node.className = cna.length ? cna.join(' ') : '';
21144 node.removeAttribute("class");
21148 if (node.hasAttribute("lang")) {
21149 node.removeAttribute("lang");
21152 if (node.hasAttribute("style")) {
21154 var styles = node.getAttribute("style").split(";");
21156 Roo.each(styles, function(s) {
21157 if (!s.match(/:/)) {
21160 var kv = s.split(":");
21161 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21164 // what ever is left... we allow.
21167 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21168 if (!nstyle.length) {
21169 node.removeAttribute('style');
21172 this.iterateChildren(node, this.cleanWord);
21178 * iterateChildren of a Node, calling fn each time, using this as the scole..
21179 * @param {DomNode} node node to iterate children of.
21180 * @param {Function} fn method of this class to call on each item.
21182 iterateChildren : function(node, fn)
21184 if (!node.childNodes.length) {
21187 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21188 fn.call(this, node.childNodes[i])
21194 * cleanTableWidths.
21196 * Quite often pasting from word etc.. results in tables with column and widths.
21197 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21200 cleanTableWidths : function(node)
21205 this.cleanTableWidths(this.doc.body);
21210 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21213 Roo.log(node.tagName);
21214 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21215 this.iterateChildren(node, this.cleanTableWidths);
21218 if (node.hasAttribute('width')) {
21219 node.removeAttribute('width');
21223 if (node.hasAttribute("style")) {
21226 var styles = node.getAttribute("style").split(";");
21228 Roo.each(styles, function(s) {
21229 if (!s.match(/:/)) {
21232 var kv = s.split(":");
21233 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21236 // what ever is left... we allow.
21239 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21240 if (!nstyle.length) {
21241 node.removeAttribute('style');
21245 this.iterateChildren(node, this.cleanTableWidths);
21253 domToHTML : function(currentElement, depth, nopadtext) {
21255 depth = depth || 0;
21256 nopadtext = nopadtext || false;
21258 if (!currentElement) {
21259 return this.domToHTML(this.doc.body);
21262 //Roo.log(currentElement);
21264 var allText = false;
21265 var nodeName = currentElement.nodeName;
21266 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21268 if (nodeName == '#text') {
21270 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21275 if (nodeName != 'BODY') {
21278 // Prints the node tagName, such as <A>, <IMG>, etc
21281 for(i = 0; i < currentElement.attributes.length;i++) {
21283 var aname = currentElement.attributes.item(i).name;
21284 if (!currentElement.attributes.item(i).value.length) {
21287 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21290 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
21299 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
21302 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
21307 // Traverse the tree
21309 var currentElementChild = currentElement.childNodes.item(i);
21310 var allText = true;
21311 var innerHTML = '';
21313 while (currentElementChild) {
21314 // Formatting code (indent the tree so it looks nice on the screen)
21315 var nopad = nopadtext;
21316 if (lastnode == 'SPAN') {
21320 if (currentElementChild.nodeName == '#text') {
21321 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
21322 toadd = nopadtext ? toadd : toadd.trim();
21323 if (!nopad && toadd.length > 80) {
21324 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
21326 innerHTML += toadd;
21329 currentElementChild = currentElement.childNodes.item(i);
21335 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
21337 // Recursively traverse the tree structure of the child node
21338 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
21339 lastnode = currentElementChild.nodeName;
21341 currentElementChild=currentElement.childNodes.item(i);
21347 // The remaining code is mostly for formatting the tree
21348 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
21353 ret+= "</"+tagName+">";
21359 applyBlacklists : function()
21361 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21362 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21366 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21367 if (b.indexOf(tag) > -1) {
21370 this.white.push(tag);
21374 Roo.each(w, function(tag) {
21375 if (b.indexOf(tag) > -1) {
21378 if (this.white.indexOf(tag) > -1) {
21381 this.white.push(tag);
21386 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21387 if (w.indexOf(tag) > -1) {
21390 this.black.push(tag);
21394 Roo.each(b, function(tag) {
21395 if (w.indexOf(tag) > -1) {
21398 if (this.black.indexOf(tag) > -1) {
21401 this.black.push(tag);
21406 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21407 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21411 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21412 if (b.indexOf(tag) > -1) {
21415 this.cwhite.push(tag);
21419 Roo.each(w, function(tag) {
21420 if (b.indexOf(tag) > -1) {
21423 if (this.cwhite.indexOf(tag) > -1) {
21426 this.cwhite.push(tag);
21431 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21432 if (w.indexOf(tag) > -1) {
21435 this.cblack.push(tag);
21439 Roo.each(b, function(tag) {
21440 if (w.indexOf(tag) > -1) {
21443 if (this.cblack.indexOf(tag) > -1) {
21446 this.cblack.push(tag);
21451 setStylesheets : function(stylesheets)
21453 if(typeof(stylesheets) == 'string'){
21454 Roo.get(this.iframe.contentDocument.head).createChild({
21456 rel : 'stylesheet',
21465 Roo.each(stylesheets, function(s) {
21470 Roo.get(_this.iframe.contentDocument.head).createChild({
21472 rel : 'stylesheet',
21481 removeStylesheets : function()
21485 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21490 // hide stuff that is not compatible
21504 * @event specialkey
21508 * @cfg {String} fieldClass @hide
21511 * @cfg {String} focusClass @hide
21514 * @cfg {String} autoCreate @hide
21517 * @cfg {String} inputType @hide
21520 * @cfg {String} invalidClass @hide
21523 * @cfg {String} invalidText @hide
21526 * @cfg {String} msgFx @hide
21529 * @cfg {String} validateOnBlur @hide
21533 Roo.HtmlEditorCore.white = [
21534 'area', 'br', 'img', 'input', 'hr', 'wbr',
21536 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21537 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21538 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21539 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21540 'table', 'ul', 'xmp',
21542 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21545 'dir', 'menu', 'ol', 'ul', 'dl',
21551 Roo.HtmlEditorCore.black = [
21552 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21554 'base', 'basefont', 'bgsound', 'blink', 'body',
21555 'frame', 'frameset', 'head', 'html', 'ilayer',
21556 'iframe', 'layer', 'link', 'meta', 'object',
21557 'script', 'style' ,'title', 'xml' // clean later..
21559 Roo.HtmlEditorCore.clean = [
21560 'script', 'style', 'title', 'xml'
21562 Roo.HtmlEditorCore.remove = [
21567 Roo.HtmlEditorCore.ablack = [
21571 Roo.HtmlEditorCore.aclean = [
21572 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21576 Roo.HtmlEditorCore.pwhite= [
21577 'http', 'https', 'mailto'
21580 // white listed style attributes.
21581 Roo.HtmlEditorCore.cwhite= [
21582 // 'text-align', /// default is to allow most things..
21588 // black listed style attributes.
21589 Roo.HtmlEditorCore.cblack= [
21590 // 'font-size' -- this can be set by the project
21594 Roo.HtmlEditorCore.swapCodes =[
21613 * @class Roo.bootstrap.HtmlEditor
21614 * @extends Roo.bootstrap.TextArea
21615 * Bootstrap HtmlEditor class
21618 * Create a new HtmlEditor
21619 * @param {Object} config The config object
21622 Roo.bootstrap.HtmlEditor = function(config){
21623 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21624 if (!this.toolbars) {
21625 this.toolbars = [];
21627 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21630 * @event initialize
21631 * Fires when the editor is fully initialized (including the iframe)
21632 * @param {HtmlEditor} this
21637 * Fires when the editor is first receives the focus. Any insertion must wait
21638 * until after this event.
21639 * @param {HtmlEditor} this
21643 * @event beforesync
21644 * Fires before the textarea is updated with content from the editor iframe. Return false
21645 * to cancel the sync.
21646 * @param {HtmlEditor} this
21647 * @param {String} html
21651 * @event beforepush
21652 * Fires before the iframe editor is updated with content from the textarea. Return false
21653 * to cancel the push.
21654 * @param {HtmlEditor} this
21655 * @param {String} html
21660 * Fires when the textarea is updated with content from the editor iframe.
21661 * @param {HtmlEditor} this
21662 * @param {String} html
21667 * Fires when the iframe editor is updated with content from the textarea.
21668 * @param {HtmlEditor} this
21669 * @param {String} html
21673 * @event editmodechange
21674 * Fires when the editor switches edit modes
21675 * @param {HtmlEditor} this
21676 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21678 editmodechange: true,
21680 * @event editorevent
21681 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21682 * @param {HtmlEditor} this
21686 * @event firstfocus
21687 * Fires when on first focus - needed by toolbars..
21688 * @param {HtmlEditor} this
21693 * Auto save the htmlEditor value as a file into Events
21694 * @param {HtmlEditor} this
21698 * @event savedpreview
21699 * preview the saved version of htmlEditor
21700 * @param {HtmlEditor} this
21707 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
21711 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
21716 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21721 * @cfg {Number} height (in pixels)
21725 * @cfg {Number} width (in pixels)
21730 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21733 stylesheets: false,
21738 // private properties
21739 validationEvent : false,
21741 initialized : false,
21744 onFocus : Roo.emptyFn,
21746 hideMode:'offsets',
21749 tbContainer : false,
21751 toolbarContainer :function() {
21752 return this.wrap.select('.x-html-editor-tb',true).first();
21756 * Protected method that will not generally be called directly. It
21757 * is called when the editor creates its toolbar. Override this method if you need to
21758 * add custom toolbar buttons.
21759 * @param {HtmlEditor} editor
21761 createToolbar : function(){
21763 Roo.log("create toolbars");
21765 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
21766 this.toolbars[0].render(this.toolbarContainer());
21770 // if (!editor.toolbars || !editor.toolbars.length) {
21771 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
21774 // for (var i =0 ; i < editor.toolbars.length;i++) {
21775 // editor.toolbars[i] = Roo.factory(
21776 // typeof(editor.toolbars[i]) == 'string' ?
21777 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
21778 // Roo.bootstrap.HtmlEditor);
21779 // editor.toolbars[i].init(editor);
21785 onRender : function(ct, position)
21787 // Roo.log("Call onRender: " + this.xtype);
21789 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
21791 this.wrap = this.inputEl().wrap({
21792 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
21795 this.editorcore.onRender(ct, position);
21797 if (this.resizable) {
21798 this.resizeEl = new Roo.Resizable(this.wrap, {
21802 minHeight : this.height,
21803 height: this.height,
21804 handles : this.resizable,
21807 resize : function(r, w, h) {
21808 _t.onResize(w,h); // -something
21814 this.createToolbar(this);
21817 if(!this.width && this.resizable){
21818 this.setSize(this.wrap.getSize());
21820 if (this.resizeEl) {
21821 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
21822 // should trigger onReize..
21828 onResize : function(w, h)
21830 Roo.log('resize: ' +w + ',' + h );
21831 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
21835 if(this.inputEl() ){
21836 if(typeof w == 'number'){
21837 var aw = w - this.wrap.getFrameWidth('lr');
21838 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
21841 if(typeof h == 'number'){
21842 var tbh = -11; // fixme it needs to tool bar size!
21843 for (var i =0; i < this.toolbars.length;i++) {
21844 // fixme - ask toolbars for heights?
21845 tbh += this.toolbars[i].el.getHeight();
21846 //if (this.toolbars[i].footer) {
21847 // tbh += this.toolbars[i].footer.el.getHeight();
21855 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
21856 ah -= 5; // knock a few pixes off for look..
21857 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
21861 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
21862 this.editorcore.onResize(ew,eh);
21867 * Toggles the editor between standard and source edit mode.
21868 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21870 toggleSourceEdit : function(sourceEditMode)
21872 this.editorcore.toggleSourceEdit(sourceEditMode);
21874 if(this.editorcore.sourceEditMode){
21875 Roo.log('editor - showing textarea');
21878 // Roo.log(this.syncValue());
21880 this.inputEl().removeClass(['hide', 'x-hidden']);
21881 this.inputEl().dom.removeAttribute('tabIndex');
21882 this.inputEl().focus();
21884 Roo.log('editor - hiding textarea');
21886 // Roo.log(this.pushValue());
21889 this.inputEl().addClass(['hide', 'x-hidden']);
21890 this.inputEl().dom.setAttribute('tabIndex', -1);
21891 //this.deferFocus();
21894 if(this.resizable){
21895 this.setSize(this.wrap.getSize());
21898 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
21901 // private (for BoxComponent)
21902 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21904 // private (for BoxComponent)
21905 getResizeEl : function(){
21909 // private (for BoxComponent)
21910 getPositionEl : function(){
21915 initEvents : function(){
21916 this.originalValue = this.getValue();
21920 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21923 // markInvalid : Roo.emptyFn,
21925 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21928 // clearInvalid : Roo.emptyFn,
21930 setValue : function(v){
21931 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
21932 this.editorcore.pushValue();
21937 deferFocus : function(){
21938 this.focus.defer(10, this);
21942 focus : function(){
21943 this.editorcore.focus();
21949 onDestroy : function(){
21955 for (var i =0; i < this.toolbars.length;i++) {
21956 // fixme - ask toolbars for heights?
21957 this.toolbars[i].onDestroy();
21960 this.wrap.dom.innerHTML = '';
21961 this.wrap.remove();
21966 onFirstFocus : function(){
21967 //Roo.log("onFirstFocus");
21968 this.editorcore.onFirstFocus();
21969 for (var i =0; i < this.toolbars.length;i++) {
21970 this.toolbars[i].onFirstFocus();
21976 syncValue : function()
21978 this.editorcore.syncValue();
21981 pushValue : function()
21983 this.editorcore.pushValue();
21987 // hide stuff that is not compatible
22001 * @event specialkey
22005 * @cfg {String} fieldClass @hide
22008 * @cfg {String} focusClass @hide
22011 * @cfg {String} autoCreate @hide
22014 * @cfg {String} inputType @hide
22017 * @cfg {String} invalidClass @hide
22020 * @cfg {String} invalidText @hide
22023 * @cfg {String} msgFx @hide
22026 * @cfg {String} validateOnBlur @hide
22035 Roo.namespace('Roo.bootstrap.htmleditor');
22037 * @class Roo.bootstrap.HtmlEditorToolbar1
22042 new Roo.bootstrap.HtmlEditor({
22045 new Roo.bootstrap.HtmlEditorToolbar1({
22046 disable : { fonts: 1 , format: 1, ..., ... , ...],
22052 * @cfg {Object} disable List of elements to disable..
22053 * @cfg {Array} btns List of additional buttons.
22057 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22060 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22063 Roo.apply(this, config);
22065 // default disabled, based on 'good practice'..
22066 this.disable = this.disable || {};
22067 Roo.applyIf(this.disable, {
22070 specialElements : true
22072 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22074 this.editor = config.editor;
22075 this.editorcore = config.editor.editorcore;
22077 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22079 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22080 // dont call parent... till later.
22082 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22087 editorcore : false,
22092 "h1","h2","h3","h4","h5","h6",
22094 "abbr", "acronym", "address", "cite", "samp", "var",
22098 onRender : function(ct, position)
22100 // Roo.log("Call onRender: " + this.xtype);
22102 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22104 this.el.dom.style.marginBottom = '0';
22106 var editorcore = this.editorcore;
22107 var editor= this.editor;
22110 var btn = function(id,cmd , toggle, handler){
22112 var event = toggle ? 'toggle' : 'click';
22117 xns: Roo.bootstrap,
22120 enableToggle:toggle !== false,
22122 pressed : toggle ? false : null,
22125 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22126 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22135 xns: Roo.bootstrap,
22136 glyphicon : 'font',
22140 xns: Roo.bootstrap,
22144 Roo.each(this.formats, function(f) {
22145 style.menu.items.push({
22147 xns: Roo.bootstrap,
22148 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22153 editorcore.insertTag(this.tagname);
22160 children.push(style);
22163 btn('bold',false,true);
22164 btn('italic',false,true);
22165 btn('align-left', 'justifyleft',true);
22166 btn('align-center', 'justifycenter',true);
22167 btn('align-right' , 'justifyright',true);
22168 btn('link', false, false, function(btn) {
22169 //Roo.log("create link?");
22170 var url = prompt(this.createLinkText, this.defaultLinkValue);
22171 if(url && url != 'http:/'+'/'){
22172 this.editorcore.relayCmd('createlink', url);
22175 btn('list','insertunorderedlist',true);
22176 btn('pencil', false,true, function(btn){
22179 this.toggleSourceEdit(btn.pressed);
22185 xns: Roo.bootstrap,
22190 xns: Roo.bootstrap,
22195 cog.menu.items.push({
22197 xns: Roo.bootstrap,
22198 html : Clean styles,
22203 editorcore.insertTag(this.tagname);
22212 this.xtype = 'NavSimplebar';
22214 for(var i=0;i< children.length;i++) {
22216 this.buttons.add(this.addxtypeChild(children[i]));
22220 editor.on('editorevent', this.updateToolbar, this);
22222 onBtnClick : function(id)
22224 this.editorcore.relayCmd(id);
22225 this.editorcore.focus();
22229 * Protected method that will not generally be called directly. It triggers
22230 * a toolbar update by reading the markup state of the current selection in the editor.
22232 updateToolbar: function(){
22234 if(!this.editorcore.activated){
22235 this.editor.onFirstFocus(); // is this neeed?
22239 var btns = this.buttons;
22240 var doc = this.editorcore.doc;
22241 btns.get('bold').setActive(doc.queryCommandState('bold'));
22242 btns.get('italic').setActive(doc.queryCommandState('italic'));
22243 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22245 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22246 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22247 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22249 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22250 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22253 var ans = this.editorcore.getAllAncestors();
22254 if (this.formatCombo) {
22257 var store = this.formatCombo.store;
22258 this.formatCombo.setValue("");
22259 for (var i =0; i < ans.length;i++) {
22260 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22262 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22270 // hides menus... - so this cant be on a menu...
22271 Roo.bootstrap.MenuMgr.hideAll();
22273 Roo.bootstrap.MenuMgr.hideAll();
22274 //this.editorsyncValue();
22276 onFirstFocus: function() {
22277 this.buttons.each(function(item){
22281 toggleSourceEdit : function(sourceEditMode){
22284 if(sourceEditMode){
22285 Roo.log("disabling buttons");
22286 this.buttons.each( function(item){
22287 if(item.cmd != 'pencil'){
22293 Roo.log("enabling buttons");
22294 if(this.editorcore.initialized){
22295 this.buttons.each( function(item){
22301 Roo.log("calling toggole on editor");
22302 // tell the editor that it's been pressed..
22303 this.editor.toggleSourceEdit(sourceEditMode);
22313 * @class Roo.bootstrap.Table.AbstractSelectionModel
22314 * @extends Roo.util.Observable
22315 * Abstract base class for grid SelectionModels. It provides the interface that should be
22316 * implemented by descendant classes. This class should not be directly instantiated.
22319 Roo.bootstrap.Table.AbstractSelectionModel = function(){
22320 this.locked = false;
22321 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
22325 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
22326 /** @ignore Called by the grid automatically. Do not call directly. */
22327 init : function(grid){
22333 * Locks the selections.
22336 this.locked = true;
22340 * Unlocks the selections.
22342 unlock : function(){
22343 this.locked = false;
22347 * Returns true if the selections are locked.
22348 * @return {Boolean}
22350 isLocked : function(){
22351 return this.locked;
22355 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22356 * @class Roo.bootstrap.Table.RowSelectionModel
22357 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22358 * It supports multiple selections and keyboard selection/navigation.
22360 * @param {Object} config
22363 Roo.bootstrap.Table.RowSelectionModel = function(config){
22364 Roo.apply(this, config);
22365 this.selections = new Roo.util.MixedCollection(false, function(o){
22370 this.lastActive = false;
22374 * @event selectionchange
22375 * Fires when the selection changes
22376 * @param {SelectionModel} this
22378 "selectionchange" : true,
22380 * @event afterselectionchange
22381 * Fires after the selection changes (eg. by key press or clicking)
22382 * @param {SelectionModel} this
22384 "afterselectionchange" : true,
22386 * @event beforerowselect
22387 * Fires when a row is selected being selected, return false to cancel.
22388 * @param {SelectionModel} this
22389 * @param {Number} rowIndex The selected index
22390 * @param {Boolean} keepExisting False if other selections will be cleared
22392 "beforerowselect" : true,
22395 * Fires when a row is selected.
22396 * @param {SelectionModel} this
22397 * @param {Number} rowIndex The selected index
22398 * @param {Roo.data.Record} r The record
22400 "rowselect" : true,
22402 * @event rowdeselect
22403 * Fires when a row is deselected.
22404 * @param {SelectionModel} this
22405 * @param {Number} rowIndex The selected index
22407 "rowdeselect" : true
22409 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22410 this.locked = false;
22413 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22415 * @cfg {Boolean} singleSelect
22416 * True to allow selection of only one row at a time (defaults to false)
22418 singleSelect : false,
22421 initEvents : function()
22424 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22425 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
22426 //}else{ // allow click to work like normal
22427 // this.grid.on("rowclick", this.handleDragableRowClick, this);
22429 this.grid.on("rowclick", this.handleMouseDown, this);
22431 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22432 "up" : function(e){
22434 this.selectPrevious(e.shiftKey);
22435 }else if(this.last !== false && this.lastActive !== false){
22436 var last = this.last;
22437 this.selectRange(this.last, this.lastActive-1);
22438 this.grid.getView().focusRow(this.lastActive);
22439 if(last !== false){
22443 this.selectFirstRow();
22445 this.fireEvent("afterselectionchange", this);
22447 "down" : function(e){
22449 this.selectNext(e.shiftKey);
22450 }else if(this.last !== false && this.lastActive !== false){
22451 var last = this.last;
22452 this.selectRange(this.last, this.lastActive+1);
22453 this.grid.getView().focusRow(this.lastActive);
22454 if(last !== false){
22458 this.selectFirstRow();
22460 this.fireEvent("afterselectionchange", this);
22465 var view = this.grid.view;
22466 view.on("refresh", this.onRefresh, this);
22467 view.on("rowupdated", this.onRowUpdated, this);
22468 view.on("rowremoved", this.onRemove, this);
22473 onRefresh : function(){
22474 var ds = this.grid.dataSource, i, v = this.grid.view;
22475 var s = this.selections;
22476 s.each(function(r){
22477 if((i = ds.indexOfId(r.id)) != -1){
22486 onRemove : function(v, index, r){
22487 this.selections.remove(r);
22491 onRowUpdated : function(v, index, r){
22492 if(this.isSelected(r)){
22493 v.onRowSelect(index);
22499 * @param {Array} records The records to select
22500 * @param {Boolean} keepExisting (optional) True to keep existing selections
22502 selectRecords : function(records, keepExisting){
22504 this.clearSelections();
22506 var ds = this.grid.dataSource;
22507 for(var i = 0, len = records.length; i < len; i++){
22508 this.selectRow(ds.indexOf(records[i]), true);
22513 * Gets the number of selected rows.
22516 getCount : function(){
22517 return this.selections.length;
22521 * Selects the first row in the grid.
22523 selectFirstRow : function(){
22528 * Select the last row.
22529 * @param {Boolean} keepExisting (optional) True to keep existing selections
22531 selectLastRow : function(keepExisting){
22532 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22536 * Selects the row immediately following the last selected row.
22537 * @param {Boolean} keepExisting (optional) True to keep existing selections
22539 selectNext : function(keepExisting){
22540 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
22541 this.selectRow(this.last+1, keepExisting);
22542 this.grid.getView().focusRow(this.last);
22547 * Selects the row that precedes the last selected row.
22548 * @param {Boolean} keepExisting (optional) True to keep existing selections
22550 selectPrevious : function(keepExisting){
22552 this.selectRow(this.last-1, keepExisting);
22553 this.grid.getView().focusRow(this.last);
22558 * Returns the selected records
22559 * @return {Array} Array of selected records
22561 getSelections : function(){
22562 return [].concat(this.selections.items);
22566 * Returns the first selected record.
22569 getSelected : function(){
22570 return this.selections.itemAt(0);
22575 * Clears all selections.
22577 clearSelections : function(fast){
22582 var ds = this.grid.dataSource;
22583 var s = this.selections;
22584 s.each(function(r){
22585 this.deselectRow(ds.indexOfId(r.id));
22589 this.selections.clear();
22596 * Selects all rows.
22598 selectAll : function(){
22602 this.selections.clear();
22603 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
22604 this.selectRow(i, true);
22609 * Returns True if there is a selection.
22610 * @return {Boolean}
22612 hasSelection : function(){
22613 return this.selections.length > 0;
22617 * Returns True if the specified row is selected.
22618 * @param {Number/Record} record The record or index of the record to check
22619 * @return {Boolean}
22621 isSelected : function(index){
22622 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
22623 return (r && this.selections.key(r.id) ? true : false);
22627 * Returns True if the specified record id is selected.
22628 * @param {String} id The id of record to check
22629 * @return {Boolean}
22631 isIdSelected : function(id){
22632 return (this.selections.key(id) ? true : false);
22636 handleMouseDown : function(e, t){
22637 var view = this.grid.getView(), rowIndex;
22638 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
22641 if(e.shiftKey && this.last !== false){
22642 var last = this.last;
22643 this.selectRange(last, rowIndex, e.ctrlKey);
22644 this.last = last; // reset the last
22645 view.focusRow(rowIndex);
22647 var isSelected = this.isSelected(rowIndex);
22648 if(e.button !== 0 && isSelected){
22649 view.focusRow(rowIndex);
22650 }else if(e.ctrlKey && isSelected){
22651 this.deselectRow(rowIndex);
22652 }else if(!isSelected){
22653 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22654 view.focusRow(rowIndex);
22657 this.fireEvent("afterselectionchange", this);
22660 handleDragableRowClick : function(grid, rowIndex, e)
22662 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
22663 this.selectRow(rowIndex, false);
22664 grid.view.focusRow(rowIndex);
22665 this.fireEvent("afterselectionchange", this);
22670 * Selects multiple rows.
22671 * @param {Array} rows Array of the indexes of the row to select
22672 * @param {Boolean} keepExisting (optional) True to keep existing selections
22674 selectRows : function(rows, keepExisting){
22676 this.clearSelections();
22678 for(var i = 0, len = rows.length; i < len; i++){
22679 this.selectRow(rows[i], true);
22684 * Selects a range of rows. All rows in between startRow and endRow are also selected.
22685 * @param {Number} startRow The index of the first row in the range
22686 * @param {Number} endRow The index of the last row in the range
22687 * @param {Boolean} keepExisting (optional) True to retain existing selections
22689 selectRange : function(startRow, endRow, keepExisting){
22694 this.clearSelections();
22696 if(startRow <= endRow){
22697 for(var i = startRow; i <= endRow; i++){
22698 this.selectRow(i, true);
22701 for(var i = startRow; i >= endRow; i--){
22702 this.selectRow(i, true);
22708 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
22709 * @param {Number} startRow The index of the first row in the range
22710 * @param {Number} endRow The index of the last row in the range
22712 deselectRange : function(startRow, endRow, preventViewNotify){
22716 for(var i = startRow; i <= endRow; i++){
22717 this.deselectRow(i, preventViewNotify);
22723 * @param {Number} row The index of the row to select
22724 * @param {Boolean} keepExisting (optional) True to keep existing selections
22726 selectRow : function(index, keepExisting, preventViewNotify){
22727 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
22730 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
22731 if(!keepExisting || this.singleSelect){
22732 this.clearSelections();
22734 var r = this.grid.dataSource.getAt(index);
22735 this.selections.add(r);
22736 this.last = this.lastActive = index;
22737 if(!preventViewNotify){
22738 this.grid.getView().onRowSelect(index);
22740 this.fireEvent("rowselect", this, index, r);
22741 this.fireEvent("selectionchange", this);
22747 * @param {Number} row The index of the row to deselect
22749 deselectRow : function(index, preventViewNotify){
22753 if(this.last == index){
22756 if(this.lastActive == index){
22757 this.lastActive = false;
22759 var r = this.grid.dataSource.getAt(index);
22760 this.selections.remove(r);
22761 if(!preventViewNotify){
22762 this.grid.getView().onRowDeselect(index);
22764 this.fireEvent("rowdeselect", this, index);
22765 this.fireEvent("selectionchange", this);
22769 restoreLast : function(){
22771 this.last = this._last;
22776 acceptsNav : function(row, col, cm){
22777 return !cm.isHidden(col) && cm.isCellEditable(col, row);
22781 onEditorKey : function(field, e){
22782 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
22787 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
22789 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
22791 }else if(k == e.ENTER && !e.ctrlKey){
22795 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
22797 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
22799 }else if(k == e.ESC){
22803 g.startEditing(newCell[0], newCell[1]);
22808 * Ext JS Library 1.1.1
22809 * Copyright(c) 2006-2007, Ext JS, LLC.
22811 * Originally Released Under LGPL - original licence link has changed is not relivant.
22814 * <script type="text/javascript">
22818 * @class Roo.bootstrap.PagingToolbar
22819 * @extends Roo.bootstrap.NavSimplebar
22820 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
22822 * Create a new PagingToolbar
22823 * @param {Object} config The config object
22824 * @param {Roo.data.Store} store
22826 Roo.bootstrap.PagingToolbar = function(config)
22828 // old args format still supported... - xtype is prefered..
22829 // created from xtype...
22831 this.ds = config.dataSource;
22833 if (config.store && !this.ds) {
22834 this.store= Roo.factory(config.store, Roo.data);
22835 this.ds = this.store;
22836 this.ds.xmodule = this.xmodule || false;
22839 this.toolbarItems = [];
22840 if (config.items) {
22841 this.toolbarItems = config.items;
22844 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
22849 this.bind(this.ds);
22852 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
22856 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
22858 * @cfg {Roo.data.Store} dataSource
22859 * The underlying data store providing the paged data
22862 * @cfg {String/HTMLElement/Element} container
22863 * container The id or element that will contain the toolbar
22866 * @cfg {Boolean} displayInfo
22867 * True to display the displayMsg (defaults to false)
22870 * @cfg {Number} pageSize
22871 * The number of records to display per page (defaults to 20)
22875 * @cfg {String} displayMsg
22876 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
22878 displayMsg : 'Displaying {0} - {1} of {2}',
22880 * @cfg {String} emptyMsg
22881 * The message to display when no records are found (defaults to "No data to display")
22883 emptyMsg : 'No data to display',
22885 * Customizable piece of the default paging text (defaults to "Page")
22888 beforePageText : "Page",
22890 * Customizable piece of the default paging text (defaults to "of %0")
22893 afterPageText : "of {0}",
22895 * Customizable piece of the default paging text (defaults to "First Page")
22898 firstText : "First Page",
22900 * Customizable piece of the default paging text (defaults to "Previous Page")
22903 prevText : "Previous Page",
22905 * Customizable piece of the default paging text (defaults to "Next Page")
22908 nextText : "Next Page",
22910 * Customizable piece of the default paging text (defaults to "Last Page")
22913 lastText : "Last Page",
22915 * Customizable piece of the default paging text (defaults to "Refresh")
22918 refreshText : "Refresh",
22922 onRender : function(ct, position)
22924 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
22925 this.navgroup.parentId = this.id;
22926 this.navgroup.onRender(this.el, null);
22927 // add the buttons to the navgroup
22929 if(this.displayInfo){
22930 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
22931 this.displayEl = this.el.select('.x-paging-info', true).first();
22932 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
22933 // this.displayEl = navel.el.select('span',true).first();
22939 Roo.each(_this.buttons, function(e){ // this might need to use render????
22940 Roo.factory(e).onRender(_this.el, null);
22944 Roo.each(_this.toolbarItems, function(e) {
22945 _this.navgroup.addItem(e);
22949 this.first = this.navgroup.addItem({
22950 tooltip: this.firstText,
22952 icon : 'fa fa-backward',
22954 preventDefault: true,
22955 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
22958 this.prev = this.navgroup.addItem({
22959 tooltip: this.prevText,
22961 icon : 'fa fa-step-backward',
22963 preventDefault: true,
22964 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
22966 //this.addSeparator();
22969 var field = this.navgroup.addItem( {
22971 cls : 'x-paging-position',
22973 html : this.beforePageText +
22974 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
22975 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
22978 this.field = field.el.select('input', true).first();
22979 this.field.on("keydown", this.onPagingKeydown, this);
22980 this.field.on("focus", function(){this.dom.select();});
22983 this.afterTextEl = field.el.select('.x-paging-after',true).first();
22984 //this.field.setHeight(18);
22985 //this.addSeparator();
22986 this.next = this.navgroup.addItem({
22987 tooltip: this.nextText,
22989 html : ' <i class="fa fa-step-forward">',
22991 preventDefault: true,
22992 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
22994 this.last = this.navgroup.addItem({
22995 tooltip: this.lastText,
22996 icon : 'fa fa-forward',
22999 preventDefault: true,
23000 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23002 //this.addSeparator();
23003 this.loading = this.navgroup.addItem({
23004 tooltip: this.refreshText,
23005 icon: 'fa fa-refresh',
23006 preventDefault: true,
23007 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23013 updateInfo : function(){
23014 if(this.displayEl){
23015 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23016 var msg = count == 0 ?
23020 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23022 this.displayEl.update(msg);
23027 onLoad : function(ds, r, o){
23028 this.cursor = o.params ? o.params.start : 0;
23029 var d = this.getPageData(),
23033 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23034 this.field.dom.value = ap;
23035 this.first.setDisabled(ap == 1);
23036 this.prev.setDisabled(ap == 1);
23037 this.next.setDisabled(ap == ps);
23038 this.last.setDisabled(ap == ps);
23039 this.loading.enable();
23044 getPageData : function(){
23045 var total = this.ds.getTotalCount();
23048 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23049 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23054 onLoadError : function(){
23055 this.loading.enable();
23059 onPagingKeydown : function(e){
23060 var k = e.getKey();
23061 var d = this.getPageData();
23063 var v = this.field.dom.value, pageNum;
23064 if(!v || isNaN(pageNum = parseInt(v, 10))){
23065 this.field.dom.value = d.activePage;
23068 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23069 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23072 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))
23074 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23075 this.field.dom.value = pageNum;
23076 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23079 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23081 var v = this.field.dom.value, pageNum;
23082 var increment = (e.shiftKey) ? 10 : 1;
23083 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23086 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23087 this.field.dom.value = d.activePage;
23090 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23092 this.field.dom.value = parseInt(v, 10) + increment;
23093 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23094 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23101 beforeLoad : function(){
23103 this.loading.disable();
23108 onClick : function(which){
23117 ds.load({params:{start: 0, limit: this.pageSize}});
23120 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23123 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23126 var total = ds.getTotalCount();
23127 var extra = total % this.pageSize;
23128 var lastStart = extra ? (total - extra) : total-this.pageSize;
23129 ds.load({params:{start: lastStart, limit: this.pageSize}});
23132 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23138 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23139 * @param {Roo.data.Store} store The data store to unbind
23141 unbind : function(ds){
23142 ds.un("beforeload", this.beforeLoad, this);
23143 ds.un("load", this.onLoad, this);
23144 ds.un("loadexception", this.onLoadError, this);
23145 ds.un("remove", this.updateInfo, this);
23146 ds.un("add", this.updateInfo, this);
23147 this.ds = undefined;
23151 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23152 * @param {Roo.data.Store} store The data store to bind
23154 bind : function(ds){
23155 ds.on("beforeload", this.beforeLoad, this);
23156 ds.on("load", this.onLoad, this);
23157 ds.on("loadexception", this.onLoadError, this);
23158 ds.on("remove", this.updateInfo, this);
23159 ds.on("add", this.updateInfo, this);
23170 * @class Roo.bootstrap.MessageBar
23171 * @extends Roo.bootstrap.Component
23172 * Bootstrap MessageBar class
23173 * @cfg {String} html contents of the MessageBar
23174 * @cfg {String} weight (info | success | warning | danger) default info
23175 * @cfg {String} beforeClass insert the bar before the given class
23176 * @cfg {Boolean} closable (true | false) default false
23177 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23180 * Create a new Element
23181 * @param {Object} config The config object
23184 Roo.bootstrap.MessageBar = function(config){
23185 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23188 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23194 beforeClass: 'bootstrap-sticky-wrap',
23196 getAutoCreate : function(){
23200 cls: 'alert alert-dismissable alert-' + this.weight,
23205 html: this.html || ''
23211 cfg.cls += ' alert-messages-fixed';
23225 onRender : function(ct, position)
23227 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23230 var cfg = Roo.apply({}, this.getAutoCreate());
23234 cfg.cls += ' ' + this.cls;
23237 cfg.style = this.style;
23239 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23241 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23244 this.el.select('>button.close').on('click', this.hide, this);
23250 if (!this.rendered) {
23256 this.fireEvent('show', this);
23262 if (!this.rendered) {
23268 this.fireEvent('hide', this);
23271 update : function()
23273 // var e = this.el.dom.firstChild;
23275 // if(this.closable){
23276 // e = e.nextSibling;
23279 // e.data = this.html || '';
23281 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
23297 * @class Roo.bootstrap.Graph
23298 * @extends Roo.bootstrap.Component
23299 * Bootstrap Graph class
23303 @cfg {String} graphtype bar | vbar | pie
23304 @cfg {number} g_x coodinator | centre x (pie)
23305 @cfg {number} g_y coodinator | centre y (pie)
23306 @cfg {number} g_r radius (pie)
23307 @cfg {number} g_height height of the chart (respected by all elements in the set)
23308 @cfg {number} g_width width of the chart (respected by all elements in the set)
23309 @cfg {Object} title The title of the chart
23312 -opts (object) options for the chart
23314 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
23315 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
23317 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.
23318 o stacked (boolean) whether or not to tread values as in a stacked bar chart
23320 o stretch (boolean)
23322 -opts (object) options for the pie
23325 o startAngle (number)
23326 o endAngle (number)
23330 * Create a new Input
23331 * @param {Object} config The config object
23334 Roo.bootstrap.Graph = function(config){
23335 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
23341 * The img click event for the img.
23342 * @param {Roo.EventObject} e
23348 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23359 //g_colors: this.colors,
23366 getAutoCreate : function(){
23377 onRender : function(ct,position){
23380 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23382 if (typeof(Raphael) == 'undefined') {
23383 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23387 this.raphael = Raphael(this.el.dom);
23389 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23390 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23391 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23392 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23394 r.text(160, 10, "Single Series Chart").attr(txtattr);
23395 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23396 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23397 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23399 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23400 r.barchart(330, 10, 300, 220, data1);
23401 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23402 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23405 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23406 // r.barchart(30, 30, 560, 250, xdata, {
23407 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23408 // axis : "0 0 1 1",
23409 // axisxlabels : xdata
23410 // //yvalues : cols,
23413 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23415 // this.load(null,xdata,{
23416 // axis : "0 0 1 1",
23417 // axisxlabels : xdata
23422 load : function(graphtype,xdata,opts)
23424 this.raphael.clear();
23426 graphtype = this.graphtype;
23431 var r = this.raphael,
23432 fin = function () {
23433 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23435 fout = function () {
23436 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23438 pfin = function() {
23439 this.sector.stop();
23440 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23443 this.label[0].stop();
23444 this.label[0].attr({ r: 7.5 });
23445 this.label[1].attr({ "font-weight": 800 });
23448 pfout = function() {
23449 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23452 this.label[0].animate({ r: 5 }, 500, "bounce");
23453 this.label[1].attr({ "font-weight": 400 });
23459 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23462 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23465 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23466 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23468 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23475 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23480 setTitle: function(o)
23485 initEvents: function() {
23488 this.el.on('click', this.onClick, this);
23492 onClick : function(e)
23494 Roo.log('img onclick');
23495 this.fireEvent('click', this, e);
23507 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23510 * @class Roo.bootstrap.dash.NumberBox
23511 * @extends Roo.bootstrap.Component
23512 * Bootstrap NumberBox class
23513 * @cfg {String} headline Box headline
23514 * @cfg {String} content Box content
23515 * @cfg {String} icon Box icon
23516 * @cfg {String} footer Footer text
23517 * @cfg {String} fhref Footer href
23520 * Create a new NumberBox
23521 * @param {Object} config The config object
23525 Roo.bootstrap.dash.NumberBox = function(config){
23526 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23530 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23539 getAutoCreate : function(){
23543 cls : 'small-box ',
23551 cls : 'roo-headline',
23552 html : this.headline
23556 cls : 'roo-content',
23557 html : this.content
23571 cls : 'ion ' + this.icon
23580 cls : 'small-box-footer',
23581 href : this.fhref || '#',
23585 cfg.cn.push(footer);
23592 onRender : function(ct,position){
23593 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23600 setHeadline: function (value)
23602 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23605 setFooter: function (value, href)
23607 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23610 this.el.select('a.small-box-footer',true).first().attr('href', href);
23615 setContent: function (value)
23617 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23620 initEvents: function()
23634 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23637 * @class Roo.bootstrap.dash.TabBox
23638 * @extends Roo.bootstrap.Component
23639 * Bootstrap TabBox class
23640 * @cfg {String} title Title of the TabBox
23641 * @cfg {String} icon Icon of the TabBox
23642 * @cfg {Boolean} showtabs (true|false) show the tabs default true
23643 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
23646 * Create a new TabBox
23647 * @param {Object} config The config object
23651 Roo.bootstrap.dash.TabBox = function(config){
23652 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
23657 * When a pane is added
23658 * @param {Roo.bootstrap.dash.TabPane} pane
23662 * @event activatepane
23663 * When a pane is activated
23664 * @param {Roo.bootstrap.dash.TabPane} pane
23666 "activatepane" : true
23674 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
23679 tabScrollable : false,
23681 getChildContainer : function()
23683 return this.el.select('.tab-content', true).first();
23686 getAutoCreate : function(){
23690 cls: 'pull-left header',
23698 cls: 'fa ' + this.icon
23704 cls: 'nav nav-tabs pull-right',
23710 if(this.tabScrollable){
23717 cls: 'nav nav-tabs pull-right',
23728 cls: 'nav-tabs-custom',
23733 cls: 'tab-content no-padding',
23741 initEvents : function()
23743 //Roo.log('add add pane handler');
23744 this.on('addpane', this.onAddPane, this);
23747 * Updates the box title
23748 * @param {String} html to set the title to.
23750 setTitle : function(value)
23752 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
23754 onAddPane : function(pane)
23756 this.panes.push(pane);
23757 //Roo.log('addpane');
23759 // tabs are rendere left to right..
23760 if(!this.showtabs){
23764 var ctr = this.el.select('.nav-tabs', true).first();
23767 var existing = ctr.select('.nav-tab',true);
23768 var qty = existing.getCount();;
23771 var tab = ctr.createChild({
23773 cls : 'nav-tab' + (qty ? '' : ' active'),
23781 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
23784 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
23786 pane.el.addClass('active');
23791 onTabClick : function(ev,un,ob,pane)
23793 //Roo.log('tab - prev default');
23794 ev.preventDefault();
23797 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
23798 pane.tab.addClass('active');
23799 //Roo.log(pane.title);
23800 this.getChildContainer().select('.tab-pane',true).removeClass('active');
23801 // technically we should have a deactivate event.. but maybe add later.
23802 // and it should not de-activate the selected tab...
23803 this.fireEvent('activatepane', pane);
23804 pane.el.addClass('active');
23805 pane.fireEvent('activate');
23810 getActivePane : function()
23813 Roo.each(this.panes, function(p) {
23814 if(p.el.hasClass('active')){
23835 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23837 * @class Roo.bootstrap.TabPane
23838 * @extends Roo.bootstrap.Component
23839 * Bootstrap TabPane class
23840 * @cfg {Boolean} active (false | true) Default false
23841 * @cfg {String} title title of panel
23845 * Create a new TabPane
23846 * @param {Object} config The config object
23849 Roo.bootstrap.dash.TabPane = function(config){
23850 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
23856 * When a pane is activated
23857 * @param {Roo.bootstrap.dash.TabPane} pane
23864 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
23869 // the tabBox that this is attached to.
23872 getAutoCreate : function()
23880 cfg.cls += ' active';
23885 initEvents : function()
23887 //Roo.log('trigger add pane handler');
23888 this.parent().fireEvent('addpane', this)
23892 * Updates the tab title
23893 * @param {String} html to set the title to.
23895 setTitle: function(str)
23901 this.tab.select('a', true).first().dom.innerHTML = str;
23918 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23921 * @class Roo.bootstrap.menu.Menu
23922 * @extends Roo.bootstrap.Component
23923 * Bootstrap Menu class - container for Menu
23924 * @cfg {String} html Text of the menu
23925 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
23926 * @cfg {String} icon Font awesome icon
23927 * @cfg {String} pos Menu align to (top | bottom) default bottom
23931 * Create a new Menu
23932 * @param {Object} config The config object
23936 Roo.bootstrap.menu.Menu = function(config){
23937 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
23941 * @event beforeshow
23942 * Fires before this menu is displayed
23943 * @param {Roo.bootstrap.menu.Menu} this
23947 * @event beforehide
23948 * Fires before this menu is hidden
23949 * @param {Roo.bootstrap.menu.Menu} this
23954 * Fires after this menu is displayed
23955 * @param {Roo.bootstrap.menu.Menu} this
23960 * Fires after this menu is hidden
23961 * @param {Roo.bootstrap.menu.Menu} this
23966 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
23967 * @param {Roo.bootstrap.menu.Menu} this
23968 * @param {Roo.EventObject} e
23975 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
23979 weight : 'default',
23984 getChildContainer : function() {
23985 if(this.isSubMenu){
23989 return this.el.select('ul.dropdown-menu', true).first();
23992 getAutoCreate : function()
23997 cls : 'roo-menu-text',
24005 cls : 'fa ' + this.icon
24016 cls : 'dropdown-button btn btn-' + this.weight,
24021 cls : 'dropdown-toggle btn btn-' + this.weight,
24031 cls : 'dropdown-menu'
24037 if(this.pos == 'top'){
24038 cfg.cls += ' dropup';
24041 if(this.isSubMenu){
24044 cls : 'dropdown-menu'
24051 onRender : function(ct, position)
24053 this.isSubMenu = ct.hasClass('dropdown-submenu');
24055 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24058 initEvents : function()
24060 if(this.isSubMenu){
24064 this.hidden = true;
24066 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24067 this.triggerEl.on('click', this.onTriggerPress, this);
24069 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24070 this.buttonEl.on('click', this.onClick, this);
24076 if(this.isSubMenu){
24080 return this.el.select('ul.dropdown-menu', true).first();
24083 onClick : function(e)
24085 this.fireEvent("click", this, e);
24088 onTriggerPress : function(e)
24090 if (this.isVisible()) {
24097 isVisible : function(){
24098 return !this.hidden;
24103 this.fireEvent("beforeshow", this);
24105 this.hidden = false;
24106 this.el.addClass('open');
24108 Roo.get(document).on("mouseup", this.onMouseUp, this);
24110 this.fireEvent("show", this);
24117 this.fireEvent("beforehide", this);
24119 this.hidden = true;
24120 this.el.removeClass('open');
24122 Roo.get(document).un("mouseup", this.onMouseUp);
24124 this.fireEvent("hide", this);
24127 onMouseUp : function()
24141 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24144 * @class Roo.bootstrap.menu.Item
24145 * @extends Roo.bootstrap.Component
24146 * Bootstrap MenuItem class
24147 * @cfg {Boolean} submenu (true | false) default false
24148 * @cfg {String} html text of the item
24149 * @cfg {String} href the link
24150 * @cfg {Boolean} disable (true | false) default false
24151 * @cfg {Boolean} preventDefault (true | false) default true
24152 * @cfg {String} icon Font awesome icon
24153 * @cfg {String} pos Submenu align to (left | right) default right
24157 * Create a new Item
24158 * @param {Object} config The config object
24162 Roo.bootstrap.menu.Item = function(config){
24163 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24167 * Fires when the mouse is hovering over this menu
24168 * @param {Roo.bootstrap.menu.Item} this
24169 * @param {Roo.EventObject} e
24174 * Fires when the mouse exits this menu
24175 * @param {Roo.bootstrap.menu.Item} this
24176 * @param {Roo.EventObject} e
24182 * The raw click event for the entire grid.
24183 * @param {Roo.EventObject} e
24189 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24194 preventDefault: true,
24199 getAutoCreate : function()
24204 cls : 'roo-menu-item-text',
24212 cls : 'fa ' + this.icon
24221 href : this.href || '#',
24228 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24232 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24234 if(this.pos == 'left'){
24235 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24242 initEvents : function()
24244 this.el.on('mouseover', this.onMouseOver, this);
24245 this.el.on('mouseout', this.onMouseOut, this);
24247 this.el.select('a', true).first().on('click', this.onClick, this);
24251 onClick : function(e)
24253 if(this.preventDefault){
24254 e.preventDefault();
24257 this.fireEvent("click", this, e);
24260 onMouseOver : function(e)
24262 if(this.submenu && this.pos == 'left'){
24263 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
24266 this.fireEvent("mouseover", this, e);
24269 onMouseOut : function(e)
24271 this.fireEvent("mouseout", this, e);
24283 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24286 * @class Roo.bootstrap.menu.Separator
24287 * @extends Roo.bootstrap.Component
24288 * Bootstrap Separator class
24291 * Create a new Separator
24292 * @param {Object} config The config object
24296 Roo.bootstrap.menu.Separator = function(config){
24297 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
24300 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
24302 getAutoCreate : function(){
24323 * @class Roo.bootstrap.Tooltip
24324 * Bootstrap Tooltip class
24325 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
24326 * to determine which dom element triggers the tooltip.
24328 * It needs to add support for additional attributes like tooltip-position
24331 * Create a new Toolti
24332 * @param {Object} config The config object
24335 Roo.bootstrap.Tooltip = function(config){
24336 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
24339 Roo.apply(Roo.bootstrap.Tooltip, {
24341 * @function init initialize tooltip monitoring.
24345 currentTip : false,
24346 currentRegion : false,
24352 Roo.get(document).on('mouseover', this.enter ,this);
24353 Roo.get(document).on('mouseout', this.leave, this);
24356 this.currentTip = new Roo.bootstrap.Tooltip();
24359 enter : function(ev)
24361 var dom = ev.getTarget();
24363 //Roo.log(['enter',dom]);
24364 var el = Roo.fly(dom);
24365 if (this.currentEl) {
24367 //Roo.log(this.currentEl);
24368 //Roo.log(this.currentEl.contains(dom));
24369 if (this.currentEl == el) {
24372 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24378 if (this.currentTip.el) {
24379 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24383 if(!el || el.dom == document){
24389 // you can not look for children, as if el is the body.. then everythign is the child..
24390 if (!el.attr('tooltip')) { //
24391 if (!el.select("[tooltip]").elements.length) {
24394 // is the mouse over this child...?
24395 bindEl = el.select("[tooltip]").first();
24396 var xy = ev.getXY();
24397 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24398 //Roo.log("not in region.");
24401 //Roo.log("child element over..");
24404 this.currentEl = bindEl;
24405 this.currentTip.bind(bindEl);
24406 this.currentRegion = Roo.lib.Region.getRegion(dom);
24407 this.currentTip.enter();
24410 leave : function(ev)
24412 var dom = ev.getTarget();
24413 //Roo.log(['leave',dom]);
24414 if (!this.currentEl) {
24419 if (dom != this.currentEl.dom) {
24422 var xy = ev.getXY();
24423 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24426 // only activate leave if mouse cursor is outside... bounding box..
24431 if (this.currentTip) {
24432 this.currentTip.leave();
24434 //Roo.log('clear currentEl');
24435 this.currentEl = false;
24440 'left' : ['r-l', [-2,0], 'right'],
24441 'right' : ['l-r', [2,0], 'left'],
24442 'bottom' : ['t-b', [0,2], 'top'],
24443 'top' : [ 'b-t', [0,-2], 'bottom']
24449 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24454 delay : null, // can be { show : 300 , hide: 500}
24458 hoverState : null, //???
24460 placement : 'bottom',
24462 getAutoCreate : function(){
24469 cls : 'tooltip-arrow'
24472 cls : 'tooltip-inner'
24479 bind : function(el)
24485 enter : function () {
24487 if (this.timeout != null) {
24488 clearTimeout(this.timeout);
24491 this.hoverState = 'in';
24492 //Roo.log("enter - show");
24493 if (!this.delay || !this.delay.show) {
24498 this.timeout = setTimeout(function () {
24499 if (_t.hoverState == 'in') {
24502 }, this.delay.show);
24506 clearTimeout(this.timeout);
24508 this.hoverState = 'out';
24509 if (!this.delay || !this.delay.hide) {
24515 this.timeout = setTimeout(function () {
24516 //Roo.log("leave - timeout");
24518 if (_t.hoverState == 'out') {
24520 Roo.bootstrap.Tooltip.currentEl = false;
24528 this.render(document.body);
24531 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24533 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24535 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24537 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24539 var placement = typeof this.placement == 'function' ?
24540 this.placement.call(this, this.el, on_el) :
24543 var autoToken = /\s?auto?\s?/i;
24544 var autoPlace = autoToken.test(placement);
24546 placement = placement.replace(autoToken, '') || 'top';
24550 //this.el.setXY([0,0]);
24552 //this.el.dom.style.display='block';
24554 //this.el.appendTo(on_el);
24556 var p = this.getPosition();
24557 var box = this.el.getBox();
24563 var align = Roo.bootstrap.Tooltip.alignment[placement];
24565 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24567 if(placement == 'top' || placement == 'bottom'){
24569 placement = 'right';
24572 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24573 placement = 'left';
24576 var scroll = Roo.select('body', true).first().getScroll();
24578 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
24584 align = Roo.bootstrap.Tooltip.alignment[placement];
24586 this.el.alignTo(this.bindEl, align[0],align[1]);
24587 //var arrow = this.el.select('.arrow',true).first();
24588 //arrow.set(align[2],
24590 this.el.addClass(placement);
24592 this.el.addClass('in fade');
24594 this.hoverState = null;
24596 if (this.el.hasClass('fade')) {
24607 //this.el.setXY([0,0]);
24608 this.el.removeClass('in');
24624 * @class Roo.bootstrap.LocationPicker
24625 * @extends Roo.bootstrap.Component
24626 * Bootstrap LocationPicker class
24627 * @cfg {Number} latitude Position when init default 0
24628 * @cfg {Number} longitude Position when init default 0
24629 * @cfg {Number} zoom default 15
24630 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24631 * @cfg {Boolean} mapTypeControl default false
24632 * @cfg {Boolean} disableDoubleClickZoom default false
24633 * @cfg {Boolean} scrollwheel default true
24634 * @cfg {Boolean} streetViewControl default false
24635 * @cfg {Number} radius default 0
24636 * @cfg {String} locationName
24637 * @cfg {Boolean} draggable default true
24638 * @cfg {Boolean} enableAutocomplete default false
24639 * @cfg {Boolean} enableReverseGeocode default true
24640 * @cfg {String} markerTitle
24643 * Create a new LocationPicker
24644 * @param {Object} config The config object
24648 Roo.bootstrap.LocationPicker = function(config){
24650 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
24655 * Fires when the picker initialized.
24656 * @param {Roo.bootstrap.LocationPicker} this
24657 * @param {Google Location} location
24661 * @event positionchanged
24662 * Fires when the picker position changed.
24663 * @param {Roo.bootstrap.LocationPicker} this
24664 * @param {Google Location} location
24666 positionchanged : true,
24669 * Fires when the map resize.
24670 * @param {Roo.bootstrap.LocationPicker} this
24675 * Fires when the map show.
24676 * @param {Roo.bootstrap.LocationPicker} this
24681 * Fires when the map hide.
24682 * @param {Roo.bootstrap.LocationPicker} this
24687 * Fires when click the map.
24688 * @param {Roo.bootstrap.LocationPicker} this
24689 * @param {Map event} e
24693 * @event mapRightClick
24694 * Fires when right click the map.
24695 * @param {Roo.bootstrap.LocationPicker} this
24696 * @param {Map event} e
24698 mapRightClick : true,
24700 * @event markerClick
24701 * Fires when click the marker.
24702 * @param {Roo.bootstrap.LocationPicker} this
24703 * @param {Map event} e
24705 markerClick : true,
24707 * @event markerRightClick
24708 * Fires when right click the marker.
24709 * @param {Roo.bootstrap.LocationPicker} this
24710 * @param {Map event} e
24712 markerRightClick : true,
24714 * @event OverlayViewDraw
24715 * Fires when OverlayView Draw
24716 * @param {Roo.bootstrap.LocationPicker} this
24718 OverlayViewDraw : true,
24720 * @event OverlayViewOnAdd
24721 * Fires when OverlayView Draw
24722 * @param {Roo.bootstrap.LocationPicker} this
24724 OverlayViewOnAdd : true,
24726 * @event OverlayViewOnRemove
24727 * Fires when OverlayView Draw
24728 * @param {Roo.bootstrap.LocationPicker} this
24730 OverlayViewOnRemove : true,
24732 * @event OverlayViewShow
24733 * Fires when OverlayView Draw
24734 * @param {Roo.bootstrap.LocationPicker} this
24735 * @param {Pixel} cpx
24737 OverlayViewShow : true,
24739 * @event OverlayViewHide
24740 * Fires when OverlayView Draw
24741 * @param {Roo.bootstrap.LocationPicker} this
24743 OverlayViewHide : true,
24745 * @event loadexception
24746 * Fires when load google lib failed.
24747 * @param {Roo.bootstrap.LocationPicker} this
24749 loadexception : true
24754 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
24756 gMapContext: false,
24762 mapTypeControl: false,
24763 disableDoubleClickZoom: false,
24765 streetViewControl: false,
24769 enableAutocomplete: false,
24770 enableReverseGeocode: true,
24773 getAutoCreate: function()
24778 cls: 'roo-location-picker'
24784 initEvents: function(ct, position)
24786 if(!this.el.getWidth() || this.isApplied()){
24790 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24795 initial: function()
24797 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
24798 this.fireEvent('loadexception', this);
24802 if(!this.mapTypeId){
24803 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
24806 this.gMapContext = this.GMapContext();
24808 this.initOverlayView();
24810 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
24814 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
24815 _this.setPosition(_this.gMapContext.marker.position);
24818 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
24819 _this.fireEvent('mapClick', this, event);
24823 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
24824 _this.fireEvent('mapRightClick', this, event);
24828 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
24829 _this.fireEvent('markerClick', this, event);
24833 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
24834 _this.fireEvent('markerRightClick', this, event);
24838 this.setPosition(this.gMapContext.location);
24840 this.fireEvent('initial', this, this.gMapContext.location);
24843 initOverlayView: function()
24847 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
24851 _this.fireEvent('OverlayViewDraw', _this);
24856 _this.fireEvent('OverlayViewOnAdd', _this);
24859 onRemove: function()
24861 _this.fireEvent('OverlayViewOnRemove', _this);
24864 show: function(cpx)
24866 _this.fireEvent('OverlayViewShow', _this, cpx);
24871 _this.fireEvent('OverlayViewHide', _this);
24877 fromLatLngToContainerPixel: function(event)
24879 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
24882 isApplied: function()
24884 return this.getGmapContext() == false ? false : true;
24887 getGmapContext: function()
24889 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
24892 GMapContext: function()
24894 var position = new google.maps.LatLng(this.latitude, this.longitude);
24896 var _map = new google.maps.Map(this.el.dom, {
24899 mapTypeId: this.mapTypeId,
24900 mapTypeControl: this.mapTypeControl,
24901 disableDoubleClickZoom: this.disableDoubleClickZoom,
24902 scrollwheel: this.scrollwheel,
24903 streetViewControl: this.streetViewControl,
24904 locationName: this.locationName,
24905 draggable: this.draggable,
24906 enableAutocomplete: this.enableAutocomplete,
24907 enableReverseGeocode: this.enableReverseGeocode
24910 var _marker = new google.maps.Marker({
24911 position: position,
24913 title: this.markerTitle,
24914 draggable: this.draggable
24921 location: position,
24922 radius: this.radius,
24923 locationName: this.locationName,
24924 addressComponents: {
24925 formatted_address: null,
24926 addressLine1: null,
24927 addressLine2: null,
24929 streetNumber: null,
24933 stateOrProvince: null
24936 domContainer: this.el.dom,
24937 geodecoder: new google.maps.Geocoder()
24941 drawCircle: function(center, radius, options)
24943 if (this.gMapContext.circle != null) {
24944 this.gMapContext.circle.setMap(null);
24948 options = Roo.apply({}, options, {
24949 strokeColor: "#0000FF",
24950 strokeOpacity: .35,
24952 fillColor: "#0000FF",
24956 options.map = this.gMapContext.map;
24957 options.radius = radius;
24958 options.center = center;
24959 this.gMapContext.circle = new google.maps.Circle(options);
24960 return this.gMapContext.circle;
24966 setPosition: function(location)
24968 this.gMapContext.location = location;
24969 this.gMapContext.marker.setPosition(location);
24970 this.gMapContext.map.panTo(location);
24971 this.drawCircle(location, this.gMapContext.radius, {});
24975 if (this.gMapContext.settings.enableReverseGeocode) {
24976 this.gMapContext.geodecoder.geocode({
24977 latLng: this.gMapContext.location
24978 }, function(results, status) {
24980 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
24981 _this.gMapContext.locationName = results[0].formatted_address;
24982 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
24984 _this.fireEvent('positionchanged', this, location);
24991 this.fireEvent('positionchanged', this, location);
24996 google.maps.event.trigger(this.gMapContext.map, "resize");
24998 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25000 this.fireEvent('resize', this);
25003 setPositionByLatLng: function(latitude, longitude)
25005 this.setPosition(new google.maps.LatLng(latitude, longitude));
25008 getCurrentPosition: function()
25011 latitude: this.gMapContext.location.lat(),
25012 longitude: this.gMapContext.location.lng()
25016 getAddressName: function()
25018 return this.gMapContext.locationName;
25021 getAddressComponents: function()
25023 return this.gMapContext.addressComponents;
25026 address_component_from_google_geocode: function(address_components)
25030 for (var i = 0; i < address_components.length; i++) {
25031 var component = address_components[i];
25032 if (component.types.indexOf("postal_code") >= 0) {
25033 result.postalCode = component.short_name;
25034 } else if (component.types.indexOf("street_number") >= 0) {
25035 result.streetNumber = component.short_name;
25036 } else if (component.types.indexOf("route") >= 0) {
25037 result.streetName = component.short_name;
25038 } else if (component.types.indexOf("neighborhood") >= 0) {
25039 result.city = component.short_name;
25040 } else if (component.types.indexOf("locality") >= 0) {
25041 result.city = component.short_name;
25042 } else if (component.types.indexOf("sublocality") >= 0) {
25043 result.district = component.short_name;
25044 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25045 result.stateOrProvince = component.short_name;
25046 } else if (component.types.indexOf("country") >= 0) {
25047 result.country = component.short_name;
25051 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25052 result.addressLine2 = "";
25056 setZoomLevel: function(zoom)
25058 this.gMapContext.map.setZoom(zoom);
25071 this.fireEvent('show', this);
25082 this.fireEvent('hide', this);
25087 Roo.apply(Roo.bootstrap.LocationPicker, {
25089 OverlayView : function(map, options)
25091 options = options || {};
25105 * @class Roo.bootstrap.Alert
25106 * @extends Roo.bootstrap.Component
25107 * Bootstrap Alert class
25108 * @cfg {String} title The title of alert
25109 * @cfg {String} html The content of alert
25110 * @cfg {String} weight ( success | info | warning | danger )
25111 * @cfg {String} faicon font-awesomeicon
25114 * Create a new alert
25115 * @param {Object} config The config object
25119 Roo.bootstrap.Alert = function(config){
25120 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25124 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25131 getAutoCreate : function()
25140 cls : 'roo-alert-icon'
25145 cls : 'roo-alert-title',
25150 cls : 'roo-alert-text',
25157 cfg.cn[0].cls += ' fa ' + this.faicon;
25161 cfg.cls += ' alert-' + this.weight;
25167 initEvents: function()
25169 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25172 setTitle : function(str)
25174 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25177 setText : function(str)
25179 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25182 setWeight : function(weight)
25185 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25188 this.weight = weight;
25190 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25193 setIcon : function(icon)
25196 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25199 this.faicon = icon;
25201 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25222 * @class Roo.bootstrap.UploadCropbox
25223 * @extends Roo.bootstrap.Component
25224 * Bootstrap UploadCropbox class
25225 * @cfg {String} emptyText show when image has been loaded
25226 * @cfg {String} rotateNotify show when image too small to rotate
25227 * @cfg {Number} errorTimeout default 3000
25228 * @cfg {Number} minWidth default 300
25229 * @cfg {Number} minHeight default 300
25230 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25231 * @cfg {Boolean} isDocument (true|false) default false
25232 * @cfg {String} url action url
25233 * @cfg {String} paramName default 'imageUpload'
25234 * @cfg {String} method default POST
25235 * @cfg {Boolean} loadMask (true|false) default true
25236 * @cfg {Boolean} loadingText default 'Loading...'
25239 * Create a new UploadCropbox
25240 * @param {Object} config The config object
25243 Roo.bootstrap.UploadCropbox = function(config){
25244 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25248 * @event beforeselectfile
25249 * Fire before select file
25250 * @param {Roo.bootstrap.UploadCropbox} this
25252 "beforeselectfile" : true,
25255 * Fire after initEvent
25256 * @param {Roo.bootstrap.UploadCropbox} this
25261 * Fire after initEvent
25262 * @param {Roo.bootstrap.UploadCropbox} this
25263 * @param {String} data
25268 * Fire when preparing the file data
25269 * @param {Roo.bootstrap.UploadCropbox} this
25270 * @param {Object} file
25275 * Fire when get exception
25276 * @param {Roo.bootstrap.UploadCropbox} this
25277 * @param {XMLHttpRequest} xhr
25279 "exception" : true,
25281 * @event beforeloadcanvas
25282 * Fire before load the canvas
25283 * @param {Roo.bootstrap.UploadCropbox} this
25284 * @param {String} src
25286 "beforeloadcanvas" : true,
25289 * Fire when trash image
25290 * @param {Roo.bootstrap.UploadCropbox} this
25295 * Fire when download the image
25296 * @param {Roo.bootstrap.UploadCropbox} this
25300 * @event footerbuttonclick
25301 * Fire when footerbuttonclick
25302 * @param {Roo.bootstrap.UploadCropbox} this
25303 * @param {String} type
25305 "footerbuttonclick" : true,
25309 * @param {Roo.bootstrap.UploadCropbox} this
25314 * Fire when rotate the image
25315 * @param {Roo.bootstrap.UploadCropbox} this
25316 * @param {String} pos
25321 * Fire when inspect the file
25322 * @param {Roo.bootstrap.UploadCropbox} this
25323 * @param {Object} file
25328 * Fire when xhr upload the file
25329 * @param {Roo.bootstrap.UploadCropbox} this
25330 * @param {Object} data
25335 * Fire when arrange the file data
25336 * @param {Roo.bootstrap.UploadCropbox} this
25337 * @param {Object} formData
25342 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
25345 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
25347 emptyText : 'Click to upload image',
25348 rotateNotify : 'Image is too small to rotate',
25349 errorTimeout : 3000,
25363 cropType : 'image/jpeg',
25365 canvasLoaded : false,
25366 isDocument : false,
25368 paramName : 'imageUpload',
25370 loadingText : 'Loading...',
25373 getAutoCreate : function()
25377 cls : 'roo-upload-cropbox',
25381 cls : 'roo-upload-cropbox-selector',
25386 cls : 'roo-upload-cropbox-body',
25387 style : 'cursor:pointer',
25391 cls : 'roo-upload-cropbox-preview'
25395 cls : 'roo-upload-cropbox-thumb'
25399 cls : 'roo-upload-cropbox-empty-notify',
25400 html : this.emptyText
25404 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25405 html : this.rotateNotify
25411 cls : 'roo-upload-cropbox-footer',
25414 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25424 onRender : function(ct, position)
25426 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25428 if (this.buttons.length) {
25430 Roo.each(this.buttons, function(bb) {
25432 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25434 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25440 this.maskEl = this.el;
25444 initEvents : function()
25446 this.urlAPI = (window.createObjectURL && window) ||
25447 (window.URL && URL.revokeObjectURL && URL) ||
25448 (window.webkitURL && webkitURL);
25450 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25451 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25453 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25454 this.selectorEl.hide();
25456 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25457 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25459 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25460 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25461 this.thumbEl.hide();
25463 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25464 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25466 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25467 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25468 this.errorEl.hide();
25470 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25471 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25472 this.footerEl.hide();
25474 this.setThumbBoxSize();
25480 this.fireEvent('initial', this);
25487 window.addEventListener("resize", function() { _this.resize(); } );
25489 this.bodyEl.on('click', this.beforeSelectFile, this);
25492 this.bodyEl.on('touchstart', this.onTouchStart, this);
25493 this.bodyEl.on('touchmove', this.onTouchMove, this);
25494 this.bodyEl.on('touchend', this.onTouchEnd, this);
25498 this.bodyEl.on('mousedown', this.onMouseDown, this);
25499 this.bodyEl.on('mousemove', this.onMouseMove, this);
25500 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25501 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25502 Roo.get(document).on('mouseup', this.onMouseUp, this);
25505 this.selectorEl.on('change', this.onFileSelected, this);
25511 this.baseScale = 1;
25513 this.baseRotate = 1;
25514 this.dragable = false;
25515 this.pinching = false;
25518 this.cropData = false;
25519 this.notifyEl.dom.innerHTML = this.emptyText;
25521 this.selectorEl.dom.value = '';
25525 resize : function()
25527 if(this.fireEvent('resize', this) != false){
25528 this.setThumbBoxPosition();
25529 this.setCanvasPosition();
25533 onFooterButtonClick : function(e, el, o, type)
25536 case 'rotate-left' :
25537 this.onRotateLeft(e);
25539 case 'rotate-right' :
25540 this.onRotateRight(e);
25543 this.beforeSelectFile(e);
25558 this.fireEvent('footerbuttonclick', this, type);
25561 beforeSelectFile : function(e)
25563 e.preventDefault();
25565 if(this.fireEvent('beforeselectfile', this) != false){
25566 this.selectorEl.dom.click();
25570 onFileSelected : function(e)
25572 e.preventDefault();
25574 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25578 var file = this.selectorEl.dom.files[0];
25580 if(this.fireEvent('inspect', this, file) != false){
25581 this.prepare(file);
25586 trash : function(e)
25588 this.fireEvent('trash', this);
25591 download : function(e)
25593 this.fireEvent('download', this);
25596 loadCanvas : function(src)
25598 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25602 this.imageEl = document.createElement('img');
25606 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25608 this.imageEl.src = src;
25612 onLoadCanvas : function()
25614 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25615 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25617 this.bodyEl.un('click', this.beforeSelectFile, this);
25619 this.notifyEl.hide();
25620 this.thumbEl.show();
25621 this.footerEl.show();
25623 this.baseRotateLevel();
25625 if(this.isDocument){
25626 this.setThumbBoxSize();
25629 this.setThumbBoxPosition();
25631 this.baseScaleLevel();
25637 this.canvasLoaded = true;
25640 this.maskEl.unmask();
25645 setCanvasPosition : function()
25647 if(!this.canvasEl){
25651 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
25652 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
25654 this.previewEl.setLeft(pw);
25655 this.previewEl.setTop(ph);
25659 onMouseDown : function(e)
25663 this.dragable = true;
25664 this.pinching = false;
25666 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
25667 this.dragable = false;
25671 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25672 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25676 onMouseMove : function(e)
25680 if(!this.canvasLoaded){
25684 if (!this.dragable){
25688 var minX = Math.ceil(this.thumbEl.getLeft(true));
25689 var minY = Math.ceil(this.thumbEl.getTop(true));
25691 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
25692 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
25694 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25695 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25697 x = x - this.mouseX;
25698 y = y - this.mouseY;
25700 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
25701 var bgY = Math.ceil(y + this.previewEl.getTop(true));
25703 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
25704 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
25706 this.previewEl.setLeft(bgX);
25707 this.previewEl.setTop(bgY);
25709 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25710 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25713 onMouseUp : function(e)
25717 this.dragable = false;
25720 onMouseWheel : function(e)
25724 this.startScale = this.scale;
25726 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
25728 if(!this.zoomable()){
25729 this.scale = this.startScale;
25738 zoomable : function()
25740 var minScale = this.thumbEl.getWidth() / this.minWidth;
25742 if(this.minWidth < this.minHeight){
25743 minScale = this.thumbEl.getHeight() / this.minHeight;
25746 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
25747 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
25751 (this.rotate == 0 || this.rotate == 180) &&
25753 width > this.imageEl.OriginWidth ||
25754 height > this.imageEl.OriginHeight ||
25755 (width < this.minWidth && height < this.minHeight)
25763 (this.rotate == 90 || this.rotate == 270) &&
25765 width > this.imageEl.OriginWidth ||
25766 height > this.imageEl.OriginHeight ||
25767 (width < this.minHeight && height < this.minWidth)
25774 !this.isDocument &&
25775 (this.rotate == 0 || this.rotate == 180) &&
25777 width < this.minWidth ||
25778 width > this.imageEl.OriginWidth ||
25779 height < this.minHeight ||
25780 height > this.imageEl.OriginHeight
25787 !this.isDocument &&
25788 (this.rotate == 90 || this.rotate == 270) &&
25790 width < this.minHeight ||
25791 width > this.imageEl.OriginWidth ||
25792 height < this.minWidth ||
25793 height > this.imageEl.OriginHeight
25803 onRotateLeft : function(e)
25805 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25807 var minScale = this.thumbEl.getWidth() / this.minWidth;
25809 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25810 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25812 this.startScale = this.scale;
25814 while (this.getScaleLevel() < minScale){
25816 this.scale = this.scale + 1;
25818 if(!this.zoomable()){
25823 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25824 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25829 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25836 this.scale = this.startScale;
25838 this.onRotateFail();
25843 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25845 if(this.isDocument){
25846 this.setThumbBoxSize();
25847 this.setThumbBoxPosition();
25848 this.setCanvasPosition();
25853 this.fireEvent('rotate', this, 'left');
25857 onRotateRight : function(e)
25859 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25861 var minScale = this.thumbEl.getWidth() / this.minWidth;
25863 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25864 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25866 this.startScale = this.scale;
25868 while (this.getScaleLevel() < minScale){
25870 this.scale = this.scale + 1;
25872 if(!this.zoomable()){
25877 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25878 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25883 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25890 this.scale = this.startScale;
25892 this.onRotateFail();
25897 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25899 if(this.isDocument){
25900 this.setThumbBoxSize();
25901 this.setThumbBoxPosition();
25902 this.setCanvasPosition();
25907 this.fireEvent('rotate', this, 'right');
25910 onRotateFail : function()
25912 this.errorEl.show(true);
25916 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
25921 this.previewEl.dom.innerHTML = '';
25923 var canvasEl = document.createElement("canvas");
25925 var contextEl = canvasEl.getContext("2d");
25927 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25928 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25929 var center = this.imageEl.OriginWidth / 2;
25931 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
25932 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25933 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25934 center = this.imageEl.OriginHeight / 2;
25937 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
25939 contextEl.translate(center, center);
25940 contextEl.rotate(this.rotate * Math.PI / 180);
25942 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25944 this.canvasEl = document.createElement("canvas");
25946 this.contextEl = this.canvasEl.getContext("2d");
25948 switch (this.rotate) {
25951 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25952 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25954 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25959 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25960 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25962 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25963 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);
25967 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25972 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25973 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25975 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25976 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);
25980 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);
25985 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25986 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25988 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25989 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25993 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);
26000 this.previewEl.appendChild(this.canvasEl);
26002 this.setCanvasPosition();
26007 if(!this.canvasLoaded){
26011 var imageCanvas = document.createElement("canvas");
26013 var imageContext = imageCanvas.getContext("2d");
26015 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26016 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26018 var center = imageCanvas.width / 2;
26020 imageContext.translate(center, center);
26022 imageContext.rotate(this.rotate * Math.PI / 180);
26024 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26026 var canvas = document.createElement("canvas");
26028 var context = canvas.getContext("2d");
26030 canvas.width = this.minWidth;
26031 canvas.height = this.minHeight;
26033 switch (this.rotate) {
26036 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26037 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26039 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26040 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26042 var targetWidth = this.minWidth - 2 * x;
26043 var targetHeight = this.minHeight - 2 * y;
26047 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26048 scale = targetWidth / width;
26051 if(x > 0 && y == 0){
26052 scale = targetHeight / height;
26055 if(x > 0 && y > 0){
26056 scale = targetWidth / width;
26058 if(width < height){
26059 scale = targetHeight / height;
26063 context.scale(scale, scale);
26065 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26066 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26068 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26069 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26071 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26076 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26077 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26079 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26080 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26082 var targetWidth = this.minWidth - 2 * x;
26083 var targetHeight = this.minHeight - 2 * y;
26087 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26088 scale = targetWidth / width;
26091 if(x > 0 && y == 0){
26092 scale = targetHeight / height;
26095 if(x > 0 && y > 0){
26096 scale = targetWidth / width;
26098 if(width < height){
26099 scale = targetHeight / height;
26103 context.scale(scale, scale);
26105 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26106 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26108 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26109 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26111 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26113 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26118 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26119 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26121 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26122 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26124 var targetWidth = this.minWidth - 2 * x;
26125 var targetHeight = this.minHeight - 2 * y;
26129 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26130 scale = targetWidth / width;
26133 if(x > 0 && y == 0){
26134 scale = targetHeight / height;
26137 if(x > 0 && y > 0){
26138 scale = targetWidth / width;
26140 if(width < height){
26141 scale = targetHeight / height;
26145 context.scale(scale, scale);
26147 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26148 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26150 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26151 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26153 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26154 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26156 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26161 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26162 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26164 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26165 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26167 var targetWidth = this.minWidth - 2 * x;
26168 var targetHeight = this.minHeight - 2 * y;
26172 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26173 scale = targetWidth / width;
26176 if(x > 0 && y == 0){
26177 scale = targetHeight / height;
26180 if(x > 0 && y > 0){
26181 scale = targetWidth / width;
26183 if(width < height){
26184 scale = targetHeight / height;
26188 context.scale(scale, scale);
26190 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26191 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26193 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26194 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26196 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26198 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26205 this.cropData = canvas.toDataURL(this.cropType);
26207 if(this.fireEvent('crop', this, this.cropData) !== false){
26208 this.process(this.file, this.cropData);
26215 setThumbBoxSize : function()
26219 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26220 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26221 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26223 this.minWidth = width;
26224 this.minHeight = height;
26226 if(this.rotate == 90 || this.rotate == 270){
26227 this.minWidth = height;
26228 this.minHeight = width;
26233 width = Math.ceil(this.minWidth * height / this.minHeight);
26235 if(this.minWidth > this.minHeight){
26237 height = Math.ceil(this.minHeight * width / this.minWidth);
26240 this.thumbEl.setStyle({
26241 width : width + 'px',
26242 height : height + 'px'
26249 setThumbBoxPosition : function()
26251 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
26252 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
26254 this.thumbEl.setLeft(x);
26255 this.thumbEl.setTop(y);
26259 baseRotateLevel : function()
26261 this.baseRotate = 1;
26264 typeof(this.exif) != 'undefined' &&
26265 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
26266 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
26268 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
26271 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
26275 baseScaleLevel : function()
26279 if(this.isDocument){
26281 if(this.baseRotate == 6 || this.baseRotate == 8){
26283 height = this.thumbEl.getHeight();
26284 this.baseScale = height / this.imageEl.OriginWidth;
26286 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
26287 width = this.thumbEl.getWidth();
26288 this.baseScale = width / this.imageEl.OriginHeight;
26294 height = this.thumbEl.getHeight();
26295 this.baseScale = height / this.imageEl.OriginHeight;
26297 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
26298 width = this.thumbEl.getWidth();
26299 this.baseScale = width / this.imageEl.OriginWidth;
26305 if(this.baseRotate == 6 || this.baseRotate == 8){
26307 width = this.thumbEl.getHeight();
26308 this.baseScale = width / this.imageEl.OriginHeight;
26310 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
26311 height = this.thumbEl.getWidth();
26312 this.baseScale = height / this.imageEl.OriginHeight;
26315 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26316 height = this.thumbEl.getWidth();
26317 this.baseScale = height / this.imageEl.OriginHeight;
26319 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
26320 width = this.thumbEl.getHeight();
26321 this.baseScale = width / this.imageEl.OriginWidth;
26328 width = this.thumbEl.getWidth();
26329 this.baseScale = width / this.imageEl.OriginWidth;
26331 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
26332 height = this.thumbEl.getHeight();
26333 this.baseScale = height / this.imageEl.OriginHeight;
26336 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26338 height = this.thumbEl.getHeight();
26339 this.baseScale = height / this.imageEl.OriginHeight;
26341 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
26342 width = this.thumbEl.getWidth();
26343 this.baseScale = width / this.imageEl.OriginWidth;
26351 getScaleLevel : function()
26353 return this.baseScale * Math.pow(1.1, this.scale);
26356 onTouchStart : function(e)
26358 if(!this.canvasLoaded){
26359 this.beforeSelectFile(e);
26363 var touches = e.browserEvent.touches;
26369 if(touches.length == 1){
26370 this.onMouseDown(e);
26374 if(touches.length != 2){
26380 for(var i = 0, finger; finger = touches[i]; i++){
26381 coords.push(finger.pageX, finger.pageY);
26384 var x = Math.pow(coords[0] - coords[2], 2);
26385 var y = Math.pow(coords[1] - coords[3], 2);
26387 this.startDistance = Math.sqrt(x + y);
26389 this.startScale = this.scale;
26391 this.pinching = true;
26392 this.dragable = false;
26396 onTouchMove : function(e)
26398 if(!this.pinching && !this.dragable){
26402 var touches = e.browserEvent.touches;
26409 this.onMouseMove(e);
26415 for(var i = 0, finger; finger = touches[i]; i++){
26416 coords.push(finger.pageX, finger.pageY);
26419 var x = Math.pow(coords[0] - coords[2], 2);
26420 var y = Math.pow(coords[1] - coords[3], 2);
26422 this.endDistance = Math.sqrt(x + y);
26424 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26426 if(!this.zoomable()){
26427 this.scale = this.startScale;
26435 onTouchEnd : function(e)
26437 this.pinching = false;
26438 this.dragable = false;
26442 process : function(file, crop)
26445 this.maskEl.mask(this.loadingText);
26448 this.xhr = new XMLHttpRequest();
26450 file.xhr = this.xhr;
26452 this.xhr.open(this.method, this.url, true);
26455 "Accept": "application/json",
26456 "Cache-Control": "no-cache",
26457 "X-Requested-With": "XMLHttpRequest"
26460 for (var headerName in headers) {
26461 var headerValue = headers[headerName];
26463 this.xhr.setRequestHeader(headerName, headerValue);
26469 this.xhr.onload = function()
26471 _this.xhrOnLoad(_this.xhr);
26474 this.xhr.onerror = function()
26476 _this.xhrOnError(_this.xhr);
26479 var formData = new FormData();
26481 formData.append('returnHTML', 'NO');
26484 formData.append('crop', crop);
26487 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26488 formData.append(this.paramName, file, file.name);
26491 if(typeof(file.filename) != 'undefined'){
26492 formData.append('filename', file.filename);
26495 if(typeof(file.mimetype) != 'undefined'){
26496 formData.append('mimetype', file.mimetype);
26499 if(this.fireEvent('arrange', this, formData) != false){
26500 this.xhr.send(formData);
26504 xhrOnLoad : function(xhr)
26507 this.maskEl.unmask();
26510 if (xhr.readyState !== 4) {
26511 this.fireEvent('exception', this, xhr);
26515 var response = Roo.decode(xhr.responseText);
26517 if(!response.success){
26518 this.fireEvent('exception', this, xhr);
26522 var response = Roo.decode(xhr.responseText);
26524 this.fireEvent('upload', this, response);
26528 xhrOnError : function()
26531 this.maskEl.unmask();
26534 Roo.log('xhr on error');
26536 var response = Roo.decode(xhr.responseText);
26542 prepare : function(file)
26545 this.maskEl.mask(this.loadingText);
26551 if(typeof(file) === 'string'){
26552 this.loadCanvas(file);
26556 if(!file || !this.urlAPI){
26561 this.cropType = file.type;
26565 if(this.fireEvent('prepare', this, this.file) != false){
26567 var reader = new FileReader();
26569 reader.onload = function (e) {
26570 if (e.target.error) {
26571 Roo.log(e.target.error);
26575 var buffer = e.target.result,
26576 dataView = new DataView(buffer),
26578 maxOffset = dataView.byteLength - 4,
26582 if (dataView.getUint16(0) === 0xffd8) {
26583 while (offset < maxOffset) {
26584 markerBytes = dataView.getUint16(offset);
26586 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26587 markerLength = dataView.getUint16(offset + 2) + 2;
26588 if (offset + markerLength > dataView.byteLength) {
26589 Roo.log('Invalid meta data: Invalid segment size.');
26593 if(markerBytes == 0xffe1){
26594 _this.parseExifData(
26601 offset += markerLength;
26611 var url = _this.urlAPI.createObjectURL(_this.file);
26613 _this.loadCanvas(url);
26618 reader.readAsArrayBuffer(this.file);
26624 parseExifData : function(dataView, offset, length)
26626 var tiffOffset = offset + 10,
26630 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26631 // No Exif data, might be XMP data instead
26635 // Check for the ASCII code for "Exif" (0x45786966):
26636 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26637 // No Exif data, might be XMP data instead
26640 if (tiffOffset + 8 > dataView.byteLength) {
26641 Roo.log('Invalid Exif data: Invalid segment size.');
26644 // Check for the two null bytes:
26645 if (dataView.getUint16(offset + 8) !== 0x0000) {
26646 Roo.log('Invalid Exif data: Missing byte alignment offset.');
26649 // Check the byte alignment:
26650 switch (dataView.getUint16(tiffOffset)) {
26652 littleEndian = true;
26655 littleEndian = false;
26658 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
26661 // Check for the TIFF tag marker (0x002A):
26662 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
26663 Roo.log('Invalid Exif data: Missing TIFF marker.');
26666 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
26667 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
26669 this.parseExifTags(
26672 tiffOffset + dirOffset,
26677 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
26682 if (dirOffset + 6 > dataView.byteLength) {
26683 Roo.log('Invalid Exif data: Invalid directory offset.');
26686 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
26687 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
26688 if (dirEndOffset + 4 > dataView.byteLength) {
26689 Roo.log('Invalid Exif data: Invalid directory size.');
26692 for (i = 0; i < tagsNumber; i += 1) {
26696 dirOffset + 2 + 12 * i, // tag offset
26700 // Return the offset to the next directory:
26701 return dataView.getUint32(dirEndOffset, littleEndian);
26704 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
26706 var tag = dataView.getUint16(offset, littleEndian);
26708 this.exif[tag] = this.getExifValue(
26712 dataView.getUint16(offset + 2, littleEndian), // tag type
26713 dataView.getUint32(offset + 4, littleEndian), // tag length
26718 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
26720 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
26729 Roo.log('Invalid Exif data: Invalid tag type.');
26733 tagSize = tagType.size * length;
26734 // Determine if the value is contained in the dataOffset bytes,
26735 // or if the value at the dataOffset is a pointer to the actual data:
26736 dataOffset = tagSize > 4 ?
26737 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
26738 if (dataOffset + tagSize > dataView.byteLength) {
26739 Roo.log('Invalid Exif data: Invalid data offset.');
26742 if (length === 1) {
26743 return tagType.getValue(dataView, dataOffset, littleEndian);
26746 for (i = 0; i < length; i += 1) {
26747 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
26750 if (tagType.ascii) {
26752 // Concatenate the chars:
26753 for (i = 0; i < values.length; i += 1) {
26755 // Ignore the terminating NULL byte(s):
26756 if (c === '\u0000') {
26768 Roo.apply(Roo.bootstrap.UploadCropbox, {
26770 'Orientation': 0x0112
26774 1: 0, //'top-left',
26776 3: 180, //'bottom-right',
26777 // 4: 'bottom-left',
26779 6: 90, //'right-top',
26780 // 7: 'right-bottom',
26781 8: 270 //'left-bottom'
26785 // byte, 8-bit unsigned int:
26787 getValue: function (dataView, dataOffset) {
26788 return dataView.getUint8(dataOffset);
26792 // ascii, 8-bit byte:
26794 getValue: function (dataView, dataOffset) {
26795 return String.fromCharCode(dataView.getUint8(dataOffset));
26800 // short, 16 bit int:
26802 getValue: function (dataView, dataOffset, littleEndian) {
26803 return dataView.getUint16(dataOffset, littleEndian);
26807 // long, 32 bit int:
26809 getValue: function (dataView, dataOffset, littleEndian) {
26810 return dataView.getUint32(dataOffset, littleEndian);
26814 // rational = two long values, first is numerator, second is denominator:
26816 getValue: function (dataView, dataOffset, littleEndian) {
26817 return dataView.getUint32(dataOffset, littleEndian) /
26818 dataView.getUint32(dataOffset + 4, littleEndian);
26822 // slong, 32 bit signed int:
26824 getValue: function (dataView, dataOffset, littleEndian) {
26825 return dataView.getInt32(dataOffset, littleEndian);
26829 // srational, two slongs, first is numerator, second is denominator:
26831 getValue: function (dataView, dataOffset, littleEndian) {
26832 return dataView.getInt32(dataOffset, littleEndian) /
26833 dataView.getInt32(dataOffset + 4, littleEndian);
26843 cls : 'btn-group roo-upload-cropbox-rotate-left',
26844 action : 'rotate-left',
26848 cls : 'btn btn-default',
26849 html : '<i class="fa fa-undo"></i>'
26855 cls : 'btn-group roo-upload-cropbox-picture',
26856 action : 'picture',
26860 cls : 'btn btn-default',
26861 html : '<i class="fa fa-picture-o"></i>'
26867 cls : 'btn-group roo-upload-cropbox-rotate-right',
26868 action : 'rotate-right',
26872 cls : 'btn btn-default',
26873 html : '<i class="fa fa-repeat"></i>'
26881 cls : 'btn-group roo-upload-cropbox-rotate-left',
26882 action : 'rotate-left',
26886 cls : 'btn btn-default',
26887 html : '<i class="fa fa-undo"></i>'
26893 cls : 'btn-group roo-upload-cropbox-download',
26894 action : 'download',
26898 cls : 'btn btn-default',
26899 html : '<i class="fa fa-download"></i>'
26905 cls : 'btn-group roo-upload-cropbox-crop',
26910 cls : 'btn btn-default',
26911 html : '<i class="fa fa-crop"></i>'
26917 cls : 'btn-group roo-upload-cropbox-trash',
26922 cls : 'btn btn-default',
26923 html : '<i class="fa fa-trash"></i>'
26929 cls : 'btn-group roo-upload-cropbox-rotate-right',
26930 action : 'rotate-right',
26934 cls : 'btn btn-default',
26935 html : '<i class="fa fa-repeat"></i>'
26943 cls : 'btn-group roo-upload-cropbox-rotate-left',
26944 action : 'rotate-left',
26948 cls : 'btn btn-default',
26949 html : '<i class="fa fa-undo"></i>'
26955 cls : 'btn-group roo-upload-cropbox-rotate-right',
26956 action : 'rotate-right',
26960 cls : 'btn btn-default',
26961 html : '<i class="fa fa-repeat"></i>'
26974 * @class Roo.bootstrap.DocumentManager
26975 * @extends Roo.bootstrap.Component
26976 * Bootstrap DocumentManager class
26977 * @cfg {String} paramName default 'imageUpload'
26978 * @cfg {String} method default POST
26979 * @cfg {String} url action url
26980 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
26981 * @cfg {Boolean} multiple multiple upload default true
26982 * @cfg {Number} thumbSize default 300
26983 * @cfg {String} fieldLabel
26984 * @cfg {Number} labelWidth default 4
26985 * @cfg {String} labelAlign (left|top) default left
26986 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
26989 * Create a new DocumentManager
26990 * @param {Object} config The config object
26993 Roo.bootstrap.DocumentManager = function(config){
26994 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
26999 * Fire when initial the DocumentManager
27000 * @param {Roo.bootstrap.DocumentManager} this
27005 * inspect selected file
27006 * @param {Roo.bootstrap.DocumentManager} this
27007 * @param {File} file
27012 * Fire when xhr load exception
27013 * @param {Roo.bootstrap.DocumentManager} this
27014 * @param {XMLHttpRequest} xhr
27016 "exception" : true,
27019 * prepare the form data
27020 * @param {Roo.bootstrap.DocumentManager} this
27021 * @param {Object} formData
27026 * Fire when remove the file
27027 * @param {Roo.bootstrap.DocumentManager} this
27028 * @param {Object} file
27033 * Fire after refresh the file
27034 * @param {Roo.bootstrap.DocumentManager} this
27039 * Fire after click the image
27040 * @param {Roo.bootstrap.DocumentManager} this
27041 * @param {Object} file
27046 * Fire when upload a image and editable set to true
27047 * @param {Roo.bootstrap.DocumentManager} this
27048 * @param {Object} file
27052 * @event beforeselectfile
27053 * Fire before select file
27054 * @param {Roo.bootstrap.DocumentManager} this
27056 "beforeselectfile" : true,
27059 * Fire before process file
27060 * @param {Roo.bootstrap.DocumentManager} this
27061 * @param {Object} file
27068 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27077 paramName : 'imageUpload',
27080 labelAlign : 'left',
27087 getAutoCreate : function()
27089 var managerWidget = {
27091 cls : 'roo-document-manager',
27095 cls : 'roo-document-manager-selector',
27100 cls : 'roo-document-manager-uploader',
27104 cls : 'roo-document-manager-upload-btn',
27105 html : '<i class="fa fa-plus"></i>'
27116 cls : 'column col-md-12',
27121 if(this.fieldLabel.length){
27126 cls : 'column col-md-12',
27127 html : this.fieldLabel
27131 cls : 'column col-md-12',
27136 if(this.labelAlign == 'left'){
27140 cls : 'column col-md-' + this.labelWidth,
27141 html : this.fieldLabel
27145 cls : 'column col-md-' + (12 - this.labelWidth),
27155 cls : 'row clearfix',
27163 initEvents : function()
27165 this.managerEl = this.el.select('.roo-document-manager', true).first();
27166 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27168 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27169 this.selectorEl.hide();
27172 this.selectorEl.attr('multiple', 'multiple');
27175 this.selectorEl.on('change', this.onFileSelected, this);
27177 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27178 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27180 this.uploader.on('click', this.onUploaderClick, this);
27182 this.renderProgressDialog();
27186 window.addEventListener("resize", function() { _this.refresh(); } );
27188 this.fireEvent('initial', this);
27191 renderProgressDialog : function()
27195 this.progressDialog = new Roo.bootstrap.Modal({
27196 cls : 'roo-document-manager-progress-dialog',
27197 allow_close : false,
27207 btnclick : function() {
27208 _this.uploadCancel();
27214 this.progressDialog.render(Roo.get(document.body));
27216 this.progress = new Roo.bootstrap.Progress({
27217 cls : 'roo-document-manager-progress',
27222 this.progress.render(this.progressDialog.getChildContainer());
27224 this.progressBar = new Roo.bootstrap.ProgressBar({
27225 cls : 'roo-document-manager-progress-bar',
27228 aria_valuemax : 12,
27232 this.progressBar.render(this.progress.getChildContainer());
27235 onUploaderClick : function(e)
27237 e.preventDefault();
27239 if(this.fireEvent('beforeselectfile', this) != false){
27240 this.selectorEl.dom.click();
27245 onFileSelected : function(e)
27247 e.preventDefault();
27249 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27253 Roo.each(this.selectorEl.dom.files, function(file){
27254 if(this.fireEvent('inspect', this, file) != false){
27255 this.files.push(file);
27265 this.selectorEl.dom.value = '';
27267 if(!this.files.length){
27271 if(this.boxes > 0 && this.files.length > this.boxes){
27272 this.files = this.files.slice(0, this.boxes);
27275 this.uploader.show();
27277 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27278 this.uploader.hide();
27287 Roo.each(this.files, function(file){
27289 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27290 var f = this.renderPreview(file);
27295 if(file.type.indexOf('image') != -1){
27296 this.delegates.push(
27298 _this.process(file);
27299 }).createDelegate(this)
27307 _this.process(file);
27308 }).createDelegate(this)
27313 this.files = files;
27315 this.delegates = this.delegates.concat(docs);
27317 if(!this.delegates.length){
27322 this.progressBar.aria_valuemax = this.delegates.length;
27329 arrange : function()
27331 if(!this.delegates.length){
27332 this.progressDialog.hide();
27337 var delegate = this.delegates.shift();
27339 this.progressDialog.show();
27341 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
27343 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
27348 refresh : function()
27350 this.uploader.show();
27352 if(this.boxes > 0 && this.files.length > this.boxes - 1){
27353 this.uploader.hide();
27356 Roo.isTouch ? this.closable(false) : this.closable(true);
27358 this.fireEvent('refresh', this);
27361 onRemove : function(e, el, o)
27363 e.preventDefault();
27365 this.fireEvent('remove', this, o);
27369 remove : function(o)
27373 Roo.each(this.files, function(file){
27374 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27383 this.files = files;
27390 Roo.each(this.files, function(file){
27395 file.target.remove();
27404 onClick : function(e, el, o)
27406 e.preventDefault();
27408 this.fireEvent('click', this, o);
27412 closable : function(closable)
27414 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27416 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27428 xhrOnLoad : function(xhr)
27430 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27434 if (xhr.readyState !== 4) {
27436 this.fireEvent('exception', this, xhr);
27440 var response = Roo.decode(xhr.responseText);
27442 if(!response.success){
27444 this.fireEvent('exception', this, xhr);
27448 var file = this.renderPreview(response.data);
27450 this.files.push(file);
27456 xhrOnError : function(xhr)
27458 Roo.log('xhr on error');
27460 var response = Roo.decode(xhr.responseText);
27467 process : function(file)
27469 if(this.fireEvent('process', this, file) !== false){
27470 if(this.editable && file.type.indexOf('image') != -1){
27471 this.fireEvent('edit', this, file);
27475 this.uploadStart(file, false);
27482 uploadStart : function(file, crop)
27484 this.xhr = new XMLHttpRequest();
27486 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27491 file.xhr = this.xhr;
27493 this.managerEl.createChild({
27495 cls : 'roo-document-manager-loading',
27499 tooltip : file.name,
27500 cls : 'roo-document-manager-thumb',
27501 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27507 this.xhr.open(this.method, this.url, true);
27510 "Accept": "application/json",
27511 "Cache-Control": "no-cache",
27512 "X-Requested-With": "XMLHttpRequest"
27515 for (var headerName in headers) {
27516 var headerValue = headers[headerName];
27518 this.xhr.setRequestHeader(headerName, headerValue);
27524 this.xhr.onload = function()
27526 _this.xhrOnLoad(_this.xhr);
27529 this.xhr.onerror = function()
27531 _this.xhrOnError(_this.xhr);
27534 var formData = new FormData();
27536 formData.append('returnHTML', 'NO');
27539 formData.append('crop', crop);
27542 formData.append(this.paramName, file, file.name);
27544 if(this.fireEvent('prepare', this, formData) != false){
27545 this.xhr.send(formData);
27549 uploadCancel : function()
27556 this.delegates = [];
27558 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27565 renderPreview : function(file)
27567 if(typeof(file.target) != 'undefined' && file.target){
27571 var previewEl = this.managerEl.createChild({
27573 cls : 'roo-document-manager-preview',
27577 tooltip : file.filename,
27578 cls : 'roo-document-manager-thumb',
27579 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27584 html : '<i class="fa fa-times-circle"></i>'
27589 var close = previewEl.select('button.close', true).first();
27591 close.on('click', this.onRemove, this, file);
27593 file.target = previewEl;
27595 var image = previewEl.select('img', true).first();
27599 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27601 image.on('click', this.onClick, this, file);
27607 onPreviewLoad : function(file, image)
27609 if(typeof(file.target) == 'undefined' || !file.target){
27613 var width = image.dom.naturalWidth || image.dom.width;
27614 var height = image.dom.naturalHeight || image.dom.height;
27616 if(width > height){
27617 file.target.addClass('wide');
27621 file.target.addClass('tall');
27626 uploadFromSource : function(file, crop)
27628 this.xhr = new XMLHttpRequest();
27630 this.managerEl.createChild({
27632 cls : 'roo-document-manager-loading',
27636 tooltip : file.name,
27637 cls : 'roo-document-manager-thumb',
27638 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27644 this.xhr.open(this.method, this.url, true);
27647 "Accept": "application/json",
27648 "Cache-Control": "no-cache",
27649 "X-Requested-With": "XMLHttpRequest"
27652 for (var headerName in headers) {
27653 var headerValue = headers[headerName];
27655 this.xhr.setRequestHeader(headerName, headerValue);
27661 this.xhr.onload = function()
27663 _this.xhrOnLoad(_this.xhr);
27666 this.xhr.onerror = function()
27668 _this.xhrOnError(_this.xhr);
27671 var formData = new FormData();
27673 formData.append('returnHTML', 'NO');
27675 formData.append('crop', crop);
27677 if(typeof(file.filename) != 'undefined'){
27678 formData.append('filename', file.filename);
27681 if(typeof(file.mimetype) != 'undefined'){
27682 formData.append('mimetype', file.mimetype);
27685 if(this.fireEvent('prepare', this, formData) != false){
27686 this.xhr.send(formData);
27696 * @class Roo.bootstrap.DocumentViewer
27697 * @extends Roo.bootstrap.Component
27698 * Bootstrap DocumentViewer class
27701 * Create a new DocumentViewer
27702 * @param {Object} config The config object
27705 Roo.bootstrap.DocumentViewer = function(config){
27706 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
27711 * Fire after initEvent
27712 * @param {Roo.bootstrap.DocumentViewer} this
27718 * @param {Roo.bootstrap.DocumentViewer} this
27723 * Fire after trash button
27724 * @param {Roo.bootstrap.DocumentViewer} this
27731 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
27733 getAutoCreate : function()
27737 cls : 'roo-document-viewer',
27741 cls : 'roo-document-viewer-body',
27745 cls : 'roo-document-viewer-thumb',
27749 cls : 'roo-document-viewer-image'
27757 cls : 'roo-document-viewer-footer',
27760 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
27768 cls : 'btn btn-default roo-document-viewer-trash',
27769 html : '<i class="fa fa-trash"></i>'
27782 initEvents : function()
27785 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
27786 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27788 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
27789 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27791 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
27792 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27794 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
27795 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27797 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
27798 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27800 this.bodyEl.on('click', this.onClick, this);
27802 this.trashBtn.on('click', this.onTrash, this);
27806 initial : function()
27808 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
27811 this.fireEvent('initial', this);
27815 onClick : function(e)
27817 e.preventDefault();
27819 this.fireEvent('click', this);
27822 onTrash : function(e)
27824 e.preventDefault();
27826 this.fireEvent('trash', this);
27838 * @class Roo.bootstrap.NavProgressBar
27839 * @extends Roo.bootstrap.Component
27840 * Bootstrap NavProgressBar class
27843 * Create a new nav progress bar
27844 * @param {Object} config The config object
27847 Roo.bootstrap.NavProgressBar = function(config){
27848 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
27850 this.bullets = this.bullets || [];
27852 // Roo.bootstrap.NavProgressBar.register(this);
27856 * Fires when the active item changes
27857 * @param {Roo.bootstrap.NavProgressBar} this
27858 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
27859 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
27866 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
27871 getAutoCreate : function()
27873 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
27877 cls : 'roo-navigation-bar-group',
27881 cls : 'roo-navigation-top-bar'
27885 cls : 'roo-navigation-bullets-bar',
27889 cls : 'roo-navigation-bar'
27896 cls : 'roo-navigation-bottom-bar'
27906 initEvents: function()
27911 onRender : function(ct, position)
27913 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
27915 if(this.bullets.length){
27916 Roo.each(this.bullets, function(b){
27925 addItem : function(cfg)
27927 var item = new Roo.bootstrap.NavProgressItem(cfg);
27929 item.parentId = this.id;
27930 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
27933 var top = new Roo.bootstrap.Element({
27935 cls : 'roo-navigation-bar-text'
27938 var bottom = new Roo.bootstrap.Element({
27940 cls : 'roo-navigation-bar-text'
27943 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
27944 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
27946 var topText = new Roo.bootstrap.Element({
27948 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
27951 var bottomText = new Roo.bootstrap.Element({
27953 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
27956 topText.onRender(top.el, null);
27957 bottomText.onRender(bottom.el, null);
27960 item.bottomEl = bottom;
27963 this.barItems.push(item);
27968 getActive : function()
27970 var active = false;
27972 Roo.each(this.barItems, function(v){
27974 if (!v.isActive()) {
27986 setActiveItem : function(item)
27990 Roo.each(this.barItems, function(v){
27991 if (v.rid == item.rid) {
27995 if (v.isActive()) {
27996 v.setActive(false);
28001 item.setActive(true);
28003 this.fireEvent('changed', this, item, prev);
28006 getBarItem: function(rid)
28010 Roo.each(this.barItems, function(e) {
28011 if (e.rid != rid) {
28022 indexOfItem : function(item)
28026 Roo.each(this.barItems, function(v, i){
28028 if (v.rid != item.rid) {
28039 setActiveNext : function()
28041 var i = this.indexOfItem(this.getActive());
28043 if (i > this.barItems.length) {
28047 this.setActiveItem(this.barItems[i+1]);
28050 setActivePrev : function()
28052 var i = this.indexOfItem(this.getActive());
28058 this.setActiveItem(this.barItems[i-1]);
28061 format : function()
28063 if(!this.barItems.length){
28067 var width = 100 / this.barItems.length;
28069 Roo.each(this.barItems, function(i){
28070 i.el.setStyle('width', width + '%');
28071 i.topEl.el.setStyle('width', width + '%');
28072 i.bottomEl.el.setStyle('width', width + '%');
28081 * Nav Progress Item
28086 * @class Roo.bootstrap.NavProgressItem
28087 * @extends Roo.bootstrap.Component
28088 * Bootstrap NavProgressItem class
28089 * @cfg {String} rid the reference id
28090 * @cfg {Boolean} active (true|false) Is item active default false
28091 * @cfg {Boolean} disabled (true|false) Is item active default false
28092 * @cfg {String} html
28093 * @cfg {String} position (top|bottom) text position default bottom
28094 * @cfg {String} icon show icon instead of number
28097 * Create a new NavProgressItem
28098 * @param {Object} config The config object
28100 Roo.bootstrap.NavProgressItem = function(config){
28101 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28106 * The raw click event for the entire grid.
28107 * @param {Roo.bootstrap.NavProgressItem} this
28108 * @param {Roo.EventObject} e
28115 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28121 position : 'bottom',
28124 getAutoCreate : function()
28126 var iconCls = 'roo-navigation-bar-item-icon';
28128 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
28132 cls: 'roo-navigation-bar-item',
28142 cfg.cls += ' active';
28145 cfg.cls += ' disabled';
28151 disable : function()
28153 this.setDisabled(true);
28156 enable : function()
28158 this.setDisabled(false);
28161 initEvents: function()
28163 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
28165 this.iconEl.on('click', this.onClick, this);
28168 onClick : function(e)
28170 e.preventDefault();
28176 if(this.fireEvent('click', this, e) === false){
28180 this.parent().setActiveItem(this);
28183 isActive: function ()
28185 return this.active;
28188 setActive : function(state)
28190 if(this.active == state){
28194 this.active = state;
28197 this.el.addClass('active');
28201 this.el.removeClass('active');
28206 setDisabled : function(state)
28208 if(this.disabled == state){
28212 this.disabled = state;
28215 this.el.addClass('disabled');
28219 this.el.removeClass('disabled');
28222 tooltipEl : function()
28224 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
28237 * @class Roo.bootstrap.FieldLabel
28238 * @extends Roo.bootstrap.Component
28239 * Bootstrap FieldLabel class
28240 * @cfg {String} html contents of the element
28241 * @cfg {String} tag tag of the element default label
28242 * @cfg {String} cls class of the element
28243 * @cfg {String} target label target
28244 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
28245 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
28246 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
28247 * @cfg {String} iconTooltip default "This field is required"
28250 * Create a new FieldLabel
28251 * @param {Object} config The config object
28254 Roo.bootstrap.FieldLabel = function(config){
28255 Roo.bootstrap.Element.superclass.constructor.call(this, config);
28260 * Fires after the field has been marked as invalid.
28261 * @param {Roo.form.FieldLabel} this
28262 * @param {String} msg The validation message
28267 * Fires after the field has been validated with no errors.
28268 * @param {Roo.form.FieldLabel} this
28274 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
28281 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
28282 validClass : 'text-success fa fa-lg fa-check',
28283 iconTooltip : 'This field is required',
28285 getAutoCreate : function(){
28289 cls : 'roo-bootstrap-field-label ' + this.cls,
28295 tooltip : this.iconTooltip
28307 initEvents: function()
28309 Roo.bootstrap.Element.superclass.initEvents.call(this);
28311 this.iconEl = this.el.select('i', true).first();
28313 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
28315 Roo.bootstrap.FieldLabel.register(this);
28319 * Mark this field as valid
28321 markValid : function()
28323 this.iconEl.show();
28325 this.iconEl.removeClass(this.invalidClass);
28327 this.iconEl.addClass(this.validClass);
28329 this.fireEvent('valid', this);
28333 * Mark this field as invalid
28334 * @param {String} msg The validation message
28336 markInvalid : function(msg)
28338 this.iconEl.show();
28340 this.iconEl.removeClass(this.validClass);
28342 this.iconEl.addClass(this.invalidClass);
28344 this.fireEvent('invalid', this, msg);
28350 Roo.apply(Roo.bootstrap.FieldLabel, {
28355 * register a FieldLabel Group
28356 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
28358 register : function(label)
28360 if(this.groups.hasOwnProperty(label.target)){
28364 this.groups[label.target] = label;
28368 * fetch a FieldLabel Group based on the target
28369 * @param {string} target
28370 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28372 get: function(target) {
28373 if (typeof(this.groups[target]) == 'undefined') {
28377 return this.groups[target] ;
28386 * page DateSplitField.
28392 * @class Roo.bootstrap.DateSplitField
28393 * @extends Roo.bootstrap.Component
28394 * Bootstrap DateSplitField class
28395 * @cfg {string} fieldLabel - the label associated
28396 * @cfg {Number} labelWidth set the width of label (0-12)
28397 * @cfg {String} labelAlign (top|left)
28398 * @cfg {Boolean} dayAllowBlank (true|false) default false
28399 * @cfg {Boolean} monthAllowBlank (true|false) default false
28400 * @cfg {Boolean} yearAllowBlank (true|false) default false
28401 * @cfg {string} dayPlaceholder
28402 * @cfg {string} monthPlaceholder
28403 * @cfg {string} yearPlaceholder
28404 * @cfg {string} dayFormat default 'd'
28405 * @cfg {string} monthFormat default 'm'
28406 * @cfg {string} yearFormat default 'Y'
28410 * Create a new DateSplitField
28411 * @param {Object} config The config object
28414 Roo.bootstrap.DateSplitField = function(config){
28415 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28421 * getting the data of years
28422 * @param {Roo.bootstrap.DateSplitField} this
28423 * @param {Object} years
28428 * getting the data of days
28429 * @param {Roo.bootstrap.DateSplitField} this
28430 * @param {Object} days
28435 * Fires after the field has been marked as invalid.
28436 * @param {Roo.form.Field} this
28437 * @param {String} msg The validation message
28442 * Fires after the field has been validated with no errors.
28443 * @param {Roo.form.Field} this
28449 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28452 labelAlign : 'top',
28454 dayAllowBlank : false,
28455 monthAllowBlank : false,
28456 yearAllowBlank : false,
28457 dayPlaceholder : '',
28458 monthPlaceholder : '',
28459 yearPlaceholder : '',
28463 isFormField : true,
28465 getAutoCreate : function()
28469 cls : 'row roo-date-split-field-group',
28474 cls : 'form-hidden-field roo-date-split-field-group-value',
28480 if(this.fieldLabel){
28483 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28487 html : this.fieldLabel
28493 Roo.each(['day', 'month', 'year'], function(t){
28496 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28503 inputEl: function ()
28505 return this.el.select('.roo-date-split-field-group-value', true).first();
28508 onRender : function(ct, position)
28512 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28514 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28516 this.dayField = new Roo.bootstrap.ComboBox({
28517 allowBlank : this.dayAllowBlank,
28518 alwaysQuery : true,
28519 displayField : 'value',
28522 forceSelection : true,
28524 placeholder : this.dayPlaceholder,
28525 selectOnFocus : true,
28526 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28527 triggerAction : 'all',
28529 valueField : 'value',
28530 store : new Roo.data.SimpleStore({
28531 data : (function() {
28533 _this.fireEvent('days', _this, days);
28536 fields : [ 'value' ]
28539 select : function (_self, record, index)
28541 _this.setValue(_this.getValue());
28546 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28548 this.monthField = new Roo.bootstrap.MonthField({
28549 after : '<i class=\"fa fa-calendar\"></i>',
28550 allowBlank : this.monthAllowBlank,
28551 placeholder : this.monthPlaceholder,
28554 render : function (_self)
28556 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28557 e.preventDefault();
28561 select : function (_self, oldvalue, newvalue)
28563 _this.setValue(_this.getValue());
28568 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28570 this.yearField = new Roo.bootstrap.ComboBox({
28571 allowBlank : this.yearAllowBlank,
28572 alwaysQuery : true,
28573 displayField : 'value',
28576 forceSelection : true,
28578 placeholder : this.yearPlaceholder,
28579 selectOnFocus : true,
28580 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28581 triggerAction : 'all',
28583 valueField : 'value',
28584 store : new Roo.data.SimpleStore({
28585 data : (function() {
28587 _this.fireEvent('years', _this, years);
28590 fields : [ 'value' ]
28593 select : function (_self, record, index)
28595 _this.setValue(_this.getValue());
28600 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28603 setValue : function(v, format)
28605 this.inputEl.dom.value = v;
28607 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28609 var d = Date.parseDate(v, f);
28616 this.setDay(d.format(this.dayFormat));
28617 this.setMonth(d.format(this.monthFormat));
28618 this.setYear(d.format(this.yearFormat));
28625 setDay : function(v)
28627 this.dayField.setValue(v);
28628 this.inputEl.dom.value = this.getValue();
28633 setMonth : function(v)
28635 this.monthField.setValue(v, true);
28636 this.inputEl.dom.value = this.getValue();
28641 setYear : function(v)
28643 this.yearField.setValue(v);
28644 this.inputEl.dom.value = this.getValue();
28649 getDay : function()
28651 return this.dayField.getValue();
28654 getMonth : function()
28656 return this.monthField.getValue();
28659 getYear : function()
28661 return this.yearField.getValue();
28664 getValue : function()
28666 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
28668 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
28678 this.inputEl.dom.value = '';
28683 validate : function()
28685 var d = this.dayField.validate();
28686 var m = this.monthField.validate();
28687 var y = this.yearField.validate();
28692 (!this.dayAllowBlank && !d) ||
28693 (!this.monthAllowBlank && !m) ||
28694 (!this.yearAllowBlank && !y)
28699 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
28708 this.markInvalid();
28713 markValid : function()
28716 var label = this.el.select('label', true).first();
28717 var icon = this.el.select('i.fa-star', true).first();
28723 this.fireEvent('valid', this);
28727 * Mark this field as invalid
28728 * @param {String} msg The validation message
28730 markInvalid : function(msg)
28733 var label = this.el.select('label', true).first();
28734 var icon = this.el.select('i.fa-star', true).first();
28736 if(label && !icon){
28737 this.el.select('.roo-date-split-field-label', true).createChild({
28739 cls : 'text-danger fa fa-lg fa-star',
28740 tooltip : 'This field is required',
28741 style : 'margin-right:5px;'
28745 this.fireEvent('invalid', this, msg);
28748 clearInvalid : function()
28750 var label = this.el.select('label', true).first();
28751 var icon = this.el.select('i.fa-star', true).first();
28757 this.fireEvent('valid', this);
28760 getName: function()
28770 * http://masonry.desandro.com
28772 * The idea is to render all the bricks based on vertical width...
28774 * The original code extends 'outlayer' - we might need to use that....
28780 * @class Roo.bootstrap.LayoutMasonry
28781 * @extends Roo.bootstrap.Component
28782 * Bootstrap Layout Masonry class
28785 * Create a new Element
28786 * @param {Object} config The config object
28789 Roo.bootstrap.LayoutMasonry = function(config){
28790 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
28796 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
28799 * @cfg {Boolean} isLayoutInstant = no animation?
28801 isLayoutInstant : false, // needed?
28804 * @cfg {Number} boxWidth width of the columns
28809 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
28814 * @cfg {Number} padWidth padding below box..
28819 * @cfg {Number} gutter gutter width..
28824 * @cfg {Number} maxCols maximum number of columns
28830 * @cfg {Boolean} isAutoInitial defalut true
28832 isAutoInitial : true,
28837 * @cfg {Boolean} isHorizontal defalut false
28839 isHorizontal : false,
28841 currentSize : null,
28847 bricks: null, //CompositeElement
28851 _isLayoutInited : false,
28853 // isAlternative : false, // only use for vertical layout...
28856 * @cfg {Number} alternativePadWidth padding below box..
28858 alternativePadWidth : 50,
28860 getAutoCreate : function(){
28864 cls: 'blog-masonary-wrapper ' + this.cls,
28866 cls : 'mas-boxes masonary'
28873 getChildContainer: function( )
28875 if (this.boxesEl) {
28876 return this.boxesEl;
28879 this.boxesEl = this.el.select('.mas-boxes').first();
28881 return this.boxesEl;
28885 initEvents : function()
28889 if(this.isAutoInitial){
28890 Roo.log('hook children rendered');
28891 this.on('childrenrendered', function() {
28892 Roo.log('children rendered');
28898 initial : function()
28900 this.currentSize = this.el.getBox(true);
28902 Roo.EventManager.onWindowResize(this.resize, this);
28904 if(!this.isAutoInitial){
28912 //this.layout.defer(500,this);
28916 resize : function()
28920 var cs = this.el.getBox(true);
28922 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
28923 Roo.log("no change in with or X");
28927 this.currentSize = cs;
28933 layout : function()
28935 this._resetLayout();
28937 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
28939 this.layoutItems( isInstant );
28941 this._isLayoutInited = true;
28945 _resetLayout : function()
28947 if(this.isHorizontal){
28948 this.horizontalMeasureColumns();
28952 this.verticalMeasureColumns();
28956 verticalMeasureColumns : function()
28958 this.getContainerWidth();
28960 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28961 // this.colWidth = Math.floor(this.containerWidth * 0.8);
28965 var boxWidth = this.boxWidth + this.padWidth;
28967 if(this.containerWidth < this.boxWidth){
28968 boxWidth = this.containerWidth
28971 var containerWidth = this.containerWidth;
28973 var cols = Math.floor(containerWidth / boxWidth);
28975 this.cols = Math.max( cols, 1 );
28977 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
28979 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
28981 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
28983 this.colWidth = boxWidth + avail - this.padWidth;
28985 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
28986 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
28989 horizontalMeasureColumns : function()
28991 this.getContainerWidth();
28993 var boxWidth = this.boxWidth;
28995 if(this.containerWidth < boxWidth){
28996 boxWidth = this.containerWidth;
28999 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29001 this.el.setHeight(boxWidth);
29005 getContainerWidth : function()
29007 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29010 layoutItems : function( isInstant )
29012 var items = Roo.apply([], this.bricks);
29014 if(this.isHorizontal){
29015 this._horizontalLayoutItems( items , isInstant );
29019 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29020 // this._verticalAlternativeLayoutItems( items , isInstant );
29024 this._verticalLayoutItems( items , isInstant );
29028 _verticalLayoutItems : function ( items , isInstant)
29030 if ( !items || !items.length ) {
29035 ['xs', 'xs', 'xs', 'tall'],
29036 ['xs', 'xs', 'tall'],
29037 ['xs', 'xs', 'sm'],
29038 ['xs', 'xs', 'xs'],
29044 ['sm', 'xs', 'xs'],
29048 ['tall', 'xs', 'xs', 'xs'],
29049 ['tall', 'xs', 'xs'],
29061 Roo.each(items, function(item, k){
29063 switch (item.size) {
29064 // these layouts take up a full box,
29075 boxes.push([item]);
29098 var filterPattern = function(box, length)
29106 var pattern = box.slice(0, length);
29110 Roo.each(pattern, function(i){
29111 format.push(i.size);
29114 Roo.each(standard, function(s){
29116 if(String(s) != String(format)){
29125 if(!match && length == 1){
29130 filterPattern(box, length - 1);
29134 queue.push(pattern);
29136 box = box.slice(length, box.length);
29138 filterPattern(box, 4);
29144 Roo.each(boxes, function(box, k){
29150 if(box.length == 1){
29155 filterPattern(box, 4);
29159 this._processVerticalLayoutQueue( queue, isInstant );
29163 // _verticalAlternativeLayoutItems : function( items , isInstant )
29165 // if ( !items || !items.length ) {
29169 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
29173 _horizontalLayoutItems : function ( items , isInstant)
29175 if ( !items || !items.length || items.length < 3) {
29181 var eItems = items.slice(0, 3);
29183 items = items.slice(3, items.length);
29186 ['xs', 'xs', 'xs', 'wide'],
29187 ['xs', 'xs', 'wide'],
29188 ['xs', 'xs', 'sm'],
29189 ['xs', 'xs', 'xs'],
29195 ['sm', 'xs', 'xs'],
29199 ['wide', 'xs', 'xs', 'xs'],
29200 ['wide', 'xs', 'xs'],
29213 Roo.each(items, function(item, k){
29215 switch (item.size) {
29226 boxes.push([item]);
29250 var filterPattern = function(box, length)
29258 var pattern = box.slice(0, length);
29262 Roo.each(pattern, function(i){
29263 format.push(i.size);
29266 Roo.each(standard, function(s){
29268 if(String(s) != String(format)){
29277 if(!match && length == 1){
29282 filterPattern(box, length - 1);
29286 queue.push(pattern);
29288 box = box.slice(length, box.length);
29290 filterPattern(box, 4);
29296 Roo.each(boxes, function(box, k){
29302 if(box.length == 1){
29307 filterPattern(box, 4);
29314 var pos = this.el.getBox(true);
29318 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29320 var hit_end = false;
29322 Roo.each(queue, function(box){
29326 Roo.each(box, function(b){
29328 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29338 Roo.each(box, function(b){
29340 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29343 mx = Math.max(mx, b.x);
29347 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
29351 Roo.each(box, function(b){
29353 b.el.setVisibilityMode(Roo.Element.DISPLAY);
29367 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
29370 /** Sets position of item in DOM
29371 * @param {Element} item
29372 * @param {Number} x - horizontal position
29373 * @param {Number} y - vertical position
29374 * @param {Boolean} isInstant - disables transitions
29376 _processVerticalLayoutQueue : function( queue, isInstant )
29378 var pos = this.el.getBox(true);
29383 for (var i = 0; i < this.cols; i++){
29387 Roo.each(queue, function(box, k){
29389 var col = k % this.cols;
29391 Roo.each(box, function(b,kk){
29393 b.el.position('absolute');
29395 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29396 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29398 if(b.size == 'md-left' || b.size == 'md-right'){
29399 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29400 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29403 b.el.setWidth(width);
29404 b.el.setHeight(height);
29406 b.el.select('iframe',true).setSize(width,height);
29410 for (var i = 0; i < this.cols; i++){
29412 if(maxY[i] < maxY[col]){
29417 col = Math.min(col, i);
29421 x = pos.x + col * (this.colWidth + this.padWidth);
29425 var positions = [];
29427 switch (box.length){
29429 positions = this.getVerticalOneBoxColPositions(x, y, box);
29432 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29435 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29438 positions = this.getVerticalFourBoxColPositions(x, y, box);
29444 Roo.each(box, function(b,kk){
29446 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29448 var sz = b.el.getSize();
29450 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29458 for (var i = 0; i < this.cols; i++){
29459 mY = Math.max(mY, maxY[i]);
29462 this.el.setHeight(mY - pos.y);
29466 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29468 // var pos = this.el.getBox(true);
29471 // var maxX = pos.right;
29473 // var maxHeight = 0;
29475 // Roo.each(items, function(item, k){
29479 // item.el.position('absolute');
29481 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29483 // item.el.setWidth(width);
29485 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29487 // item.el.setHeight(height);
29490 // item.el.setXY([x, y], isInstant ? false : true);
29492 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29495 // y = y + height + this.alternativePadWidth;
29497 // maxHeight = maxHeight + height + this.alternativePadWidth;
29501 // this.el.setHeight(maxHeight);
29505 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29507 var pos = this.el.getBox(true);
29512 var maxX = pos.right;
29514 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29516 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29518 Roo.each(queue, function(box, k){
29520 Roo.each(box, function(b, kk){
29522 b.el.position('absolute');
29524 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29525 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29527 if(b.size == 'md-left' || b.size == 'md-right'){
29528 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29529 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29532 b.el.setWidth(width);
29533 b.el.setHeight(height);
29541 var positions = [];
29543 switch (box.length){
29545 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29548 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29551 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29554 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29560 Roo.each(box, function(b,kk){
29562 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29564 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29572 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29574 Roo.each(eItems, function(b,k){
29576 b.size = (k == 0) ? 'sm' : 'xs';
29577 b.x = (k == 0) ? 2 : 1;
29578 b.y = (k == 0) ? 2 : 1;
29580 b.el.position('absolute');
29582 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29584 b.el.setWidth(width);
29586 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29588 b.el.setHeight(height);
29592 var positions = [];
29595 x : maxX - this.unitWidth * 2 - this.gutter,
29600 x : maxX - this.unitWidth,
29601 y : minY + (this.unitWidth + this.gutter) * 2
29605 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29609 Roo.each(eItems, function(b,k){
29611 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29617 getVerticalOneBoxColPositions : function(x, y, box)
29621 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29623 if(box[0].size == 'md-left'){
29627 if(box[0].size == 'md-right'){
29632 x : x + (this.unitWidth + this.gutter) * rand,
29639 getVerticalTwoBoxColPositions : function(x, y, box)
29643 if(box[0].size == 'xs'){
29647 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
29651 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
29665 x : x + (this.unitWidth + this.gutter) * 2,
29666 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
29673 getVerticalThreeBoxColPositions : function(x, y, box)
29677 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29685 x : x + (this.unitWidth + this.gutter) * 1,
29690 x : x + (this.unitWidth + this.gutter) * 2,
29698 if(box[0].size == 'xs' && box[1].size == 'xs'){
29707 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
29711 x : x + (this.unitWidth + this.gutter) * 1,
29725 x : x + (this.unitWidth + this.gutter) * 2,
29730 x : x + (this.unitWidth + this.gutter) * 2,
29731 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
29738 getVerticalFourBoxColPositions : function(x, y, box)
29742 if(box[0].size == 'xs'){
29751 y : y + (this.unitHeight + this.gutter) * 1
29756 y : y + (this.unitHeight + this.gutter) * 2
29760 x : x + (this.unitWidth + this.gutter) * 1,
29774 x : x + (this.unitWidth + this.gutter) * 2,
29779 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
29780 y : y + (this.unitHeight + this.gutter) * 1
29784 x : x + (this.unitWidth + this.gutter) * 2,
29785 y : y + (this.unitWidth + this.gutter) * 2
29792 getHorizontalOneBoxColPositions : function(maxX, minY, box)
29796 if(box[0].size == 'md-left'){
29798 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29805 if(box[0].size == 'md-right'){
29807 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29808 y : minY + (this.unitWidth + this.gutter) * 1
29814 var rand = Math.floor(Math.random() * (4 - box[0].y));
29817 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29818 y : minY + (this.unitWidth + this.gutter) * rand
29825 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
29829 if(box[0].size == 'xs'){
29832 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29837 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29838 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
29846 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29851 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29852 y : minY + (this.unitWidth + this.gutter) * 2
29859 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
29863 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29866 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29871 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29872 y : minY + (this.unitWidth + this.gutter) * 1
29876 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29877 y : minY + (this.unitWidth + this.gutter) * 2
29884 if(box[0].size == 'xs' && box[1].size == 'xs'){
29887 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29892 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29897 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29898 y : minY + (this.unitWidth + this.gutter) * 1
29906 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29911 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29912 y : minY + (this.unitWidth + this.gutter) * 2
29916 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29917 y : minY + (this.unitWidth + this.gutter) * 2
29924 getHorizontalFourBoxColPositions : function(maxX, minY, box)
29928 if(box[0].size == 'xs'){
29931 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29936 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29941 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),
29946 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
29947 y : minY + (this.unitWidth + this.gutter) * 1
29955 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29960 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29961 y : minY + (this.unitWidth + this.gutter) * 2
29965 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29966 y : minY + (this.unitWidth + this.gutter) * 2
29970 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),
29971 y : minY + (this.unitWidth + this.gutter) * 2
29985 * http://masonry.desandro.com
29987 * The idea is to render all the bricks based on vertical width...
29989 * The original code extends 'outlayer' - we might need to use that....
29995 * @class Roo.bootstrap.LayoutMasonryAuto
29996 * @extends Roo.bootstrap.Component
29997 * Bootstrap Layout Masonry class
30000 * Create a new Element
30001 * @param {Object} config The config object
30004 Roo.bootstrap.LayoutMasonryAuto = function(config){
30005 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30008 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30011 * @cfg {Boolean} isFitWidth - resize the width..
30013 isFitWidth : false, // options..
30015 * @cfg {Boolean} isOriginLeft = left align?
30017 isOriginLeft : true,
30019 * @cfg {Boolean} isOriginTop = top align?
30021 isOriginTop : false,
30023 * @cfg {Boolean} isLayoutInstant = no animation?
30025 isLayoutInstant : false, // needed?
30027 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30029 isResizingContainer : true,
30031 * @cfg {Number} columnWidth width of the columns
30037 * @cfg {Number} maxCols maximum number of columns
30042 * @cfg {Number} padHeight padding below box..
30048 * @cfg {Boolean} isAutoInitial defalut true
30051 isAutoInitial : true,
30057 initialColumnWidth : 0,
30058 currentSize : null,
30060 colYs : null, // array.
30067 bricks: null, //CompositeElement
30068 cols : 0, // array?
30069 // element : null, // wrapped now this.el
30070 _isLayoutInited : null,
30073 getAutoCreate : function(){
30077 cls: 'blog-masonary-wrapper ' + this.cls,
30079 cls : 'mas-boxes masonary'
30086 getChildContainer: function( )
30088 if (this.boxesEl) {
30089 return this.boxesEl;
30092 this.boxesEl = this.el.select('.mas-boxes').first();
30094 return this.boxesEl;
30098 initEvents : function()
30102 if(this.isAutoInitial){
30103 Roo.log('hook children rendered');
30104 this.on('childrenrendered', function() {
30105 Roo.log('children rendered');
30112 initial : function()
30114 this.reloadItems();
30116 this.currentSize = this.el.getBox(true);
30118 /// was window resize... - let's see if this works..
30119 Roo.EventManager.onWindowResize(this.resize, this);
30121 if(!this.isAutoInitial){
30126 this.layout.defer(500,this);
30129 reloadItems: function()
30131 this.bricks = this.el.select('.masonry-brick', true);
30133 this.bricks.each(function(b) {
30134 //Roo.log(b.getSize());
30135 if (!b.attr('originalwidth')) {
30136 b.attr('originalwidth', b.getSize().width);
30141 Roo.log(this.bricks.elements.length);
30144 resize : function()
30147 var cs = this.el.getBox(true);
30149 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
30150 Roo.log("no change in with or X");
30153 this.currentSize = cs;
30157 layout : function()
30160 this._resetLayout();
30161 //this._manageStamps();
30163 // don't animate first layout
30164 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30165 this.layoutItems( isInstant );
30167 // flag for initalized
30168 this._isLayoutInited = true;
30171 layoutItems : function( isInstant )
30173 //var items = this._getItemsForLayout( this.items );
30174 // original code supports filtering layout items.. we just ignore it..
30176 this._layoutItems( this.bricks , isInstant );
30178 this._postLayout();
30180 _layoutItems : function ( items , isInstant)
30182 //this.fireEvent( 'layout', this, items );
30185 if ( !items || !items.elements.length ) {
30186 // no items, emit event with empty array
30191 items.each(function(item) {
30192 Roo.log("layout item");
30194 // get x/y object from method
30195 var position = this._getItemLayoutPosition( item );
30197 position.item = item;
30198 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
30199 queue.push( position );
30202 this._processLayoutQueue( queue );
30204 /** Sets position of item in DOM
30205 * @param {Element} item
30206 * @param {Number} x - horizontal position
30207 * @param {Number} y - vertical position
30208 * @param {Boolean} isInstant - disables transitions
30210 _processLayoutQueue : function( queue )
30212 for ( var i=0, len = queue.length; i < len; i++ ) {
30213 var obj = queue[i];
30214 obj.item.position('absolute');
30215 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
30221 * Any logic you want to do after each layout,
30222 * i.e. size the container
30224 _postLayout : function()
30226 this.resizeContainer();
30229 resizeContainer : function()
30231 if ( !this.isResizingContainer ) {
30234 var size = this._getContainerSize();
30236 this.el.setSize(size.width,size.height);
30237 this.boxesEl.setSize(size.width,size.height);
30243 _resetLayout : function()
30245 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
30246 this.colWidth = this.el.getWidth();
30247 //this.gutter = this.el.getWidth();
30249 this.measureColumns();
30255 this.colYs.push( 0 );
30261 measureColumns : function()
30263 this.getContainerWidth();
30264 // if columnWidth is 0, default to outerWidth of first item
30265 if ( !this.columnWidth ) {
30266 var firstItem = this.bricks.first();
30267 Roo.log(firstItem);
30268 this.columnWidth = this.containerWidth;
30269 if (firstItem && firstItem.attr('originalwidth') ) {
30270 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
30272 // columnWidth fall back to item of first element
30273 Roo.log("set column width?");
30274 this.initialColumnWidth = this.columnWidth ;
30276 // if first elem has no width, default to size of container
30281 if (this.initialColumnWidth) {
30282 this.columnWidth = this.initialColumnWidth;
30287 // column width is fixed at the top - however if container width get's smaller we should
30290 // this bit calcs how man columns..
30292 var columnWidth = this.columnWidth += this.gutter;
30294 // calculate columns
30295 var containerWidth = this.containerWidth + this.gutter;
30297 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
30298 // fix rounding errors, typically with gutters
30299 var excess = columnWidth - containerWidth % columnWidth;
30302 // if overshoot is less than a pixel, round up, otherwise floor it
30303 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
30304 cols = Math[ mathMethod ]( cols );
30305 this.cols = Math.max( cols, 1 );
30306 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30308 // padding positioning..
30309 var totalColWidth = this.cols * this.columnWidth;
30310 var padavail = this.containerWidth - totalColWidth;
30311 // so for 2 columns - we need 3 'pads'
30313 var padNeeded = (1+this.cols) * this.padWidth;
30315 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
30317 this.columnWidth += padExtra
30318 //this.padWidth = Math.floor(padavail / ( this.cols));
30320 // adjust colum width so that padding is fixed??
30322 // we have 3 columns ... total = width * 3
30323 // we have X left over... that should be used by
30325 //if (this.expandC) {
30333 getContainerWidth : function()
30335 /* // container is parent if fit width
30336 var container = this.isFitWidth ? this.element.parentNode : this.element;
30337 // check that this.size and size are there
30338 // IE8 triggers resize on body size change, so they might not be
30340 var size = getSize( container ); //FIXME
30341 this.containerWidth = size && size.innerWidth; //FIXME
30344 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30348 _getItemLayoutPosition : function( item ) // what is item?
30350 // we resize the item to our columnWidth..
30352 item.setWidth(this.columnWidth);
30353 item.autoBoxAdjust = false;
30355 var sz = item.getSize();
30357 // how many columns does this brick span
30358 var remainder = this.containerWidth % this.columnWidth;
30360 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
30361 // round if off by 1 pixel, otherwise use ceil
30362 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
30363 colSpan = Math.min( colSpan, this.cols );
30365 // normally this should be '1' as we dont' currently allow multi width columns..
30367 var colGroup = this._getColGroup( colSpan );
30368 // get the minimum Y value from the columns
30369 var minimumY = Math.min.apply( Math, colGroup );
30370 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30372 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
30374 // position the brick
30376 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
30377 y: this.currentSize.y + minimumY + this.padHeight
30381 // apply setHeight to necessary columns
30382 var setHeight = minimumY + sz.height + this.padHeight;
30383 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
30385 var setSpan = this.cols + 1 - colGroup.length;
30386 for ( var i = 0; i < setSpan; i++ ) {
30387 this.colYs[ shortColIndex + i ] = setHeight ;
30394 * @param {Number} colSpan - number of columns the element spans
30395 * @returns {Array} colGroup
30397 _getColGroup : function( colSpan )
30399 if ( colSpan < 2 ) {
30400 // if brick spans only one column, use all the column Ys
30405 // how many different places could this brick fit horizontally
30406 var groupCount = this.cols + 1 - colSpan;
30407 // for each group potential horizontal position
30408 for ( var i = 0; i < groupCount; i++ ) {
30409 // make an array of colY values for that one group
30410 var groupColYs = this.colYs.slice( i, i + colSpan );
30411 // and get the max value of the array
30412 colGroup[i] = Math.max.apply( Math, groupColYs );
30417 _manageStamp : function( stamp )
30419 var stampSize = stamp.getSize();
30420 var offset = stamp.getBox();
30421 // get the columns that this stamp affects
30422 var firstX = this.isOriginLeft ? offset.x : offset.right;
30423 var lastX = firstX + stampSize.width;
30424 var firstCol = Math.floor( firstX / this.columnWidth );
30425 firstCol = Math.max( 0, firstCol );
30427 var lastCol = Math.floor( lastX / this.columnWidth );
30428 // lastCol should not go over if multiple of columnWidth #425
30429 lastCol -= lastX % this.columnWidth ? 0 : 1;
30430 lastCol = Math.min( this.cols - 1, lastCol );
30432 // set colYs to bottom of the stamp
30433 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30436 for ( var i = firstCol; i <= lastCol; i++ ) {
30437 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30442 _getContainerSize : function()
30444 this.maxY = Math.max.apply( Math, this.colYs );
30449 if ( this.isFitWidth ) {
30450 size.width = this._getContainerFitWidth();
30456 _getContainerFitWidth : function()
30458 var unusedCols = 0;
30459 // count unused columns
30462 if ( this.colYs[i] !== 0 ) {
30467 // fit container to columns that have been used
30468 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30471 needsResizeLayout : function()
30473 var previousWidth = this.containerWidth;
30474 this.getContainerWidth();
30475 return previousWidth !== this.containerWidth;
30490 * @class Roo.bootstrap.MasonryBrick
30491 * @extends Roo.bootstrap.Component
30492 * Bootstrap MasonryBrick class
30495 * Create a new MasonryBrick
30496 * @param {Object} config The config object
30499 Roo.bootstrap.MasonryBrick = function(config){
30500 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30506 * When a MasonryBrick is clcik
30507 * @param {Roo.bootstrap.MasonryBrick} this
30508 * @param {Roo.EventObject} e
30514 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30517 * @cfg {String} title
30521 * @cfg {String} html
30525 * @cfg {String} bgimage
30529 * @cfg {String} videourl
30533 * @cfg {String} cls
30537 * @cfg {String} href
30541 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30546 * @cfg {String} (center|bottom) placetitle
30550 getAutoCreate : function()
30552 var cls = 'masonry-brick';
30554 if(this.href.length){
30555 cls += ' masonry-brick-link';
30558 if(this.bgimage.length){
30559 cls += ' masonry-brick-image';
30563 cls += ' masonry-' + this.size + '-brick';
30566 if(this.placetitle.length){
30568 switch (this.placetitle) {
30570 cls += ' masonry-center-title';
30573 cls += ' masonry-bottom-title';
30580 if(!this.html.length && !this.bgimage.length){
30581 cls += ' masonry-center-title';
30584 if(!this.html.length && this.bgimage.length){
30585 cls += ' masonry-bottom-title';
30590 cls += ' ' + this.cls;
30594 tag: (this.href.length) ? 'a' : 'div',
30599 cls: 'masonry-brick-paragraph',
30605 if(this.href.length){
30606 cfg.href = this.href;
30609 var cn = cfg.cn[0].cn;
30611 if(this.title.length){
30614 cls: 'masonry-brick-title',
30619 if(this.html.length){
30622 cls: 'masonry-brick-text',
30626 if (!this.title.length && !this.html.length) {
30627 cfg.cn[0].cls += ' hide';
30630 if(this.bgimage.length){
30633 cls: 'masonry-brick-image-view',
30637 if(this.videourl.length){
30638 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
30639 // youtube support only?
30642 cls: 'masonry-brick-image-view',
30645 allowfullscreen : true
30654 initEvents: function()
30656 switch (this.size) {
30658 // this.intSize = 1;
30663 // this.intSize = 2;
30670 // this.intSize = 3;
30675 // this.intSize = 3;
30680 // this.intSize = 3;
30685 // this.intSize = 3;
30697 this.el.on('touchstart', this.onTouchStart, this);
30698 this.el.on('touchmove', this.onTouchMove, this);
30699 this.el.on('touchend', this.onTouchEnd, this);
30700 this.el.on('contextmenu', this.onContextMenu, this);
30702 this.el.on('mouseenter' ,this.enter, this);
30703 this.el.on('mouseleave', this.leave, this);
30706 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
30707 this.parent().bricks.push(this);
30712 onClick: function(e, el)
30718 var time = this.endTimer - this.startTimer;
30726 e.preventDefault();
30729 enter: function(e, el)
30731 e.preventDefault();
30733 if(this.bgimage.length && this.html.length){
30734 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30738 leave: function(e, el)
30740 e.preventDefault();
30742 if(this.bgimage.length && this.html.length){
30743 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30747 onTouchStart: function(e, el)
30749 // e.preventDefault();
30751 this.touchmoved = false;
30753 if(!this.bgimage.length || !this.html.length){
30757 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30759 this.timer = new Date().getTime();
30763 onTouchMove: function(e, el)
30765 this.touchmoved = true;
30768 onContextMenu : function(e,el)
30770 e.preventDefault();
30771 e.stopPropagation();
30775 onTouchEnd: function(e, el)
30777 // e.preventDefault();
30779 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
30786 if(!this.bgimage.length || !this.html.length){
30788 if(this.href.length){
30789 window.location.href = this.href;
30795 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30797 window.location.href = this.href;
30812 * @class Roo.bootstrap.Brick
30813 * @extends Roo.bootstrap.Component
30814 * Bootstrap Brick class
30817 * Create a new Brick
30818 * @param {Object} config The config object
30821 Roo.bootstrap.Brick = function(config){
30822 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
30828 * When a Brick is click
30829 * @param {Roo.bootstrap.Brick} this
30830 * @param {Roo.EventObject} e
30836 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
30839 * @cfg {String} title
30843 * @cfg {String} html
30847 * @cfg {String} bgimage
30851 * @cfg {String} cls
30855 * @cfg {String} href
30859 * @cfg {String} video
30863 * @cfg {Boolean} square
30867 getAutoCreate : function()
30869 var cls = 'roo-brick';
30871 if(this.href.length){
30872 cls += ' roo-brick-link';
30875 if(this.bgimage.length){
30876 cls += ' roo-brick-image';
30879 if(!this.html.length && !this.bgimage.length){
30880 cls += ' roo-brick-center-title';
30883 if(!this.html.length && this.bgimage.length){
30884 cls += ' roo-brick-bottom-title';
30888 cls += ' ' + this.cls;
30892 tag: (this.href.length) ? 'a' : 'div',
30897 cls: 'roo-brick-paragraph',
30903 if(this.href.length){
30904 cfg.href = this.href;
30907 var cn = cfg.cn[0].cn;
30909 if(this.title.length){
30912 cls: 'roo-brick-title',
30917 if(this.html.length){
30920 cls: 'roo-brick-text',
30927 if(this.bgimage.length){
30930 cls: 'roo-brick-image-view',
30938 initEvents: function()
30940 if(this.title.length || this.html.length){
30941 this.el.on('mouseenter' ,this.enter, this);
30942 this.el.on('mouseleave', this.leave, this);
30946 Roo.EventManager.onWindowResize(this.resize, this);
30951 resize : function()
30953 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
30955 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
30956 // paragraph.setHeight(paragraph.getWidth());
30958 if(this.bgimage.length){
30959 var image = this.el.select('.roo-brick-image-view', true).first();
30960 image.setWidth(paragraph.getWidth());
30961 image.setHeight(paragraph.getWidth());
30966 enter: function(e, el)
30968 e.preventDefault();
30970 if(this.bgimage.length){
30971 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
30972 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
30976 leave: function(e, el)
30978 e.preventDefault();
30980 if(this.bgimage.length){
30981 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
30982 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
30992 * Ext JS Library 1.1.1
30993 * Copyright(c) 2006-2007, Ext JS, LLC.
30995 * Originally Released Under LGPL - original licence link has changed is not relivant.
30998 * <script type="text/javascript">
31003 * @class Roo.bootstrap.SplitBar
31004 * @extends Roo.util.Observable
31005 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
31009 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
31010 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
31011 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
31012 split.minSize = 100;
31013 split.maxSize = 600;
31014 split.animate = true;
31015 split.on('moved', splitterMoved);
31018 * Create a new SplitBar
31019 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
31020 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
31021 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31022 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
31023 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
31024 position of the SplitBar).
31026 Roo.bootstrap.SplitBar = function(cfg){
31031 // dragElement : elm
31032 // resizingElement: el,
31034 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
31035 // placement : Roo.bootstrap.SplitBar.LEFT ,
31036 // existingProxy ???
31039 this.el = Roo.get(cfg.dragElement, true);
31040 this.el.dom.unselectable = "on";
31042 this.resizingEl = Roo.get(cfg.resizingElement, true);
31046 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
31047 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
31050 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
31053 * The minimum size of the resizing element. (Defaults to 0)
31059 * The maximum size of the resizing element. (Defaults to 2000)
31062 this.maxSize = 2000;
31065 * Whether to animate the transition to the new size
31068 this.animate = false;
31071 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
31074 this.useShim = false;
31079 if(!cfg.existingProxy){
31081 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
31083 this.proxy = Roo.get(cfg.existingProxy).dom;
31086 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
31089 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
31092 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
31095 this.dragSpecs = {};
31098 * @private The adapter to use to positon and resize elements
31100 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31101 this.adapter.init(this);
31103 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31105 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
31106 this.el.addClass("roo-splitbar-h");
31109 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
31110 this.el.addClass("roo-splitbar-v");
31116 * Fires when the splitter is moved (alias for {@link #event-moved})
31117 * @param {Roo.bootstrap.SplitBar} this
31118 * @param {Number} newSize the new width or height
31123 * Fires when the splitter is moved
31124 * @param {Roo.bootstrap.SplitBar} this
31125 * @param {Number} newSize the new width or height
31129 * @event beforeresize
31130 * Fires before the splitter is dragged
31131 * @param {Roo.bootstrap.SplitBar} this
31133 "beforeresize" : true,
31135 "beforeapply" : true
31138 Roo.util.Observable.call(this);
31141 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
31142 onStartProxyDrag : function(x, y){
31143 this.fireEvent("beforeresize", this);
31145 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
31147 o.enableDisplayMode("block");
31148 // all splitbars share the same overlay
31149 Roo.bootstrap.SplitBar.prototype.overlay = o;
31151 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31152 this.overlay.show();
31153 Roo.get(this.proxy).setDisplayed("block");
31154 var size = this.adapter.getElementSize(this);
31155 this.activeMinSize = this.getMinimumSize();;
31156 this.activeMaxSize = this.getMaximumSize();;
31157 var c1 = size - this.activeMinSize;
31158 var c2 = Math.max(this.activeMaxSize - size, 0);
31159 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31160 this.dd.resetConstraints();
31161 this.dd.setXConstraint(
31162 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
31163 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
31165 this.dd.setYConstraint(0, 0);
31167 this.dd.resetConstraints();
31168 this.dd.setXConstraint(0, 0);
31169 this.dd.setYConstraint(
31170 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
31171 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
31174 this.dragSpecs.startSize = size;
31175 this.dragSpecs.startPoint = [x, y];
31176 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
31180 * @private Called after the drag operation by the DDProxy
31182 onEndProxyDrag : function(e){
31183 Roo.get(this.proxy).setDisplayed(false);
31184 var endPoint = Roo.lib.Event.getXY(e);
31186 this.overlay.hide();
31189 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31190 newSize = this.dragSpecs.startSize +
31191 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
31192 endPoint[0] - this.dragSpecs.startPoint[0] :
31193 this.dragSpecs.startPoint[0] - endPoint[0]
31196 newSize = this.dragSpecs.startSize +
31197 (this.placement == Roo.bootstrap.SplitBar.TOP ?
31198 endPoint[1] - this.dragSpecs.startPoint[1] :
31199 this.dragSpecs.startPoint[1] - endPoint[1]
31202 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
31203 if(newSize != this.dragSpecs.startSize){
31204 if(this.fireEvent('beforeapply', this, newSize) !== false){
31205 this.adapter.setElementSize(this, newSize);
31206 this.fireEvent("moved", this, newSize);
31207 this.fireEvent("resize", this, newSize);
31213 * Get the adapter this SplitBar uses
31214 * @return The adapter object
31216 getAdapter : function(){
31217 return this.adapter;
31221 * Set the adapter this SplitBar uses
31222 * @param {Object} adapter A SplitBar adapter object
31224 setAdapter : function(adapter){
31225 this.adapter = adapter;
31226 this.adapter.init(this);
31230 * Gets the minimum size for the resizing element
31231 * @return {Number} The minimum size
31233 getMinimumSize : function(){
31234 return this.minSize;
31238 * Sets the minimum size for the resizing element
31239 * @param {Number} minSize The minimum size
31241 setMinimumSize : function(minSize){
31242 this.minSize = minSize;
31246 * Gets the maximum size for the resizing element
31247 * @return {Number} The maximum size
31249 getMaximumSize : function(){
31250 return this.maxSize;
31254 * Sets the maximum size for the resizing element
31255 * @param {Number} maxSize The maximum size
31257 setMaximumSize : function(maxSize){
31258 this.maxSize = maxSize;
31262 * Sets the initialize size for the resizing element
31263 * @param {Number} size The initial size
31265 setCurrentSize : function(size){
31266 var oldAnimate = this.animate;
31267 this.animate = false;
31268 this.adapter.setElementSize(this, size);
31269 this.animate = oldAnimate;
31273 * Destroy this splitbar.
31274 * @param {Boolean} removeEl True to remove the element
31276 destroy : function(removeEl){
31278 this.shim.remove();
31281 this.proxy.parentNode.removeChild(this.proxy);
31289 * @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.
31291 Roo.bootstrap.SplitBar.createProxy = function(dir){
31292 var proxy = new Roo.Element(document.createElement("div"));
31293 proxy.unselectable();
31294 var cls = 'roo-splitbar-proxy';
31295 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
31296 document.body.appendChild(proxy.dom);
31301 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
31302 * Default Adapter. It assumes the splitter and resizing element are not positioned
31303 * elements and only gets/sets the width of the element. Generally used for table based layouts.
31305 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
31308 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
31309 // do nothing for now
31310 init : function(s){
31314 * Called before drag operations to get the current size of the resizing element.
31315 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31317 getElementSize : function(s){
31318 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31319 return s.resizingEl.getWidth();
31321 return s.resizingEl.getHeight();
31326 * Called after drag operations to set the size of the resizing element.
31327 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
31328 * @param {Number} newSize The new size to set
31329 * @param {Function} onComplete A function to be invoked when resizing is complete
31331 setElementSize : function(s, newSize, onComplete){
31332 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
31334 s.resizingEl.setWidth(newSize);
31336 onComplete(s, newSize);
31339 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
31344 s.resizingEl.setHeight(newSize);
31346 onComplete(s, newSize);
31349 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
31356 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
31357 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
31358 * Adapter that moves the splitter element to align with the resized sizing element.
31359 * Used with an absolute positioned SplitBar.
31360 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
31361 * document.body, make sure you assign an id to the body element.
31363 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
31364 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
31365 this.container = Roo.get(container);
31368 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
31369 init : function(s){
31370 this.basic.init(s);
31373 getElementSize : function(s){
31374 return this.basic.getElementSize(s);
31377 setElementSize : function(s, newSize, onComplete){
31378 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
31381 moveSplitter : function(s){
31382 var yes = Roo.bootstrap.SplitBar;
31383 switch(s.placement){
31385 s.el.setX(s.resizingEl.getRight());
31388 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
31391 s.el.setY(s.resizingEl.getBottom());
31394 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
31401 * Orientation constant - Create a vertical SplitBar
31405 Roo.bootstrap.SplitBar.VERTICAL = 1;
31408 * Orientation constant - Create a horizontal SplitBar
31412 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
31415 * Placement constant - The resizing element is to the left of the splitter element
31419 Roo.bootstrap.SplitBar.LEFT = 1;
31422 * Placement constant - The resizing element is to the right of the splitter element
31426 Roo.bootstrap.SplitBar.RIGHT = 2;
31429 * Placement constant - The resizing element is positioned above the splitter element
31433 Roo.bootstrap.SplitBar.TOP = 3;
31436 * Placement constant - The resizing element is positioned under splitter element
31440 Roo.bootstrap.SplitBar.BOTTOM = 4;
31441 Roo.namespace("Roo.bootstrap.layout");/*
31443 * Ext JS Library 1.1.1
31444 * Copyright(c) 2006-2007, Ext JS, LLC.
31446 * Originally Released Under LGPL - original licence link has changed is not relivant.
31449 * <script type="text/javascript">
31453 * @class Roo.bootstrap.layout.Manager
31454 * @extends Roo.bootstrap.Component
31455 * Base class for layout managers.
31457 Roo.bootstrap.layout.Manager = function(config)
31459 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
31465 /** false to disable window resize monitoring @type Boolean */
31466 this.monitorWindowResize = true;
31471 * Fires when a layout is performed.
31472 * @param {Roo.LayoutManager} this
31476 * @event regionresized
31477 * Fires when the user resizes a region.
31478 * @param {Roo.LayoutRegion} region The resized region
31479 * @param {Number} newSize The new size (width for east/west, height for north/south)
31481 "regionresized" : true,
31483 * @event regioncollapsed
31484 * Fires when a region is collapsed.
31485 * @param {Roo.LayoutRegion} region The collapsed region
31487 "regioncollapsed" : true,
31489 * @event regionexpanded
31490 * Fires when a region is expanded.
31491 * @param {Roo.LayoutRegion} region The expanded region
31493 "regionexpanded" : true
31495 this.updating = false;
31498 this.el = Roo.get(config.el);
31504 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31509 monitorWindowResize : true,
31515 onRender : function(ct, position)
31518 this.el = Roo.get(ct);
31524 initEvents: function()
31528 // ie scrollbar fix
31529 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31530 document.body.scroll = "no";
31531 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31532 this.el.position('relative');
31534 this.id = this.el.id;
31535 this.el.addClass("roo-layout-container");
31536 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31537 if(this.el.dom != document.body ) {
31538 this.el.on('resize', this.layout,this);
31539 this.el.on('show', this.layout,this);
31545 * Returns true if this layout is currently being updated
31546 * @return {Boolean}
31548 isUpdating : function(){
31549 return this.updating;
31553 * Suspend the LayoutManager from doing auto-layouts while
31554 * making multiple add or remove calls
31556 beginUpdate : function(){
31557 this.updating = true;
31561 * Restore auto-layouts and optionally disable the manager from performing a layout
31562 * @param {Boolean} noLayout true to disable a layout update
31564 endUpdate : function(noLayout){
31565 this.updating = false;
31571 layout: function(){
31575 onRegionResized : function(region, newSize){
31576 this.fireEvent("regionresized", region, newSize);
31580 onRegionCollapsed : function(region){
31581 this.fireEvent("regioncollapsed", region);
31584 onRegionExpanded : function(region){
31585 this.fireEvent("regionexpanded", region);
31589 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31590 * performs box-model adjustments.
31591 * @return {Object} The size as an object {width: (the width), height: (the height)}
31593 getViewSize : function()
31596 if(this.el.dom != document.body){
31597 size = this.el.getSize();
31599 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31601 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31602 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31607 * Returns the Element this layout is bound to.
31608 * @return {Roo.Element}
31610 getEl : function(){
31615 * Returns the specified region.
31616 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31617 * @return {Roo.LayoutRegion}
31619 getRegion : function(target){
31620 return this.regions[target.toLowerCase()];
31623 onWindowResize : function(){
31624 if(this.monitorWindowResize){
31630 * Ext JS Library 1.1.1
31631 * Copyright(c) 2006-2007, Ext JS, LLC.
31633 * Originally Released Under LGPL - original licence link has changed is not relivant.
31636 * <script type="text/javascript">
31639 * @class Roo.bootstrap.layout.Border
31640 * @extends Roo.bootstrap.layout.Manager
31641 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
31642 * please see: examples/bootstrap/nested.html<br><br>
31644 <b>The container the layout is rendered into can be either the body element or any other element.
31645 If it is not the body element, the container needs to either be an absolute positioned element,
31646 or you will need to add "position:relative" to the css of the container. You will also need to specify
31647 the container size if it is not the body element.</b>
31650 * Create a new Border
31651 * @param {Object} config Configuration options
31653 Roo.bootstrap.layout.Border = function(config){
31654 config = config || {};
31655 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
31659 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
31660 if(config[region]){
31661 config[region].region = region;
31662 this.addRegion(config[region]);
31668 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
31670 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
31672 * Creates and adds a new region if it doesn't already exist.
31673 * @param {String} target The target region key (north, south, east, west or center).
31674 * @param {Object} config The regions config object
31675 * @return {BorderLayoutRegion} The new region
31677 addRegion : function(config)
31679 if(!this.regions[config.region]){
31680 var r = this.factory(config);
31681 this.bindRegion(r);
31683 return this.regions[config.region];
31687 bindRegion : function(r){
31688 this.regions[r.config.region] = r;
31690 r.on("visibilitychange", this.layout, this);
31691 r.on("paneladded", this.layout, this);
31692 r.on("panelremoved", this.layout, this);
31693 r.on("invalidated", this.layout, this);
31694 r.on("resized", this.onRegionResized, this);
31695 r.on("collapsed", this.onRegionCollapsed, this);
31696 r.on("expanded", this.onRegionExpanded, this);
31700 * Performs a layout update.
31702 layout : function()
31704 if(this.updating) {
31707 var size = this.getViewSize();
31708 var w = size.width;
31709 var h = size.height;
31714 //var x = 0, y = 0;
31716 var rs = this.regions;
31717 var north = rs["north"];
31718 var south = rs["south"];
31719 var west = rs["west"];
31720 var east = rs["east"];
31721 var center = rs["center"];
31722 //if(this.hideOnLayout){ // not supported anymore
31723 //c.el.setStyle("display", "none");
31725 if(north && north.isVisible()){
31726 var b = north.getBox();
31727 var m = north.getMargins();
31728 b.width = w - (m.left+m.right);
31731 centerY = b.height + b.y + m.bottom;
31732 centerH -= centerY;
31733 north.updateBox(this.safeBox(b));
31735 if(south && south.isVisible()){
31736 var b = south.getBox();
31737 var m = south.getMargins();
31738 b.width = w - (m.left+m.right);
31740 var totalHeight = (b.height + m.top + m.bottom);
31741 b.y = h - totalHeight + m.top;
31742 centerH -= totalHeight;
31743 south.updateBox(this.safeBox(b));
31745 if(west && west.isVisible()){
31746 var b = west.getBox();
31747 var m = west.getMargins();
31748 b.height = centerH - (m.top+m.bottom);
31750 b.y = centerY + m.top;
31751 var totalWidth = (b.width + m.left + m.right);
31752 centerX += totalWidth;
31753 centerW -= totalWidth;
31754 west.updateBox(this.safeBox(b));
31756 if(east && east.isVisible()){
31757 var b = east.getBox();
31758 var m = east.getMargins();
31759 b.height = centerH - (m.top+m.bottom);
31760 var totalWidth = (b.width + m.left + m.right);
31761 b.x = w - totalWidth + m.left;
31762 b.y = centerY + m.top;
31763 centerW -= totalWidth;
31764 east.updateBox(this.safeBox(b));
31767 var m = center.getMargins();
31769 x: centerX + m.left,
31770 y: centerY + m.top,
31771 width: centerW - (m.left+m.right),
31772 height: centerH - (m.top+m.bottom)
31774 //if(this.hideOnLayout){
31775 //center.el.setStyle("display", "block");
31777 center.updateBox(this.safeBox(centerBox));
31780 this.fireEvent("layout", this);
31784 safeBox : function(box){
31785 box.width = Math.max(0, box.width);
31786 box.height = Math.max(0, box.height);
31791 * Adds a ContentPanel (or subclass) to this layout.
31792 * @param {String} target The target region key (north, south, east, west or center).
31793 * @param {Roo.ContentPanel} panel The panel to add
31794 * @return {Roo.ContentPanel} The added panel
31796 add : function(target, panel){
31798 target = target.toLowerCase();
31799 return this.regions[target].add(panel);
31803 * Remove a ContentPanel (or subclass) to this layout.
31804 * @param {String} target The target region key (north, south, east, west or center).
31805 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
31806 * @return {Roo.ContentPanel} The removed panel
31808 remove : function(target, panel){
31809 target = target.toLowerCase();
31810 return this.regions[target].remove(panel);
31814 * Searches all regions for a panel with the specified id
31815 * @param {String} panelId
31816 * @return {Roo.ContentPanel} The panel or null if it wasn't found
31818 findPanel : function(panelId){
31819 var rs = this.regions;
31820 for(var target in rs){
31821 if(typeof rs[target] != "function"){
31822 var p = rs[target].getPanel(panelId);
31832 * Searches all regions for a panel with the specified id and activates (shows) it.
31833 * @param {String/ContentPanel} panelId The panels id or the panel itself
31834 * @return {Roo.ContentPanel} The shown panel or null
31836 showPanel : function(panelId) {
31837 var rs = this.regions;
31838 for(var target in rs){
31839 var r = rs[target];
31840 if(typeof r != "function"){
31841 if(r.hasPanel(panelId)){
31842 return r.showPanel(panelId);
31850 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
31851 * @param {Roo.state.Provider} provider (optional) An alternate state provider
31854 restoreState : function(provider){
31856 provider = Roo.state.Manager;
31858 var sm = new Roo.LayoutStateManager();
31859 sm.init(this, provider);
31865 * Adds a xtype elements to the layout.
31869 xtype : 'ContentPanel',
31876 xtype : 'NestedLayoutPanel',
31882 items : [ ... list of content panels or nested layout panels.. ]
31886 * @param {Object} cfg Xtype definition of item to add.
31888 addxtype : function(cfg)
31890 // basically accepts a pannel...
31891 // can accept a layout region..!?!?
31892 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
31895 // theory? children can only be panels??
31897 //if (!cfg.xtype.match(/Panel$/)) {
31902 if (typeof(cfg.region) == 'undefined') {
31903 Roo.log("Failed to add Panel, region was not set");
31907 var region = cfg.region;
31913 xitems = cfg.items;
31920 case 'Content': // ContentPanel (el, cfg)
31921 case 'Scroll': // ContentPanel (el, cfg)
31923 cfg.autoCreate = true;
31924 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31926 // var el = this.el.createChild();
31927 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
31930 this.add(region, ret);
31934 case 'TreePanel': // our new panel!
31935 cfg.el = this.el.createChild();
31936 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31937 this.add(region, ret);
31942 // create a new Layout (which is a Border Layout...
31944 var clayout = cfg.layout;
31945 clayout.el = this.el.createChild();
31946 clayout.items = clayout.items || [];
31950 // replace this exitems with the clayout ones..
31951 xitems = clayout.items;
31953 // force background off if it's in center...
31954 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
31955 cfg.background = false;
31957 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
31960 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31961 //console.log('adding nested layout panel ' + cfg.toSource());
31962 this.add(region, ret);
31963 nb = {}; /// find first...
31968 // needs grid and region
31970 //var el = this.getRegion(region).el.createChild();
31972 *var el = this.el.createChild();
31973 // create the grid first...
31974 cfg.grid.container = el;
31975 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
31978 if (region == 'center' && this.active ) {
31979 cfg.background = false;
31982 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31984 this.add(region, ret);
31986 if (cfg.background) {
31987 // render grid on panel activation (if panel background)
31988 ret.on('activate', function(gp) {
31989 if (!gp.grid.rendered) {
31990 // gp.grid.render(el);
31994 // cfg.grid.render(el);
32000 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
32001 // it was the old xcomponent building that caused this before.
32002 // espeically if border is the top element in the tree.
32012 if (typeof(Roo[cfg.xtype]) != 'undefined') {
32014 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32015 this.add(region, ret);
32019 throw "Can not add '" + cfg.xtype + "' to Border";
32025 this.beginUpdate();
32029 Roo.each(xitems, function(i) {
32030 region = nb && i.region ? i.region : false;
32032 var add = ret.addxtype(i);
32035 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32036 if (!i.background) {
32037 abn[region] = nb[region] ;
32044 // make the last non-background panel active..
32045 //if (nb) { Roo.log(abn); }
32048 for(var r in abn) {
32049 region = this.getRegion(r);
32051 // tried using nb[r], but it does not work..
32053 region.showPanel(abn[r]);
32064 factory : function(cfg)
32067 var validRegions = Roo.bootstrap.layout.Border.regions;
32069 var target = cfg.region;
32072 var r = Roo.bootstrap.layout;
32076 return new r.North(cfg);
32078 return new r.South(cfg);
32080 return new r.East(cfg);
32082 return new r.West(cfg);
32084 return new r.Center(cfg);
32086 throw 'Layout region "'+target+'" not supported.';
32093 * Ext JS Library 1.1.1
32094 * Copyright(c) 2006-2007, Ext JS, LLC.
32096 * Originally Released Under LGPL - original licence link has changed is not relivant.
32099 * <script type="text/javascript">
32103 * @class Roo.bootstrap.layout.Basic
32104 * @extends Roo.util.Observable
32105 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32106 * and does not have a titlebar, tabs or any other features. All it does is size and position
32107 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32108 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32109 * @cfg {string} region the region that it inhabits..
32110 * @cfg {bool} skipConfig skip config?
32114 Roo.bootstrap.layout.Basic = function(config){
32116 this.mgr = config.mgr;
32118 this.position = config.region;
32120 var skipConfig = config.skipConfig;
32124 * @scope Roo.BasicLayoutRegion
32128 * @event beforeremove
32129 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32130 * @param {Roo.LayoutRegion} this
32131 * @param {Roo.ContentPanel} panel The panel
32132 * @param {Object} e The cancel event object
32134 "beforeremove" : true,
32136 * @event invalidated
32137 * Fires when the layout for this region is changed.
32138 * @param {Roo.LayoutRegion} this
32140 "invalidated" : true,
32142 * @event visibilitychange
32143 * Fires when this region is shown or hidden
32144 * @param {Roo.LayoutRegion} this
32145 * @param {Boolean} visibility true or false
32147 "visibilitychange" : true,
32149 * @event paneladded
32150 * Fires when a panel is added.
32151 * @param {Roo.LayoutRegion} this
32152 * @param {Roo.ContentPanel} panel The panel
32154 "paneladded" : true,
32156 * @event panelremoved
32157 * Fires when a panel is removed.
32158 * @param {Roo.LayoutRegion} this
32159 * @param {Roo.ContentPanel} panel The panel
32161 "panelremoved" : true,
32163 * @event beforecollapse
32164 * Fires when this region before collapse.
32165 * @param {Roo.LayoutRegion} this
32167 "beforecollapse" : true,
32170 * Fires when this region is collapsed.
32171 * @param {Roo.LayoutRegion} this
32173 "collapsed" : true,
32176 * Fires when this region is expanded.
32177 * @param {Roo.LayoutRegion} this
32182 * Fires when this region is slid into view.
32183 * @param {Roo.LayoutRegion} this
32185 "slideshow" : true,
32188 * Fires when this region slides out of view.
32189 * @param {Roo.LayoutRegion} this
32191 "slidehide" : true,
32193 * @event panelactivated
32194 * Fires when a panel is activated.
32195 * @param {Roo.LayoutRegion} this
32196 * @param {Roo.ContentPanel} panel The activated panel
32198 "panelactivated" : true,
32201 * Fires when the user resizes this region.
32202 * @param {Roo.LayoutRegion} this
32203 * @param {Number} newSize The new size (width for east/west, height for north/south)
32207 /** A collection of panels in this region. @type Roo.util.MixedCollection */
32208 this.panels = new Roo.util.MixedCollection();
32209 this.panels.getKey = this.getPanelId.createDelegate(this);
32211 this.activePanel = null;
32212 // ensure listeners are added...
32214 if (config.listeners || config.events) {
32215 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
32216 listeners : config.listeners || {},
32217 events : config.events || {}
32221 if(skipConfig !== true){
32222 this.applyConfig(config);
32226 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
32228 getPanelId : function(p){
32232 applyConfig : function(config){
32233 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32234 this.config = config;
32239 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
32240 * the width, for horizontal (north, south) the height.
32241 * @param {Number} newSize The new width or height
32243 resizeTo : function(newSize){
32244 var el = this.el ? this.el :
32245 (this.activePanel ? this.activePanel.getEl() : null);
32247 switch(this.position){
32250 el.setWidth(newSize);
32251 this.fireEvent("resized", this, newSize);
32255 el.setHeight(newSize);
32256 this.fireEvent("resized", this, newSize);
32262 getBox : function(){
32263 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
32266 getMargins : function(){
32267 return this.margins;
32270 updateBox : function(box){
32272 var el = this.activePanel.getEl();
32273 el.dom.style.left = box.x + "px";
32274 el.dom.style.top = box.y + "px";
32275 this.activePanel.setSize(box.width, box.height);
32279 * Returns the container element for this region.
32280 * @return {Roo.Element}
32282 getEl : function(){
32283 return this.activePanel;
32287 * Returns true if this region is currently visible.
32288 * @return {Boolean}
32290 isVisible : function(){
32291 return this.activePanel ? true : false;
32294 setActivePanel : function(panel){
32295 panel = this.getPanel(panel);
32296 if(this.activePanel && this.activePanel != panel){
32297 this.activePanel.setActiveState(false);
32298 this.activePanel.getEl().setLeftTop(-10000,-10000);
32300 this.activePanel = panel;
32301 panel.setActiveState(true);
32303 panel.setSize(this.box.width, this.box.height);
32305 this.fireEvent("panelactivated", this, panel);
32306 this.fireEvent("invalidated");
32310 * Show the specified panel.
32311 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
32312 * @return {Roo.ContentPanel} The shown panel or null
32314 showPanel : function(panel){
32315 panel = this.getPanel(panel);
32317 this.setActivePanel(panel);
32323 * Get the active panel for this region.
32324 * @return {Roo.ContentPanel} The active panel or null
32326 getActivePanel : function(){
32327 return this.activePanel;
32331 * Add the passed ContentPanel(s)
32332 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32333 * @return {Roo.ContentPanel} The panel added (if only one was added)
32335 add : function(panel){
32336 if(arguments.length > 1){
32337 for(var i = 0, len = arguments.length; i < len; i++) {
32338 this.add(arguments[i]);
32342 if(this.hasPanel(panel)){
32343 this.showPanel(panel);
32346 var el = panel.getEl();
32347 if(el.dom.parentNode != this.mgr.el.dom){
32348 this.mgr.el.dom.appendChild(el.dom);
32350 if(panel.setRegion){
32351 panel.setRegion(this);
32353 this.panels.add(panel);
32354 el.setStyle("position", "absolute");
32355 if(!panel.background){
32356 this.setActivePanel(panel);
32357 if(this.config.initialSize && this.panels.getCount()==1){
32358 this.resizeTo(this.config.initialSize);
32361 this.fireEvent("paneladded", this, panel);
32366 * Returns true if the panel is in this region.
32367 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32368 * @return {Boolean}
32370 hasPanel : function(panel){
32371 if(typeof panel == "object"){ // must be panel obj
32372 panel = panel.getId();
32374 return this.getPanel(panel) ? true : false;
32378 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32379 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32380 * @param {Boolean} preservePanel Overrides the config preservePanel option
32381 * @return {Roo.ContentPanel} The panel that was removed
32383 remove : function(panel, preservePanel){
32384 panel = this.getPanel(panel);
32389 this.fireEvent("beforeremove", this, panel, e);
32390 if(e.cancel === true){
32393 var panelId = panel.getId();
32394 this.panels.removeKey(panelId);
32399 * Returns the panel specified or null if it's not in this region.
32400 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
32401 * @return {Roo.ContentPanel}
32403 getPanel : function(id){
32404 if(typeof id == "object"){ // must be panel obj
32407 return this.panels.get(id);
32411 * Returns this regions position (north/south/east/west/center).
32414 getPosition: function(){
32415 return this.position;
32419 * Ext JS Library 1.1.1
32420 * Copyright(c) 2006-2007, Ext JS, LLC.
32422 * Originally Released Under LGPL - original licence link has changed is not relivant.
32425 * <script type="text/javascript">
32429 * @class Roo.bootstrap.layout.Region
32430 * @extends Roo.bootstrap.layout.Basic
32431 * This class represents a region in a layout manager.
32433 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
32434 * @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})
32435 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
32436 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
32437 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
32438 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
32439 * @cfg {String} title The title for the region (overrides panel titles)
32440 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
32441 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
32442 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
32443 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
32444 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
32445 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
32446 * the space available, similar to FireFox 1.5 tabs (defaults to false)
32447 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
32448 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
32449 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
32451 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
32452 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
32453 * @cfg {Boolean} disableTabTips True to disable tab tooltips
32454 * @cfg {Number} width For East/West panels
32455 * @cfg {Number} height For North/South panels
32456 * @cfg {Boolean} split To show the splitter
32457 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
32459 * @cfg {string} cls Extra CSS classes to add to region
32461 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32462 * @cfg {string} region the region that it inhabits..
32465 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
32466 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
32468 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
32469 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
32470 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
32472 Roo.bootstrap.layout.Region = function(config)
32474 this.applyConfig(config);
32476 var mgr = config.mgr;
32477 var pos = config.region;
32478 config.skipConfig = true;
32479 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
32482 this.onRender(mgr.el);
32485 this.visible = true;
32486 this.collapsed = false;
32489 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32491 position: '', // set by wrapper (eg. north/south etc..)
32493 createBody : function(){
32494 /** This region's body element
32495 * @type Roo.Element */
32496 this.bodyEl = this.el.createChild({
32498 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32502 onRender: function(ctr, pos)
32504 var dh = Roo.DomHelper;
32505 /** This region's container element
32506 * @type Roo.Element */
32507 this.el = dh.append(ctr.dom, {
32509 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
32511 /** This region's title element
32512 * @type Roo.Element */
32514 this.titleEl = dh.append(this.el.dom,
32517 unselectable: "on",
32518 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32520 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32521 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32524 this.titleEl.enableDisplayMode();
32525 /** This region's title text element
32526 * @type HTMLElement */
32527 this.titleTextEl = this.titleEl.dom.firstChild;
32528 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32530 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32531 this.closeBtn.enableDisplayMode();
32532 this.closeBtn.on("click", this.closeClicked, this);
32533 this.closeBtn.hide();
32535 this.createBody(this.config);
32536 if(this.config.hideWhenEmpty){
32538 this.on("paneladded", this.validateVisibility, this);
32539 this.on("panelremoved", this.validateVisibility, this);
32541 if(this.autoScroll){
32542 this.bodyEl.setStyle("overflow", "auto");
32544 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
32546 //if(c.titlebar !== false){
32547 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
32548 this.titleEl.hide();
32550 this.titleEl.show();
32551 if(this.config.title){
32552 this.titleTextEl.innerHTML = this.config.title;
32556 if(this.config.collapsed){
32557 this.collapse(true);
32559 if(this.config.hidden){
32564 applyConfig : function(c)
32567 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32568 var dh = Roo.DomHelper;
32569 if(c.titlebar !== false){
32570 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32571 this.collapseBtn.on("click", this.collapse, this);
32572 this.collapseBtn.enableDisplayMode();
32574 if(c.showPin === true || this.showPin){
32575 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32576 this.stickBtn.enableDisplayMode();
32577 this.stickBtn.on("click", this.expand, this);
32578 this.stickBtn.hide();
32583 /** This region's collapsed element
32584 * @type Roo.Element */
32587 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32588 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32591 if(c.floatable !== false){
32592 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32593 this.collapsedEl.on("click", this.collapseClick, this);
32596 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32597 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32598 id: "message", unselectable: "on", style:{"float":"left"}});
32599 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32601 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32602 this.expandBtn.on("click", this.expand, this);
32606 if(this.collapseBtn){
32607 this.collapseBtn.setVisible(c.collapsible == true);
32610 this.cmargins = c.cmargins || this.cmargins ||
32611 (this.position == "west" || this.position == "east" ?
32612 {top: 0, left: 2, right:2, bottom: 0} :
32613 {top: 2, left: 0, right:0, bottom: 2});
32615 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32618 this.bottomTabs = c.tabPosition != "top";
32620 this.autoScroll = c.autoScroll || false;
32625 this.duration = c.duration || .30;
32626 this.slideDuration = c.slideDuration || .45;
32631 * Returns true if this region is currently visible.
32632 * @return {Boolean}
32634 isVisible : function(){
32635 return this.visible;
32639 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
32640 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
32642 //setCollapsedTitle : function(title){
32643 // title = title || " ";
32644 // if(this.collapsedTitleTextEl){
32645 // this.collapsedTitleTextEl.innerHTML = title;
32649 getBox : function(){
32651 // if(!this.collapsed){
32652 b = this.el.getBox(false, true);
32654 // b = this.collapsedEl.getBox(false, true);
32659 getMargins : function(){
32660 return this.margins;
32661 //return this.collapsed ? this.cmargins : this.margins;
32664 highlight : function(){
32665 this.el.addClass("x-layout-panel-dragover");
32668 unhighlight : function(){
32669 this.el.removeClass("x-layout-panel-dragover");
32672 updateBox : function(box)
32675 if(!this.collapsed){
32676 this.el.dom.style.left = box.x + "px";
32677 this.el.dom.style.top = box.y + "px";
32678 this.updateBody(box.width, box.height);
32680 this.collapsedEl.dom.style.left = box.x + "px";
32681 this.collapsedEl.dom.style.top = box.y + "px";
32682 this.collapsedEl.setSize(box.width, box.height);
32685 this.tabs.autoSizeTabs();
32689 updateBody : function(w, h)
32692 this.el.setWidth(w);
32693 w -= this.el.getBorderWidth("rl");
32694 if(this.config.adjustments){
32695 w += this.config.adjustments[0];
32699 this.el.setHeight(h);
32700 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
32701 h -= this.el.getBorderWidth("tb");
32702 if(this.config.adjustments){
32703 h += this.config.adjustments[1];
32705 this.bodyEl.setHeight(h);
32707 h = this.tabs.syncHeight(h);
32710 if(this.panelSize){
32711 w = w !== null ? w : this.panelSize.width;
32712 h = h !== null ? h : this.panelSize.height;
32714 if(this.activePanel){
32715 var el = this.activePanel.getEl();
32716 w = w !== null ? w : el.getWidth();
32717 h = h !== null ? h : el.getHeight();
32718 this.panelSize = {width: w, height: h};
32719 this.activePanel.setSize(w, h);
32721 if(Roo.isIE && this.tabs){
32722 this.tabs.el.repaint();
32727 * Returns the container element for this region.
32728 * @return {Roo.Element}
32730 getEl : function(){
32735 * Hides this region.
32738 //if(!this.collapsed){
32739 this.el.dom.style.left = "-2000px";
32742 // this.collapsedEl.dom.style.left = "-2000px";
32743 // this.collapsedEl.hide();
32745 this.visible = false;
32746 this.fireEvent("visibilitychange", this, false);
32750 * Shows this region if it was previously hidden.
32753 //if(!this.collapsed){
32756 // this.collapsedEl.show();
32758 this.visible = true;
32759 this.fireEvent("visibilitychange", this, true);
32762 closeClicked : function(){
32763 if(this.activePanel){
32764 this.remove(this.activePanel);
32768 collapseClick : function(e){
32770 e.stopPropagation();
32773 e.stopPropagation();
32779 * Collapses this region.
32780 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
32783 collapse : function(skipAnim, skipCheck = false){
32784 if(this.collapsed) {
32788 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
32790 this.collapsed = true;
32792 this.split.el.hide();
32794 if(this.config.animate && skipAnim !== true){
32795 this.fireEvent("invalidated", this);
32796 this.animateCollapse();
32798 this.el.setLocation(-20000,-20000);
32800 this.collapsedEl.show();
32801 this.fireEvent("collapsed", this);
32802 this.fireEvent("invalidated", this);
32808 animateCollapse : function(){
32813 * Expands this region if it was previously collapsed.
32814 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
32815 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
32818 expand : function(e, skipAnim){
32820 e.stopPropagation();
32822 if(!this.collapsed || this.el.hasActiveFx()) {
32826 this.afterSlideIn();
32829 this.collapsed = false;
32830 if(this.config.animate && skipAnim !== true){
32831 this.animateExpand();
32835 this.split.el.show();
32837 this.collapsedEl.setLocation(-2000,-2000);
32838 this.collapsedEl.hide();
32839 this.fireEvent("invalidated", this);
32840 this.fireEvent("expanded", this);
32844 animateExpand : function(){
32848 initTabs : function()
32850 this.bodyEl.setStyle("overflow", "hidden");
32851 var ts = new Roo.bootstrap.panel.Tabs({
32852 el: this.bodyEl.dom,
32853 tabPosition: this.bottomTabs ? 'bottom' : 'top',
32854 disableTooltips: this.config.disableTabTips,
32855 toolbar : this.config.toolbar
32858 if(this.config.hideTabs){
32859 ts.stripWrap.setDisplayed(false);
32862 ts.resizeTabs = this.config.resizeTabs === true;
32863 ts.minTabWidth = this.config.minTabWidth || 40;
32864 ts.maxTabWidth = this.config.maxTabWidth || 250;
32865 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
32866 ts.monitorResize = false;
32867 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32868 ts.bodyEl.addClass('roo-layout-tabs-body');
32869 this.panels.each(this.initPanelAsTab, this);
32872 initPanelAsTab : function(panel){
32873 var ti = this.tabs.addTab(
32875 panel.getTitle(), null,
32876 this.config.closeOnTab && panel.isClosable()
32878 if(panel.tabTip !== undefined){
32879 ti.setTooltip(panel.tabTip);
32881 ti.on("activate", function(){
32882 this.setActivePanel(panel);
32885 if(this.config.closeOnTab){
32886 ti.on("beforeclose", function(t, e){
32888 this.remove(panel);
32894 updatePanelTitle : function(panel, title)
32896 if(this.activePanel == panel){
32897 this.updateTitle(title);
32900 var ti = this.tabs.getTab(panel.getEl().id);
32902 if(panel.tabTip !== undefined){
32903 ti.setTooltip(panel.tabTip);
32908 updateTitle : function(title){
32909 if(this.titleTextEl && !this.config.title){
32910 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
32914 setActivePanel : function(panel)
32916 panel = this.getPanel(panel);
32917 if(this.activePanel && this.activePanel != panel){
32918 this.activePanel.setActiveState(false);
32920 this.activePanel = panel;
32921 panel.setActiveState(true);
32922 if(this.panelSize){
32923 panel.setSize(this.panelSize.width, this.panelSize.height);
32926 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
32928 this.updateTitle(panel.getTitle());
32930 this.fireEvent("invalidated", this);
32932 this.fireEvent("panelactivated", this, panel);
32936 * Shows the specified panel.
32937 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
32938 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
32940 showPanel : function(panel)
32942 panel = this.getPanel(panel);
32945 var tab = this.tabs.getTab(panel.getEl().id);
32946 if(tab.isHidden()){
32947 this.tabs.unhideTab(tab.id);
32951 this.setActivePanel(panel);
32958 * Get the active panel for this region.
32959 * @return {Roo.ContentPanel} The active panel or null
32961 getActivePanel : function(){
32962 return this.activePanel;
32965 validateVisibility : function(){
32966 if(this.panels.getCount() < 1){
32967 this.updateTitle(" ");
32968 this.closeBtn.hide();
32971 if(!this.isVisible()){
32978 * Adds the passed ContentPanel(s) to this region.
32979 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32980 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
32982 add : function(panel){
32983 if(arguments.length > 1){
32984 for(var i = 0, len = arguments.length; i < len; i++) {
32985 this.add(arguments[i]);
32989 if(this.hasPanel(panel)){
32990 this.showPanel(panel);
32993 panel.setRegion(this);
32994 this.panels.add(panel);
32995 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
32996 this.bodyEl.dom.appendChild(panel.getEl().dom);
32997 if(panel.background !== true){
32998 this.setActivePanel(panel);
33000 this.fireEvent("paneladded", this, panel);
33006 this.initPanelAsTab(panel);
33010 if(panel.background !== true){
33011 this.tabs.activate(panel.getEl().id);
33013 this.fireEvent("paneladded", this, panel);
33018 * Hides the tab for the specified panel.
33019 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33021 hidePanel : function(panel){
33022 if(this.tabs && (panel = this.getPanel(panel))){
33023 this.tabs.hideTab(panel.getEl().id);
33028 * Unhides the tab for a previously hidden panel.
33029 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33031 unhidePanel : function(panel){
33032 if(this.tabs && (panel = this.getPanel(panel))){
33033 this.tabs.unhideTab(panel.getEl().id);
33037 clearPanels : function(){
33038 while(this.panels.getCount() > 0){
33039 this.remove(this.panels.first());
33044 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33045 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33046 * @param {Boolean} preservePanel Overrides the config preservePanel option
33047 * @return {Roo.ContentPanel} The panel that was removed
33049 remove : function(panel, preservePanel)
33051 panel = this.getPanel(panel);
33056 this.fireEvent("beforeremove", this, panel, e);
33057 if(e.cancel === true){
33060 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33061 var panelId = panel.getId();
33062 this.panels.removeKey(panelId);
33064 document.body.appendChild(panel.getEl().dom);
33067 this.tabs.removeTab(panel.getEl().id);
33068 }else if (!preservePanel){
33069 this.bodyEl.dom.removeChild(panel.getEl().dom);
33071 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33072 var p = this.panels.first();
33073 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33074 tempEl.appendChild(p.getEl().dom);
33075 this.bodyEl.update("");
33076 this.bodyEl.dom.appendChild(p.getEl().dom);
33078 this.updateTitle(p.getTitle());
33080 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33081 this.setActivePanel(p);
33083 panel.setRegion(null);
33084 if(this.activePanel == panel){
33085 this.activePanel = null;
33087 if(this.config.autoDestroy !== false && preservePanel !== true){
33088 try{panel.destroy();}catch(e){}
33090 this.fireEvent("panelremoved", this, panel);
33095 * Returns the TabPanel component used by this region
33096 * @return {Roo.TabPanel}
33098 getTabs : function(){
33102 createTool : function(parentEl, className){
33103 var btn = Roo.DomHelper.append(parentEl, {
33105 cls: "x-layout-tools-button",
33108 cls: "roo-layout-tools-button-inner " + className,
33112 btn.addClassOnOver("roo-layout-tools-button-over");
33117 * Ext JS Library 1.1.1
33118 * Copyright(c) 2006-2007, Ext JS, LLC.
33120 * Originally Released Under LGPL - original licence link has changed is not relivant.
33123 * <script type="text/javascript">
33129 * @class Roo.SplitLayoutRegion
33130 * @extends Roo.LayoutRegion
33131 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33133 Roo.bootstrap.layout.Split = function(config){
33134 this.cursor = config.cursor;
33135 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
33138 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
33140 splitTip : "Drag to resize.",
33141 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33142 useSplitTips : false,
33144 applyConfig : function(config){
33145 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
33148 onRender : function(ctr,pos) {
33150 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
33151 if(!this.config.split){
33156 var splitEl = Roo.DomHelper.append(ctr.dom, {
33158 id: this.el.id + "-split",
33159 cls: "roo-layout-split roo-layout-split-"+this.position,
33162 /** The SplitBar for this region
33163 * @type Roo.SplitBar */
33164 // does not exist yet...
33165 Roo.log([this.position, this.orientation]);
33167 this.split = new Roo.bootstrap.SplitBar({
33168 dragElement : splitEl,
33169 resizingElement: this.el,
33170 orientation : this.orientation
33173 this.split.on("moved", this.onSplitMove, this);
33174 this.split.useShim = this.config.useShim === true;
33175 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33176 if(this.useSplitTips){
33177 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33179 //if(config.collapsible){
33180 // this.split.el.on("dblclick", this.collapse, this);
33183 if(typeof this.config.minSize != "undefined"){
33184 this.split.minSize = this.config.minSize;
33186 if(typeof this.config.maxSize != "undefined"){
33187 this.split.maxSize = this.config.maxSize;
33189 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
33190 this.hideSplitter();
33195 getHMaxSize : function(){
33196 var cmax = this.config.maxSize || 10000;
33197 var center = this.mgr.getRegion("center");
33198 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33201 getVMaxSize : function(){
33202 var cmax = this.config.maxSize || 10000;
33203 var center = this.mgr.getRegion("center");
33204 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33207 onSplitMove : function(split, newSize){
33208 this.fireEvent("resized", this, newSize);
33212 * Returns the {@link Roo.SplitBar} for this region.
33213 * @return {Roo.SplitBar}
33215 getSplitBar : function(){
33220 this.hideSplitter();
33221 Roo.bootstrap.layout.Split.superclass.hide.call(this);
33224 hideSplitter : function(){
33226 this.split.el.setLocation(-2000,-2000);
33227 this.split.el.hide();
33233 this.split.el.show();
33235 Roo.bootstrap.layout.Split.superclass.show.call(this);
33238 beforeSlide: function(){
33239 if(Roo.isGecko){// firefox overflow auto bug workaround
33240 this.bodyEl.clip();
33242 this.tabs.bodyEl.clip();
33244 if(this.activePanel){
33245 this.activePanel.getEl().clip();
33247 if(this.activePanel.beforeSlide){
33248 this.activePanel.beforeSlide();
33254 afterSlide : function(){
33255 if(Roo.isGecko){// firefox overflow auto bug workaround
33256 this.bodyEl.unclip();
33258 this.tabs.bodyEl.unclip();
33260 if(this.activePanel){
33261 this.activePanel.getEl().unclip();
33262 if(this.activePanel.afterSlide){
33263 this.activePanel.afterSlide();
33269 initAutoHide : function(){
33270 if(this.autoHide !== false){
33271 if(!this.autoHideHd){
33272 var st = new Roo.util.DelayedTask(this.slideIn, this);
33273 this.autoHideHd = {
33274 "mouseout": function(e){
33275 if(!e.within(this.el, true)){
33279 "mouseover" : function(e){
33285 this.el.on(this.autoHideHd);
33289 clearAutoHide : function(){
33290 if(this.autoHide !== false){
33291 this.el.un("mouseout", this.autoHideHd.mouseout);
33292 this.el.un("mouseover", this.autoHideHd.mouseover);
33296 clearMonitor : function(){
33297 Roo.get(document).un("click", this.slideInIf, this);
33300 // these names are backwards but not changed for compat
33301 slideOut : function(){
33302 if(this.isSlid || this.el.hasActiveFx()){
33305 this.isSlid = true;
33306 if(this.collapseBtn){
33307 this.collapseBtn.hide();
33309 this.closeBtnState = this.closeBtn.getStyle('display');
33310 this.closeBtn.hide();
33312 this.stickBtn.show();
33315 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
33316 this.beforeSlide();
33317 this.el.setStyle("z-index", 10001);
33318 this.el.slideIn(this.getSlideAnchor(), {
33319 callback: function(){
33321 this.initAutoHide();
33322 Roo.get(document).on("click", this.slideInIf, this);
33323 this.fireEvent("slideshow", this);
33330 afterSlideIn : function(){
33331 this.clearAutoHide();
33332 this.isSlid = false;
33333 this.clearMonitor();
33334 this.el.setStyle("z-index", "");
33335 if(this.collapseBtn){
33336 this.collapseBtn.show();
33338 this.closeBtn.setStyle('display', this.closeBtnState);
33340 this.stickBtn.hide();
33342 this.fireEvent("slidehide", this);
33345 slideIn : function(cb){
33346 if(!this.isSlid || this.el.hasActiveFx()){
33350 this.isSlid = false;
33351 this.beforeSlide();
33352 this.el.slideOut(this.getSlideAnchor(), {
33353 callback: function(){
33354 this.el.setLeftTop(-10000, -10000);
33356 this.afterSlideIn();
33364 slideInIf : function(e){
33365 if(!e.within(this.el)){
33370 animateCollapse : function(){
33371 this.beforeSlide();
33372 this.el.setStyle("z-index", 20000);
33373 var anchor = this.getSlideAnchor();
33374 this.el.slideOut(anchor, {
33375 callback : function(){
33376 this.el.setStyle("z-index", "");
33377 this.collapsedEl.slideIn(anchor, {duration:.3});
33379 this.el.setLocation(-10000,-10000);
33381 this.fireEvent("collapsed", this);
33388 animateExpand : function(){
33389 this.beforeSlide();
33390 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
33391 this.el.setStyle("z-index", 20000);
33392 this.collapsedEl.hide({
33395 this.el.slideIn(this.getSlideAnchor(), {
33396 callback : function(){
33397 this.el.setStyle("z-index", "");
33400 this.split.el.show();
33402 this.fireEvent("invalidated", this);
33403 this.fireEvent("expanded", this);
33431 getAnchor : function(){
33432 return this.anchors[this.position];
33435 getCollapseAnchor : function(){
33436 return this.canchors[this.position];
33439 getSlideAnchor : function(){
33440 return this.sanchors[this.position];
33443 getAlignAdj : function(){
33444 var cm = this.cmargins;
33445 switch(this.position){
33461 getExpandAdj : function(){
33462 var c = this.collapsedEl, cm = this.cmargins;
33463 switch(this.position){
33465 return [-(cm.right+c.getWidth()+cm.left), 0];
33468 return [cm.right+c.getWidth()+cm.left, 0];
33471 return [0, -(cm.top+cm.bottom+c.getHeight())];
33474 return [0, cm.top+cm.bottom+c.getHeight()];
33480 * Ext JS Library 1.1.1
33481 * Copyright(c) 2006-2007, Ext JS, LLC.
33483 * Originally Released Under LGPL - original licence link has changed is not relivant.
33486 * <script type="text/javascript">
33489 * These classes are private internal classes
33491 Roo.bootstrap.layout.Center = function(config){
33492 config.region = "center";
33493 Roo.bootstrap.layout.Region.call(this, config);
33494 this.visible = true;
33495 this.minWidth = config.minWidth || 20;
33496 this.minHeight = config.minHeight || 20;
33499 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
33501 // center panel can't be hidden
33505 // center panel can't be hidden
33508 getMinWidth: function(){
33509 return this.minWidth;
33512 getMinHeight: function(){
33513 return this.minHeight;
33526 Roo.bootstrap.layout.North = function(config)
33528 config.region = 'north';
33529 config.cursor = 'n-resize';
33531 Roo.bootstrap.layout.Split.call(this, config);
33535 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33536 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33537 this.split.el.addClass("roo-layout-split-v");
33539 var size = config.initialSize || config.height;
33540 if(typeof size != "undefined"){
33541 this.el.setHeight(size);
33544 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
33546 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33550 getBox : function(){
33551 if(this.collapsed){
33552 return this.collapsedEl.getBox();
33554 var box = this.el.getBox();
33556 box.height += this.split.el.getHeight();
33561 updateBox : function(box){
33562 if(this.split && !this.collapsed){
33563 box.height -= this.split.el.getHeight();
33564 this.split.el.setLeft(box.x);
33565 this.split.el.setTop(box.y+box.height);
33566 this.split.el.setWidth(box.width);
33568 if(this.collapsed){
33569 this.updateBody(box.width, null);
33571 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33579 Roo.bootstrap.layout.South = function(config){
33580 config.region = 'south';
33581 config.cursor = 's-resize';
33582 Roo.bootstrap.layout.Split.call(this, config);
33584 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33585 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33586 this.split.el.addClass("roo-layout-split-v");
33588 var size = config.initialSize || config.height;
33589 if(typeof size != "undefined"){
33590 this.el.setHeight(size);
33594 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33595 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33596 getBox : function(){
33597 if(this.collapsed){
33598 return this.collapsedEl.getBox();
33600 var box = this.el.getBox();
33602 var sh = this.split.el.getHeight();
33609 updateBox : function(box){
33610 if(this.split && !this.collapsed){
33611 var sh = this.split.el.getHeight();
33614 this.split.el.setLeft(box.x);
33615 this.split.el.setTop(box.y-sh);
33616 this.split.el.setWidth(box.width);
33618 if(this.collapsed){
33619 this.updateBody(box.width, null);
33621 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33625 Roo.bootstrap.layout.East = function(config){
33626 config.region = "east";
33627 config.cursor = "e-resize";
33628 Roo.bootstrap.layout.Split.call(this, config);
33630 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
33631 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33632 this.split.el.addClass("roo-layout-split-h");
33634 var size = config.initialSize || config.width;
33635 if(typeof size != "undefined"){
33636 this.el.setWidth(size);
33639 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
33640 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33641 getBox : function(){
33642 if(this.collapsed){
33643 return this.collapsedEl.getBox();
33645 var box = this.el.getBox();
33647 var sw = this.split.el.getWidth();
33654 updateBox : function(box){
33655 if(this.split && !this.collapsed){
33656 var sw = this.split.el.getWidth();
33658 this.split.el.setLeft(box.x);
33659 this.split.el.setTop(box.y);
33660 this.split.el.setHeight(box.height);
33663 if(this.collapsed){
33664 this.updateBody(null, box.height);
33666 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33670 Roo.bootstrap.layout.West = function(config){
33671 config.region = "west";
33672 config.cursor = "w-resize";
33674 Roo.bootstrap.layout.Split.call(this, config);
33676 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
33677 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33678 this.split.el.addClass("roo-layout-split-h");
33682 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
33683 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33685 onRender: function(ctr, pos)
33687 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
33688 var size = this.config.initialSize || this.config.width;
33689 if(typeof size != "undefined"){
33690 this.el.setWidth(size);
33694 getBox : function(){
33695 if(this.collapsed){
33696 return this.collapsedEl.getBox();
33698 var box = this.el.getBox();
33700 box.width += this.split.el.getWidth();
33705 updateBox : function(box){
33706 if(this.split && !this.collapsed){
33707 var sw = this.split.el.getWidth();
33709 this.split.el.setLeft(box.x+box.width);
33710 this.split.el.setTop(box.y);
33711 this.split.el.setHeight(box.height);
33713 if(this.collapsed){
33714 this.updateBody(null, box.height);
33716 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33719 Roo.namespace("Roo.bootstrap.panel");/*
33721 * Ext JS Library 1.1.1
33722 * Copyright(c) 2006-2007, Ext JS, LLC.
33724 * Originally Released Under LGPL - original licence link has changed is not relivant.
33727 * <script type="text/javascript">
33730 * @class Roo.ContentPanel
33731 * @extends Roo.util.Observable
33732 * A basic ContentPanel element.
33733 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
33734 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
33735 * @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
33736 * @cfg {Boolean} closable True if the panel can be closed/removed
33737 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
33738 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
33739 * @cfg {Toolbar} toolbar A toolbar for this panel
33740 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
33741 * @cfg {String} title The title for this panel
33742 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
33743 * @cfg {String} url Calls {@link #setUrl} with this value
33744 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
33745 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
33746 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
33747 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
33750 * Create a new ContentPanel.
33751 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
33752 * @param {String/Object} config A string to set only the title or a config object
33753 * @param {String} content (optional) Set the HTML content for this panel
33754 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
33756 Roo.bootstrap.panel.Content = function( config){
33758 var el = config.el;
33759 var content = config.content;
33761 if(config.autoCreate){ // xtype is available if this is called from factory
33764 this.el = Roo.get(el);
33765 if(!this.el && config && config.autoCreate){
33766 if(typeof config.autoCreate == "object"){
33767 if(!config.autoCreate.id){
33768 config.autoCreate.id = config.id||el;
33770 this.el = Roo.DomHelper.append(document.body,
33771 config.autoCreate, true);
33773 var elcfg = { tag: "div",
33774 cls: "roo-layout-inactive-content",
33778 elcfg.html = config.html;
33782 this.el = Roo.DomHelper.append(document.body, elcfg , true);
33785 this.closable = false;
33786 this.loaded = false;
33787 this.active = false;
33790 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
33792 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
33794 this.wrapEl = this.el.wrap();
33796 if (config.toolbar.items) {
33797 ti = config.toolbar.items ;
33798 delete config.toolbar.items ;
33802 this.toolbar.render(this.wrapEl, 'before');
33803 for(var i =0;i < ti.length;i++) {
33804 // Roo.log(['add child', items[i]]);
33805 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
33807 this.toolbar.items = nitems;
33808 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
33809 delete config.toolbar;
33813 // xtype created footer. - not sure if will work as we normally have to render first..
33814 if (this.footer && !this.footer.el && this.footer.xtype) {
33815 if (!this.wrapEl) {
33816 this.wrapEl = this.el.wrap();
33819 this.footer.container = this.wrapEl.createChild();
33821 this.footer = Roo.factory(this.footer, Roo);
33826 if(typeof config == "string"){
33827 this.title = config;
33829 Roo.apply(this, config);
33833 this.resizeEl = Roo.get(this.resizeEl, true);
33835 this.resizeEl = this.el;
33837 // handle view.xtype
33845 * Fires when this panel is activated.
33846 * @param {Roo.ContentPanel} this
33850 * @event deactivate
33851 * Fires when this panel is activated.
33852 * @param {Roo.ContentPanel} this
33854 "deactivate" : true,
33858 * Fires when this panel is resized if fitToFrame is true.
33859 * @param {Roo.ContentPanel} this
33860 * @param {Number} width The width after any component adjustments
33861 * @param {Number} height The height after any component adjustments
33867 * Fires when this tab is created
33868 * @param {Roo.ContentPanel} this
33879 if(this.autoScroll){
33880 this.resizeEl.setStyle("overflow", "auto");
33882 // fix randome scrolling
33883 //this.el.on('scroll', function() {
33884 // Roo.log('fix random scolling');
33885 // this.scrollTo('top',0);
33888 content = content || this.content;
33890 this.setContent(content);
33892 if(config && config.url){
33893 this.setUrl(this.url, this.params, this.loadOnce);
33898 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
33900 if (this.view && typeof(this.view.xtype) != 'undefined') {
33901 this.view.el = this.el.appendChild(document.createElement("div"));
33902 this.view = Roo.factory(this.view);
33903 this.view.render && this.view.render(false, '');
33907 this.fireEvent('render', this);
33910 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
33912 setRegion : function(region){
33913 this.region = region;
33915 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
33917 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
33922 * Returns the toolbar for this Panel if one was configured.
33923 * @return {Roo.Toolbar}
33925 getToolbar : function(){
33926 return this.toolbar;
33929 setActiveState : function(active){
33930 this.active = active;
33932 this.fireEvent("deactivate", this);
33934 this.fireEvent("activate", this);
33938 * Updates this panel's element
33939 * @param {String} content The new content
33940 * @param {Boolean} loadScripts (optional) true to look for and process scripts
33942 setContent : function(content, loadScripts){
33943 this.el.update(content, loadScripts);
33946 ignoreResize : function(w, h){
33947 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
33950 this.lastSize = {width: w, height: h};
33955 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
33956 * @return {Roo.UpdateManager} The UpdateManager
33958 getUpdateManager : function(){
33959 return this.el.getUpdateManager();
33962 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
33963 * @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:
33966 url: "your-url.php",
33967 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
33968 callback: yourFunction,
33969 scope: yourObject, //(optional scope)
33972 text: "Loading...",
33977 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
33978 * 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.
33979 * @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}
33980 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
33981 * @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.
33982 * @return {Roo.ContentPanel} this
33985 var um = this.el.getUpdateManager();
33986 um.update.apply(um, arguments);
33992 * 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.
33993 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
33994 * @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)
33995 * @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)
33996 * @return {Roo.UpdateManager} The UpdateManager
33998 setUrl : function(url, params, loadOnce){
33999 if(this.refreshDelegate){
34000 this.removeListener("activate", this.refreshDelegate);
34002 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34003 this.on("activate", this.refreshDelegate);
34004 return this.el.getUpdateManager();
34007 _handleRefresh : function(url, params, loadOnce){
34008 if(!loadOnce || !this.loaded){
34009 var updater = this.el.getUpdateManager();
34010 updater.update(url, params, this._setLoaded.createDelegate(this));
34014 _setLoaded : function(){
34015 this.loaded = true;
34019 * Returns this panel's id
34022 getId : function(){
34027 * Returns this panel's element - used by regiosn to add.
34028 * @return {Roo.Element}
34030 getEl : function(){
34031 return this.wrapEl || this.el;
34036 adjustForComponents : function(width, height)
34038 //Roo.log('adjustForComponents ');
34039 if(this.resizeEl != this.el){
34040 width -= this.el.getFrameWidth('lr');
34041 height -= this.el.getFrameWidth('tb');
34044 var te = this.toolbar.getEl();
34045 height -= te.getHeight();
34046 te.setWidth(width);
34049 var te = this.footer.getEl();
34050 Roo.log("footer:" + te.getHeight());
34052 height -= te.getHeight();
34053 te.setWidth(width);
34057 if(this.adjustments){
34058 width += this.adjustments[0];
34059 height += this.adjustments[1];
34061 return {"width": width, "height": height};
34064 setSize : function(width, height){
34065 if(this.fitToFrame && !this.ignoreResize(width, height)){
34066 if(this.fitContainer && this.resizeEl != this.el){
34067 this.el.setSize(width, height);
34069 var size = this.adjustForComponents(width, height);
34070 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34071 this.fireEvent('resize', this, size.width, size.height);
34076 * Returns this panel's title
34079 getTitle : function(){
34084 * Set this panel's title
34085 * @param {String} title
34087 setTitle : function(title){
34088 this.title = title;
34090 this.region.updatePanelTitle(this, title);
34095 * Returns true is this panel was configured to be closable
34096 * @return {Boolean}
34098 isClosable : function(){
34099 return this.closable;
34102 beforeSlide : function(){
34104 this.resizeEl.clip();
34107 afterSlide : function(){
34109 this.resizeEl.unclip();
34113 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34114 * Will fail silently if the {@link #setUrl} method has not been called.
34115 * This does not activate the panel, just updates its content.
34117 refresh : function(){
34118 if(this.refreshDelegate){
34119 this.loaded = false;
34120 this.refreshDelegate();
34125 * Destroys this panel
34127 destroy : function(){
34128 this.el.removeAllListeners();
34129 var tempEl = document.createElement("span");
34130 tempEl.appendChild(this.el.dom);
34131 tempEl.innerHTML = "";
34137 * form - if the content panel contains a form - this is a reference to it.
34138 * @type {Roo.form.Form}
34142 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34143 * This contains a reference to it.
34149 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34159 * @param {Object} cfg Xtype definition of item to add.
34163 getChildContainer: function () {
34164 return this.getEl();
34169 var ret = new Roo.factory(cfg);
34174 if (cfg.xtype.match(/^Form$/)) {
34177 //if (this.footer) {
34178 // el = this.footer.container.insertSibling(false, 'before');
34180 el = this.el.createChild();
34183 this.form = new Roo.form.Form(cfg);
34186 if ( this.form.allItems.length) {
34187 this.form.render(el.dom);
34191 // should only have one of theses..
34192 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34193 // views.. should not be just added - used named prop 'view''
34195 cfg.el = this.el.appendChild(document.createElement("div"));
34198 var ret = new Roo.factory(cfg);
34200 ret.render && ret.render(false, ''); // render blank..
34210 * @class Roo.bootstrap.panel.Grid
34211 * @extends Roo.bootstrap.panel.Content
34213 * Create a new GridPanel.
34214 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
34215 * @param {Object} config A the config object
34221 Roo.bootstrap.panel.Grid = function(config)
34225 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34226 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
34228 config.el = this.wrapper;
34229 //this.el = this.wrapper;
34231 if (config.container) {
34232 // ctor'ed from a Border/panel.grid
34235 this.wrapper.setStyle("overflow", "hidden");
34236 this.wrapper.addClass('roo-grid-container');
34241 if(config.toolbar){
34242 var tool_el = this.wrapper.createChild();
34243 this.toolbar = Roo.factory(config.toolbar);
34245 if (config.toolbar.items) {
34246 ti = config.toolbar.items ;
34247 delete config.toolbar.items ;
34251 this.toolbar.render(tool_el);
34252 for(var i =0;i < ti.length;i++) {
34253 // Roo.log(['add child', items[i]]);
34254 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
34256 this.toolbar.items = nitems;
34258 delete config.toolbar;
34261 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
34262 config.grid.scrollBody = true;;
34263 config.grid.monitorWindowResize = false; // turn off autosizing
34264 config.grid.autoHeight = false;
34265 config.grid.autoWidth = false;
34267 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
34269 if (config.background) {
34270 // render grid on panel activation (if panel background)
34271 this.on('activate', function(gp) {
34272 if (!gp.grid.rendered) {
34273 gp.grid.render(el);
34274 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34280 this.grid.render(this.wrapper);
34281 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
34284 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
34285 // ??? needed ??? config.el = this.wrapper;
34290 // xtype created footer. - not sure if will work as we normally have to render first..
34291 if (this.footer && !this.footer.el && this.footer.xtype) {
34293 var ctr = this.grid.getView().getFooterPanel(true);
34294 this.footer.dataSource = this.grid.dataSource;
34295 this.footer = Roo.factory(this.footer, Roo);
34296 this.footer.render(ctr);
34306 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
34307 getId : function(){
34308 return this.grid.id;
34312 * Returns the grid for this panel
34313 * @return {Roo.bootstrap.Table}
34315 getGrid : function(){
34319 setSize : function(width, height){
34320 if(!this.ignoreResize(width, height)){
34321 var grid = this.grid;
34322 var size = this.adjustForComponents(width, height);
34323 var gridel = grid.getGridEl();
34324 gridel.setSize(size.width, size.height);
34326 var thd = grid.getGridEl().select('thead',true).first();
34327 var tbd = grid.getGridEl().select('tbody', true).first();
34329 tbd.setSize(width, height - thd.getHeight());
34338 beforeSlide : function(){
34339 this.grid.getView().scroller.clip();
34342 afterSlide : function(){
34343 this.grid.getView().scroller.unclip();
34346 destroy : function(){
34347 this.grid.destroy();
34349 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
34354 * @class Roo.bootstrap.panel.Nest
34355 * @extends Roo.bootstrap.panel.Content
34357 * Create a new Panel, that can contain a layout.Border.
34360 * @param {Roo.BorderLayout} layout The layout for this panel
34361 * @param {String/Object} config A string to set only the title or a config object
34363 Roo.bootstrap.panel.Nest = function(config)
34365 // construct with only one argument..
34366 /* FIXME - implement nicer consturctors
34367 if (layout.layout) {
34369 layout = config.layout;
34370 delete config.layout;
34372 if (layout.xtype && !layout.getEl) {
34373 // then layout needs constructing..
34374 layout = Roo.factory(layout, Roo);
34378 config.el = config.layout.getEl();
34380 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
34382 config.layout.monitorWindowResize = false; // turn off autosizing
34383 this.layout = config.layout;
34384 this.layout.getEl().addClass("roo-layout-nested-layout");
34391 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
34393 setSize : function(width, height){
34394 if(!this.ignoreResize(width, height)){
34395 var size = this.adjustForComponents(width, height);
34396 var el = this.layout.getEl();
34397 el.setSize(size.width, size.height);
34398 var touch = el.dom.offsetWidth;
34399 this.layout.layout();
34400 // ie requires a double layout on the first pass
34401 if(Roo.isIE && !this.initialized){
34402 this.initialized = true;
34403 this.layout.layout();
34408 // activate all subpanels if not currently active..
34410 setActiveState : function(active){
34411 this.active = active;
34413 this.fireEvent("deactivate", this);
34417 this.fireEvent("activate", this);
34418 // not sure if this should happen before or after..
34419 if (!this.layout) {
34420 return; // should not happen..
34423 for (var r in this.layout.regions) {
34424 reg = this.layout.getRegion(r);
34425 if (reg.getActivePanel()) {
34426 //reg.showPanel(reg.getActivePanel()); // force it to activate..
34427 reg.setActivePanel(reg.getActivePanel());
34430 if (!reg.panels.length) {
34433 reg.showPanel(reg.getPanel(0));
34442 * Returns the nested BorderLayout for this panel
34443 * @return {Roo.BorderLayout}
34445 getLayout : function(){
34446 return this.layout;
34450 * Adds a xtype elements to the layout of the nested panel
34454 xtype : 'ContentPanel',
34461 xtype : 'NestedLayoutPanel',
34467 items : [ ... list of content panels or nested layout panels.. ]
34471 * @param {Object} cfg Xtype definition of item to add.
34473 addxtype : function(cfg) {
34474 return this.layout.addxtype(cfg);
34479 * Ext JS Library 1.1.1
34480 * Copyright(c) 2006-2007, Ext JS, LLC.
34482 * Originally Released Under LGPL - original licence link has changed is not relivant.
34485 * <script type="text/javascript">
34488 * @class Roo.TabPanel
34489 * @extends Roo.util.Observable
34490 * A lightweight tab container.
34494 // basic tabs 1, built from existing content
34495 var tabs = new Roo.TabPanel("tabs1");
34496 tabs.addTab("script", "View Script");
34497 tabs.addTab("markup", "View Markup");
34498 tabs.activate("script");
34500 // more advanced tabs, built from javascript
34501 var jtabs = new Roo.TabPanel("jtabs");
34502 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
34504 // set up the UpdateManager
34505 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
34506 var updater = tab2.getUpdateManager();
34507 updater.setDefaultUrl("ajax1.htm");
34508 tab2.on('activate', updater.refresh, updater, true);
34510 // Use setUrl for Ajax loading
34511 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
34512 tab3.setUrl("ajax2.htm", null, true);
34515 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
34518 jtabs.activate("jtabs-1");
34521 * Create a new TabPanel.
34522 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
34523 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
34525 Roo.bootstrap.panel.Tabs = function(config){
34527 * The container element for this TabPanel.
34528 * @type Roo.Element
34530 this.el = Roo.get(config.el);
34533 if(typeof config == "boolean"){
34534 this.tabPosition = config ? "bottom" : "top";
34536 Roo.apply(this, config);
34540 if(this.tabPosition == "bottom"){
34541 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34542 this.el.addClass("roo-tabs-bottom");
34544 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
34545 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
34546 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
34548 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
34550 if(this.tabPosition != "bottom"){
34551 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
34552 * @type Roo.Element
34554 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34555 this.el.addClass("roo-tabs-top");
34559 this.bodyEl.setStyle("position", "relative");
34561 this.active = null;
34562 this.activateDelegate = this.activate.createDelegate(this);
34567 * Fires when the active tab changes
34568 * @param {Roo.TabPanel} this
34569 * @param {Roo.TabPanelItem} activePanel The new active tab
34573 * @event beforetabchange
34574 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
34575 * @param {Roo.TabPanel} this
34576 * @param {Object} e Set cancel to true on this object to cancel the tab change
34577 * @param {Roo.TabPanelItem} tab The tab being changed to
34579 "beforetabchange" : true
34582 Roo.EventManager.onWindowResize(this.onResize, this);
34583 this.cpad = this.el.getPadding("lr");
34584 this.hiddenCount = 0;
34587 // toolbar on the tabbar support...
34588 if (this.toolbar) {
34589 alert("no toolbar support yet");
34590 this.toolbar = false;
34592 var tcfg = this.toolbar;
34593 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
34594 this.toolbar = new Roo.Toolbar(tcfg);
34595 if (Roo.isSafari) {
34596 var tbl = tcfg.container.child('table', true);
34597 tbl.setAttribute('width', '100%');
34605 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
34608 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
34610 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
34612 tabPosition : "top",
34614 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
34616 currentTabWidth : 0,
34618 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
34622 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
34626 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
34628 preferredTabWidth : 175,
34630 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
34632 resizeTabs : false,
34634 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
34636 monitorResize : true,
34638 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
34643 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
34644 * @param {String} id The id of the div to use <b>or create</b>
34645 * @param {String} text The text for the tab
34646 * @param {String} content (optional) Content to put in the TabPanelItem body
34647 * @param {Boolean} closable (optional) True to create a close icon on the tab
34648 * @return {Roo.TabPanelItem} The created TabPanelItem
34650 addTab : function(id, text, content, closable)
34652 var item = new Roo.bootstrap.panel.TabItem({
34656 closable : closable
34658 this.addTabItem(item);
34660 item.setContent(content);
34666 * Returns the {@link Roo.TabPanelItem} with the specified id/index
34667 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
34668 * @return {Roo.TabPanelItem}
34670 getTab : function(id){
34671 return this.items[id];
34675 * Hides the {@link Roo.TabPanelItem} with the specified id/index
34676 * @param {String/Number} id The id or index of the TabPanelItem to hide.
34678 hideTab : function(id){
34679 var t = this.items[id];
34682 this.hiddenCount++;
34683 this.autoSizeTabs();
34688 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
34689 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
34691 unhideTab : function(id){
34692 var t = this.items[id];
34694 t.setHidden(false);
34695 this.hiddenCount--;
34696 this.autoSizeTabs();
34701 * Adds an existing {@link Roo.TabPanelItem}.
34702 * @param {Roo.TabPanelItem} item The TabPanelItem to add
34704 addTabItem : function(item){
34705 this.items[item.id] = item;
34706 this.items.push(item);
34707 // if(this.resizeTabs){
34708 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
34709 // this.autoSizeTabs();
34711 // item.autoSize();
34716 * Removes a {@link Roo.TabPanelItem}.
34717 * @param {String/Number} id The id or index of the TabPanelItem to remove.
34719 removeTab : function(id){
34720 var items = this.items;
34721 var tab = items[id];
34722 if(!tab) { return; }
34723 var index = items.indexOf(tab);
34724 if(this.active == tab && items.length > 1){
34725 var newTab = this.getNextAvailable(index);
34730 this.stripEl.dom.removeChild(tab.pnode.dom);
34731 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
34732 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
34734 items.splice(index, 1);
34735 delete this.items[tab.id];
34736 tab.fireEvent("close", tab);
34737 tab.purgeListeners();
34738 this.autoSizeTabs();
34741 getNextAvailable : function(start){
34742 var items = this.items;
34744 // look for a next tab that will slide over to
34745 // replace the one being removed
34746 while(index < items.length){
34747 var item = items[++index];
34748 if(item && !item.isHidden()){
34752 // if one isn't found select the previous tab (on the left)
34755 var item = items[--index];
34756 if(item && !item.isHidden()){
34764 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
34765 * @param {String/Number} id The id or index of the TabPanelItem to disable.
34767 disableTab : function(id){
34768 var tab = this.items[id];
34769 if(tab && this.active != tab){
34775 * Enables a {@link Roo.TabPanelItem} that is disabled.
34776 * @param {String/Number} id The id or index of the TabPanelItem to enable.
34778 enableTab : function(id){
34779 var tab = this.items[id];
34784 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
34785 * @param {String/Number} id The id or index of the TabPanelItem to activate.
34786 * @return {Roo.TabPanelItem} The TabPanelItem.
34788 activate : function(id){
34789 var tab = this.items[id];
34793 if(tab == this.active || tab.disabled){
34797 this.fireEvent("beforetabchange", this, e, tab);
34798 if(e.cancel !== true && !tab.disabled){
34800 this.active.hide();
34802 this.active = this.items[id];
34803 this.active.show();
34804 this.fireEvent("tabchange", this, this.active);
34810 * Gets the active {@link Roo.TabPanelItem}.
34811 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
34813 getActiveTab : function(){
34814 return this.active;
34818 * Updates the tab body element to fit the height of the container element
34819 * for overflow scrolling
34820 * @param {Number} targetHeight (optional) Override the starting height from the elements height
34822 syncHeight : function(targetHeight){
34823 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34824 var bm = this.bodyEl.getMargins();
34825 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
34826 this.bodyEl.setHeight(newHeight);
34830 onResize : function(){
34831 if(this.monitorResize){
34832 this.autoSizeTabs();
34837 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
34839 beginUpdate : function(){
34840 this.updating = true;
34844 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
34846 endUpdate : function(){
34847 this.updating = false;
34848 this.autoSizeTabs();
34852 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
34854 autoSizeTabs : function(){
34855 var count = this.items.length;
34856 var vcount = count - this.hiddenCount;
34857 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
34860 var w = Math.max(this.el.getWidth() - this.cpad, 10);
34861 var availWidth = Math.floor(w / vcount);
34862 var b = this.stripBody;
34863 if(b.getWidth() > w){
34864 var tabs = this.items;
34865 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
34866 if(availWidth < this.minTabWidth){
34867 /*if(!this.sleft){ // incomplete scrolling code
34868 this.createScrollButtons();
34871 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
34874 if(this.currentTabWidth < this.preferredTabWidth){
34875 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
34881 * Returns the number of tabs in this TabPanel.
34884 getCount : function(){
34885 return this.items.length;
34889 * Resizes all the tabs to the passed width
34890 * @param {Number} The new width
34892 setTabWidth : function(width){
34893 this.currentTabWidth = width;
34894 for(var i = 0, len = this.items.length; i < len; i++) {
34895 if(!this.items[i].isHidden()) {
34896 this.items[i].setWidth(width);
34902 * Destroys this TabPanel
34903 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
34905 destroy : function(removeEl){
34906 Roo.EventManager.removeResizeListener(this.onResize, this);
34907 for(var i = 0, len = this.items.length; i < len; i++){
34908 this.items[i].purgeListeners();
34910 if(removeEl === true){
34911 this.el.update("");
34916 createStrip : function(container)
34918 var strip = document.createElement("nav");
34919 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
34920 container.appendChild(strip);
34924 createStripList : function(strip)
34926 // div wrapper for retard IE
34927 // returns the "tr" element.
34928 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
34929 //'<div class="x-tabs-strip-wrap">'+
34930 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
34931 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
34932 return strip.firstChild; //.firstChild.firstChild.firstChild;
34934 createBody : function(container)
34936 var body = document.createElement("div");
34937 Roo.id(body, "tab-body");
34938 //Roo.fly(body).addClass("x-tabs-body");
34939 Roo.fly(body).addClass("tab-content");
34940 container.appendChild(body);
34943 createItemBody :function(bodyEl, id){
34944 var body = Roo.getDom(id);
34946 body = document.createElement("div");
34949 //Roo.fly(body).addClass("x-tabs-item-body");
34950 Roo.fly(body).addClass("tab-pane");
34951 bodyEl.insertBefore(body, bodyEl.firstChild);
34955 createStripElements : function(stripEl, text, closable)
34957 var td = document.createElement("li"); // was td..
34958 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
34959 //stripEl.appendChild(td);
34961 td.className = "x-tabs-closable";
34962 if(!this.closeTpl){
34963 this.closeTpl = new Roo.Template(
34964 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34965 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
34966 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
34969 var el = this.closeTpl.overwrite(td, {"text": text});
34970 var close = el.getElementsByTagName("div")[0];
34971 var inner = el.getElementsByTagName("em")[0];
34972 return {"el": el, "close": close, "inner": inner};
34975 // not sure what this is..
34977 //this.tabTpl = new Roo.Template(
34978 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34979 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
34981 this.tabTpl = new Roo.Template(
34983 '<span unselectable="on"' +
34984 (this.disableTooltips ? '' : ' title="{text}"') +
34985 ' >{text}</span></span></a>'
34989 var el = this.tabTpl.overwrite(td, {"text": text});
34990 var inner = el.getElementsByTagName("span")[0];
34991 return {"el": el, "inner": inner};
34999 * @class Roo.TabPanelItem
35000 * @extends Roo.util.Observable
35001 * Represents an individual item (tab plus body) in a TabPanel.
35002 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
35003 * @param {String} id The id of this TabPanelItem
35004 * @param {String} text The text for the tab of this TabPanelItem
35005 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
35007 Roo.bootstrap.panel.TabItem = function(config){
35009 * The {@link Roo.TabPanel} this TabPanelItem belongs to
35010 * @type Roo.TabPanel
35012 this.tabPanel = config.panel;
35014 * The id for this TabPanelItem
35017 this.id = config.id;
35019 this.disabled = false;
35021 this.text = config.text;
35023 this.loaded = false;
35024 this.closable = config.closable;
35027 * The body element for this TabPanelItem.
35028 * @type Roo.Element
35030 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
35031 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
35032 this.bodyEl.setStyle("display", "block");
35033 this.bodyEl.setStyle("zoom", "1");
35034 //this.hideAction();
35036 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
35038 this.el = Roo.get(els.el);
35039 this.inner = Roo.get(els.inner, true);
35040 this.textEl = Roo.get(this.el.dom.firstChild, true);
35041 this.pnode = Roo.get(els.el.parentNode, true);
35042 this.el.on("mousedown", this.onTabMouseDown, this);
35043 this.el.on("click", this.onTabClick, this);
35045 if(config.closable){
35046 var c = Roo.get(els.close, true);
35047 c.dom.title = this.closeText;
35048 c.addClassOnOver("close-over");
35049 c.on("click", this.closeClick, this);
35055 * Fires when this tab becomes the active tab.
35056 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35057 * @param {Roo.TabPanelItem} this
35061 * @event beforeclose
35062 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
35063 * @param {Roo.TabPanelItem} this
35064 * @param {Object} e Set cancel to true on this object to cancel the close.
35066 "beforeclose": true,
35069 * Fires when this tab is closed.
35070 * @param {Roo.TabPanelItem} this
35074 * @event deactivate
35075 * Fires when this tab is no longer the active tab.
35076 * @param {Roo.TabPanel} tabPanel The parent TabPanel
35077 * @param {Roo.TabPanelItem} this
35079 "deactivate" : true
35081 this.hidden = false;
35083 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
35086 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
35088 purgeListeners : function(){
35089 Roo.util.Observable.prototype.purgeListeners.call(this);
35090 this.el.removeAllListeners();
35093 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
35096 this.pnode.addClass("active");
35099 this.tabPanel.stripWrap.repaint();
35101 this.fireEvent("activate", this.tabPanel, this);
35105 * Returns true if this tab is the active tab.
35106 * @return {Boolean}
35108 isActive : function(){
35109 return this.tabPanel.getActiveTab() == this;
35113 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
35116 this.pnode.removeClass("active");
35118 this.fireEvent("deactivate", this.tabPanel, this);
35121 hideAction : function(){
35122 this.bodyEl.hide();
35123 this.bodyEl.setStyle("position", "absolute");
35124 this.bodyEl.setLeft("-20000px");
35125 this.bodyEl.setTop("-20000px");
35128 showAction : function(){
35129 this.bodyEl.setStyle("position", "relative");
35130 this.bodyEl.setTop("");
35131 this.bodyEl.setLeft("");
35132 this.bodyEl.show();
35136 * Set the tooltip for the tab.
35137 * @param {String} tooltip The tab's tooltip
35139 setTooltip : function(text){
35140 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
35141 this.textEl.dom.qtip = text;
35142 this.textEl.dom.removeAttribute('title');
35144 this.textEl.dom.title = text;
35148 onTabClick : function(e){
35149 e.preventDefault();
35150 this.tabPanel.activate(this.id);
35153 onTabMouseDown : function(e){
35154 e.preventDefault();
35155 this.tabPanel.activate(this.id);
35158 getWidth : function(){
35159 return this.inner.getWidth();
35162 setWidth : function(width){
35163 var iwidth = width - this.pnode.getPadding("lr");
35164 this.inner.setWidth(iwidth);
35165 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
35166 this.pnode.setWidth(width);
35170 * Show or hide the tab
35171 * @param {Boolean} hidden True to hide or false to show.
35173 setHidden : function(hidden){
35174 this.hidden = hidden;
35175 this.pnode.setStyle("display", hidden ? "none" : "");
35179 * Returns true if this tab is "hidden"
35180 * @return {Boolean}
35182 isHidden : function(){
35183 return this.hidden;
35187 * Returns the text for this tab
35190 getText : function(){
35194 autoSize : function(){
35195 //this.el.beginMeasure();
35196 this.textEl.setWidth(1);
35198 * #2804 [new] Tabs in Roojs
35199 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
35201 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
35202 //this.el.endMeasure();
35206 * Sets the text for the tab (Note: this also sets the tooltip text)
35207 * @param {String} text The tab's text and tooltip
35209 setText : function(text){
35211 this.textEl.update(text);
35212 this.setTooltip(text);
35213 //if(!this.tabPanel.resizeTabs){
35214 // this.autoSize();
35218 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
35220 activate : function(){
35221 this.tabPanel.activate(this.id);
35225 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
35227 disable : function(){
35228 if(this.tabPanel.active != this){
35229 this.disabled = true;
35230 this.pnode.addClass("disabled");
35235 * Enables this TabPanelItem if it was previously disabled.
35237 enable : function(){
35238 this.disabled = false;
35239 this.pnode.removeClass("disabled");
35243 * Sets the content for this TabPanelItem.
35244 * @param {String} content The content
35245 * @param {Boolean} loadScripts true to look for and load scripts
35247 setContent : function(content, loadScripts){
35248 this.bodyEl.update(content, loadScripts);
35252 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
35253 * @return {Roo.UpdateManager} The UpdateManager
35255 getUpdateManager : function(){
35256 return this.bodyEl.getUpdateManager();
35260 * Set a URL to be used to load the content for this TabPanelItem.
35261 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
35262 * @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)
35263 * @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)
35264 * @return {Roo.UpdateManager} The UpdateManager
35266 setUrl : function(url, params, loadOnce){
35267 if(this.refreshDelegate){
35268 this.un('activate', this.refreshDelegate);
35270 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35271 this.on("activate", this.refreshDelegate);
35272 return this.bodyEl.getUpdateManager();
35276 _handleRefresh : function(url, params, loadOnce){
35277 if(!loadOnce || !this.loaded){
35278 var updater = this.bodyEl.getUpdateManager();
35279 updater.update(url, params, this._setLoaded.createDelegate(this));
35284 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
35285 * Will fail silently if the setUrl method has not been called.
35286 * This does not activate the panel, just updates its content.
35288 refresh : function(){
35289 if(this.refreshDelegate){
35290 this.loaded = false;
35291 this.refreshDelegate();
35296 _setLoaded : function(){
35297 this.loaded = true;
35301 closeClick : function(e){
35304 this.fireEvent("beforeclose", this, o);
35305 if(o.cancel !== true){
35306 this.tabPanel.removeTab(this.id);
35310 * The text displayed in the tooltip for the close icon.
35313 closeText : "Close this tab"