4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
233 addxtypeChild : function (tree, cntr, is_body)
235 Roo.debug && Roo.log('addxtypeChild:' + cntr);
237 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
240 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
241 (typeof(tree['flexy:foreach']) != 'undefined');
245 skip_children = false;
246 // render the element if it's not BODY.
249 cn = Roo.factory(tree);
251 cn.parentType = this.xtype; //??
252 cn.parentId = this.id;
254 var build_from_html = Roo.XComponent.build_from_html;
257 // does the container contain child eleemnts with 'xtype' attributes.
258 // that match this xtype..
259 // note - when we render we create these as well..
260 // so we should check to see if body has xtype set.
261 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
263 var self_cntr_el = Roo.get(this[cntr](false));
264 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
266 //Roo.log(Roo.XComponent.build_from_html);
267 //Roo.log("got echild:");
270 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
271 // and are not displayed -this causes this to use up the wrong element when matching.
272 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
275 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
276 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
282 //echild.dom.removeAttribute('xtype');
284 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
285 Roo.debug && Roo.log(self_cntr_el);
286 Roo.debug && Roo.log(echild);
287 Roo.debug && Roo.log(cn);
293 // if object has flexy:if - then it may or may not be rendered.
294 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
295 // skip a flexy if element.
296 Roo.debug && Roo.log('skipping render');
297 Roo.debug && Roo.log(tree);
299 Roo.debug && Roo.log('skipping all children');
300 skip_children = true;
305 // actually if flexy:foreach is found, we really want to create
306 // multiple copies here...
308 //Roo.log(this[cntr]());
309 // some elements do not have render methods.. like the layouts...
310 cn.render && cn.render(this[cntr](true));
312 // then add the element..
320 if (typeof (tree.menu) != 'undefined') {
321 tree.menu.parentType = cn.xtype;
322 tree.menu.triggerEl = cn.el;
323 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
327 if (!tree.items || !tree.items.length) {
329 //Roo.log(["no children", this]);
334 var items = tree.items;
337 //Roo.log(items.length);
339 if (!skip_children) {
340 for(var i =0;i < items.length;i++) {
341 // Roo.log(['add child', items[i]]);
342 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
348 //Roo.log("fire childrenrendered");
350 cn.fireEvent('childrenrendered', this);
355 * Show a component - removes 'hidden' class
360 this.el.removeClass('hidden');
364 * Hide a component - adds 'hidden' class
368 if (this.el && !this.el.hasClass('hidden')) {
369 this.el.addClass('hidden');
383 * @class Roo.bootstrap.Body
384 * @extends Roo.bootstrap.Component
385 * Bootstrap Body class
389 * @param {Object} config The config object
392 Roo.bootstrap.Body = function(config){
393 Roo.bootstrap.Body.superclass.constructor.call(this, config);
394 this.el = Roo.get(document.body);
395 if (this.cls && this.cls.length) {
396 Roo.get(document.body).addClass(this.cls);
400 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
402 is_body : true,// just to make sure it's constructed?
407 onRender : function(ct, position)
409 /* Roo.log("Roo.bootstrap.Body - onRender");
410 if (this.cls && this.cls.length) {
411 Roo.get(document.body).addClass(this.cls);
431 * @class Roo.bootstrap.ButtonGroup
432 * @extends Roo.bootstrap.Component
433 * Bootstrap ButtonGroup class
434 * @cfg {String} size lg | sm | xs (default empty normal)
435 * @cfg {String} align vertical | justified (default none)
436 * @cfg {String} direction up | down (default down)
437 * @cfg {Boolean} toolbar false | true
438 * @cfg {Boolean} btn true | false
443 * @param {Object} config The config object
446 Roo.bootstrap.ButtonGroup = function(config){
447 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
450 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
458 getAutoCreate : function(){
464 cfg.html = this.html || cfg.html;
475 if (['vertical','justified'].indexOf(this.align)!==-1) {
476 cfg.cls = 'btn-group-' + this.align;
478 if (this.align == 'justified') {
479 console.log(this.items);
483 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
484 cfg.cls += ' btn-group-' + this.size;
487 if (this.direction == 'up') {
488 cfg.cls += ' dropup' ;
504 * @class Roo.bootstrap.Button
505 * @extends Roo.bootstrap.Component
506 * Bootstrap Button class
507 * @cfg {String} html The button content
508 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
509 * @cfg {String} size ( lg | sm | xs)
510 * @cfg {String} tag ( a | input | submit)
511 * @cfg {String} href empty or href
512 * @cfg {Boolean} disabled default false;
513 * @cfg {Boolean} isClose default false;
514 * @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)
515 * @cfg {String} badge text for badge
516 * @cfg {String} theme default
517 * @cfg {Boolean} inverse
518 * @cfg {Boolean} toggle
519 * @cfg {String} ontext text for on toggle state
520 * @cfg {String} offtext text for off toggle state
521 * @cfg {Boolean} defaulton
522 * @cfg {Boolean} preventDefault default true
523 * @cfg {Boolean} removeClass remove the standard class..
524 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
527 * Create a new button
528 * @param {Object} config The config object
532 Roo.bootstrap.Button = function(config){
533 Roo.bootstrap.Button.superclass.constructor.call(this, config);
538 * When a butotn is pressed
539 * @param {Roo.bootstrap.Button} this
540 * @param {Roo.EventObject} e
545 * After the button has been toggles
546 * @param {Roo.EventObject} e
547 * @param {boolean} pressed (also available as button.pressed)
553 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
571 preventDefault: true,
580 getAutoCreate : function(){
588 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
589 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
594 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
596 if (this.toggle == true) {
599 cls: 'slider-frame roo-button',
604 'data-off-text':'OFF',
605 cls: 'slider-button',
611 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
612 cfg.cls += ' '+this.weight;
621 cfg["aria-hidden"] = true;
623 cfg.html = "×";
629 if (this.theme==='default') {
630 cfg.cls = 'btn roo-button';
632 //if (this.parentType != 'Navbar') {
633 this.weight = this.weight.length ? this.weight : 'default';
635 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
637 cfg.cls += ' btn-' + this.weight;
639 } else if (this.theme==='glow') {
642 cfg.cls = 'btn-glow roo-button';
644 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
646 cfg.cls += ' ' + this.weight;
652 this.cls += ' inverse';
657 cfg.cls += ' active';
661 cfg.disabled = 'disabled';
665 Roo.log('changing to ul' );
667 this.glyphicon = 'caret';
670 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
672 //gsRoo.log(this.parentType);
673 if (this.parentType === 'Navbar' && !this.parent().bar) {
674 Roo.log('changing to li?');
683 href : this.href || '#'
686 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
687 cfg.cls += ' dropdown';
694 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
696 if (this.glyphicon) {
697 cfg.html = ' ' + cfg.html;
702 cls: 'glyphicon glyphicon-' + this.glyphicon
712 // cfg.cls='btn roo-button';
716 var value = cfg.html;
721 cls: 'glyphicon glyphicon-' + this.glyphicon,
740 cfg.cls += ' dropdown';
741 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
744 if (cfg.tag !== 'a' && this.href !== '') {
745 throw "Tag must be a to set href.";
746 } else if (this.href.length > 0) {
747 cfg.href = this.href;
750 if(this.removeClass){
755 cfg.target = this.target;
760 initEvents: function() {
761 // Roo.log('init events?');
762 // Roo.log(this.el.dom);
765 if (typeof (this.menu) != 'undefined') {
766 this.menu.parentType = this.xtype;
767 this.menu.triggerEl = this.el;
768 this.addxtype(Roo.apply({}, this.menu));
772 if (this.el.hasClass('roo-button')) {
773 this.el.on('click', this.onClick, this);
775 this.el.select('.roo-button').on('click', this.onClick, this);
778 if(this.removeClass){
779 this.el.on('click', this.onClick, this);
782 this.el.enableDisplayMode();
785 onClick : function(e)
792 Roo.log('button on click ');
793 if(this.preventDefault){
796 if (this.pressed === true || this.pressed === false) {
797 this.pressed = !this.pressed;
798 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
799 this.fireEvent('toggle', this, e, this.pressed);
803 this.fireEvent('click', this, e);
807 * Enables this button
811 this.disabled = false;
812 this.el.removeClass('disabled');
816 * Disable this button
820 this.disabled = true;
821 this.el.addClass('disabled');
824 * sets the active state on/off,
825 * @param {Boolean} state (optional) Force a particular state
827 setActive : function(v) {
829 this.el[v ? 'addClass' : 'removeClass']('active');
832 * toggles the current active state
834 toggleActive : function()
836 var active = this.el.hasClass('active');
837 this.setActive(!active);
841 setText : function(str)
843 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
847 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
870 * @class Roo.bootstrap.Column
871 * @extends Roo.bootstrap.Component
872 * Bootstrap Column class
873 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
874 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
875 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
876 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
877 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
878 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
879 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
880 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
883 * @cfg {Boolean} hidden (true|false) hide the element
884 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
885 * @cfg {String} fa (ban|check|...) font awesome icon
886 * @cfg {Number} fasize (1|2|....) font awsome size
888 * @cfg {String} icon (info-sign|check|...) glyphicon name
890 * @cfg {String} html content of column.
893 * Create a new Column
894 * @param {Object} config The config object
897 Roo.bootstrap.Column = function(config){
898 Roo.bootstrap.Column.superclass.constructor.call(this, config);
901 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
919 getAutoCreate : function(){
920 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
928 ['xs','sm','md','lg'].map(function(size){
929 //Roo.log( size + ':' + settings[size]);
931 if (settings[size+'off'] !== false) {
932 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
935 if (settings[size] === false) {
939 if (!settings[size]) { // 0 = hidden
940 cfg.cls += ' hidden-' + size;
943 cfg.cls += ' col-' + size + '-' + settings[size];
948 cfg.cls += ' hidden';
951 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
952 cfg.cls +=' alert alert-' + this.alert;
956 if (this.html.length) {
957 cfg.html = this.html;
961 if (this.fasize > 1) {
962 fasize = ' fa-' + this.fasize + 'x';
964 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
969 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
988 * @class Roo.bootstrap.Container
989 * @extends Roo.bootstrap.Component
990 * Bootstrap Container class
991 * @cfg {Boolean} jumbotron is it a jumbotron element
992 * @cfg {String} html content of element
993 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
994 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
995 * @cfg {String} header content of header (for panel)
996 * @cfg {String} footer content of footer (for panel)
997 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
998 * @cfg {String} tag (header|aside|section) type of HTML tag.
999 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1000 * @cfg {String} fa font awesome icon
1001 * @cfg {String} icon (info-sign|check|...) glyphicon name
1002 * @cfg {Boolean} hidden (true|false) hide the element
1003 * @cfg {Boolean} expandable (true|false) default false
1004 * @cfg {Boolean} expanded (true|false) default true
1005 * @cfg {String} rheader contet on the right of header
1006 * @cfg {Boolean} clickable (true|false) default false
1010 * Create a new Container
1011 * @param {Object} config The config object
1014 Roo.bootstrap.Container = function(config){
1015 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1021 * After the panel has been expand
1023 * @param {Roo.bootstrap.Container} this
1028 * After the panel has been collapsed
1030 * @param {Roo.bootstrap.Container} this
1035 * When a element is chick
1036 * @param {Roo.bootstrap.Container} this
1037 * @param {Roo.EventObject} e
1043 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1061 getChildContainer : function() {
1067 if (this.panel.length) {
1068 return this.el.select('.panel-body',true).first();
1075 getAutoCreate : function(){
1078 tag : this.tag || 'div',
1082 if (this.jumbotron) {
1083 cfg.cls = 'jumbotron';
1088 // - this is applied by the parent..
1090 // cfg.cls = this.cls + '';
1093 if (this.sticky.length) {
1095 var bd = Roo.get(document.body);
1096 if (!bd.hasClass('bootstrap-sticky')) {
1097 bd.addClass('bootstrap-sticky');
1098 Roo.select('html',true).setStyle('height', '100%');
1101 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1105 if (this.well.length) {
1106 switch (this.well) {
1109 cfg.cls +=' well well-' +this.well;
1118 cfg.cls += ' hidden';
1122 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1123 cfg.cls +=' alert alert-' + this.alert;
1128 if (this.panel.length) {
1129 cfg.cls += ' panel panel-' + this.panel;
1131 if (this.header.length) {
1135 if(this.expandable){
1137 cfg.cls = cfg.cls + ' expandable';
1141 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1149 cls : 'panel-title',
1150 html : (this.expandable ? ' ' : '') + this.header
1154 cls: 'panel-header-right',
1160 cls : 'panel-heading',
1161 style : this.expandable ? 'cursor: pointer' : '',
1169 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1174 if (this.footer.length) {
1176 cls : 'panel-footer',
1185 body.html = this.html || cfg.html;
1186 // prefix with the icons..
1188 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1191 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1196 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1197 cfg.cls = 'container';
1203 initEvents: function()
1205 if(this.expandable){
1206 var headerEl = this.headerEl();
1209 headerEl.on('click', this.onToggleClick, this);
1214 this.el.on('click', this.onClick, this);
1219 onToggleClick : function()
1221 var headerEl = this.headerEl();
1237 if(this.fireEvent('expand', this)) {
1239 this.expanded = true;
1241 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1243 this.el.select('.panel-body',true).first().removeClass('hide');
1245 var toggleEl = this.toggleEl();
1251 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1256 collapse : function()
1258 if(this.fireEvent('collapse', this)) {
1260 this.expanded = false;
1262 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1263 this.el.select('.panel-body',true).first().addClass('hide');
1265 var toggleEl = this.toggleEl();
1271 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1275 toggleEl : function()
1277 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1281 return this.el.select('.panel-heading .fa',true).first();
1284 headerEl : function()
1286 if(!this.el || !this.panel.length || !this.header.length){
1290 return this.el.select('.panel-heading',true).first()
1293 titleEl : function()
1295 if(!this.el || !this.panel.length || !this.header.length){
1299 return this.el.select('.panel-title',true).first();
1302 setTitle : function(v)
1304 var titleEl = this.titleEl();
1310 titleEl.dom.innerHTML = v;
1313 getTitle : function()
1316 var titleEl = this.titleEl();
1322 return titleEl.dom.innerHTML;
1325 setRightTitle : function(v)
1327 var t = this.el.select('.panel-header-right',true).first();
1333 t.dom.innerHTML = v;
1336 onClick : function(e)
1340 this.fireEvent('click', this, e);
1354 * @class Roo.bootstrap.Img
1355 * @extends Roo.bootstrap.Component
1356 * Bootstrap Img class
1357 * @cfg {Boolean} imgResponsive false | true
1358 * @cfg {String} border rounded | circle | thumbnail
1359 * @cfg {String} src image source
1360 * @cfg {String} alt image alternative text
1361 * @cfg {String} href a tag href
1362 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1363 * @cfg {String} xsUrl xs image source
1364 * @cfg {String} smUrl sm image source
1365 * @cfg {String} mdUrl md image source
1366 * @cfg {String} lgUrl lg image source
1369 * Create a new Input
1370 * @param {Object} config The config object
1373 Roo.bootstrap.Img = function(config){
1374 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1380 * The img click event for the img.
1381 * @param {Roo.EventObject} e
1387 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1389 imgResponsive: true,
1399 getAutoCreate : function()
1401 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1402 return this.createSingleImg();
1407 cls: 'roo-image-responsive-group',
1412 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1414 if(!_this[size + 'Url']){
1420 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1421 html: _this.html || cfg.html,
1422 src: _this[size + 'Url']
1425 img.cls += ' roo-image-responsive-' + size;
1427 var s = ['xs', 'sm', 'md', 'lg'];
1429 s.splice(s.indexOf(size), 1);
1431 Roo.each(s, function(ss){
1432 img.cls += ' hidden-' + ss;
1435 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1436 cfg.cls += ' img-' + _this.border;
1440 cfg.alt = _this.alt;
1453 a.target = _this.target;
1457 cfg.cn.push((_this.href) ? a : img);
1464 createSingleImg : function()
1468 cls: (this.imgResponsive) ? 'img-responsive' : '',
1470 src : 'about:blank' // just incase src get's set to undefined?!?
1473 cfg.html = this.html || cfg.html;
1475 cfg.src = this.src || cfg.src;
1477 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1478 cfg.cls += ' img-' + this.border;
1495 a.target = this.target;
1500 return (this.href) ? a : cfg;
1503 initEvents: function()
1506 this.el.on('click', this.onClick, this);
1511 onClick : function(e)
1513 Roo.log('img onclick');
1514 this.fireEvent('click', this, e);
1528 * @class Roo.bootstrap.Link
1529 * @extends Roo.bootstrap.Component
1530 * Bootstrap Link Class
1531 * @cfg {String} alt image alternative text
1532 * @cfg {String} href a tag href
1533 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1534 * @cfg {String} html the content of the link.
1535 * @cfg {String} anchor name for the anchor link
1536 * @cfg {String} fa - favicon
1538 * @cfg {Boolean} preventDefault (true | false) default false
1542 * Create a new Input
1543 * @param {Object} config The config object
1546 Roo.bootstrap.Link = function(config){
1547 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1553 * The img click event for the img.
1554 * @param {Roo.EventObject} e
1560 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1564 preventDefault: false,
1570 getAutoCreate : function()
1572 var html = this.html || '';
1574 if (this.fa !== false) {
1575 html = '<i class="fa fa-' + this.fa + '"></i>';
1580 // anchor's do not require html/href...
1581 if (this.anchor === false) {
1583 cfg.href = this.href || '#';
1585 cfg.name = this.anchor;
1586 if (this.html !== false || this.fa !== false) {
1589 if (this.href !== false) {
1590 cfg.href = this.href;
1594 if(this.alt !== false){
1599 if(this.target !== false) {
1600 cfg.target = this.target;
1606 initEvents: function() {
1608 if(!this.href || this.preventDefault){
1609 this.el.on('click', this.onClick, this);
1613 onClick : function(e)
1615 if(this.preventDefault){
1618 //Roo.log('img onclick');
1619 this.fireEvent('click', this, e);
1632 * @class Roo.bootstrap.Header
1633 * @extends Roo.bootstrap.Component
1634 * Bootstrap Header class
1635 * @cfg {String} html content of header
1636 * @cfg {Number} level (1|2|3|4|5|6) default 1
1639 * Create a new Header
1640 * @param {Object} config The config object
1644 Roo.bootstrap.Header = function(config){
1645 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1648 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1656 getAutoCreate : function(){
1661 tag: 'h' + (1 *this.level),
1662 html: this.html || ''
1674 * Ext JS Library 1.1.1
1675 * Copyright(c) 2006-2007, Ext JS, LLC.
1677 * Originally Released Under LGPL - original licence link has changed is not relivant.
1680 * <script type="text/javascript">
1684 * @class Roo.bootstrap.MenuMgr
1685 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1688 Roo.bootstrap.MenuMgr = function(){
1689 var menus, active, groups = {}, attached = false, lastShow = new Date();
1691 // private - called when first menu is created
1694 active = new Roo.util.MixedCollection();
1695 Roo.get(document).addKeyListener(27, function(){
1696 if(active.length > 0){
1704 if(active && active.length > 0){
1705 var c = active.clone();
1715 if(active.length < 1){
1716 Roo.get(document).un("mouseup", onMouseDown);
1724 var last = active.last();
1725 lastShow = new Date();
1728 Roo.get(document).on("mouseup", onMouseDown);
1733 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1734 m.parentMenu.activeChild = m;
1735 }else if(last && last.isVisible()){
1736 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1741 function onBeforeHide(m){
1743 m.activeChild.hide();
1745 if(m.autoHideTimer){
1746 clearTimeout(m.autoHideTimer);
1747 delete m.autoHideTimer;
1752 function onBeforeShow(m){
1753 var pm = m.parentMenu;
1754 if(!pm && !m.allowOtherMenus){
1756 }else if(pm && pm.activeChild && active != m){
1757 pm.activeChild.hide();
1761 // private this should really trigger on mouseup..
1762 function onMouseDown(e){
1763 Roo.log("on Mouse Up");
1765 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1766 Roo.log("MenuManager hideAll");
1775 function onBeforeCheck(mi, state){
1777 var g = groups[mi.group];
1778 for(var i = 0, l = g.length; i < l; i++){
1780 g[i].setChecked(false);
1789 * Hides all menus that are currently visible
1791 hideAll : function(){
1796 register : function(menu){
1800 menus[menu.id] = menu;
1801 menu.on("beforehide", onBeforeHide);
1802 menu.on("hide", onHide);
1803 menu.on("beforeshow", onBeforeShow);
1804 menu.on("show", onShow);
1806 if(g && menu.events["checkchange"]){
1810 groups[g].push(menu);
1811 menu.on("checkchange", onCheck);
1816 * Returns a {@link Roo.menu.Menu} object
1817 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1818 * be used to generate and return a new Menu instance.
1820 get : function(menu){
1821 if(typeof menu == "string"){ // menu id
1823 }else if(menu.events){ // menu instance
1826 /*else if(typeof menu.length == 'number'){ // array of menu items?
1827 return new Roo.bootstrap.Menu({items:menu});
1828 }else{ // otherwise, must be a config
1829 return new Roo.bootstrap.Menu(menu);
1836 unregister : function(menu){
1837 delete menus[menu.id];
1838 menu.un("beforehide", onBeforeHide);
1839 menu.un("hide", onHide);
1840 menu.un("beforeshow", onBeforeShow);
1841 menu.un("show", onShow);
1843 if(g && menu.events["checkchange"]){
1844 groups[g].remove(menu);
1845 menu.un("checkchange", onCheck);
1850 registerCheckable : function(menuItem){
1851 var g = menuItem.group;
1856 groups[g].push(menuItem);
1857 menuItem.on("beforecheckchange", onBeforeCheck);
1862 unregisterCheckable : function(menuItem){
1863 var g = menuItem.group;
1865 groups[g].remove(menuItem);
1866 menuItem.un("beforecheckchange", onBeforeCheck);
1878 * @class Roo.bootstrap.Menu
1879 * @extends Roo.bootstrap.Component
1880 * Bootstrap Menu class - container for MenuItems
1881 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1882 * @cfg {bool} hidden if the menu should be hidden when rendered.
1883 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1884 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1888 * @param {Object} config The config object
1892 Roo.bootstrap.Menu = function(config){
1893 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1894 if (this.registerMenu && this.type != 'treeview') {
1895 Roo.bootstrap.MenuMgr.register(this);
1900 * Fires before this menu is displayed
1901 * @param {Roo.menu.Menu} this
1906 * Fires before this menu is hidden
1907 * @param {Roo.menu.Menu} this
1912 * Fires after this menu is displayed
1913 * @param {Roo.menu.Menu} this
1918 * Fires after this menu is hidden
1919 * @param {Roo.menu.Menu} this
1924 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1925 * @param {Roo.menu.Menu} this
1926 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1927 * @param {Roo.EventObject} e
1932 * Fires when the mouse is hovering over this menu
1933 * @param {Roo.menu.Menu} this
1934 * @param {Roo.EventObject} e
1935 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1940 * Fires when the mouse exits this menu
1941 * @param {Roo.menu.Menu} this
1942 * @param {Roo.EventObject} e
1943 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1948 * Fires when a menu item contained in this menu is clicked
1949 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1950 * @param {Roo.EventObject} e
1954 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1957 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1961 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1964 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1966 registerMenu : true,
1968 menuItems :false, // stores the menu items..
1978 getChildContainer : function() {
1982 getAutoCreate : function(){
1984 //if (['right'].indexOf(this.align)!==-1) {
1985 // cfg.cn[1].cls += ' pull-right'
1991 cls : 'dropdown-menu' ,
1992 style : 'z-index:1000'
1996 if (this.type === 'submenu') {
1997 cfg.cls = 'submenu active';
1999 if (this.type === 'treeview') {
2000 cfg.cls = 'treeview-menu';
2005 initEvents : function() {
2007 // Roo.log("ADD event");
2008 // Roo.log(this.triggerEl.dom);
2010 this.triggerEl.on('click', this.onTriggerClick, this);
2012 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2014 this.triggerEl.addClass('dropdown-toggle');
2017 this.el.on('touchstart' , this.onTouch, this);
2019 this.el.on('click' , this.onClick, this);
2021 this.el.on("mouseover", this.onMouseOver, this);
2022 this.el.on("mouseout", this.onMouseOut, this);
2026 findTargetItem : function(e)
2028 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2032 //Roo.log(t); Roo.log(t.id);
2034 //Roo.log(this.menuitems);
2035 return this.menuitems.get(t.id);
2037 //return this.items.get(t.menuItemId);
2043 onTouch : function(e)
2045 Roo.log("menu.onTouch");
2046 //e.stopEvent(); this make the user popdown broken
2050 onClick : function(e)
2052 Roo.log("menu.onClick");
2054 var t = this.findTargetItem(e);
2055 if(!t || t.isContainer){
2060 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2061 if(t == this.activeItem && t.shouldDeactivate(e)){
2062 this.activeItem.deactivate();
2063 delete this.activeItem;
2067 this.setActiveItem(t, true);
2075 Roo.log('pass click event');
2079 this.fireEvent("click", this, t, e);
2083 (function() { _this.hide(); }).defer(500);
2086 onMouseOver : function(e){
2087 var t = this.findTargetItem(e);
2090 // if(t.canActivate && !t.disabled){
2091 // this.setActiveItem(t, true);
2095 this.fireEvent("mouseover", this, e, t);
2097 isVisible : function(){
2098 return !this.hidden;
2100 onMouseOut : function(e){
2101 var t = this.findTargetItem(e);
2104 // if(t == this.activeItem && t.shouldDeactivate(e)){
2105 // this.activeItem.deactivate();
2106 // delete this.activeItem;
2109 this.fireEvent("mouseout", this, e, t);
2114 * Displays this menu relative to another element
2115 * @param {String/HTMLElement/Roo.Element} element The element to align to
2116 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2117 * the element (defaults to this.defaultAlign)
2118 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2120 show : function(el, pos, parentMenu){
2121 this.parentMenu = parentMenu;
2125 this.fireEvent("beforeshow", this);
2126 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2129 * Displays this menu at a specific xy position
2130 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2131 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2133 showAt : function(xy, parentMenu, /* private: */_e){
2134 this.parentMenu = parentMenu;
2139 this.fireEvent("beforeshow", this);
2140 //xy = this.el.adjustForConstraints(xy);
2144 this.hideMenuItems();
2145 this.hidden = false;
2146 this.triggerEl.addClass('open');
2148 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2149 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2152 if(this.el.getStyle('top').slice(-1) != "%"){
2157 this.fireEvent("show", this);
2163 this.doFocus.defer(50, this);
2167 doFocus : function(){
2169 this.focusEl.focus();
2174 * Hides this menu and optionally all parent menus
2175 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2177 hide : function(deep)
2180 this.hideMenuItems();
2181 if(this.el && this.isVisible()){
2182 this.fireEvent("beforehide", this);
2183 if(this.activeItem){
2184 this.activeItem.deactivate();
2185 this.activeItem = null;
2187 this.triggerEl.removeClass('open');;
2189 this.fireEvent("hide", this);
2191 if(deep === true && this.parentMenu){
2192 this.parentMenu.hide(true);
2196 onTriggerClick : function(e)
2198 Roo.log('trigger click');
2200 var target = e.getTarget();
2202 Roo.log(target.nodeName.toLowerCase());
2204 if(target.nodeName.toLowerCase() === 'i'){
2210 onTriggerPress : function(e)
2212 Roo.log('trigger press');
2213 //Roo.log(e.getTarget());
2214 // Roo.log(this.triggerEl.dom);
2216 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2217 var pel = Roo.get(e.getTarget());
2218 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2219 Roo.log('is treeview or dropdown?');
2223 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2227 if (this.isVisible()) {
2232 this.show(this.triggerEl, false, false);
2235 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2242 hideMenuItems : function()
2244 Roo.log("hide Menu Items");
2248 //$(backdrop).remove()
2249 this.el.select('.open',true).each(function(aa) {
2251 aa.removeClass('open');
2252 //var parent = getParent($(this))
2253 //var relatedTarget = { relatedTarget: this }
2255 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2256 //if (e.isDefaultPrevented()) return
2257 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2260 addxtypeChild : function (tree, cntr) {
2261 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2263 this.menuitems.add(comp);
2284 * @class Roo.bootstrap.MenuItem
2285 * @extends Roo.bootstrap.Component
2286 * Bootstrap MenuItem class
2287 * @cfg {String} html the menu label
2288 * @cfg {String} href the link
2289 * @cfg {Boolean} preventDefault do not trigger A href on clicks.
2290 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2291 * @cfg {Boolean} active used on sidebars to highlight active itesm
2292 * @cfg {String} fa favicon to show on left of menu item.
2293 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2297 * Create a new MenuItem
2298 * @param {Object} config The config object
2302 Roo.bootstrap.MenuItem = function(config){
2303 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2308 * The raw click event for the entire grid.
2309 * @param {Roo.bootstrap.MenuItem} this
2310 * @param {Roo.EventObject} e
2316 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2320 preventDefault: true,
2321 isContainer : false,
2325 getAutoCreate : function(){
2327 if(this.isContainer){
2330 cls: 'dropdown-menu-item'
2344 if (this.fa !== false) {
2347 cls : 'fa fa-' + this.fa
2356 cls: 'dropdown-menu-item',
2359 if (this.parent().type == 'treeview') {
2360 cfg.cls = 'treeview-menu';
2363 cfg.cls += ' active';
2368 anc.href = this.href || cfg.cn[0].href ;
2369 ctag.html = this.html || cfg.cn[0].html ;
2373 initEvents: function()
2375 if (this.parent().type == 'treeview') {
2376 this.el.select('a').on('click', this.onClick, this);
2379 this.menu.parentType = this.xtype;
2380 this.menu.triggerEl = this.el;
2381 this.menu = this.addxtype(Roo.apply({}, this.menu));
2385 onClick : function(e)
2387 Roo.log('item on click ');
2388 //if(this.preventDefault){
2389 // e.preventDefault();
2391 //this.parent().hideMenuItems();
2393 this.fireEvent('click', this, e);
2412 * @class Roo.bootstrap.MenuSeparator
2413 * @extends Roo.bootstrap.Component
2414 * Bootstrap MenuSeparator class
2417 * Create a new MenuItem
2418 * @param {Object} config The config object
2422 Roo.bootstrap.MenuSeparator = function(config){
2423 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2426 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2428 getAutoCreate : function(){
2447 * @class Roo.bootstrap.Modal
2448 * @extends Roo.bootstrap.Component
2449 * Bootstrap Modal class
2450 * @cfg {String} title Title of dialog
2451 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2452 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2453 * @cfg {Boolean} specificTitle default false
2454 * @cfg {Array} buttons Array of buttons or standard button set..
2455 * @cfg {String} buttonPosition (left|right|center) default right
2456 * @cfg {Boolean} animate default true
2457 * @cfg {Boolean} allow_close default true
2460 * Create a new Modal Dialog
2461 * @param {Object} config The config object
2464 Roo.bootstrap.Modal = function(config){
2465 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2470 * The raw btnclick event for the button
2471 * @param {Roo.EventObject} e
2475 this.buttons = this.buttons || [];
2478 this.tmpl = Roo.factory(this.tmpl);
2483 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2485 title : 'test dialog',
2495 specificTitle: false,
2497 buttonPosition: 'right',
2511 onRender : function(ct, position)
2513 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2516 var cfg = Roo.apply({}, this.getAutoCreate());
2519 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2521 //if (!cfg.name.length) {
2525 cfg.cls += ' ' + this.cls;
2528 cfg.style = this.style;
2530 this.el = Roo.get(document.body).createChild(cfg, position);
2532 //var type = this.el.dom.type;
2535 if(this.tabIndex !== undefined){
2536 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2540 this.bodyEl = this.el.select('.modal-body',true).first();
2541 this.closeEl = this.el.select('.modal-header .close', true).first();
2542 this.footerEl = this.el.select('.modal-footer',true).first();
2543 this.titleEl = this.el.select('.modal-title',true).first();
2547 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2548 this.maskEl.enableDisplayMode("block");
2550 //this.el.addClass("x-dlg-modal");
2552 if (this.buttons.length) {
2553 Roo.each(this.buttons, function(bb) {
2554 var b = Roo.apply({}, bb);
2555 b.xns = b.xns || Roo.bootstrap;
2556 b.xtype = b.xtype || 'Button';
2557 if (typeof(b.listeners) == 'undefined') {
2558 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2561 var btn = Roo.factory(b);
2563 btn.render(this.el.select('.modal-footer div').first());
2567 // render the children.
2570 if(typeof(this.items) != 'undefined'){
2571 var items = this.items;
2574 for(var i =0;i < items.length;i++) {
2575 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2579 this.items = nitems;
2581 // where are these used - they used to be body/close/footer
2585 //this.el.addClass([this.fieldClass, this.cls]);
2589 getAutoCreate : function(){
2594 html : this.html || ''
2599 cls : 'modal-title',
2603 if(this.specificTitle){
2609 if (this.allow_close) {
2620 style : 'display: none',
2623 cls: "modal-dialog",
2626 cls : "modal-content",
2629 cls : 'modal-header',
2634 cls : 'modal-footer',
2638 cls: 'btn-' + this.buttonPosition
2655 modal.cls += ' fade';
2661 getChildContainer : function() {
2666 getButtonContainer : function() {
2667 return this.el.select('.modal-footer div',true).first();
2670 initEvents : function()
2672 if (this.allow_close) {
2673 this.closeEl.on('click', this.hide, this);
2678 window.addEventListener("resize", function() { _this.resize(); } );
2684 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2689 if (!this.rendered) {
2693 this.el.setStyle('display', 'block');
2695 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2698 this.el.addClass('in');
2701 this.el.addClass('in');
2705 // not sure how we can show data in here..
2707 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2710 Roo.get(document.body).addClass("x-body-masked");
2711 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2713 this.el.setStyle('zIndex', '10001');
2715 this.fireEvent('show', this);
2723 Roo.get(document.body).removeClass("x-body-masked");
2724 this.el.removeClass('in');
2725 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2727 if(this.animate){ // why
2729 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2731 this.el.setStyle('display', 'none');
2734 this.fireEvent('hide', this);
2737 addButton : function(str, cb)
2741 var b = Roo.apply({}, { html : str } );
2742 b.xns = b.xns || Roo.bootstrap;
2743 b.xtype = b.xtype || 'Button';
2744 if (typeof(b.listeners) == 'undefined') {
2745 b.listeners = { click : cb.createDelegate(this) };
2748 var btn = Roo.factory(b);
2750 btn.render(this.el.select('.modal-footer div').first());
2756 setDefaultButton : function(btn)
2758 //this.el.select('.modal-footer').()
2762 resizeTo: function(w,h)
2766 this.el.select('.modal-dialog',true).first().setWidth(w);
2767 if (this.diff === false) {
2768 this.diff = this.el.select('.modal-dialog',true).first().getHeight() - this.el.select('.modal-body',true).first().getHeight();
2771 this.el.select('.modal-body',true).first().setHeight(h-this.diff);
2775 setContentSize : function(w, h)
2779 onButtonClick: function(btn,e)
2782 this.fireEvent('btnclick', btn.name, e);
2785 * Set the title of the Dialog
2786 * @param {String} str new Title
2788 setTitle: function(str) {
2789 this.titleEl.dom.innerHTML = str;
2792 * Set the body of the Dialog
2793 * @param {String} str new Title
2795 setBody: function(str) {
2796 this.bodyEl.dom.innerHTML = str;
2799 * Set the body of the Dialog using the template
2800 * @param {Obj} data - apply this data to the template and replace the body contents.
2802 applyBody: function(obj)
2805 Roo.log("Error - using apply Body without a template");
2808 this.tmpl.overwrite(this.bodyEl, obj);
2814 Roo.apply(Roo.bootstrap.Modal, {
2816 * Button config that displays a single OK button
2825 * Button config that displays Yes and No buttons
2841 * Button config that displays OK and Cancel buttons
2856 * Button config that displays Yes, No and Cancel buttons
2879 * messagebox - can be used as a replace
2883 * @class Roo.MessageBox
2884 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2888 Roo.Msg.alert('Status', 'Changes saved successfully.');
2890 // Prompt for user data:
2891 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2893 // process text value...
2897 // Show a dialog using config options:
2899 title:'Save Changes?',
2900 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2901 buttons: Roo.Msg.YESNOCANCEL,
2908 Roo.bootstrap.MessageBox = function(){
2909 var dlg, opt, mask, waitTimer;
2910 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2911 var buttons, activeTextEl, bwidth;
2915 var handleButton = function(button){
2917 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2921 var handleHide = function(){
2923 dlg.el.removeClass(opt.cls);
2926 // Roo.TaskMgr.stop(waitTimer);
2927 // waitTimer = null;
2932 var updateButtons = function(b){
2935 buttons["ok"].hide();
2936 buttons["cancel"].hide();
2937 buttons["yes"].hide();
2938 buttons["no"].hide();
2939 //dlg.footer.dom.style.display = 'none';
2942 dlg.footerEl.dom.style.display = '';
2943 for(var k in buttons){
2944 if(typeof buttons[k] != "function"){
2947 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2948 width += buttons[k].el.getWidth()+15;
2958 var handleEsc = function(d, k, e){
2959 if(opt && opt.closable !== false){
2969 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2970 * @return {Roo.BasicDialog} The BasicDialog element
2972 getDialog : function(){
2974 dlg = new Roo.bootstrap.Modal( {
2977 //constraintoviewport:false,
2979 //collapsible : false,
2984 //buttonAlign:"center",
2985 closeClick : function(){
2986 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2989 handleButton("cancel");
2994 dlg.on("hide", handleHide);
2996 //dlg.addKeyListener(27, handleEsc);
2998 this.buttons = buttons;
2999 var bt = this.buttonText;
3000 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3001 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3002 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3003 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3005 bodyEl = dlg.bodyEl.createChild({
3007 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3008 '<textarea class="roo-mb-textarea"></textarea>' +
3009 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3011 msgEl = bodyEl.dom.firstChild;
3012 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3013 textboxEl.enableDisplayMode();
3014 textboxEl.addKeyListener([10,13], function(){
3015 if(dlg.isVisible() && opt && opt.buttons){
3018 }else if(opt.buttons.yes){
3019 handleButton("yes");
3023 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3024 textareaEl.enableDisplayMode();
3025 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3026 progressEl.enableDisplayMode();
3027 var pf = progressEl.dom.firstChild;
3029 pp = Roo.get(pf.firstChild);
3030 pp.setHeight(pf.offsetHeight);
3038 * Updates the message box body text
3039 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3040 * the XHTML-compliant non-breaking space character '&#160;')
3041 * @return {Roo.MessageBox} This message box
3043 updateText : function(text){
3044 if(!dlg.isVisible() && !opt.width){
3045 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
3047 msgEl.innerHTML = text || ' ';
3049 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3050 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3052 Math.min(opt.width || cw , this.maxWidth),
3053 Math.max(opt.minWidth || this.minWidth, bwidth)
3056 activeTextEl.setWidth(w);
3058 if(dlg.isVisible()){
3059 dlg.fixedcenter = false;
3061 // to big, make it scroll. = But as usual stupid IE does not support
3064 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3065 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3066 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3068 bodyEl.dom.style.height = '';
3069 bodyEl.dom.style.overflowY = '';
3072 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3074 bodyEl.dom.style.overflowX = '';
3077 dlg.setContentSize(w, bodyEl.getHeight());
3078 if(dlg.isVisible()){
3079 dlg.fixedcenter = true;
3085 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3086 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3087 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3088 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3089 * @return {Roo.MessageBox} This message box
3091 updateProgress : function(value, text){
3093 this.updateText(text);
3095 if (pp) { // weird bug on my firefox - for some reason this is not defined
3096 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3102 * Returns true if the message box is currently displayed
3103 * @return {Boolean} True if the message box is visible, else false
3105 isVisible : function(){
3106 return dlg && dlg.isVisible();
3110 * Hides the message box if it is displayed
3113 if(this.isVisible()){
3119 * Displays a new message box, or reinitializes an existing message box, based on the config options
3120 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3121 * The following config object properties are supported:
3123 Property Type Description
3124 ---------- --------------- ------------------------------------------------------------------------------------
3125 animEl String/Element An id or Element from which the message box should animate as it opens and
3126 closes (defaults to undefined)
3127 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3128 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3129 closable Boolean False to hide the top-right close button (defaults to true). Note that
3130 progress and wait dialogs will ignore this property and always hide the
3131 close button as they can only be closed programmatically.
3132 cls String A custom CSS class to apply to the message box element
3133 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3134 displayed (defaults to 75)
3135 fn Function A callback function to execute after closing the dialog. The arguments to the
3136 function will be btn (the name of the button that was clicked, if applicable,
3137 e.g. "ok"), and text (the value of the active text field, if applicable).
3138 Progress and wait dialogs will ignore this option since they do not respond to
3139 user actions and can only be closed programmatically, so any required function
3140 should be called by the same code after it closes the dialog.
3141 icon String A CSS class that provides a background image to be used as an icon for
3142 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3143 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3144 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3145 modal Boolean False to allow user interaction with the page while the message box is
3146 displayed (defaults to true)
3147 msg String A string that will replace the existing message box body text (defaults
3148 to the XHTML-compliant non-breaking space character ' ')
3149 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3150 progress Boolean True to display a progress bar (defaults to false)
3151 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3152 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3153 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3154 title String The title text
3155 value String The string value to set into the active textbox element if displayed
3156 wait Boolean True to display a progress bar (defaults to false)
3157 width Number The width of the dialog in pixels
3164 msg: 'Please enter your address:',
3166 buttons: Roo.MessageBox.OKCANCEL,
3169 animEl: 'addAddressBtn'
3172 * @param {Object} config Configuration options
3173 * @return {Roo.MessageBox} This message box
3175 show : function(options)
3178 // this causes nightmares if you show one dialog after another
3179 // especially on callbacks..
3181 if(this.isVisible()){
3184 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3185 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3186 Roo.log("New Dialog Message:" + options.msg )
3187 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3188 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3191 var d = this.getDialog();
3193 d.setTitle(opt.title || " ");
3194 d.closeEl.setDisplayed(opt.closable !== false);
3195 activeTextEl = textboxEl;
3196 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3201 textareaEl.setHeight(typeof opt.multiline == "number" ?
3202 opt.multiline : this.defaultTextHeight);
3203 activeTextEl = textareaEl;
3212 progressEl.setDisplayed(opt.progress === true);
3213 this.updateProgress(0);
3214 activeTextEl.dom.value = opt.value || "";
3216 dlg.setDefaultButton(activeTextEl);
3218 var bs = opt.buttons;
3222 }else if(bs && bs.yes){
3223 db = buttons["yes"];
3225 dlg.setDefaultButton(db);
3227 bwidth = updateButtons(opt.buttons);
3228 this.updateText(opt.msg);
3230 d.el.addClass(opt.cls);
3232 d.proxyDrag = opt.proxyDrag === true;
3233 d.modal = opt.modal !== false;
3234 d.mask = opt.modal !== false ? mask : false;
3236 // force it to the end of the z-index stack so it gets a cursor in FF
3237 document.body.appendChild(dlg.el.dom);
3238 d.animateTarget = null;
3239 d.show(options.animEl);
3245 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3246 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3247 * and closing the message box when the process is complete.
3248 * @param {String} title The title bar text
3249 * @param {String} msg The message box body text
3250 * @return {Roo.MessageBox} This message box
3252 progress : function(title, msg){
3259 minWidth: this.minProgressWidth,
3266 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3267 * If a callback function is passed it will be called after the user clicks the button, and the
3268 * id of the button that was clicked will be passed as the only parameter to the callback
3269 * (could also be the top-right close button).
3270 * @param {String} title The title bar text
3271 * @param {String} msg The message box body text
3272 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3273 * @param {Object} scope (optional) The scope of the callback function
3274 * @return {Roo.MessageBox} This message box
3276 alert : function(title, msg, fn, scope){
3289 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3290 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3291 * You are responsible for closing the message box when the process is complete.
3292 * @param {String} msg The message box body text
3293 * @param {String} title (optional) The title bar text
3294 * @return {Roo.MessageBox} This message box
3296 wait : function(msg, title){
3307 waitTimer = Roo.TaskMgr.start({
3309 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3317 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3318 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3319 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3320 * @param {String} title The title bar text
3321 * @param {String} msg The message box body text
3322 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3323 * @param {Object} scope (optional) The scope of the callback function
3324 * @return {Roo.MessageBox} This message box
3326 confirm : function(title, msg, fn, scope){
3330 buttons: this.YESNO,
3339 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3340 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3341 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3342 * (could also be the top-right close button) and the text that was entered will be passed as the two
3343 * parameters to the callback.
3344 * @param {String} title The title bar text
3345 * @param {String} msg The message box body text
3346 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3347 * @param {Object} scope (optional) The scope of the callback function
3348 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3349 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3350 * @return {Roo.MessageBox} This message box
3352 prompt : function(title, msg, fn, scope, multiline){
3356 buttons: this.OKCANCEL,
3361 multiline: multiline,
3368 * Button config that displays a single OK button
3373 * Button config that displays Yes and No buttons
3376 YESNO : {yes:true, no:true},
3378 * Button config that displays OK and Cancel buttons
3381 OKCANCEL : {ok:true, cancel:true},
3383 * Button config that displays Yes, No and Cancel buttons
3386 YESNOCANCEL : {yes:true, no:true, cancel:true},
3389 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3392 defaultTextHeight : 75,
3394 * The maximum width in pixels of the message box (defaults to 600)
3399 * The minimum width in pixels of the message box (defaults to 100)
3404 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3405 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3408 minProgressWidth : 250,
3410 * An object containing the default button text strings that can be overriden for localized language support.
3411 * Supported properties are: ok, cancel, yes and no.
3412 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3425 * Shorthand for {@link Roo.MessageBox}
3427 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3428 Roo.Msg = Roo.Msg || Roo.MessageBox;
3437 * @class Roo.bootstrap.Navbar
3438 * @extends Roo.bootstrap.Component
3439 * Bootstrap Navbar class
3442 * Create a new Navbar
3443 * @param {Object} config The config object
3447 Roo.bootstrap.Navbar = function(config){
3448 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3452 * @event beforetoggle
3453 * Fire before toggle the menu
3454 * @param {Roo.EventObject} e
3456 "beforetoggle" : true
3460 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3469 getAutoCreate : function(){
3472 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3476 initEvents :function ()
3478 //Roo.log(this.el.select('.navbar-toggle',true));
3479 this.el.select('.navbar-toggle',true).on('click', function() {
3480 if(this.fireEvent('beforetoggle', this) !== false){
3481 this.el.select('.navbar-collapse',true).toggleClass('in');
3491 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3493 var size = this.el.getSize();
3494 this.maskEl.setSize(size.width, size.height);
3495 this.maskEl.enableDisplayMode("block");
3504 getChildContainer : function()
3506 if (this.el.select('.collapse').getCount()) {
3507 return this.el.select('.collapse',true).first();
3540 * @class Roo.bootstrap.NavSimplebar
3541 * @extends Roo.bootstrap.Navbar
3542 * Bootstrap Sidebar class
3544 * @cfg {Boolean} inverse is inverted color
3546 * @cfg {String} type (nav | pills | tabs)
3547 * @cfg {Boolean} arrangement stacked | justified
3548 * @cfg {String} align (left | right) alignment
3550 * @cfg {Boolean} main (true|false) main nav bar? default false
3551 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3553 * @cfg {String} tag (header|footer|nav|div) default is nav
3559 * Create a new Sidebar
3560 * @param {Object} config The config object
3564 Roo.bootstrap.NavSimplebar = function(config){
3565 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3568 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3584 getAutoCreate : function(){
3588 tag : this.tag || 'div',
3601 this.type = this.type || 'nav';
3602 if (['tabs','pills'].indexOf(this.type)!==-1) {
3603 cfg.cn[0].cls += ' nav-' + this.type
3607 if (this.type!=='nav') {
3608 Roo.log('nav type must be nav/tabs/pills')
3610 cfg.cn[0].cls += ' navbar-nav'
3616 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3617 cfg.cn[0].cls += ' nav-' + this.arrangement;
3621 if (this.align === 'right') {
3622 cfg.cn[0].cls += ' navbar-right';
3626 cfg.cls += ' navbar-inverse';
3653 * @class Roo.bootstrap.NavHeaderbar
3654 * @extends Roo.bootstrap.NavSimplebar
3655 * Bootstrap Sidebar class
3657 * @cfg {String} brand what is brand
3658 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3659 * @cfg {String} brand_href href of the brand
3660 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3661 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3662 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3663 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3666 * Create a new Sidebar
3667 * @param {Object} config The config object
3671 Roo.bootstrap.NavHeaderbar = function(config){
3672 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3676 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3683 desktopCenter : false,
3686 getAutoCreate : function(){
3689 tag: this.nav || 'nav',
3696 if (this.desktopCenter) {
3697 cn.push({cls : 'container', cn : []});
3704 cls: 'navbar-header',
3709 cls: 'navbar-toggle',
3710 'data-toggle': 'collapse',
3715 html: 'Toggle navigation'
3737 cls: 'collapse navbar-collapse',
3741 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3743 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3744 cfg.cls += ' navbar-' + this.position;
3746 // tag can override this..
3748 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3751 if (this.brand !== '') {
3754 href: this.brand_href ? this.brand_href : '#',
3755 cls: 'navbar-brand',
3763 cfg.cls += ' main-nav';
3771 getHeaderChildContainer : function()
3773 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3774 return this.el.select('.navbar-header',true).first();
3777 return this.getChildContainer();
3781 initEvents : function()
3783 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3785 if (this.autohide) {
3790 Roo.get(document).on('scroll',function(e) {
3791 var ns = Roo.get(document).getScroll().top;
3792 var os = prevScroll;
3796 ft.removeClass('slideDown');
3797 ft.addClass('slideUp');
3800 ft.removeClass('slideUp');
3801 ft.addClass('slideDown');
3822 * @class Roo.bootstrap.NavSidebar
3823 * @extends Roo.bootstrap.Navbar
3824 * Bootstrap Sidebar class
3827 * Create a new Sidebar
3828 * @param {Object} config The config object
3832 Roo.bootstrap.NavSidebar = function(config){
3833 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3836 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3838 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3840 getAutoCreate : function(){
3845 cls: 'sidebar sidebar-nav'
3867 * @class Roo.bootstrap.NavGroup
3868 * @extends Roo.bootstrap.Component
3869 * Bootstrap NavGroup class
3870 * @cfg {String} align (left|right)
3871 * @cfg {Boolean} inverse
3872 * @cfg {String} type (nav|pills|tab) default nav
3873 * @cfg {String} navId - reference Id for navbar.
3877 * Create a new nav group
3878 * @param {Object} config The config object
3881 Roo.bootstrap.NavGroup = function(config){
3882 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3885 Roo.bootstrap.NavGroup.register(this);
3889 * Fires when the active item changes
3890 * @param {Roo.bootstrap.NavGroup} this
3891 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3892 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3899 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3910 getAutoCreate : function()
3912 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3919 if (['tabs','pills'].indexOf(this.type)!==-1) {
3920 cfg.cls += ' nav-' + this.type
3922 if (this.type!=='nav') {
3923 Roo.log('nav type must be nav/tabs/pills')
3925 cfg.cls += ' navbar-nav'
3928 if (this.parent().sidebar) {
3931 cls: 'dashboard-menu sidebar-menu'
3937 if (this.form === true) {
3943 if (this.align === 'right') {
3944 cfg.cls += ' navbar-right';
3946 cfg.cls += ' navbar-left';
3950 if (this.align === 'right') {
3951 cfg.cls += ' navbar-right';
3955 cfg.cls += ' navbar-inverse';
3963 * sets the active Navigation item
3964 * @param {Roo.bootstrap.NavItem} the new current navitem
3966 setActiveItem : function(item)
3969 Roo.each(this.navItems, function(v){
3974 v.setActive(false, true);
3981 item.setActive(true, true);
3982 this.fireEvent('changed', this, item, prev);
3987 * gets the active Navigation item
3988 * @return {Roo.bootstrap.NavItem} the current navitem
3990 getActive : function()
3994 Roo.each(this.navItems, function(v){
4005 indexOfNav : function()
4009 Roo.each(this.navItems, function(v,i){
4020 * adds a Navigation item
4021 * @param {Roo.bootstrap.NavItem} the navitem to add
4023 addItem : function(cfg)
4025 var cn = new Roo.bootstrap.NavItem(cfg);
4027 cn.parentId = this.id;
4028 cn.onRender(this.el, null);
4032 * register a Navigation item
4033 * @param {Roo.bootstrap.NavItem} the navitem to add
4035 register : function(item)
4037 this.navItems.push( item);
4038 item.navId = this.navId;
4043 * clear all the Navigation item
4046 clearAll : function()
4049 this.el.dom.innerHTML = '';
4052 getNavItem: function(tabId)
4055 Roo.each(this.navItems, function(e) {
4056 if (e.tabId == tabId) {
4066 setActiveNext : function()
4068 var i = this.indexOfNav(this.getActive());
4069 if (i > this.navItems.length) {
4072 this.setActiveItem(this.navItems[i+1]);
4074 setActivePrev : function()
4076 var i = this.indexOfNav(this.getActive());
4080 this.setActiveItem(this.navItems[i-1]);
4082 clearWasActive : function(except) {
4083 Roo.each(this.navItems, function(e) {
4084 if (e.tabId != except.tabId && e.was_active) {
4085 e.was_active = false;
4092 getWasActive : function ()
4095 Roo.each(this.navItems, function(e) {
4110 Roo.apply(Roo.bootstrap.NavGroup, {
4114 * register a Navigation Group
4115 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4117 register : function(navgrp)
4119 this.groups[navgrp.navId] = navgrp;
4123 * fetch a Navigation Group based on the navigation ID
4124 * @param {string} the navgroup to add
4125 * @returns {Roo.bootstrap.NavGroup} the navgroup
4127 get: function(navId) {
4128 if (typeof(this.groups[navId]) == 'undefined') {
4130 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4132 return this.groups[navId] ;
4147 * @class Roo.bootstrap.NavItem
4148 * @extends Roo.bootstrap.Component
4149 * Bootstrap Navbar.NavItem class
4150 * @cfg {String} href link to
4151 * @cfg {String} html content of button
4152 * @cfg {String} badge text inside badge
4153 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4154 * @cfg {String} glyphicon name of glyphicon
4155 * @cfg {String} icon name of font awesome icon
4156 * @cfg {Boolean} active Is item active
4157 * @cfg {Boolean} disabled Is item disabled
4159 * @cfg {Boolean} preventDefault (true | false) default false
4160 * @cfg {String} tabId the tab that this item activates.
4161 * @cfg {String} tagtype (a|span) render as a href or span?
4162 * @cfg {Boolean} animateRef (true|false) link to element default false
4165 * Create a new Navbar Item
4166 * @param {Object} config The config object
4168 Roo.bootstrap.NavItem = function(config){
4169 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4174 * The raw click event for the entire grid.
4175 * @param {Roo.EventObject} e
4180 * Fires when the active item active state changes
4181 * @param {Roo.bootstrap.NavItem} this
4182 * @param {boolean} state the new state
4188 * Fires when scroll to element
4189 * @param {Roo.bootstrap.NavItem} this
4190 * @param {Object} options
4191 * @param {Roo.EventObject} e
4199 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4207 preventDefault : false,
4214 getAutoCreate : function(){
4223 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4225 if (this.disabled) {
4226 cfg.cls += ' disabled';
4229 if (this.href || this.html || this.glyphicon || this.icon) {
4233 href : this.href || "#",
4234 html: this.html || ''
4239 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4242 if(this.glyphicon) {
4243 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4248 cfg.cn[0].html += " <span class='caret'></span>";
4252 if (this.badge !== '') {
4254 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4262 initEvents: function()
4264 if (typeof (this.menu) != 'undefined') {
4265 this.menu.parentType = this.xtype;
4266 this.menu.triggerEl = this.el;
4267 this.menu = this.addxtype(Roo.apply({}, this.menu));
4270 this.el.select('a',true).on('click', this.onClick, this);
4272 if(this.tagtype == 'span'){
4273 this.el.select('span',true).on('click', this.onClick, this);
4276 // at this point parent should be available..
4277 this.parent().register(this);
4280 onClick : function(e)
4282 if (e.getTarget('.dropdown-menu-item')) {
4283 // did you click on a menu itemm.... - then don't trigger onclick..
4288 this.preventDefault ||
4291 Roo.log("NavItem - prevent Default?");
4295 if (this.disabled) {
4299 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4300 if (tg && tg.transition) {
4301 Roo.log("waiting for the transitionend");
4307 //Roo.log("fire event clicked");
4308 if(this.fireEvent('click', this, e) === false){
4312 if(this.tagtype == 'span'){
4316 //Roo.log(this.href);
4317 var ael = this.el.select('a',true).first();
4320 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4321 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4322 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4323 return; // ignore... - it's a 'hash' to another page.
4325 Roo.log("NavItem - prevent Default?");
4327 this.scrollToElement(e);
4331 var p = this.parent();
4333 if (['tabs','pills'].indexOf(p.type)!==-1) {
4334 if (typeof(p.setActiveItem) !== 'undefined') {
4335 p.setActiveItem(this);
4339 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4340 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4341 // remove the collapsed menu expand...
4342 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4346 isActive: function () {
4349 setActive : function(state, fire, is_was_active)
4351 if (this.active && !state && this.navId) {
4352 this.was_active = true;
4353 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4355 nv.clearWasActive(this);
4359 this.active = state;
4362 this.el.removeClass('active');
4363 } else if (!this.el.hasClass('active')) {
4364 this.el.addClass('active');
4367 this.fireEvent('changed', this, state);
4370 // show a panel if it's registered and related..
4372 if (!this.navId || !this.tabId || !state || is_was_active) {
4376 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4380 var pan = tg.getPanelByName(this.tabId);
4384 // if we can not flip to new panel - go back to old nav highlight..
4385 if (false == tg.showPanel(pan)) {
4386 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4388 var onav = nv.getWasActive();
4390 onav.setActive(true, false, true);
4399 // this should not be here...
4400 setDisabled : function(state)
4402 this.disabled = state;
4404 this.el.removeClass('disabled');
4405 } else if (!this.el.hasClass('disabled')) {
4406 this.el.addClass('disabled');
4412 * Fetch the element to display the tooltip on.
4413 * @return {Roo.Element} defaults to this.el
4415 tooltipEl : function()
4417 return this.el.select('' + this.tagtype + '', true).first();
4420 scrollToElement : function(e)
4422 var c = document.body;
4425 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4427 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4428 c = document.documentElement;
4431 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4437 var o = target.calcOffsetsTo(c);
4444 this.fireEvent('scrollto', this, options, e);
4446 Roo.get(c).scrollTo('top', options.value, true);
4459 * <span> icon </span>
4460 * <span> text </span>
4461 * <span>badge </span>
4465 * @class Roo.bootstrap.NavSidebarItem
4466 * @extends Roo.bootstrap.NavItem
4467 * Bootstrap Navbar.NavSidebarItem class
4468 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4469 * {bool} open is the menu open
4471 * Create a new Navbar Button
4472 * @param {Object} config The config object
4474 Roo.bootstrap.NavSidebarItem = function(config){
4475 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4480 * The raw click event for the entire grid.
4481 * @param {Roo.EventObject} e
4486 * Fires when the active item active state changes
4487 * @param {Roo.bootstrap.NavSidebarItem} this
4488 * @param {boolean} state the new state
4496 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4498 badgeWeight : 'default',
4502 getAutoCreate : function(){
4507 href : this.href || '#',
4519 html : this.html || ''
4524 cfg.cls += ' active';
4527 if (this.disabled) {
4528 cfg.cls += ' disabled';
4531 cfg.cls += ' open x-open';
4534 if (this.glyphicon || this.icon) {
4535 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4536 a.cn.push({ tag : 'i', cls : c }) ;
4541 if (this.badge !== '') {
4543 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4547 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4548 a.cls += 'dropdown-toggle treeview' ;
4556 initEvents : function()
4558 if (typeof (this.menu) != 'undefined') {
4559 this.menu.parentType = this.xtype;
4560 this.menu.triggerEl = this.el;
4561 this.menu = this.addxtype(Roo.apply({}, this.menu));
4564 this.el.on('click', this.onClick, this);
4567 if(this.badge !== ''){
4569 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4574 onClick : function(e)
4581 if(this.preventDefault){
4585 this.fireEvent('click', this);
4588 disable : function()
4590 this.setDisabled(true);
4595 this.setDisabled(false);
4598 setDisabled : function(state)
4600 if(this.disabled == state){
4604 this.disabled = state;
4607 this.el.addClass('disabled');
4611 this.el.removeClass('disabled');
4616 setActive : function(state)
4618 if(this.active == state){
4622 this.active = state;
4625 this.el.addClass('active');
4629 this.el.removeClass('active');
4634 isActive: function ()
4639 setBadge : function(str)
4645 this.badgeEl.dom.innerHTML = str;
4662 * @class Roo.bootstrap.Row
4663 * @extends Roo.bootstrap.Component
4664 * Bootstrap Row class (contains columns...)
4668 * @param {Object} config The config object
4671 Roo.bootstrap.Row = function(config){
4672 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4675 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4677 getAutoCreate : function(){
4696 * @class Roo.bootstrap.Element
4697 * @extends Roo.bootstrap.Component
4698 * Bootstrap Element class
4699 * @cfg {String} html contents of the element
4700 * @cfg {String} tag tag of the element
4701 * @cfg {String} cls class of the element
4702 * @cfg {Boolean} preventDefault (true|false) default false
4703 * @cfg {Boolean} clickable (true|false) default false
4706 * Create a new Element
4707 * @param {Object} config The config object
4710 Roo.bootstrap.Element = function(config){
4711 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4717 * When a element is chick
4718 * @param {Roo.bootstrap.Element} this
4719 * @param {Roo.EventObject} e
4725 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4730 preventDefault: false,
4733 getAutoCreate : function(){
4744 initEvents: function()
4746 Roo.bootstrap.Element.superclass.initEvents.call(this);
4749 this.el.on('click', this.onClick, this);
4754 onClick : function(e)
4756 if(this.preventDefault){
4760 this.fireEvent('click', this, e);
4763 getValue : function()
4765 return this.el.dom.innerHTML;
4768 setValue : function(value)
4770 this.el.dom.innerHTML = value;
4785 * @class Roo.bootstrap.Pagination
4786 * @extends Roo.bootstrap.Component
4787 * Bootstrap Pagination class
4788 * @cfg {String} size xs | sm | md | lg
4789 * @cfg {Boolean} inverse false | true
4792 * Create a new Pagination
4793 * @param {Object} config The config object
4796 Roo.bootstrap.Pagination = function(config){
4797 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4800 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4806 getAutoCreate : function(){
4812 cfg.cls += ' inverse';
4818 cfg.cls += " " + this.cls;
4836 * @class Roo.bootstrap.PaginationItem
4837 * @extends Roo.bootstrap.Component
4838 * Bootstrap PaginationItem class
4839 * @cfg {String} html text
4840 * @cfg {String} href the link
4841 * @cfg {Boolean} preventDefault (true | false) default true
4842 * @cfg {Boolean} active (true | false) default false
4843 * @cfg {Boolean} disabled default false
4847 * Create a new PaginationItem
4848 * @param {Object} config The config object
4852 Roo.bootstrap.PaginationItem = function(config){
4853 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4858 * The raw click event for the entire grid.
4859 * @param {Roo.EventObject} e
4865 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4869 preventDefault: true,
4874 getAutoCreate : function(){
4880 href : this.href ? this.href : '#',
4881 html : this.html ? this.html : ''
4891 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4895 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4901 initEvents: function() {
4903 this.el.on('click', this.onClick, this);
4906 onClick : function(e)
4908 Roo.log('PaginationItem on click ');
4909 if(this.preventDefault){
4917 this.fireEvent('click', this, e);
4933 * @class Roo.bootstrap.Slider
4934 * @extends Roo.bootstrap.Component
4935 * Bootstrap Slider class
4938 * Create a new Slider
4939 * @param {Object} config The config object
4942 Roo.bootstrap.Slider = function(config){
4943 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4946 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4948 getAutoCreate : function(){
4952 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4956 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4968 * Ext JS Library 1.1.1
4969 * Copyright(c) 2006-2007, Ext JS, LLC.
4971 * Originally Released Under LGPL - original licence link has changed is not relivant.
4974 * <script type="text/javascript">
4979 * @class Roo.grid.ColumnModel
4980 * @extends Roo.util.Observable
4981 * This is the default implementation of a ColumnModel used by the Grid. It defines
4982 * the columns in the grid.
4985 var colModel = new Roo.grid.ColumnModel([
4986 {header: "Ticker", width: 60, sortable: true, locked: true},
4987 {header: "Company Name", width: 150, sortable: true},
4988 {header: "Market Cap.", width: 100, sortable: true},
4989 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4990 {header: "Employees", width: 100, sortable: true, resizable: false}
4995 * The config options listed for this class are options which may appear in each
4996 * individual column definition.
4997 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4999 * @param {Object} config An Array of column config objects. See this class's
5000 * config objects for details.
5002 Roo.grid.ColumnModel = function(config){
5004 * The config passed into the constructor
5006 this.config = config;
5009 // if no id, create one
5010 // if the column does not have a dataIndex mapping,
5011 // map it to the order it is in the config
5012 for(var i = 0, len = config.length; i < len; i++){
5014 if(typeof c.dataIndex == "undefined"){
5017 if(typeof c.renderer == "string"){
5018 c.renderer = Roo.util.Format[c.renderer];
5020 if(typeof c.id == "undefined"){
5023 if(c.editor && c.editor.xtype){
5024 c.editor = Roo.factory(c.editor, Roo.grid);
5026 if(c.editor && c.editor.isFormField){
5027 c.editor = new Roo.grid.GridEditor(c.editor);
5029 this.lookup[c.id] = c;
5033 * The width of columns which have no width specified (defaults to 100)
5036 this.defaultWidth = 100;
5039 * Default sortable of columns which have no sortable specified (defaults to false)
5042 this.defaultSortable = false;
5046 * @event widthchange
5047 * Fires when the width of a column changes.
5048 * @param {ColumnModel} this
5049 * @param {Number} columnIndex The column index
5050 * @param {Number} newWidth The new width
5052 "widthchange": true,
5054 * @event headerchange
5055 * Fires when the text of a header changes.
5056 * @param {ColumnModel} this
5057 * @param {Number} columnIndex The column index
5058 * @param {Number} newText The new header text
5060 "headerchange": true,
5062 * @event hiddenchange
5063 * Fires when a column is hidden or "unhidden".
5064 * @param {ColumnModel} this
5065 * @param {Number} columnIndex The column index
5066 * @param {Boolean} hidden true if hidden, false otherwise
5068 "hiddenchange": true,
5070 * @event columnmoved
5071 * Fires when a column is moved.
5072 * @param {ColumnModel} this
5073 * @param {Number} oldIndex
5074 * @param {Number} newIndex
5076 "columnmoved" : true,
5078 * @event columlockchange
5079 * Fires when a column's locked state is changed
5080 * @param {ColumnModel} this
5081 * @param {Number} colIndex
5082 * @param {Boolean} locked true if locked
5084 "columnlockchange" : true
5086 Roo.grid.ColumnModel.superclass.constructor.call(this);
5088 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5090 * @cfg {String} header The header text to display in the Grid view.
5093 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5094 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5095 * specified, the column's index is used as an index into the Record's data Array.
5098 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5099 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5102 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5103 * Defaults to the value of the {@link #defaultSortable} property.
5104 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5107 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5110 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5113 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5116 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5119 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5120 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5121 * default renderer uses the raw data value. If an object is returned (bootstrap only)
5122 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5125 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5128 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5131 * @cfg {String} cursor (Optional)
5134 * @cfg {String} tooltip (Optional)
5137 * @cfg {Number} xs (Optional)
5140 * @cfg {Number} sm (Optional)
5143 * @cfg {Number} md (Optional)
5146 * @cfg {Number} lg (Optional)
5149 * Returns the id of the column at the specified index.
5150 * @param {Number} index The column index
5151 * @return {String} the id
5153 getColumnId : function(index){
5154 return this.config[index].id;
5158 * Returns the column for a specified id.
5159 * @param {String} id The column id
5160 * @return {Object} the column
5162 getColumnById : function(id){
5163 return this.lookup[id];
5168 * Returns the column for a specified dataIndex.
5169 * @param {String} dataIndex The column dataIndex
5170 * @return {Object|Boolean} the column or false if not found
5172 getColumnByDataIndex: function(dataIndex){
5173 var index = this.findColumnIndex(dataIndex);
5174 return index > -1 ? this.config[index] : false;
5178 * Returns the index for a specified column id.
5179 * @param {String} id The column id
5180 * @return {Number} the index, or -1 if not found
5182 getIndexById : function(id){
5183 for(var i = 0, len = this.config.length; i < len; i++){
5184 if(this.config[i].id == id){
5192 * Returns the index for a specified column dataIndex.
5193 * @param {String} dataIndex The column dataIndex
5194 * @return {Number} the index, or -1 if not found
5197 findColumnIndex : function(dataIndex){
5198 for(var i = 0, len = this.config.length; i < len; i++){
5199 if(this.config[i].dataIndex == dataIndex){
5207 moveColumn : function(oldIndex, newIndex){
5208 var c = this.config[oldIndex];
5209 this.config.splice(oldIndex, 1);
5210 this.config.splice(newIndex, 0, c);
5211 this.dataMap = null;
5212 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5215 isLocked : function(colIndex){
5216 return this.config[colIndex].locked === true;
5219 setLocked : function(colIndex, value, suppressEvent){
5220 if(this.isLocked(colIndex) == value){
5223 this.config[colIndex].locked = value;
5225 this.fireEvent("columnlockchange", this, colIndex, value);
5229 getTotalLockedWidth : function(){
5231 for(var i = 0; i < this.config.length; i++){
5232 if(this.isLocked(i) && !this.isHidden(i)){
5233 this.totalWidth += this.getColumnWidth(i);
5239 getLockedCount : function(){
5240 for(var i = 0, len = this.config.length; i < len; i++){
5241 if(!this.isLocked(i)){
5246 return this.config.length;
5250 * Returns the number of columns.
5253 getColumnCount : function(visibleOnly){
5254 if(visibleOnly === true){
5256 for(var i = 0, len = this.config.length; i < len; i++){
5257 if(!this.isHidden(i)){
5263 return this.config.length;
5267 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5268 * @param {Function} fn
5269 * @param {Object} scope (optional)
5270 * @return {Array} result
5272 getColumnsBy : function(fn, scope){
5274 for(var i = 0, len = this.config.length; i < len; i++){
5275 var c = this.config[i];
5276 if(fn.call(scope||this, c, i) === true){
5284 * Returns true if the specified column is sortable.
5285 * @param {Number} col The column index
5288 isSortable : function(col){
5289 if(typeof this.config[col].sortable == "undefined"){
5290 return this.defaultSortable;
5292 return this.config[col].sortable;
5296 * Returns the rendering (formatting) function defined for the column.
5297 * @param {Number} col The column index.
5298 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5300 getRenderer : function(col){
5301 if(!this.config[col].renderer){
5302 return Roo.grid.ColumnModel.defaultRenderer;
5304 return this.config[col].renderer;
5308 * Sets the rendering (formatting) function for a column.
5309 * @param {Number} col The column index
5310 * @param {Function} fn The function to use to process the cell's raw data
5311 * to return HTML markup for the grid view. The render function is called with
5312 * the following parameters:<ul>
5313 * <li>Data value.</li>
5314 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5315 * <li>css A CSS style string to apply to the table cell.</li>
5316 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5317 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5318 * <li>Row index</li>
5319 * <li>Column index</li>
5320 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5322 setRenderer : function(col, fn){
5323 this.config[col].renderer = fn;
5327 * Returns the width for the specified column.
5328 * @param {Number} col The column index
5331 getColumnWidth : function(col){
5332 return this.config[col].width * 1 || this.defaultWidth;
5336 * Sets the width for a column.
5337 * @param {Number} col The column index
5338 * @param {Number} width The new width
5340 setColumnWidth : function(col, width, suppressEvent){
5341 this.config[col].width = width;
5342 this.totalWidth = null;
5344 this.fireEvent("widthchange", this, col, width);
5349 * Returns the total width of all columns.
5350 * @param {Boolean} includeHidden True to include hidden column widths
5353 getTotalWidth : function(includeHidden){
5354 if(!this.totalWidth){
5355 this.totalWidth = 0;
5356 for(var i = 0, len = this.config.length; i < len; i++){
5357 if(includeHidden || !this.isHidden(i)){
5358 this.totalWidth += this.getColumnWidth(i);
5362 return this.totalWidth;
5366 * Returns the header for the specified column.
5367 * @param {Number} col The column index
5370 getColumnHeader : function(col){
5371 return this.config[col].header;
5375 * Sets the header for a column.
5376 * @param {Number} col The column index
5377 * @param {String} header The new header
5379 setColumnHeader : function(col, header){
5380 this.config[col].header = header;
5381 this.fireEvent("headerchange", this, col, header);
5385 * Returns the tooltip for the specified column.
5386 * @param {Number} col The column index
5389 getColumnTooltip : function(col){
5390 return this.config[col].tooltip;
5393 * Sets the tooltip for a column.
5394 * @param {Number} col The column index
5395 * @param {String} tooltip The new tooltip
5397 setColumnTooltip : function(col, tooltip){
5398 this.config[col].tooltip = tooltip;
5402 * Returns the dataIndex for the specified column.
5403 * @param {Number} col The column index
5406 getDataIndex : function(col){
5407 return this.config[col].dataIndex;
5411 * Sets the dataIndex for a column.
5412 * @param {Number} col The column index
5413 * @param {Number} dataIndex The new dataIndex
5415 setDataIndex : function(col, dataIndex){
5416 this.config[col].dataIndex = dataIndex;
5422 * Returns true if the cell is editable.
5423 * @param {Number} colIndex The column index
5424 * @param {Number} rowIndex The row index - this is nto actually used..?
5427 isCellEditable : function(colIndex, rowIndex){
5428 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5432 * Returns the editor defined for the cell/column.
5433 * return false or null to disable editing.
5434 * @param {Number} colIndex The column index
5435 * @param {Number} rowIndex The row index
5438 getCellEditor : function(colIndex, rowIndex){
5439 return this.config[colIndex].editor;
5443 * Sets if a column is editable.
5444 * @param {Number} col The column index
5445 * @param {Boolean} editable True if the column is editable
5447 setEditable : function(col, editable){
5448 this.config[col].editable = editable;
5453 * Returns true if the column is hidden.
5454 * @param {Number} colIndex The column index
5457 isHidden : function(colIndex){
5458 return this.config[colIndex].hidden;
5463 * Returns true if the column width cannot be changed
5465 isFixed : function(colIndex){
5466 return this.config[colIndex].fixed;
5470 * Returns true if the column can be resized
5473 isResizable : function(colIndex){
5474 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5477 * Sets if a column is hidden.
5478 * @param {Number} colIndex The column index
5479 * @param {Boolean} hidden True if the column is hidden
5481 setHidden : function(colIndex, hidden){
5482 this.config[colIndex].hidden = hidden;
5483 this.totalWidth = null;
5484 this.fireEvent("hiddenchange", this, colIndex, hidden);
5488 * Sets the editor for a column.
5489 * @param {Number} col The column index
5490 * @param {Object} editor The editor object
5492 setEditor : function(col, editor){
5493 this.config[col].editor = editor;
5497 Roo.grid.ColumnModel.defaultRenderer = function(value){
5498 if(typeof value == "string" && value.length < 1){
5504 // Alias for backwards compatibility
5505 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5508 * Ext JS Library 1.1.1
5509 * Copyright(c) 2006-2007, Ext JS, LLC.
5511 * Originally Released Under LGPL - original licence link has changed is not relivant.
5514 * <script type="text/javascript">
5518 * @class Roo.LoadMask
5519 * A simple utility class for generically masking elements while loading data. If the element being masked has
5520 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5521 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5522 * element's UpdateManager load indicator and will be destroyed after the initial load.
5524 * Create a new LoadMask
5525 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5526 * @param {Object} config The config object
5528 Roo.LoadMask = function(el, config){
5529 this.el = Roo.get(el);
5530 Roo.apply(this, config);
5532 this.store.on('beforeload', this.onBeforeLoad, this);
5533 this.store.on('load', this.onLoad, this);
5534 this.store.on('loadexception', this.onLoadException, this);
5535 this.removeMask = false;
5537 var um = this.el.getUpdateManager();
5538 um.showLoadIndicator = false; // disable the default indicator
5539 um.on('beforeupdate', this.onBeforeLoad, this);
5540 um.on('update', this.onLoad, this);
5541 um.on('failure', this.onLoad, this);
5542 this.removeMask = true;
5546 Roo.LoadMask.prototype = {
5548 * @cfg {Boolean} removeMask
5549 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5550 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5554 * The text to display in a centered loading message box (defaults to 'Loading...')
5558 * @cfg {String} msgCls
5559 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5561 msgCls : 'x-mask-loading',
5564 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5570 * Disables the mask to prevent it from being displayed
5572 disable : function(){
5573 this.disabled = true;
5577 * Enables the mask so that it can be displayed
5579 enable : function(){
5580 this.disabled = false;
5583 onLoadException : function()
5587 if (typeof(arguments[3]) != 'undefined') {
5588 Roo.MessageBox.alert("Error loading",arguments[3]);
5592 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5593 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5602 this.el.unmask(this.removeMask);
5607 this.el.unmask(this.removeMask);
5611 onBeforeLoad : function(){
5613 this.el.mask(this.msg, this.msgCls);
5618 destroy : function(){
5620 this.store.un('beforeload', this.onBeforeLoad, this);
5621 this.store.un('load', this.onLoad, this);
5622 this.store.un('loadexception', this.onLoadException, this);
5624 var um = this.el.getUpdateManager();
5625 um.un('beforeupdate', this.onBeforeLoad, this);
5626 um.un('update', this.onLoad, this);
5627 um.un('failure', this.onLoad, this);
5638 * @class Roo.bootstrap.Table
5639 * @extends Roo.bootstrap.Component
5640 * Bootstrap Table class
5641 * @cfg {String} cls table class
5642 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5643 * @cfg {String} bgcolor Specifies the background color for a table
5644 * @cfg {Number} border Specifies whether the table cells should have borders or not
5645 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5646 * @cfg {Number} cellspacing Specifies the space between cells
5647 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5648 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5649 * @cfg {String} sortable Specifies that the table should be sortable
5650 * @cfg {String} summary Specifies a summary of the content of a table
5651 * @cfg {Number} width Specifies the width of a table
5652 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5654 * @cfg {boolean} striped Should the rows be alternative striped
5655 * @cfg {boolean} bordered Add borders to the table
5656 * @cfg {boolean} hover Add hover highlighting
5657 * @cfg {boolean} condensed Format condensed
5658 * @cfg {boolean} responsive Format condensed
5659 * @cfg {Boolean} loadMask (true|false) default false
5660 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5661 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5662 * @cfg {Boolean} rowSelection (true|false) default false
5663 * @cfg {Boolean} cellSelection (true|false) default false
5664 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5668 * Create a new Table
5669 * @param {Object} config The config object
5672 Roo.bootstrap.Table = function(config){
5673 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5675 if (config.container) {
5676 // ctor'ed from a Border/panel.grid
5677 this.container = Roo.get(config.container);
5678 this.container.update("");
5679 this.container.setStyle("overflow", "hidden");
5680 this.container.addClass('x-grid-container');
5685 this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
5686 this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
5687 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5688 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5692 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5693 this.sm = this.selModel;
5694 this.sm.xmodule = this.xmodule || false;
5696 if (this.cm && typeof(this.cm.config) == 'undefined') {
5697 this.colModel = new Roo.grid.ColumnModel(this.cm);
5698 this.cm = this.colModel;
5699 this.cm.xmodule = this.xmodule || false;
5702 this.store= Roo.factory(this.store, Roo.data);
5703 this.ds = this.store;
5704 this.ds.xmodule = this.xmodule || false;
5707 if (this.footer && this.store) {
5708 this.footer.dataSource = this.ds;
5709 this.footer = Roo.factory(this.footer);
5716 * Fires when a cell is clicked
5717 * @param {Roo.bootstrap.Table} this
5718 * @param {Roo.Element} el
5719 * @param {Number} rowIndex
5720 * @param {Number} columnIndex
5721 * @param {Roo.EventObject} e
5725 * @event celldblclick
5726 * Fires when a cell is double clicked
5727 * @param {Roo.bootstrap.Table} this
5728 * @param {Roo.Element} el
5729 * @param {Number} rowIndex
5730 * @param {Number} columnIndex
5731 * @param {Roo.EventObject} e
5733 "celldblclick" : true,
5736 * Fires when a row is clicked
5737 * @param {Roo.bootstrap.Table} this
5738 * @param {Roo.Element} el
5739 * @param {Number} rowIndex
5740 * @param {Roo.EventObject} e
5744 * @event rowdblclick
5745 * Fires when a row is double clicked
5746 * @param {Roo.bootstrap.Table} this
5747 * @param {Roo.Element} el
5748 * @param {Number} rowIndex
5749 * @param {Roo.EventObject} e
5751 "rowdblclick" : true,
5754 * Fires when a mouseover occur
5755 * @param {Roo.bootstrap.Table} this
5756 * @param {Roo.Element} el
5757 * @param {Number} rowIndex
5758 * @param {Number} columnIndex
5759 * @param {Roo.EventObject} e
5764 * Fires when a mouseout occur
5765 * @param {Roo.bootstrap.Table} this
5766 * @param {Roo.Element} el
5767 * @param {Number} rowIndex
5768 * @param {Number} columnIndex
5769 * @param {Roo.EventObject} e
5774 * Fires when a row is rendered, so you can change add a style to it.
5775 * @param {Roo.bootstrap.Table} this
5776 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5780 * @event rowsrendered
5781 * Fires when all the rows have been rendered
5782 * @param {Roo.bootstrap.Table} this
5784 'rowsrendered' : true,
5786 * @event contextmenu
5787 * The raw contextmenu event for the entire grid.
5788 * @param {Roo.EventObject} e
5790 "contextmenu" : true,
5792 * @event rowcontextmenu
5793 * Fires when a row is right clicked
5794 * @param {Roo.bootstrap.Table} this
5795 * @param {Number} rowIndex
5796 * @param {Roo.EventObject} e
5798 "rowcontextmenu" : true,
5800 * @event cellcontextmenu
5801 * Fires when a cell is right clicked
5802 * @param {Roo.bootstrap.Table} this
5803 * @param {Number} rowIndex
5804 * @param {Number} cellIndex
5805 * @param {Roo.EventObject} e
5807 "cellcontextmenu" : true,
5809 * @event headercontextmenu
5810 * Fires when a header is right clicked
5811 * @param {Roo.bootstrap.Table} this
5812 * @param {Number} columnIndex
5813 * @param {Roo.EventObject} e
5815 "headercontextmenu" : true
5819 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5844 rowSelection : false,
5845 cellSelection : false,
5848 // Roo.Element - the tbody
5852 container: false, // used by gridpanel...
5854 getAutoCreate : function()
5856 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5860 cls : 'table table-body-fixed',
5865 cfg.cls += ' table-striped';
5869 cfg.cls += ' table-hover';
5871 if (this.bordered) {
5872 cfg.cls += ' table-bordered';
5874 if (this.condensed) {
5875 cfg.cls += ' table-condensed';
5877 if (this.responsive) {
5878 cfg.cls += ' table-responsive';
5882 cfg.cls+= ' ' +this.cls;
5885 // this lot should be simplifed...
5888 cfg.align=this.align;
5891 cfg.bgcolor=this.bgcolor;
5894 cfg.border=this.border;
5896 if (this.cellpadding) {
5897 cfg.cellpadding=this.cellpadding;
5899 if (this.cellspacing) {
5900 cfg.cellspacing=this.cellspacing;
5903 cfg.frame=this.frame;
5906 cfg.rules=this.rules;
5908 if (this.sortable) {
5909 cfg.sortable=this.sortable;
5912 cfg.summary=this.summary;
5915 cfg.width=this.width;
5918 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5921 if(this.store || this.cm){
5922 if(this.headerShow){
5923 cfg.cn.push(this.renderHeader());
5926 cfg.cn.push(this.renderBody());
5928 if(this.footerShow){
5929 cfg.cn.push(this.renderFooter());
5931 // where does this come from?
5932 //cfg.cls+= ' TableGrid';
5935 return { cn : [ cfg ] };
5938 initEvents : function()
5940 if(!this.store || !this.cm){
5944 //Roo.log('initEvents with ds!!!!');
5946 this.mainBody = this.el.select('tbody', true).first();
5951 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5952 e.on('click', _this.sort, _this);
5955 this.el.on("click", this.onClick, this);
5956 this.el.on("dblclick", this.onDblClick, this);
5958 // why is this done????? = it breaks dialogs??
5959 //this.parent().el.setStyle('position', 'relative');
5963 this.footer.parentId = this.id;
5964 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5967 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5969 this.store.on('load', this.onLoad, this);
5970 this.store.on('beforeload', this.onBeforeLoad, this);
5971 this.store.on('update', this.onUpdate, this);
5972 this.store.on('add', this.onAdd, this);
5974 this.el.on("contextmenu", this.onContextMenu, this);
5980 onContextMenu : function(e, t)
5982 this.processEvent("contextmenu", e);
5985 processEvent : function(name, e)
5987 if (name != 'touchstart' ) {
5988 this.fireEvent(name, e);
5991 var t = e.getTarget();
5993 var cell = Roo.get(t);
5999 if(cell.findParent('tfoot', false, true)){
6003 if(cell.findParent('thead', false, true)){
6005 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6006 cell = Roo.get(t).findParent('th', false, true);
6009 var cellIndex = cell.dom.cellIndex;
6011 var ename = name == 'touchstart' ? 'click' : name;
6012 this.fireEvent("header" + ename, this, cellIndex, e);
6017 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6018 cell = Roo.get(t).findParent('td', false, true);
6021 var row = cell.findParent('tr', false, true);
6022 var cellIndex = cell.dom.cellIndex;
6023 var rowIndex = row.dom.rowIndex - 1;
6027 this.fireEvent("row" + name, this, rowIndex, e);
6031 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6037 onMouseover : function(e, el)
6039 var cell = Roo.get(el);
6045 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6046 cell = cell.findParent('td', false, true);
6049 var row = cell.findParent('tr', false, true);
6050 var cellIndex = cell.dom.cellIndex;
6051 var rowIndex = row.dom.rowIndex - 1; // start from 0
6053 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6057 onMouseout : function(e, el)
6059 var cell = Roo.get(el);
6065 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6066 cell = cell.findParent('td', false, true);
6069 var row = cell.findParent('tr', false, true);
6070 var cellIndex = cell.dom.cellIndex;
6071 var rowIndex = row.dom.rowIndex - 1; // start from 0
6073 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6077 onClick : function(e, el)
6079 var cell = Roo.get(el);
6081 if(!cell || (!this.cellSelection && !this.rowSelection)){
6085 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6086 cell = cell.findParent('td', false, true);
6089 if(!cell || typeof(cell) == 'undefined'){
6093 var row = cell.findParent('tr', false, true);
6095 if(!row || typeof(row) == 'undefined'){
6099 var cellIndex = cell.dom.cellIndex;
6100 var rowIndex = this.getRowIndex(row);
6102 // why??? - should these not be based on SelectionModel?
6103 if(this.cellSelection){
6104 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6107 if(this.rowSelection){
6108 this.fireEvent('rowclick', this, row, rowIndex, e);
6114 onDblClick : function(e,el)
6116 var cell = Roo.get(el);
6118 if(!cell || (!this.CellSelection && !this.RowSelection)){
6122 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6123 cell = cell.findParent('td', false, true);
6126 if(!cell || typeof(cell) == 'undefined'){
6130 var row = cell.findParent('tr', false, true);
6132 if(!row || typeof(row) == 'undefined'){
6136 var cellIndex = cell.dom.cellIndex;
6137 var rowIndex = this.getRowIndex(row);
6139 if(this.CellSelection){
6140 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6143 if(this.RowSelection){
6144 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6148 sort : function(e,el)
6150 var col = Roo.get(el);
6152 if(!col.hasClass('sortable')){
6156 var sort = col.attr('sort');
6159 if(col.hasClass('glyphicon-arrow-up')){
6163 this.store.sortInfo = {field : sort, direction : dir};
6166 Roo.log("calling footer first");
6167 this.footer.onClick('first');
6170 this.store.load({ params : { start : 0 } });
6174 renderHeader : function()
6183 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6185 var config = cm.config[i];
6190 html: cm.getColumnHeader(i)
6195 if(typeof(config.lgHeader) != 'undefined'){
6196 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6199 if(typeof(config.mdHeader) != 'undefined'){
6200 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6203 if(typeof(config.smHeader) != 'undefined'){
6204 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6207 if(typeof(config.xsHeader) != 'undefined'){
6208 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6215 if(typeof(config.tooltip) != 'undefined'){
6216 c.tooltip = config.tooltip;
6219 if(typeof(config.colspan) != 'undefined'){
6220 c.colspan = config.colspan;
6223 if(typeof(config.hidden) != 'undefined' && config.hidden){
6224 c.style += ' display:none;';
6227 if(typeof(config.dataIndex) != 'undefined'){
6228 c.sort = config.dataIndex;
6231 if(typeof(config.sortable) != 'undefined' && config.sortable){
6235 if(typeof(config.align) != 'undefined' && config.align.length){
6236 c.style += ' text-align:' + config.align + ';';
6239 if(typeof(config.width) != 'undefined'){
6240 c.style += ' width:' + config.width + 'px;';
6243 if(typeof(config.cls) != 'undefined'){
6244 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6247 ['xs','sm','md','lg'].map(function(size){
6249 if(typeof(config[size]) == 'undefined'){
6253 if (!config[size]) { // 0 = hidden
6254 c.cls += ' hidden-' + size;
6258 c.cls += ' col-' + size + '-' + config[size];
6268 renderBody : function()
6278 colspan : this.cm.getColumnCount()
6288 renderFooter : function()
6298 colspan : this.cm.getColumnCount()
6312 // Roo.log('ds onload');
6317 var ds = this.store;
6319 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6320 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
6321 if (_this.store.sortInfo) {
6323 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6324 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
6327 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6328 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
6333 var tbody = this.mainBody;
6335 if(ds.getCount() > 0){
6336 ds.data.each(function(d,rowIndex){
6337 var row = this.renderRow(cm, ds, rowIndex);
6339 tbody.createChild(row);
6343 if(row.cellObjects.length){
6344 Roo.each(row.cellObjects, function(r){
6345 _this.renderCellObject(r);
6352 Roo.each(this.el.select('tbody td', true).elements, function(e){
6353 e.on('mouseover', _this.onMouseover, _this);
6356 Roo.each(this.el.select('tbody td', true).elements, function(e){
6357 e.on('mouseout', _this.onMouseout, _this);
6359 this.fireEvent('rowsrendered', this);
6360 //if(this.loadMask){
6361 // this.maskEl.hide();
6366 onUpdate : function(ds,record)
6368 this.refreshRow(record);
6371 onRemove : function(ds, record, index, isUpdate){
6372 if(isUpdate !== true){
6373 this.fireEvent("beforerowremoved", this, index, record);
6375 var bt = this.mainBody.dom;
6377 var rows = this.el.select('tbody > tr', true).elements;
6379 if(typeof(rows[index]) != 'undefined'){
6380 bt.removeChild(rows[index].dom);
6383 // if(bt.rows[index]){
6384 // bt.removeChild(bt.rows[index]);
6387 if(isUpdate !== true){
6388 //this.stripeRows(index);
6389 //this.syncRowHeights(index, index);
6391 this.fireEvent("rowremoved", this, index, record);
6395 onAdd : function(ds, records, rowIndex)
6397 //Roo.log('on Add called');
6398 // - note this does not handle multiple adding very well..
6399 var bt = this.mainBody.dom;
6400 for (var i =0 ; i < records.length;i++) {
6401 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6402 //Roo.log(records[i]);
6403 //Roo.log(this.store.getAt(rowIndex+i));
6404 this.insertRow(this.store, rowIndex + i, false);
6411 refreshRow : function(record){
6412 var ds = this.store, index;
6413 if(typeof record == 'number'){
6415 record = ds.getAt(index);
6417 index = ds.indexOf(record);
6419 this.insertRow(ds, index, true);
6420 this.onRemove(ds, record, index+1, true);
6421 //this.syncRowHeights(index, index);
6423 this.fireEvent("rowupdated", this, index, record);
6426 insertRow : function(dm, rowIndex, isUpdate){
6429 this.fireEvent("beforerowsinserted", this, rowIndex);
6431 //var s = this.getScrollState();
6432 var row = this.renderRow(this.cm, this.store, rowIndex);
6433 // insert before rowIndex..
6434 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6438 if(row.cellObjects.length){
6439 Roo.each(row.cellObjects, function(r){
6440 _this.renderCellObject(r);
6445 this.fireEvent("rowsinserted", this, rowIndex);
6446 //this.syncRowHeights(firstRow, lastRow);
6447 //this.stripeRows(firstRow);
6454 getRowDom : function(rowIndex)
6456 var rows = this.el.select('tbody > tr', true).elements;
6458 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6461 // returns the object tree for a tr..
6464 renderRow : function(cm, ds, rowIndex)
6467 var d = ds.getAt(rowIndex);
6474 var cellObjects = [];
6476 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6477 var config = cm.config[i];
6479 var renderer = cm.getRenderer(i);
6483 if(typeof(renderer) !== 'undefined'){
6484 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6486 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6487 // and are rendered into the cells after the row is rendered - using the id for the element.
6489 if(typeof(value) === 'object'){
6499 rowIndex : rowIndex,
6504 this.fireEvent('rowclass', this, rowcfg);
6508 cls : rowcfg.rowClass,
6510 html: (typeof(value) === 'object') ? '' : value
6517 if(typeof(config.colspan) != 'undefined'){
6518 td.colspan = config.colspan;
6521 if(typeof(config.hidden) != 'undefined' && config.hidden){
6522 td.style += ' display:none;';
6525 if(typeof(config.align) != 'undefined' && config.align.length){
6526 td.style += ' text-align:' + config.align + ';';
6529 if(typeof(config.width) != 'undefined'){
6530 td.style += ' width:' + config.width + 'px;';
6533 if(typeof(config.cursor) != 'undefined'){
6534 td.style += ' cursor:' + config.cursor + ';';
6537 if(typeof(config.cls) != 'undefined'){
6538 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6541 ['xs','sm','md','lg'].map(function(size){
6543 if(typeof(config[size]) == 'undefined'){
6547 if (!config[size]) { // 0 = hidden
6548 td.cls += ' hidden-' + size;
6552 td.cls += ' col-' + size + '-' + config[size];
6560 row.cellObjects = cellObjects;
6568 onBeforeLoad : function()
6570 //Roo.log('ds onBeforeLoad');
6574 //if(this.loadMask){
6575 // this.maskEl.show();
6583 this.el.select('tbody', true).first().dom.innerHTML = '';
6586 * Show or hide a row.
6587 * @param {Number} rowIndex to show or hide
6588 * @param {Boolean} state hide
6590 setRowVisibility : function(rowIndex, state)
6592 var bt = this.mainBody.dom;
6594 var rows = this.el.select('tbody > tr', true).elements;
6596 if(typeof(rows[rowIndex]) == 'undefined'){
6599 rows[rowIndex].dom.style.display = state ? '' : 'none';
6603 getSelectionModel : function(){
6605 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6607 return this.selModel;
6610 * Render the Roo.bootstrap object from renderder
6612 renderCellObject : function(r)
6616 var t = r.cfg.render(r.container);
6619 Roo.each(r.cfg.cn, function(c){
6621 container: t.getChildContainer(),
6624 _this.renderCellObject(child);
6629 getRowIndex : function(row)
6633 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6644 * Returns the grid's underlying element = used by panel.Grid
6645 * @return {Element} The element
6647 getGridEl : function(){
6648 return this.container;
6651 * Forces a resize - used by panel.Grid
6652 * @return {Element} The element
6654 autoSize : function(){
6655 return; // we doe not have a view in this design..
6658 if(this.view.adjustForScroll){
6659 this.view.adjustForScroll();
6675 * @class Roo.bootstrap.TableCell
6676 * @extends Roo.bootstrap.Component
6677 * Bootstrap TableCell class
6678 * @cfg {String} html cell contain text
6679 * @cfg {String} cls cell class
6680 * @cfg {String} tag cell tag (td|th) default td
6681 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6682 * @cfg {String} align Aligns the content in a cell
6683 * @cfg {String} axis Categorizes cells
6684 * @cfg {String} bgcolor Specifies the background color of a cell
6685 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6686 * @cfg {Number} colspan Specifies the number of columns a cell should span
6687 * @cfg {String} headers Specifies one or more header cells a cell is related to
6688 * @cfg {Number} height Sets the height of a cell
6689 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6690 * @cfg {Number} rowspan Sets the number of rows a cell should span
6691 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6692 * @cfg {String} valign Vertical aligns the content in a cell
6693 * @cfg {Number} width Specifies the width of a cell
6696 * Create a new TableCell
6697 * @param {Object} config The config object
6700 Roo.bootstrap.TableCell = function(config){
6701 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6704 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6724 getAutoCreate : function(){
6725 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6745 cfg.align=this.align
6751 cfg.bgcolor=this.bgcolor
6754 cfg.charoff=this.charoff
6757 cfg.colspan=this.colspan
6760 cfg.headers=this.headers
6763 cfg.height=this.height
6766 cfg.nowrap=this.nowrap
6769 cfg.rowspan=this.rowspan
6772 cfg.scope=this.scope
6775 cfg.valign=this.valign
6778 cfg.width=this.width
6797 * @class Roo.bootstrap.TableRow
6798 * @extends Roo.bootstrap.Component
6799 * Bootstrap TableRow class
6800 * @cfg {String} cls row class
6801 * @cfg {String} align Aligns the content in a table row
6802 * @cfg {String} bgcolor Specifies a background color for a table row
6803 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6804 * @cfg {String} valign Vertical aligns the content in a table row
6807 * Create a new TableRow
6808 * @param {Object} config The config object
6811 Roo.bootstrap.TableRow = function(config){
6812 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6815 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6823 getAutoCreate : function(){
6824 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6834 cfg.align = this.align;
6837 cfg.bgcolor = this.bgcolor;
6840 cfg.charoff = this.charoff;
6843 cfg.valign = this.valign;
6861 * @class Roo.bootstrap.TableBody
6862 * @extends Roo.bootstrap.Component
6863 * Bootstrap TableBody class
6864 * @cfg {String} cls element class
6865 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6866 * @cfg {String} align Aligns the content inside the element
6867 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6868 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6871 * Create a new TableBody
6872 * @param {Object} config The config object
6875 Roo.bootstrap.TableBody = function(config){
6876 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6879 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6887 getAutoCreate : function(){
6888 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6902 cfg.align = this.align;
6905 cfg.charoff = this.charoff;
6908 cfg.valign = this.valign;
6915 // initEvents : function()
6922 // this.store = Roo.factory(this.store, Roo.data);
6923 // this.store.on('load', this.onLoad, this);
6925 // this.store.load();
6929 // onLoad: function ()
6931 // this.fireEvent('load', this);
6941 * Ext JS Library 1.1.1
6942 * Copyright(c) 2006-2007, Ext JS, LLC.
6944 * Originally Released Under LGPL - original licence link has changed is not relivant.
6947 * <script type="text/javascript">
6950 // as we use this in bootstrap.
6951 Roo.namespace('Roo.form');
6953 * @class Roo.form.Action
6954 * Internal Class used to handle form actions
6956 * @param {Roo.form.BasicForm} el The form element or its id
6957 * @param {Object} config Configuration options
6962 // define the action interface
6963 Roo.form.Action = function(form, options){
6965 this.options = options || {};
6968 * Client Validation Failed
6971 Roo.form.Action.CLIENT_INVALID = 'client';
6973 * Server Validation Failed
6976 Roo.form.Action.SERVER_INVALID = 'server';
6978 * Connect to Server Failed
6981 Roo.form.Action.CONNECT_FAILURE = 'connect';
6983 * Reading Data from Server Failed
6986 Roo.form.Action.LOAD_FAILURE = 'load';
6988 Roo.form.Action.prototype = {
6990 failureType : undefined,
6991 response : undefined,
6995 run : function(options){
7000 success : function(response){
7005 handleResponse : function(response){
7009 // default connection failure
7010 failure : function(response){
7012 this.response = response;
7013 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7014 this.form.afterAction(this, false);
7017 processResponse : function(response){
7018 this.response = response;
7019 if(!response.responseText){
7022 this.result = this.handleResponse(response);
7026 // utility functions used internally
7027 getUrl : function(appendParams){
7028 var url = this.options.url || this.form.url || this.form.el.dom.action;
7030 var p = this.getParams();
7032 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7038 getMethod : function(){
7039 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7042 getParams : function(){
7043 var bp = this.form.baseParams;
7044 var p = this.options.params;
7046 if(typeof p == "object"){
7047 p = Roo.urlEncode(Roo.applyIf(p, bp));
7048 }else if(typeof p == 'string' && bp){
7049 p += '&' + Roo.urlEncode(bp);
7052 p = Roo.urlEncode(bp);
7057 createCallback : function(){
7059 success: this.success,
7060 failure: this.failure,
7062 timeout: (this.form.timeout*1000),
7063 upload: this.form.fileUpload ? this.success : undefined
7068 Roo.form.Action.Submit = function(form, options){
7069 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7072 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7075 haveProgress : false,
7076 uploadComplete : false,
7078 // uploadProgress indicator.
7079 uploadProgress : function()
7081 if (!this.form.progressUrl) {
7085 if (!this.haveProgress) {
7086 Roo.MessageBox.progress("Uploading", "Uploading");
7088 if (this.uploadComplete) {
7089 Roo.MessageBox.hide();
7093 this.haveProgress = true;
7095 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7097 var c = new Roo.data.Connection();
7099 url : this.form.progressUrl,
7104 success : function(req){
7105 //console.log(data);
7109 rdata = Roo.decode(req.responseText)
7111 Roo.log("Invalid data from server..");
7115 if (!rdata || !rdata.success) {
7117 Roo.MessageBox.alert(Roo.encode(rdata));
7120 var data = rdata.data;
7122 if (this.uploadComplete) {
7123 Roo.MessageBox.hide();
7128 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7129 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7132 this.uploadProgress.defer(2000,this);
7135 failure: function(data) {
7136 Roo.log('progress url failed ');
7147 // run get Values on the form, so it syncs any secondary forms.
7148 this.form.getValues();
7150 var o = this.options;
7151 var method = this.getMethod();
7152 var isPost = method == 'POST';
7153 if(o.clientValidation === false || this.form.isValid()){
7155 if (this.form.progressUrl) {
7156 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7157 (new Date() * 1) + '' + Math.random());
7162 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7163 form:this.form.el.dom,
7164 url:this.getUrl(!isPost),
7166 params:isPost ? this.getParams() : null,
7167 isUpload: this.form.fileUpload
7170 this.uploadProgress();
7172 }else if (o.clientValidation !== false){ // client validation failed
7173 this.failureType = Roo.form.Action.CLIENT_INVALID;
7174 this.form.afterAction(this, false);
7178 success : function(response)
7180 this.uploadComplete= true;
7181 if (this.haveProgress) {
7182 Roo.MessageBox.hide();
7186 var result = this.processResponse(response);
7187 if(result === true || result.success){
7188 this.form.afterAction(this, true);
7192 this.form.markInvalid(result.errors);
7193 this.failureType = Roo.form.Action.SERVER_INVALID;
7195 this.form.afterAction(this, false);
7197 failure : function(response)
7199 this.uploadComplete= true;
7200 if (this.haveProgress) {
7201 Roo.MessageBox.hide();
7204 this.response = response;
7205 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7206 this.form.afterAction(this, false);
7209 handleResponse : function(response){
7210 if(this.form.errorReader){
7211 var rs = this.form.errorReader.read(response);
7214 for(var i = 0, len = rs.records.length; i < len; i++) {
7215 var r = rs.records[i];
7219 if(errors.length < 1){
7223 success : rs.success,
7229 ret = Roo.decode(response.responseText);
7233 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7243 Roo.form.Action.Load = function(form, options){
7244 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7245 this.reader = this.form.reader;
7248 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7253 Roo.Ajax.request(Roo.apply(
7254 this.createCallback(), {
7255 method:this.getMethod(),
7256 url:this.getUrl(false),
7257 params:this.getParams()
7261 success : function(response){
7263 var result = this.processResponse(response);
7264 if(result === true || !result.success || !result.data){
7265 this.failureType = Roo.form.Action.LOAD_FAILURE;
7266 this.form.afterAction(this, false);
7269 this.form.clearInvalid();
7270 this.form.setValues(result.data);
7271 this.form.afterAction(this, true);
7274 handleResponse : function(response){
7275 if(this.form.reader){
7276 var rs = this.form.reader.read(response);
7277 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7279 success : rs.success,
7283 return Roo.decode(response.responseText);
7287 Roo.form.Action.ACTION_TYPES = {
7288 'load' : Roo.form.Action.Load,
7289 'submit' : Roo.form.Action.Submit
7298 * @class Roo.bootstrap.Form
7299 * @extends Roo.bootstrap.Component
7300 * Bootstrap Form class
7301 * @cfg {String} method GET | POST (default POST)
7302 * @cfg {String} labelAlign top | left (default top)
7303 * @cfg {String} align left | right - for navbars
7304 * @cfg {Boolean} loadMask load mask when submit (default true)
7309 * @param {Object} config The config object
7313 Roo.bootstrap.Form = function(config){
7314 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7317 * @event clientvalidation
7318 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7319 * @param {Form} this
7320 * @param {Boolean} valid true if the form has passed client-side validation
7322 clientvalidation: true,
7324 * @event beforeaction
7325 * Fires before any action is performed. Return false to cancel the action.
7326 * @param {Form} this
7327 * @param {Action} action The action to be performed
7331 * @event actionfailed
7332 * Fires when an action fails.
7333 * @param {Form} this
7334 * @param {Action} action The action that failed
7336 actionfailed : true,
7338 * @event actioncomplete
7339 * Fires when an action is completed.
7340 * @param {Form} this
7341 * @param {Action} action The action that completed
7343 actioncomplete : true
7348 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7351 * @cfg {String} method
7352 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7357 * The URL to use for form actions if one isn't supplied in the action options.
7360 * @cfg {Boolean} fileUpload
7361 * Set to true if this form is a file upload.
7365 * @cfg {Object} baseParams
7366 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7370 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7374 * @cfg {Sting} align (left|right) for navbar forms
7379 activeAction : null,
7382 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7383 * element by passing it or its id or mask the form itself by passing in true.
7386 waitMsgTarget : false,
7390 getAutoCreate : function(){
7394 method : this.method || 'POST',
7395 id : this.id || Roo.id(),
7398 if (this.parent().xtype.match(/^Nav/)) {
7399 cfg.cls = 'navbar-form navbar-' + this.align;
7403 if (this.labelAlign == 'left' ) {
7404 cfg.cls += ' form-horizontal';
7410 initEvents : function()
7412 this.el.on('submit', this.onSubmit, this);
7413 // this was added as random key presses on the form where triggering form submit.
7414 this.el.on('keypress', function(e) {
7415 if (e.getCharCode() != 13) {
7418 // we might need to allow it for textareas.. and some other items.
7419 // check e.getTarget().
7421 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7425 Roo.log("keypress blocked");
7433 onSubmit : function(e){
7438 * Returns true if client-side validation on the form is successful.
7441 isValid : function(){
7442 var items = this.getItems();
7444 items.each(function(f){
7453 * Returns true if any fields in this form have changed since their original load.
7456 isDirty : function(){
7458 var items = this.getItems();
7459 items.each(function(f){
7469 * Performs a predefined action (submit or load) or custom actions you define on this form.
7470 * @param {String} actionName The name of the action type
7471 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7472 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7473 * accept other config options):
7475 Property Type Description
7476 ---------------- --------------- ----------------------------------------------------------------------------------
7477 url String The url for the action (defaults to the form's url)
7478 method String The form method to use (defaults to the form's method, or POST if not defined)
7479 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7480 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7481 validate the form on the client (defaults to false)
7483 * @return {BasicForm} this
7485 doAction : function(action, options){
7486 if(typeof action == 'string'){
7487 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7489 if(this.fireEvent('beforeaction', this, action) !== false){
7490 this.beforeAction(action);
7491 action.run.defer(100, action);
7497 beforeAction : function(action){
7498 var o = action.options;
7501 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7503 // not really supported yet.. ??
7505 //if(this.waitMsgTarget === true){
7506 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7507 //}else if(this.waitMsgTarget){
7508 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7509 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7511 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7517 afterAction : function(action, success){
7518 this.activeAction = null;
7519 var o = action.options;
7521 //if(this.waitMsgTarget === true){
7523 //}else if(this.waitMsgTarget){
7524 // this.waitMsgTarget.unmask();
7526 // Roo.MessageBox.updateProgress(1);
7527 // Roo.MessageBox.hide();
7534 Roo.callback(o.success, o.scope, [this, action]);
7535 this.fireEvent('actioncomplete', this, action);
7539 // failure condition..
7540 // we have a scenario where updates need confirming.
7541 // eg. if a locking scenario exists..
7542 // we look for { errors : { needs_confirm : true }} in the response.
7544 (typeof(action.result) != 'undefined') &&
7545 (typeof(action.result.errors) != 'undefined') &&
7546 (typeof(action.result.errors.needs_confirm) != 'undefined')
7549 Roo.log("not supported yet");
7552 Roo.MessageBox.confirm(
7553 "Change requires confirmation",
7554 action.result.errorMsg,
7559 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7569 Roo.callback(o.failure, o.scope, [this, action]);
7570 // show an error message if no failed handler is set..
7571 if (!this.hasListener('actionfailed')) {
7572 Roo.log("need to add dialog support");
7574 Roo.MessageBox.alert("Error",
7575 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7576 action.result.errorMsg :
7577 "Saving Failed, please check your entries or try again"
7582 this.fireEvent('actionfailed', this, action);
7587 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7588 * @param {String} id The value to search for
7591 findField : function(id){
7592 var items = this.getItems();
7593 var field = items.get(id);
7595 items.each(function(f){
7596 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7603 return field || null;
7606 * Mark fields in this form invalid in bulk.
7607 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7608 * @return {BasicForm} this
7610 markInvalid : function(errors){
7611 if(errors instanceof Array){
7612 for(var i = 0, len = errors.length; i < len; i++){
7613 var fieldError = errors[i];
7614 var f = this.findField(fieldError.id);
7616 f.markInvalid(fieldError.msg);
7622 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7623 field.markInvalid(errors[id]);
7627 //Roo.each(this.childForms || [], function (f) {
7628 // f.markInvalid(errors);
7635 * Set values for fields in this form in bulk.
7636 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7637 * @return {BasicForm} this
7639 setValues : function(values){
7640 if(values instanceof Array){ // array of objects
7641 for(var i = 0, len = values.length; i < len; i++){
7643 var f = this.findField(v.id);
7645 f.setValue(v.value);
7646 if(this.trackResetOnLoad){
7647 f.originalValue = f.getValue();
7651 }else{ // object hash
7654 if(typeof values[id] != 'function' && (field = this.findField(id))){
7656 if (field.setFromData &&
7658 field.displayField &&
7659 // combos' with local stores can
7660 // be queried via setValue()
7661 // to set their value..
7662 (field.store && !field.store.isLocal)
7666 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7667 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7668 field.setFromData(sd);
7671 field.setValue(values[id]);
7675 if(this.trackResetOnLoad){
7676 field.originalValue = field.getValue();
7682 //Roo.each(this.childForms || [], function (f) {
7683 // f.setValues(values);
7690 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7691 * they are returned as an array.
7692 * @param {Boolean} asString
7695 getValues : function(asString){
7696 //if (this.childForms) {
7697 // copy values from the child forms
7698 // Roo.each(this.childForms, function (f) {
7699 // this.setValues(f.getValues());
7705 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7706 if(asString === true){
7709 return Roo.urlDecode(fs);
7713 * Returns the fields in this form as an object with key/value pairs.
7714 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7717 getFieldValues : function(with_hidden)
7719 var items = this.getItems();
7721 items.each(function(f){
7725 var v = f.getValue();
7726 if (f.inputType =='radio') {
7727 if (typeof(ret[f.getName()]) == 'undefined') {
7728 ret[f.getName()] = ''; // empty..
7731 if (!f.el.dom.checked) {
7739 // not sure if this supported any more..
7740 if ((typeof(v) == 'object') && f.getRawValue) {
7741 v = f.getRawValue() ; // dates..
7743 // combo boxes where name != hiddenName...
7744 if (f.name != f.getName()) {
7745 ret[f.name] = f.getRawValue();
7747 ret[f.getName()] = v;
7754 * Clears all invalid messages in this form.
7755 * @return {BasicForm} this
7757 clearInvalid : function(){
7758 var items = this.getItems();
7760 items.each(function(f){
7771 * @return {BasicForm} this
7774 var items = this.getItems();
7775 items.each(function(f){
7779 Roo.each(this.childForms || [], function (f) {
7786 getItems : function()
7788 var r=new Roo.util.MixedCollection(false, function(o){
7789 return o.id || (o.id = Roo.id());
7791 var iter = function(el) {
7798 Roo.each(el.items,function(e) {
7818 * Ext JS Library 1.1.1
7819 * Copyright(c) 2006-2007, Ext JS, LLC.
7821 * Originally Released Under LGPL - original licence link has changed is not relivant.
7824 * <script type="text/javascript">
7827 * @class Roo.form.VTypes
7828 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7831 Roo.form.VTypes = function(){
7832 // closure these in so they are only created once.
7833 var alpha = /^[a-zA-Z_]+$/;
7834 var alphanum = /^[a-zA-Z0-9_]+$/;
7835 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7836 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7838 // All these messages and functions are configurable
7841 * The function used to validate email addresses
7842 * @param {String} value The email address
7844 'email' : function(v){
7845 return email.test(v);
7848 * The error text to display when the email validation function returns false
7851 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7853 * The keystroke filter mask to be applied on email input
7856 'emailMask' : /[a-z0-9_\.\-@]/i,
7859 * The function used to validate URLs
7860 * @param {String} value The URL
7862 'url' : function(v){
7866 * The error text to display when the url validation function returns false
7869 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7872 * The function used to validate alpha values
7873 * @param {String} value The value
7875 'alpha' : function(v){
7876 return alpha.test(v);
7879 * The error text to display when the alpha validation function returns false
7882 'alphaText' : 'This field should only contain letters and _',
7884 * The keystroke filter mask to be applied on alpha input
7887 'alphaMask' : /[a-z_]/i,
7890 * The function used to validate alphanumeric values
7891 * @param {String} value The value
7893 'alphanum' : function(v){
7894 return alphanum.test(v);
7897 * The error text to display when the alphanumeric validation function returns false
7900 'alphanumText' : 'This field should only contain letters, numbers and _',
7902 * The keystroke filter mask to be applied on alphanumeric input
7905 'alphanumMask' : /[a-z0-9_]/i
7915 * @class Roo.bootstrap.Input
7916 * @extends Roo.bootstrap.Component
7917 * Bootstrap Input class
7918 * @cfg {Boolean} disabled is it disabled
7919 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7920 * @cfg {String} name name of the input
7921 * @cfg {string} fieldLabel - the label associated
7922 * @cfg {string} placeholder - placeholder to put in text.
7923 * @cfg {string} before - input group add on before
7924 * @cfg {string} after - input group add on after
7925 * @cfg {string} size - (lg|sm) or leave empty..
7926 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7927 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7928 * @cfg {Number} md colspan out of 12 for computer-sized screens
7929 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7930 * @cfg {string} value default value of the input
7931 * @cfg {Number} labelWidth set the width of label (0-12)
7932 * @cfg {String} labelAlign (top|left)
7933 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7934 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7936 * @cfg {String} align (left|center|right) Default left
7937 * @cfg {Boolean} forceFeedback (true|false) Default false
7943 * Create a new Input
7944 * @param {Object} config The config object
7947 Roo.bootstrap.Input = function(config){
7948 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7953 * Fires when this field receives input focus.
7954 * @param {Roo.form.Field} this
7959 * Fires when this field loses input focus.
7960 * @param {Roo.form.Field} this
7965 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7966 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7967 * @param {Roo.form.Field} this
7968 * @param {Roo.EventObject} e The event object
7973 * Fires just before the field blurs if the field value has changed.
7974 * @param {Roo.form.Field} this
7975 * @param {Mixed} newValue The new value
7976 * @param {Mixed} oldValue The original value
7981 * Fires after the field has been marked as invalid.
7982 * @param {Roo.form.Field} this
7983 * @param {String} msg The validation message
7988 * Fires after the field has been validated with no errors.
7989 * @param {Roo.form.Field} this
7994 * Fires after the key up
7995 * @param {Roo.form.Field} this
7996 * @param {Roo.EventObject} e The event Object
8002 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8004 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8005 automatic validation (defaults to "keyup").
8007 validationEvent : "keyup",
8009 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8011 validateOnBlur : true,
8013 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8015 validationDelay : 250,
8017 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8019 focusClass : "x-form-focus", // not needed???
8023 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8025 invalidClass : "has-warning",
8028 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8030 validClass : "has-success",
8033 * @cfg {Boolean} hasFeedback (true|false) default true
8038 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8040 invalidFeedbackClass : "glyphicon-warning-sign",
8043 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8045 validFeedbackClass : "glyphicon-ok",
8048 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8050 selectOnFocus : false,
8053 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8057 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8062 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8064 disableKeyFilter : false,
8067 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8071 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8075 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8077 blankText : "This field is required",
8080 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8084 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8086 maxLength : Number.MAX_VALUE,
8088 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8090 minLengthText : "The minimum length for this field is {0}",
8092 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8094 maxLengthText : "The maximum length for this field is {0}",
8098 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8099 * If available, this function will be called only after the basic validators all return true, and will be passed the
8100 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8104 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8105 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8106 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8110 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8114 autocomplete: false,
8133 formatedValue : false,
8134 forceFeedback : false,
8136 parentLabelAlign : function()
8139 while (parent.parent()) {
8140 parent = parent.parent();
8141 if (typeof(parent.labelAlign) !='undefined') {
8142 return parent.labelAlign;
8149 getAutoCreate : function(){
8151 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8157 if(this.inputType != 'hidden'){
8158 cfg.cls = 'form-group' //input-group
8164 type : this.inputType,
8166 cls : 'form-control',
8167 placeholder : this.placeholder || '',
8168 autocomplete : this.autocomplete || 'new-password'
8173 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8176 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8177 input.maxLength = this.maxLength;
8180 if (this.disabled) {
8181 input.disabled=true;
8184 if (this.readOnly) {
8185 input.readonly=true;
8189 input.name = this.name;
8192 input.cls += ' input-' + this.size;
8195 ['xs','sm','md','lg'].map(function(size){
8196 if (settings[size]) {
8197 cfg.cls += ' col-' + size + '-' + settings[size];
8201 var inputblock = input;
8205 cls: 'glyphicon form-control-feedback'
8208 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8211 cls : 'has-feedback',
8219 if (this.before || this.after) {
8222 cls : 'input-group',
8226 if (this.before && typeof(this.before) == 'string') {
8228 inputblock.cn.push({
8230 cls : 'roo-input-before input-group-addon',
8234 if (this.before && typeof(this.before) == 'object') {
8235 this.before = Roo.factory(this.before);
8237 inputblock.cn.push({
8239 cls : 'roo-input-before input-group-' +
8240 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8244 inputblock.cn.push(input);
8246 if (this.after && typeof(this.after) == 'string') {
8247 inputblock.cn.push({
8249 cls : 'roo-input-after input-group-addon',
8253 if (this.after && typeof(this.after) == 'object') {
8254 this.after = Roo.factory(this.after);
8256 inputblock.cn.push({
8258 cls : 'roo-input-after input-group-' +
8259 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8263 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8264 inputblock.cls += ' has-feedback';
8265 inputblock.cn.push(feedback);
8269 if (align ==='left' && this.fieldLabel.length) {
8276 cls : 'control-label col-sm-' + this.labelWidth,
8277 html : this.fieldLabel
8281 cls : "col-sm-" + (12 - this.labelWidth),
8288 } else if ( this.fieldLabel.length) {
8294 //cls : 'input-group-addon',
8295 html : this.fieldLabel
8314 if (this.parentType === 'Navbar' && this.parent().bar) {
8315 cfg.cls += ' navbar-form';
8322 * return the real input element.
8324 inputEl: function ()
8326 return this.el.select('input.form-control',true).first();
8329 tooltipEl : function()
8331 return this.inputEl();
8334 setDisabled : function(v)
8336 var i = this.inputEl().dom;
8338 i.removeAttribute('disabled');
8342 i.setAttribute('disabled','true');
8344 initEvents : function()
8347 this.inputEl().on("keydown" , this.fireKey, this);
8348 this.inputEl().on("focus", this.onFocus, this);
8349 this.inputEl().on("blur", this.onBlur, this);
8351 this.inputEl().relayEvent('keyup', this);
8353 // reference to original value for reset
8354 this.originalValue = this.getValue();
8355 //Roo.form.TextField.superclass.initEvents.call(this);
8356 if(this.validationEvent == 'keyup'){
8357 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8358 this.inputEl().on('keyup', this.filterValidation, this);
8360 else if(this.validationEvent !== false){
8361 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8364 if(this.selectOnFocus){
8365 this.on("focus", this.preFocus, this);
8368 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8369 this.inputEl().on("keypress", this.filterKeys, this);
8372 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8373 this.el.on("click", this.autoSize, this);
8376 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8377 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8380 if (typeof(this.before) == 'object') {
8381 this.before.render(this.el.select('.roo-input-before',true).first());
8383 if (typeof(this.after) == 'object') {
8384 this.after.render(this.el.select('.roo-input-after',true).first());
8389 filterValidation : function(e){
8390 if(!e.isNavKeyPress()){
8391 this.validationTask.delay(this.validationDelay);
8395 * Validates the field value
8396 * @return {Boolean} True if the value is valid, else false
8398 validate : function(){
8399 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8400 if(this.disabled || this.validateValue(this.getRawValue())){
8411 * Validates a value according to the field's validation rules and marks the field as invalid
8412 * if the validation fails
8413 * @param {Mixed} value The value to validate
8414 * @return {Boolean} True if the value is valid, else false
8416 validateValue : function(value){
8417 if(value.length < 1) { // if it's blank
8418 if(this.allowBlank){
8424 if(value.length < this.minLength){
8427 if(value.length > this.maxLength){
8431 var vt = Roo.form.VTypes;
8432 if(!vt[this.vtype](value, this)){
8436 if(typeof this.validator == "function"){
8437 var msg = this.validator(value);
8443 if(this.regex && !this.regex.test(value)){
8453 fireKey : function(e){
8454 //Roo.log('field ' + e.getKey());
8455 if(e.isNavKeyPress()){
8456 this.fireEvent("specialkey", this, e);
8459 focus : function (selectText){
8461 this.inputEl().focus();
8462 if(selectText === true){
8463 this.inputEl().dom.select();
8469 onFocus : function(){
8470 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8471 // this.el.addClass(this.focusClass);
8474 this.hasFocus = true;
8475 this.startValue = this.getValue();
8476 this.fireEvent("focus", this);
8480 beforeBlur : Roo.emptyFn,
8484 onBlur : function(){
8486 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8487 //this.el.removeClass(this.focusClass);
8489 this.hasFocus = false;
8490 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8493 var v = this.getValue();
8494 if(String(v) !== String(this.startValue)){
8495 this.fireEvent('change', this, v, this.startValue);
8497 this.fireEvent("blur", this);
8501 * Resets the current field value to the originally loaded value and clears any validation messages
8504 this.setValue(this.originalValue);
8508 * Returns the name of the field
8509 * @return {Mixed} name The name field
8511 getName: function(){
8515 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8516 * @return {Mixed} value The field value
8518 getValue : function(){
8520 var v = this.inputEl().getValue();
8525 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8526 * @return {Mixed} value The field value
8528 getRawValue : function(){
8529 var v = this.inputEl().getValue();
8535 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8536 * @param {Mixed} value The value to set
8538 setRawValue : function(v){
8539 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8542 selectText : function(start, end){
8543 var v = this.getRawValue();
8545 start = start === undefined ? 0 : start;
8546 end = end === undefined ? v.length : end;
8547 var d = this.inputEl().dom;
8548 if(d.setSelectionRange){
8549 d.setSelectionRange(start, end);
8550 }else if(d.createTextRange){
8551 var range = d.createTextRange();
8552 range.moveStart("character", start);
8553 range.moveEnd("character", v.length-end);
8560 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8561 * @param {Mixed} value The value to set
8563 setValue : function(v){
8566 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8572 processValue : function(value){
8573 if(this.stripCharsRe){
8574 var newValue = value.replace(this.stripCharsRe, '');
8575 if(newValue !== value){
8576 this.setRawValue(newValue);
8583 preFocus : function(){
8585 if(this.selectOnFocus){
8586 this.inputEl().dom.select();
8589 filterKeys : function(e){
8591 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8594 var c = e.getCharCode(), cc = String.fromCharCode(c);
8595 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8598 if(!this.maskRe.test(cc)){
8603 * Clear any invalid styles/messages for this field
8605 clearInvalid : function(){
8607 if(!this.el || this.preventMark){ // not rendered
8611 var label = this.el.select('label', true).first();
8612 var icon = this.el.select('i.fa-star', true).first();
8618 this.el.removeClass(this.invalidClass);
8620 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8622 var feedback = this.el.select('.form-control-feedback', true).first();
8625 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8630 this.fireEvent('valid', this);
8634 * Mark this field as valid
8636 markValid : function()
8638 if(!this.el || this.preventMark){ // not rendered
8642 this.el.removeClass([this.invalidClass, this.validClass]);
8644 var feedback = this.el.select('.form-control-feedback', true).first();
8647 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8650 if(this.disabled || this.allowBlank){
8654 var formGroup = this.el.findParent('.form-group', false, true);
8658 var label = formGroup.select('label', true).first();
8659 var icon = formGroup.select('i.fa-star', true).first();
8666 this.el.addClass(this.validClass);
8668 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8670 var feedback = this.el.select('.form-control-feedback', true).first();
8673 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8674 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8679 this.fireEvent('valid', this);
8683 * Mark this field as invalid
8684 * @param {String} msg The validation message
8686 markInvalid : function(msg)
8688 if(!this.el || this.preventMark){ // not rendered
8692 this.el.removeClass([this.invalidClass, this.validClass]);
8694 var feedback = this.el.select('.form-control-feedback', true).first();
8697 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8700 if(this.disabled || this.allowBlank){
8704 var formGroup = this.el.findParent('.form-group', false, true);
8707 var label = formGroup.select('label', true).first();
8708 var icon = formGroup.select('i.fa-star', true).first();
8710 if(!this.getValue().length && label && !icon){
8711 this.el.findParent('.form-group', false, true).createChild({
8713 cls : 'text-danger fa fa-lg fa-star',
8714 tooltip : 'This field is required',
8715 style : 'margin-right:5px;'
8721 this.el.addClass(this.invalidClass);
8723 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8725 var feedback = this.el.select('.form-control-feedback', true).first();
8728 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8730 if(this.getValue().length || this.forceFeedback){
8731 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8738 this.fireEvent('invalid', this, msg);
8741 SafariOnKeyDown : function(event)
8743 // this is a workaround for a password hang bug on chrome/ webkit.
8745 var isSelectAll = false;
8747 if(this.inputEl().dom.selectionEnd > 0){
8748 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8750 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8751 event.preventDefault();
8756 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8758 event.preventDefault();
8759 // this is very hacky as keydown always get's upper case.
8761 var cc = String.fromCharCode(event.getCharCode());
8762 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8766 adjustWidth : function(tag, w){
8767 tag = tag.toLowerCase();
8768 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8769 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8773 if(tag == 'textarea'){
8776 }else if(Roo.isOpera){
8780 if(tag == 'textarea'){
8799 * @class Roo.bootstrap.TextArea
8800 * @extends Roo.bootstrap.Input
8801 * Bootstrap TextArea class
8802 * @cfg {Number} cols Specifies the visible width of a text area
8803 * @cfg {Number} rows Specifies the visible number of lines in a text area
8804 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8805 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8806 * @cfg {string} html text
8809 * Create a new TextArea
8810 * @param {Object} config The config object
8813 Roo.bootstrap.TextArea = function(config){
8814 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8818 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8828 getAutoCreate : function(){
8830 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8841 value : this.value || '',
8842 html: this.html || '',
8843 cls : 'form-control',
8844 placeholder : this.placeholder || ''
8848 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8849 input.maxLength = this.maxLength;
8853 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8857 input.cols = this.cols;
8860 if (this.readOnly) {
8861 input.readonly = true;
8865 input.name = this.name;
8869 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8873 ['xs','sm','md','lg'].map(function(size){
8874 if (settings[size]) {
8875 cfg.cls += ' col-' + size + '-' + settings[size];
8879 var inputblock = input;
8881 if(this.hasFeedback && !this.allowBlank){
8885 cls: 'glyphicon form-control-feedback'
8889 cls : 'has-feedback',
8898 if (this.before || this.after) {
8901 cls : 'input-group',
8905 inputblock.cn.push({
8907 cls : 'input-group-addon',
8912 inputblock.cn.push(input);
8914 if(this.hasFeedback && !this.allowBlank){
8915 inputblock.cls += ' has-feedback';
8916 inputblock.cn.push(feedback);
8920 inputblock.cn.push({
8922 cls : 'input-group-addon',
8929 if (align ==='left' && this.fieldLabel.length) {
8930 // Roo.log("left and has label");
8936 cls : 'control-label col-sm-' + this.labelWidth,
8937 html : this.fieldLabel
8941 cls : "col-sm-" + (12 - this.labelWidth),
8948 } else if ( this.fieldLabel.length) {
8949 // Roo.log(" label");
8954 //cls : 'input-group-addon',
8955 html : this.fieldLabel
8965 // Roo.log(" no label && no align");
8975 if (this.disabled) {
8976 input.disabled=true;
8983 * return the real textarea element.
8985 inputEl: function ()
8987 return this.el.select('textarea.form-control',true).first();
8991 * Clear any invalid styles/messages for this field
8993 clearInvalid : function()
8996 if(!this.el || this.preventMark){ // not rendered
9000 var label = this.el.select('label', true).first();
9001 var icon = this.el.select('i.fa-star', true).first();
9007 this.el.removeClass(this.invalidClass);
9009 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9011 var feedback = this.el.select('.form-control-feedback', true).first();
9014 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9019 this.fireEvent('valid', this);
9023 * Mark this field as valid
9025 markValid : function()
9027 if(!this.el || this.preventMark){ // not rendered
9031 this.el.removeClass([this.invalidClass, this.validClass]);
9033 var feedback = this.el.select('.form-control-feedback', true).first();
9036 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9039 if(this.disabled || this.allowBlank){
9043 var label = this.el.select('label', true).first();
9044 var icon = this.el.select('i.fa-star', true).first();
9050 this.el.addClass(this.validClass);
9052 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9054 var feedback = this.el.select('.form-control-feedback', true).first();
9057 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9058 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9063 this.fireEvent('valid', this);
9067 * Mark this field as invalid
9068 * @param {String} msg The validation message
9070 markInvalid : function(msg)
9072 if(!this.el || this.preventMark){ // not rendered
9076 this.el.removeClass([this.invalidClass, this.validClass]);
9078 var feedback = this.el.select('.form-control-feedback', true).first();
9081 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9084 if(this.disabled || this.allowBlank){
9088 var label = this.el.select('label', true).first();
9089 var icon = this.el.select('i.fa-star', true).first();
9091 if(!this.getValue().length && label && !icon){
9092 this.el.createChild({
9094 cls : 'text-danger fa fa-lg fa-star',
9095 tooltip : 'This field is required',
9096 style : 'margin-right:5px;'
9100 this.el.addClass(this.invalidClass);
9102 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9104 var feedback = this.el.select('.form-control-feedback', true).first();
9107 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9109 if(this.getValue().length || this.forceFeedback){
9110 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9117 this.fireEvent('invalid', this, msg);
9125 * trigger field - base class for combo..
9130 * @class Roo.bootstrap.TriggerField
9131 * @extends Roo.bootstrap.Input
9132 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9133 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9134 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9135 * for which you can provide a custom implementation. For example:
9137 var trigger = new Roo.bootstrap.TriggerField();
9138 trigger.onTriggerClick = myTriggerFn;
9139 trigger.applyTo('my-field');
9142 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9143 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9144 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9145 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9146 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9149 * Create a new TriggerField.
9150 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9151 * to the base TextField)
9153 Roo.bootstrap.TriggerField = function(config){
9154 this.mimicing = false;
9155 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9158 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9160 * @cfg {String} triggerClass A CSS class to apply to the trigger
9163 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9168 * @cfg {Boolean} removable (true|false) special filter default false
9172 /** @cfg {Boolean} grow @hide */
9173 /** @cfg {Number} growMin @hide */
9174 /** @cfg {Number} growMax @hide */
9180 autoSize: Roo.emptyFn,
9187 actionMode : 'wrap',
9192 getAutoCreate : function(){
9194 var align = this.labelAlign || this.parentLabelAlign();
9199 cls: 'form-group' //input-group
9206 type : this.inputType,
9207 cls : 'form-control',
9208 autocomplete: 'new-password',
9209 placeholder : this.placeholder || ''
9213 input.name = this.name;
9216 input.cls += ' input-' + this.size;
9219 if (this.disabled) {
9220 input.disabled=true;
9223 var inputblock = input;
9225 if(this.hasFeedback && !this.allowBlank){
9229 cls: 'glyphicon form-control-feedback'
9232 if(this.removable && !this.editable && !this.tickable){
9234 cls : 'has-feedback',
9240 cls : 'roo-combo-removable-btn close'
9247 cls : 'has-feedback',
9256 if(this.removable && !this.editable && !this.tickable){
9258 cls : 'roo-removable',
9264 cls : 'roo-combo-removable-btn close'
9271 if (this.before || this.after) {
9274 cls : 'input-group',
9278 inputblock.cn.push({
9280 cls : 'input-group-addon',
9285 inputblock.cn.push(input);
9287 if(this.hasFeedback && !this.allowBlank){
9288 inputblock.cls += ' has-feedback';
9289 inputblock.cn.push(feedback);
9293 inputblock.cn.push({
9295 cls : 'input-group-addon',
9308 cls: 'form-hidden-field'
9322 cls: 'form-hidden-field'
9326 cls: 'roo-select2-choices',
9330 cls: 'roo-select2-search-field',
9343 cls: 'roo-select2-container input-group',
9348 // cls: 'typeahead typeahead-long dropdown-menu',
9349 // style: 'display:none'
9354 if(!this.multiple && this.showToggleBtn){
9360 if (this.caret != false) {
9363 cls: 'fa fa-' + this.caret
9370 cls : 'input-group-addon btn dropdown-toggle',
9375 cls: 'combobox-clear',
9389 combobox.cls += ' roo-select2-container-multi';
9392 if (align ==='left' && this.fieldLabel.length) {
9394 // Roo.log("left and has label");
9400 cls : 'control-label col-sm-' + this.labelWidth,
9401 html : this.fieldLabel
9405 cls : "col-sm-" + (12 - this.labelWidth),
9412 } else if ( this.fieldLabel.length) {
9413 // Roo.log(" label");
9418 //cls : 'input-group-addon',
9419 html : this.fieldLabel
9429 // Roo.log(" no label && no align");
9436 ['xs','sm','md','lg'].map(function(size){
9437 if (settings[size]) {
9438 cfg.cls += ' col-' + size + '-' + settings[size];
9449 onResize : function(w, h){
9450 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9451 // if(typeof w == 'number'){
9452 // var x = w - this.trigger.getWidth();
9453 // this.inputEl().setWidth(this.adjustWidth('input', x));
9454 // this.trigger.setStyle('left', x+'px');
9459 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9462 getResizeEl : function(){
9463 return this.inputEl();
9467 getPositionEl : function(){
9468 return this.inputEl();
9472 alignErrorIcon : function(){
9473 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9477 initEvents : function(){
9481 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9482 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9483 if(!this.multiple && this.showToggleBtn){
9484 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9485 if(this.hideTrigger){
9486 this.trigger.setDisplayed(false);
9488 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9492 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9495 if(this.removable && !this.editable && !this.tickable){
9496 var close = this.closeTriggerEl();
9499 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9500 close.on('click', this.removeBtnClick, this, close);
9504 //this.trigger.addClassOnOver('x-form-trigger-over');
9505 //this.trigger.addClassOnClick('x-form-trigger-click');
9508 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9512 closeTriggerEl : function()
9514 var close = this.el.select('.roo-combo-removable-btn', true).first();
9515 return close ? close : false;
9518 removeBtnClick : function(e, h, el)
9522 if(this.fireEvent("remove", this) !== false){
9524 this.fireEvent("afterremove", this)
9528 createList : function()
9530 this.list = Roo.get(document.body).createChild({
9532 cls: 'typeahead typeahead-long dropdown-menu',
9533 style: 'display:none'
9536 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9541 initTrigger : function(){
9546 onDestroy : function(){
9548 this.trigger.removeAllListeners();
9549 // this.trigger.remove();
9552 // this.wrap.remove();
9554 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9558 onFocus : function(){
9559 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9562 this.wrap.addClass('x-trigger-wrap-focus');
9563 this.mimicing = true;
9564 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9565 if(this.monitorTab){
9566 this.el.on("keydown", this.checkTab, this);
9573 checkTab : function(e){
9574 if(e.getKey() == e.TAB){
9580 onBlur : function(){
9585 mimicBlur : function(e, t){
9587 if(!this.wrap.contains(t) && this.validateBlur()){
9594 triggerBlur : function(){
9595 this.mimicing = false;
9596 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9597 if(this.monitorTab){
9598 this.el.un("keydown", this.checkTab, this);
9600 //this.wrap.removeClass('x-trigger-wrap-focus');
9601 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9605 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9606 validateBlur : function(e, t){
9611 onDisable : function(){
9612 this.inputEl().dom.disabled = true;
9613 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9615 // this.wrap.addClass('x-item-disabled');
9620 onEnable : function(){
9621 this.inputEl().dom.disabled = false;
9622 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9624 // this.el.removeClass('x-item-disabled');
9629 onShow : function(){
9630 var ae = this.getActionEl();
9633 ae.dom.style.display = '';
9634 ae.dom.style.visibility = 'visible';
9640 onHide : function(){
9641 var ae = this.getActionEl();
9642 ae.dom.style.display = 'none';
9646 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9647 * by an implementing function.
9649 * @param {EventObject} e
9651 onTriggerClick : Roo.emptyFn
9655 * Ext JS Library 1.1.1
9656 * Copyright(c) 2006-2007, Ext JS, LLC.
9658 * Originally Released Under LGPL - original licence link has changed is not relivant.
9661 * <script type="text/javascript">
9666 * @class Roo.data.SortTypes
9668 * Defines the default sorting (casting?) comparison functions used when sorting data.
9670 Roo.data.SortTypes = {
9672 * Default sort that does nothing
9673 * @param {Mixed} s The value being converted
9674 * @return {Mixed} The comparison value
9681 * The regular expression used to strip tags
9685 stripTagsRE : /<\/?[^>]+>/gi,
9688 * Strips all HTML tags to sort on text only
9689 * @param {Mixed} s The value being converted
9690 * @return {String} The comparison value
9692 asText : function(s){
9693 return String(s).replace(this.stripTagsRE, "");
9697 * Strips all HTML tags to sort on text only - Case insensitive
9698 * @param {Mixed} s The value being converted
9699 * @return {String} The comparison value
9701 asUCText : function(s){
9702 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9706 * Case insensitive string
9707 * @param {Mixed} s The value being converted
9708 * @return {String} The comparison value
9710 asUCString : function(s) {
9711 return String(s).toUpperCase();
9716 * @param {Mixed} s The value being converted
9717 * @return {Number} The comparison value
9719 asDate : function(s) {
9723 if(s instanceof Date){
9726 return Date.parse(String(s));
9731 * @param {Mixed} s The value being converted
9732 * @return {Float} The comparison value
9734 asFloat : function(s) {
9735 var val = parseFloat(String(s).replace(/,/g, ""));
9744 * @param {Mixed} s The value being converted
9745 * @return {Number} The comparison value
9747 asInt : function(s) {
9748 var val = parseInt(String(s).replace(/,/g, ""));
9756 * Ext JS Library 1.1.1
9757 * Copyright(c) 2006-2007, Ext JS, LLC.
9759 * Originally Released Under LGPL - original licence link has changed is not relivant.
9762 * <script type="text/javascript">
9766 * @class Roo.data.Record
9767 * Instances of this class encapsulate both record <em>definition</em> information, and record
9768 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9769 * to access Records cached in an {@link Roo.data.Store} object.<br>
9771 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9772 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9775 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9777 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9778 * {@link #create}. The parameters are the same.
9779 * @param {Array} data An associative Array of data values keyed by the field name.
9780 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9781 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9782 * not specified an integer id is generated.
9784 Roo.data.Record = function(data, id){
9785 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9790 * Generate a constructor for a specific record layout.
9791 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9792 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9793 * Each field definition object may contain the following properties: <ul>
9794 * <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,
9795 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9796 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9797 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9798 * is being used, then this is a string containing the javascript expression to reference the data relative to
9799 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9800 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9801 * this may be omitted.</p></li>
9802 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9803 * <ul><li>auto (Default, implies no conversion)</li>
9808 * <li>date</li></ul></p></li>
9809 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9810 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9811 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9812 * by the Reader into an object that will be stored in the Record. It is passed the
9813 * following parameters:<ul>
9814 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9816 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9818 * <br>usage:<br><pre><code>
9819 var TopicRecord = Roo.data.Record.create(
9820 {name: 'title', mapping: 'topic_title'},
9821 {name: 'author', mapping: 'username'},
9822 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9823 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9824 {name: 'lastPoster', mapping: 'user2'},
9825 {name: 'excerpt', mapping: 'post_text'}
9828 var myNewRecord = new TopicRecord({
9829 title: 'Do my job please',
9832 lastPost: new Date(),
9833 lastPoster: 'Animal',
9834 excerpt: 'No way dude!'
9836 myStore.add(myNewRecord);
9841 Roo.data.Record.create = function(o){
9843 f.superclass.constructor.apply(this, arguments);
9845 Roo.extend(f, Roo.data.Record);
9846 var p = f.prototype;
9847 p.fields = new Roo.util.MixedCollection(false, function(field){
9850 for(var i = 0, len = o.length; i < len; i++){
9851 p.fields.add(new Roo.data.Field(o[i]));
9853 f.getField = function(name){
9854 return p.fields.get(name);
9859 Roo.data.Record.AUTO_ID = 1000;
9860 Roo.data.Record.EDIT = 'edit';
9861 Roo.data.Record.REJECT = 'reject';
9862 Roo.data.Record.COMMIT = 'commit';
9864 Roo.data.Record.prototype = {
9866 * Readonly flag - true if this record has been modified.
9875 join : function(store){
9880 * Set the named field to the specified value.
9881 * @param {String} name The name of the field to set.
9882 * @param {Object} value The value to set the field to.
9884 set : function(name, value){
9885 if(this.data[name] == value){
9892 if(typeof this.modified[name] == 'undefined'){
9893 this.modified[name] = this.data[name];
9895 this.data[name] = value;
9896 if(!this.editing && this.store){
9897 this.store.afterEdit(this);
9902 * Get the value of the named field.
9903 * @param {String} name The name of the field to get the value of.
9904 * @return {Object} The value of the field.
9906 get : function(name){
9907 return this.data[name];
9911 beginEdit : function(){
9912 this.editing = true;
9917 cancelEdit : function(){
9918 this.editing = false;
9919 delete this.modified;
9923 endEdit : function(){
9924 this.editing = false;
9925 if(this.dirty && this.store){
9926 this.store.afterEdit(this);
9931 * Usually called by the {@link Roo.data.Store} which owns the Record.
9932 * Rejects all changes made to the Record since either creation, or the last commit operation.
9933 * Modified fields are reverted to their original values.
9935 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9936 * of reject operations.
9938 reject : function(){
9939 var m = this.modified;
9941 if(typeof m[n] != "function"){
9942 this.data[n] = m[n];
9946 delete this.modified;
9947 this.editing = false;
9949 this.store.afterReject(this);
9954 * Usually called by the {@link Roo.data.Store} which owns the Record.
9955 * Commits all changes made to the Record since either creation, or the last commit operation.
9957 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9958 * of commit operations.
9960 commit : function(){
9962 delete this.modified;
9963 this.editing = false;
9965 this.store.afterCommit(this);
9970 hasError : function(){
9971 return this.error != null;
9975 clearError : function(){
9980 * Creates a copy of this record.
9981 * @param {String} id (optional) A new record id if you don't want to use this record's id
9984 copy : function(newId) {
9985 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9989 * Ext JS Library 1.1.1
9990 * Copyright(c) 2006-2007, Ext JS, LLC.
9992 * Originally Released Under LGPL - original licence link has changed is not relivant.
9995 * <script type="text/javascript">
10001 * @class Roo.data.Store
10002 * @extends Roo.util.Observable
10003 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10004 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10006 * 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
10007 * has no knowledge of the format of the data returned by the Proxy.<br>
10009 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10010 * instances from the data object. These records are cached and made available through accessor functions.
10012 * Creates a new Store.
10013 * @param {Object} config A config object containing the objects needed for the Store to access data,
10014 * and read the data into Records.
10016 Roo.data.Store = function(config){
10017 this.data = new Roo.util.MixedCollection(false);
10018 this.data.getKey = function(o){
10021 this.baseParams = {};
10023 this.paramNames = {
10028 "multisort" : "_multisort"
10031 if(config && config.data){
10032 this.inlineData = config.data;
10033 delete config.data;
10036 Roo.apply(this, config);
10038 if(this.reader){ // reader passed
10039 this.reader = Roo.factory(this.reader, Roo.data);
10040 this.reader.xmodule = this.xmodule || false;
10041 if(!this.recordType){
10042 this.recordType = this.reader.recordType;
10044 if(this.reader.onMetaChange){
10045 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10049 if(this.recordType){
10050 this.fields = this.recordType.prototype.fields;
10052 this.modified = [];
10056 * @event datachanged
10057 * Fires when the data cache has changed, and a widget which is using this Store
10058 * as a Record cache should refresh its view.
10059 * @param {Store} this
10061 datachanged : true,
10063 * @event metachange
10064 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10065 * @param {Store} this
10066 * @param {Object} meta The JSON metadata
10071 * Fires when Records have been added to the Store
10072 * @param {Store} this
10073 * @param {Roo.data.Record[]} records The array of Records added
10074 * @param {Number} index The index at which the record(s) were added
10079 * Fires when a Record has been removed from the Store
10080 * @param {Store} this
10081 * @param {Roo.data.Record} record The Record that was removed
10082 * @param {Number} index The index at which the record was removed
10087 * Fires when a Record has been updated
10088 * @param {Store} this
10089 * @param {Roo.data.Record} record The Record that was updated
10090 * @param {String} operation The update operation being performed. Value may be one of:
10092 Roo.data.Record.EDIT
10093 Roo.data.Record.REJECT
10094 Roo.data.Record.COMMIT
10100 * Fires when the data cache has been cleared.
10101 * @param {Store} this
10105 * @event beforeload
10106 * Fires before a request is made for a new data object. If the beforeload handler returns false
10107 * the load action will be canceled.
10108 * @param {Store} this
10109 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10113 * @event beforeloadadd
10114 * Fires after a new set of Records has been loaded.
10115 * @param {Store} this
10116 * @param {Roo.data.Record[]} records The Records that were loaded
10117 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10119 beforeloadadd : true,
10122 * Fires after a new set of Records has been loaded, before they are added to the store.
10123 * @param {Store} this
10124 * @param {Roo.data.Record[]} records The Records that were loaded
10125 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10126 * @params {Object} return from reader
10130 * @event loadexception
10131 * Fires if an exception occurs in the Proxy during loading.
10132 * Called with the signature of the Proxy's "loadexception" event.
10133 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10136 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10137 * @param {Object} load options
10138 * @param {Object} jsonData from your request (normally this contains the Exception)
10140 loadexception : true
10144 this.proxy = Roo.factory(this.proxy, Roo.data);
10145 this.proxy.xmodule = this.xmodule || false;
10146 this.relayEvents(this.proxy, ["loadexception"]);
10148 this.sortToggle = {};
10149 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10151 Roo.data.Store.superclass.constructor.call(this);
10153 if(this.inlineData){
10154 this.loadData(this.inlineData);
10155 delete this.inlineData;
10159 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10161 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10162 * without a remote query - used by combo/forms at present.
10166 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10169 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10172 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10173 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10176 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10177 * on any HTTP request
10180 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10183 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10187 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10188 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10190 remoteSort : false,
10193 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10194 * loaded or when a record is removed. (defaults to false).
10196 pruneModifiedRecords : false,
10199 lastOptions : null,
10202 * Add Records to the Store and fires the add event.
10203 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10205 add : function(records){
10206 records = [].concat(records);
10207 for(var i = 0, len = records.length; i < len; i++){
10208 records[i].join(this);
10210 var index = this.data.length;
10211 this.data.addAll(records);
10212 this.fireEvent("add", this, records, index);
10216 * Remove a Record from the Store and fires the remove event.
10217 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10219 remove : function(record){
10220 var index = this.data.indexOf(record);
10221 this.data.removeAt(index);
10222 if(this.pruneModifiedRecords){
10223 this.modified.remove(record);
10225 this.fireEvent("remove", this, record, index);
10229 * Remove all Records from the Store and fires the clear event.
10231 removeAll : function(){
10233 if(this.pruneModifiedRecords){
10234 this.modified = [];
10236 this.fireEvent("clear", this);
10240 * Inserts Records to the Store at the given index and fires the add event.
10241 * @param {Number} index The start index at which to insert the passed Records.
10242 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10244 insert : function(index, records){
10245 records = [].concat(records);
10246 for(var i = 0, len = records.length; i < len; i++){
10247 this.data.insert(index, records[i]);
10248 records[i].join(this);
10250 this.fireEvent("add", this, records, index);
10254 * Get the index within the cache of the passed Record.
10255 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10256 * @return {Number} The index of the passed Record. Returns -1 if not found.
10258 indexOf : function(record){
10259 return this.data.indexOf(record);
10263 * Get the index within the cache of the Record with the passed id.
10264 * @param {String} id The id of the Record to find.
10265 * @return {Number} The index of the Record. Returns -1 if not found.
10267 indexOfId : function(id){
10268 return this.data.indexOfKey(id);
10272 * Get the Record with the specified id.
10273 * @param {String} id The id of the Record to find.
10274 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10276 getById : function(id){
10277 return this.data.key(id);
10281 * Get the Record at the specified index.
10282 * @param {Number} index The index of the Record to find.
10283 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10285 getAt : function(index){
10286 return this.data.itemAt(index);
10290 * Returns a range of Records between specified indices.
10291 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10292 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10293 * @return {Roo.data.Record[]} An array of Records
10295 getRange : function(start, end){
10296 return this.data.getRange(start, end);
10300 storeOptions : function(o){
10301 o = Roo.apply({}, o);
10304 this.lastOptions = o;
10308 * Loads the Record cache from the configured Proxy using the configured Reader.
10310 * If using remote paging, then the first load call must specify the <em>start</em>
10311 * and <em>limit</em> properties in the options.params property to establish the initial
10312 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10314 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10315 * and this call will return before the new data has been loaded. Perform any post-processing
10316 * in a callback function, or in a "load" event handler.</strong>
10318 * @param {Object} options An object containing properties which control loading options:<ul>
10319 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10320 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10321 * passed the following arguments:<ul>
10322 * <li>r : Roo.data.Record[]</li>
10323 * <li>options: Options object from the load call</li>
10324 * <li>success: Boolean success indicator</li></ul></li>
10325 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10326 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10329 load : function(options){
10330 options = options || {};
10331 if(this.fireEvent("beforeload", this, options) !== false){
10332 this.storeOptions(options);
10333 var p = Roo.apply(options.params || {}, this.baseParams);
10334 // if meta was not loaded from remote source.. try requesting it.
10335 if (!this.reader.metaFromRemote) {
10336 p._requestMeta = 1;
10338 if(this.sortInfo && this.remoteSort){
10339 var pn = this.paramNames;
10340 p[pn["sort"]] = this.sortInfo.field;
10341 p[pn["dir"]] = this.sortInfo.direction;
10343 if (this.multiSort) {
10344 var pn = this.paramNames;
10345 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10348 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10353 * Reloads the Record cache from the configured Proxy using the configured Reader and
10354 * the options from the last load operation performed.
10355 * @param {Object} options (optional) An object containing properties which may override the options
10356 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10357 * the most recently used options are reused).
10359 reload : function(options){
10360 this.load(Roo.applyIf(options||{}, this.lastOptions));
10364 // Called as a callback by the Reader during a load operation.
10365 loadRecords : function(o, options, success){
10366 if(!o || success === false){
10367 if(success !== false){
10368 this.fireEvent("load", this, [], options, o);
10370 if(options.callback){
10371 options.callback.call(options.scope || this, [], options, false);
10375 // if data returned failure - throw an exception.
10376 if (o.success === false) {
10377 // show a message if no listener is registered.
10378 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10379 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10381 // loadmask wil be hooked into this..
10382 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10385 var r = o.records, t = o.totalRecords || r.length;
10387 this.fireEvent("beforeloadadd", this, r, options, o);
10389 if(!options || options.add !== true){
10390 if(this.pruneModifiedRecords){
10391 this.modified = [];
10393 for(var i = 0, len = r.length; i < len; i++){
10397 this.data = this.snapshot;
10398 delete this.snapshot;
10401 this.data.addAll(r);
10402 this.totalLength = t;
10404 this.fireEvent("datachanged", this);
10406 this.totalLength = Math.max(t, this.data.length+r.length);
10409 this.fireEvent("load", this, r, options, o);
10410 if(options.callback){
10411 options.callback.call(options.scope || this, r, options, true);
10417 * Loads data from a passed data block. A Reader which understands the format of the data
10418 * must have been configured in the constructor.
10419 * @param {Object} data The data block from which to read the Records. The format of the data expected
10420 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10421 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10423 loadData : function(o, append){
10424 var r = this.reader.readRecords(o);
10425 this.loadRecords(r, {add: append}, true);
10429 * Gets the number of cached records.
10431 * <em>If using paging, this may not be the total size of the dataset. If the data object
10432 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10433 * the data set size</em>
10435 getCount : function(){
10436 return this.data.length || 0;
10440 * Gets the total number of records in the dataset as returned by the server.
10442 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10443 * the dataset size</em>
10445 getTotalCount : function(){
10446 return this.totalLength || 0;
10450 * Returns the sort state of the Store as an object with two properties:
10452 field {String} The name of the field by which the Records are sorted
10453 direction {String} The sort order, "ASC" or "DESC"
10456 getSortState : function(){
10457 return this.sortInfo;
10461 applySort : function(){
10462 if(this.sortInfo && !this.remoteSort){
10463 var s = this.sortInfo, f = s.field;
10464 var st = this.fields.get(f).sortType;
10465 var fn = function(r1, r2){
10466 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10467 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10469 this.data.sort(s.direction, fn);
10470 if(this.snapshot && this.snapshot != this.data){
10471 this.snapshot.sort(s.direction, fn);
10477 * Sets the default sort column and order to be used by the next load operation.
10478 * @param {String} fieldName The name of the field to sort by.
10479 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10481 setDefaultSort : function(field, dir){
10482 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10486 * Sort the Records.
10487 * If remote sorting is used, the sort is performed on the server, and the cache is
10488 * reloaded. If local sorting is used, the cache is sorted internally.
10489 * @param {String} fieldName The name of the field to sort by.
10490 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10492 sort : function(fieldName, dir){
10493 var f = this.fields.get(fieldName);
10495 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10497 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10498 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10503 this.sortToggle[f.name] = dir;
10504 this.sortInfo = {field: f.name, direction: dir};
10505 if(!this.remoteSort){
10507 this.fireEvent("datachanged", this);
10509 this.load(this.lastOptions);
10514 * Calls the specified function for each of the Records in the cache.
10515 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10516 * Returning <em>false</em> aborts and exits the iteration.
10517 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10519 each : function(fn, scope){
10520 this.data.each(fn, scope);
10524 * Gets all records modified since the last commit. Modified records are persisted across load operations
10525 * (e.g., during paging).
10526 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10528 getModifiedRecords : function(){
10529 return this.modified;
10533 createFilterFn : function(property, value, anyMatch){
10534 if(!value.exec){ // not a regex
10535 value = String(value);
10536 if(value.length == 0){
10539 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10541 return function(r){
10542 return value.test(r.data[property]);
10547 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10548 * @param {String} property A field on your records
10549 * @param {Number} start The record index to start at (defaults to 0)
10550 * @param {Number} end The last record index to include (defaults to length - 1)
10551 * @return {Number} The sum
10553 sum : function(property, start, end){
10554 var rs = this.data.items, v = 0;
10555 start = start || 0;
10556 end = (end || end === 0) ? end : rs.length-1;
10558 for(var i = start; i <= end; i++){
10559 v += (rs[i].data[property] || 0);
10565 * Filter the records by a specified property.
10566 * @param {String} field A field on your records
10567 * @param {String/RegExp} value Either a string that the field
10568 * should start with or a RegExp to test against the field
10569 * @param {Boolean} anyMatch True to match any part not just the beginning
10571 filter : function(property, value, anyMatch){
10572 var fn = this.createFilterFn(property, value, anyMatch);
10573 return fn ? this.filterBy(fn) : this.clearFilter();
10577 * Filter by a function. The specified function will be called with each
10578 * record in this data source. If the function returns true the record is included,
10579 * otherwise it is filtered.
10580 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10581 * @param {Object} scope (optional) The scope of the function (defaults to this)
10583 filterBy : function(fn, scope){
10584 this.snapshot = this.snapshot || this.data;
10585 this.data = this.queryBy(fn, scope||this);
10586 this.fireEvent("datachanged", this);
10590 * Query the records by a specified property.
10591 * @param {String} field A field on your records
10592 * @param {String/RegExp} value Either a string that the field
10593 * should start with or a RegExp to test against the field
10594 * @param {Boolean} anyMatch True to match any part not just the beginning
10595 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10597 query : function(property, value, anyMatch){
10598 var fn = this.createFilterFn(property, value, anyMatch);
10599 return fn ? this.queryBy(fn) : this.data.clone();
10603 * Query by a function. The specified function will be called with each
10604 * record in this data source. If the function returns true the record is included
10606 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10607 * @param {Object} scope (optional) The scope of the function (defaults to this)
10608 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10610 queryBy : function(fn, scope){
10611 var data = this.snapshot || this.data;
10612 return data.filterBy(fn, scope||this);
10616 * Collects unique values for a particular dataIndex from this store.
10617 * @param {String} dataIndex The property to collect
10618 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10619 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10620 * @return {Array} An array of the unique values
10622 collect : function(dataIndex, allowNull, bypassFilter){
10623 var d = (bypassFilter === true && this.snapshot) ?
10624 this.snapshot.items : this.data.items;
10625 var v, sv, r = [], l = {};
10626 for(var i = 0, len = d.length; i < len; i++){
10627 v = d[i].data[dataIndex];
10629 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10638 * Revert to a view of the Record cache with no filtering applied.
10639 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10641 clearFilter : function(suppressEvent){
10642 if(this.snapshot && this.snapshot != this.data){
10643 this.data = this.snapshot;
10644 delete this.snapshot;
10645 if(suppressEvent !== true){
10646 this.fireEvent("datachanged", this);
10652 afterEdit : function(record){
10653 if(this.modified.indexOf(record) == -1){
10654 this.modified.push(record);
10656 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10660 afterReject : function(record){
10661 this.modified.remove(record);
10662 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10666 afterCommit : function(record){
10667 this.modified.remove(record);
10668 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10672 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10673 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10675 commitChanges : function(){
10676 var m = this.modified.slice(0);
10677 this.modified = [];
10678 for(var i = 0, len = m.length; i < len; i++){
10684 * Cancel outstanding changes on all changed records.
10686 rejectChanges : function(){
10687 var m = this.modified.slice(0);
10688 this.modified = [];
10689 for(var i = 0, len = m.length; i < len; i++){
10694 onMetaChange : function(meta, rtype, o){
10695 this.recordType = rtype;
10696 this.fields = rtype.prototype.fields;
10697 delete this.snapshot;
10698 this.sortInfo = meta.sortInfo || this.sortInfo;
10699 this.modified = [];
10700 this.fireEvent('metachange', this, this.reader.meta);
10703 moveIndex : function(data, type)
10705 var index = this.indexOf(data);
10707 var newIndex = index + type;
10711 this.insert(newIndex, data);
10716 * Ext JS Library 1.1.1
10717 * Copyright(c) 2006-2007, Ext JS, LLC.
10719 * Originally Released Under LGPL - original licence link has changed is not relivant.
10722 * <script type="text/javascript">
10726 * @class Roo.data.SimpleStore
10727 * @extends Roo.data.Store
10728 * Small helper class to make creating Stores from Array data easier.
10729 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10730 * @cfg {Array} fields An array of field definition objects, or field name strings.
10731 * @cfg {Array} data The multi-dimensional array of data
10733 * @param {Object} config
10735 Roo.data.SimpleStore = function(config){
10736 Roo.data.SimpleStore.superclass.constructor.call(this, {
10738 reader: new Roo.data.ArrayReader({
10741 Roo.data.Record.create(config.fields)
10743 proxy : new Roo.data.MemoryProxy(config.data)
10747 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10749 * Ext JS Library 1.1.1
10750 * Copyright(c) 2006-2007, Ext JS, LLC.
10752 * Originally Released Under LGPL - original licence link has changed is not relivant.
10755 * <script type="text/javascript">
10760 * @extends Roo.data.Store
10761 * @class Roo.data.JsonStore
10762 * Small helper class to make creating Stores for JSON data easier. <br/>
10764 var store = new Roo.data.JsonStore({
10765 url: 'get-images.php',
10767 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10770 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10771 * JsonReader and HttpProxy (unless inline data is provided).</b>
10772 * @cfg {Array} fields An array of field definition objects, or field name strings.
10774 * @param {Object} config
10776 Roo.data.JsonStore = function(c){
10777 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10778 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10779 reader: new Roo.data.JsonReader(c, c.fields)
10782 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10784 * Ext JS Library 1.1.1
10785 * Copyright(c) 2006-2007, Ext JS, LLC.
10787 * Originally Released Under LGPL - original licence link has changed is not relivant.
10790 * <script type="text/javascript">
10794 Roo.data.Field = function(config){
10795 if(typeof config == "string"){
10796 config = {name: config};
10798 Roo.apply(this, config);
10801 this.type = "auto";
10804 var st = Roo.data.SortTypes;
10805 // named sortTypes are supported, here we look them up
10806 if(typeof this.sortType == "string"){
10807 this.sortType = st[this.sortType];
10810 // set default sortType for strings and dates
10811 if(!this.sortType){
10814 this.sortType = st.asUCString;
10817 this.sortType = st.asDate;
10820 this.sortType = st.none;
10825 var stripRe = /[\$,%]/g;
10827 // prebuilt conversion function for this field, instead of
10828 // switching every time we're reading a value
10830 var cv, dateFormat = this.dateFormat;
10835 cv = function(v){ return v; };
10838 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10842 return v !== undefined && v !== null && v !== '' ?
10843 parseInt(String(v).replace(stripRe, ""), 10) : '';
10848 return v !== undefined && v !== null && v !== '' ?
10849 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10854 cv = function(v){ return v === true || v === "true" || v == 1; };
10861 if(v instanceof Date){
10865 if(dateFormat == "timestamp"){
10866 return new Date(v*1000);
10868 return Date.parseDate(v, dateFormat);
10870 var parsed = Date.parse(v);
10871 return parsed ? new Date(parsed) : null;
10880 Roo.data.Field.prototype = {
10888 * Ext JS Library 1.1.1
10889 * Copyright(c) 2006-2007, Ext JS, LLC.
10891 * Originally Released Under LGPL - original licence link has changed is not relivant.
10894 * <script type="text/javascript">
10897 // Base class for reading structured data from a data source. This class is intended to be
10898 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10901 * @class Roo.data.DataReader
10902 * Base class for reading structured data from a data source. This class is intended to be
10903 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10906 Roo.data.DataReader = function(meta, recordType){
10910 this.recordType = recordType instanceof Array ?
10911 Roo.data.Record.create(recordType) : recordType;
10914 Roo.data.DataReader.prototype = {
10916 * Create an empty record
10917 * @param {Object} data (optional) - overlay some values
10918 * @return {Roo.data.Record} record created.
10920 newRow : function(d) {
10922 this.recordType.prototype.fields.each(function(c) {
10924 case 'int' : da[c.name] = 0; break;
10925 case 'date' : da[c.name] = new Date(); break;
10926 case 'float' : da[c.name] = 0.0; break;
10927 case 'boolean' : da[c.name] = false; break;
10928 default : da[c.name] = ""; break;
10932 return new this.recordType(Roo.apply(da, d));
10937 * Ext JS Library 1.1.1
10938 * Copyright(c) 2006-2007, Ext JS, LLC.
10940 * Originally Released Under LGPL - original licence link has changed is not relivant.
10943 * <script type="text/javascript">
10947 * @class Roo.data.DataProxy
10948 * @extends Roo.data.Observable
10949 * This class is an abstract base class for implementations which provide retrieval of
10950 * unformatted data objects.<br>
10952 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10953 * (of the appropriate type which knows how to parse the data object) to provide a block of
10954 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10956 * Custom implementations must implement the load method as described in
10957 * {@link Roo.data.HttpProxy#load}.
10959 Roo.data.DataProxy = function(){
10962 * @event beforeload
10963 * Fires before a network request is made to retrieve a data object.
10964 * @param {Object} This DataProxy object.
10965 * @param {Object} params The params parameter to the load function.
10970 * Fires before the load method's callback is called.
10971 * @param {Object} This DataProxy object.
10972 * @param {Object} o The data object.
10973 * @param {Object} arg The callback argument object passed to the load function.
10977 * @event loadexception
10978 * Fires if an Exception occurs during data retrieval.
10979 * @param {Object} This DataProxy object.
10980 * @param {Object} o The data object.
10981 * @param {Object} arg The callback argument object passed to the load function.
10982 * @param {Object} e The Exception.
10984 loadexception : true
10986 Roo.data.DataProxy.superclass.constructor.call(this);
10989 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10992 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10996 * Ext JS Library 1.1.1
10997 * Copyright(c) 2006-2007, Ext JS, LLC.
10999 * Originally Released Under LGPL - original licence link has changed is not relivant.
11002 * <script type="text/javascript">
11005 * @class Roo.data.MemoryProxy
11006 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11007 * to the Reader when its load method is called.
11009 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11011 Roo.data.MemoryProxy = function(data){
11015 Roo.data.MemoryProxy.superclass.constructor.call(this);
11019 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11022 * Load data from the requested source (in this case an in-memory
11023 * data object passed to the constructor), read the data object into
11024 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11025 * process that block using the passed callback.
11026 * @param {Object} params This parameter is not used by the MemoryProxy class.
11027 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11028 * object into a block of Roo.data.Records.
11029 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11030 * The function must be passed <ul>
11031 * <li>The Record block object</li>
11032 * <li>The "arg" argument from the load function</li>
11033 * <li>A boolean success indicator</li>
11035 * @param {Object} scope The scope in which to call the callback
11036 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11038 load : function(params, reader, callback, scope, arg){
11039 params = params || {};
11042 result = reader.readRecords(this.data);
11044 this.fireEvent("loadexception", this, arg, null, e);
11045 callback.call(scope, null, arg, false);
11048 callback.call(scope, result, arg, true);
11052 update : function(params, records){
11057 * Ext JS Library 1.1.1
11058 * Copyright(c) 2006-2007, Ext JS, LLC.
11060 * Originally Released Under LGPL - original licence link has changed is not relivant.
11063 * <script type="text/javascript">
11066 * @class Roo.data.HttpProxy
11067 * @extends Roo.data.DataProxy
11068 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11069 * configured to reference a certain URL.<br><br>
11071 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11072 * from which the running page was served.<br><br>
11074 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11076 * Be aware that to enable the browser to parse an XML document, the server must set
11077 * the Content-Type header in the HTTP response to "text/xml".
11079 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11080 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11081 * will be used to make the request.
11083 Roo.data.HttpProxy = function(conn){
11084 Roo.data.HttpProxy.superclass.constructor.call(this);
11085 // is conn a conn config or a real conn?
11087 this.useAjax = !conn || !conn.events;
11091 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11092 // thse are take from connection...
11095 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11098 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11099 * extra parameters to each request made by this object. (defaults to undefined)
11102 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11103 * to each request made by this object. (defaults to undefined)
11106 * @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)
11109 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11112 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11118 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11122 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11123 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11124 * a finer-grained basis than the DataProxy events.
11126 getConnection : function(){
11127 return this.useAjax ? Roo.Ajax : this.conn;
11131 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11132 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11133 * process that block using the passed callback.
11134 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11135 * for the request to the remote server.
11136 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11137 * object into a block of Roo.data.Records.
11138 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11139 * The function must be passed <ul>
11140 * <li>The Record block object</li>
11141 * <li>The "arg" argument from the load function</li>
11142 * <li>A boolean success indicator</li>
11144 * @param {Object} scope The scope in which to call the callback
11145 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11147 load : function(params, reader, callback, scope, arg){
11148 if(this.fireEvent("beforeload", this, params) !== false){
11150 params : params || {},
11152 callback : callback,
11157 callback : this.loadResponse,
11161 Roo.applyIf(o, this.conn);
11162 if(this.activeRequest){
11163 Roo.Ajax.abort(this.activeRequest);
11165 this.activeRequest = Roo.Ajax.request(o);
11167 this.conn.request(o);
11170 callback.call(scope||this, null, arg, false);
11175 loadResponse : function(o, success, response){
11176 delete this.activeRequest;
11178 this.fireEvent("loadexception", this, o, response);
11179 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11184 result = o.reader.read(response);
11186 this.fireEvent("loadexception", this, o, response, e);
11187 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11191 this.fireEvent("load", this, o, o.request.arg);
11192 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11196 update : function(dataSet){
11201 updateResponse : function(dataSet){
11206 * Ext JS Library 1.1.1
11207 * Copyright(c) 2006-2007, Ext JS, LLC.
11209 * Originally Released Under LGPL - original licence link has changed is not relivant.
11212 * <script type="text/javascript">
11216 * @class Roo.data.ScriptTagProxy
11217 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11218 * other than the originating domain of the running page.<br><br>
11220 * <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
11221 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11223 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11224 * source code that is used as the source inside a <script> tag.<br><br>
11226 * In order for the browser to process the returned data, the server must wrap the data object
11227 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11228 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11229 * depending on whether the callback name was passed:
11232 boolean scriptTag = false;
11233 String cb = request.getParameter("callback");
11236 response.setContentType("text/javascript");
11238 response.setContentType("application/x-json");
11240 Writer out = response.getWriter();
11242 out.write(cb + "(");
11244 out.print(dataBlock.toJsonString());
11251 * @param {Object} config A configuration object.
11253 Roo.data.ScriptTagProxy = function(config){
11254 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11255 Roo.apply(this, config);
11256 this.head = document.getElementsByTagName("head")[0];
11259 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11261 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11263 * @cfg {String} url The URL from which to request the data object.
11266 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11270 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11271 * the server the name of the callback function set up by the load call to process the returned data object.
11272 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11273 * javascript output which calls this named function passing the data object as its only parameter.
11275 callbackParam : "callback",
11277 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11278 * name to the request.
11283 * Load data from the configured URL, read the data object into
11284 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11285 * process that block using the passed callback.
11286 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11287 * for the request to the remote server.
11288 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11289 * object into a block of Roo.data.Records.
11290 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11291 * The function must be passed <ul>
11292 * <li>The Record block object</li>
11293 * <li>The "arg" argument from the load function</li>
11294 * <li>A boolean success indicator</li>
11296 * @param {Object} scope The scope in which to call the callback
11297 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11299 load : function(params, reader, callback, scope, arg){
11300 if(this.fireEvent("beforeload", this, params) !== false){
11302 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11304 var url = this.url;
11305 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11307 url += "&_dc=" + (new Date().getTime());
11309 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11312 cb : "stcCallback"+transId,
11313 scriptId : "stcScript"+transId,
11317 callback : callback,
11323 window[trans.cb] = function(o){
11324 conn.handleResponse(o, trans);
11327 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11329 if(this.autoAbort !== false){
11333 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11335 var script = document.createElement("script");
11336 script.setAttribute("src", url);
11337 script.setAttribute("type", "text/javascript");
11338 script.setAttribute("id", trans.scriptId);
11339 this.head.appendChild(script);
11341 this.trans = trans;
11343 callback.call(scope||this, null, arg, false);
11348 isLoading : function(){
11349 return this.trans ? true : false;
11353 * Abort the current server request.
11355 abort : function(){
11356 if(this.isLoading()){
11357 this.destroyTrans(this.trans);
11362 destroyTrans : function(trans, isLoaded){
11363 this.head.removeChild(document.getElementById(trans.scriptId));
11364 clearTimeout(trans.timeoutId);
11366 window[trans.cb] = undefined;
11368 delete window[trans.cb];
11371 // if hasn't been loaded, wait for load to remove it to prevent script error
11372 window[trans.cb] = function(){
11373 window[trans.cb] = undefined;
11375 delete window[trans.cb];
11382 handleResponse : function(o, trans){
11383 this.trans = false;
11384 this.destroyTrans(trans, true);
11387 result = trans.reader.readRecords(o);
11389 this.fireEvent("loadexception", this, o, trans.arg, e);
11390 trans.callback.call(trans.scope||window, null, trans.arg, false);
11393 this.fireEvent("load", this, o, trans.arg);
11394 trans.callback.call(trans.scope||window, result, trans.arg, true);
11398 handleFailure : function(trans){
11399 this.trans = false;
11400 this.destroyTrans(trans, false);
11401 this.fireEvent("loadexception", this, null, trans.arg);
11402 trans.callback.call(trans.scope||window, null, trans.arg, false);
11406 * Ext JS Library 1.1.1
11407 * Copyright(c) 2006-2007, Ext JS, LLC.
11409 * Originally Released Under LGPL - original licence link has changed is not relivant.
11412 * <script type="text/javascript">
11416 * @class Roo.data.JsonReader
11417 * @extends Roo.data.DataReader
11418 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11419 * based on mappings in a provided Roo.data.Record constructor.
11421 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11422 * in the reply previously.
11427 var RecordDef = Roo.data.Record.create([
11428 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11429 {name: 'occupation'} // This field will use "occupation" as the mapping.
11431 var myReader = new Roo.data.JsonReader({
11432 totalProperty: "results", // The property which contains the total dataset size (optional)
11433 root: "rows", // The property which contains an Array of row objects
11434 id: "id" // The property within each row object that provides an ID for the record (optional)
11438 * This would consume a JSON file like this:
11440 { 'results': 2, 'rows': [
11441 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11442 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11445 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11446 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11447 * paged from the remote server.
11448 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11449 * @cfg {String} root name of the property which contains the Array of row objects.
11450 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11451 * @cfg {Array} fields Array of field definition objects
11453 * Create a new JsonReader
11454 * @param {Object} meta Metadata configuration options
11455 * @param {Object} recordType Either an Array of field definition objects,
11456 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11458 Roo.data.JsonReader = function(meta, recordType){
11461 // set some defaults:
11462 Roo.applyIf(meta, {
11463 totalProperty: 'total',
11464 successProperty : 'success',
11469 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11471 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11474 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11475 * Used by Store query builder to append _requestMeta to params.
11478 metaFromRemote : false,
11480 * This method is only used by a DataProxy which has retrieved data from a remote server.
11481 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11482 * @return {Object} data A data block which is used by an Roo.data.Store object as
11483 * a cache of Roo.data.Records.
11485 read : function(response){
11486 var json = response.responseText;
11488 var o = /* eval:var:o */ eval("("+json+")");
11490 throw {message: "JsonReader.read: Json object not found"};
11496 this.metaFromRemote = true;
11497 this.meta = o.metaData;
11498 this.recordType = Roo.data.Record.create(o.metaData.fields);
11499 this.onMetaChange(this.meta, this.recordType, o);
11501 return this.readRecords(o);
11504 // private function a store will implement
11505 onMetaChange : function(meta, recordType, o){
11512 simpleAccess: function(obj, subsc) {
11519 getJsonAccessor: function(){
11521 return function(expr) {
11523 return(re.test(expr))
11524 ? new Function("obj", "return obj." + expr)
11529 return Roo.emptyFn;
11534 * Create a data block containing Roo.data.Records from an XML document.
11535 * @param {Object} o An object which contains an Array of row objects in the property specified
11536 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11537 * which contains the total size of the dataset.
11538 * @return {Object} data A data block which is used by an Roo.data.Store object as
11539 * a cache of Roo.data.Records.
11541 readRecords : function(o){
11543 * After any data loads, the raw JSON data is available for further custom processing.
11547 var s = this.meta, Record = this.recordType,
11548 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11550 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11552 if(s.totalProperty) {
11553 this.getTotal = this.getJsonAccessor(s.totalProperty);
11555 if(s.successProperty) {
11556 this.getSuccess = this.getJsonAccessor(s.successProperty);
11558 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11560 var g = this.getJsonAccessor(s.id);
11561 this.getId = function(rec) {
11563 return (r === undefined || r === "") ? null : r;
11566 this.getId = function(){return null;};
11569 for(var jj = 0; jj < fl; jj++){
11571 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11572 this.ef[jj] = this.getJsonAccessor(map);
11576 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11577 if(s.totalProperty){
11578 var vt = parseInt(this.getTotal(o), 10);
11583 if(s.successProperty){
11584 var vs = this.getSuccess(o);
11585 if(vs === false || vs === 'false'){
11590 for(var i = 0; i < c; i++){
11593 var id = this.getId(n);
11594 for(var j = 0; j < fl; j++){
11596 var v = this.ef[j](n);
11598 Roo.log('missing convert for ' + f.name);
11602 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11604 var record = new Record(values, id);
11606 records[i] = record;
11612 totalRecords : totalRecords
11617 * Ext JS Library 1.1.1
11618 * Copyright(c) 2006-2007, Ext JS, LLC.
11620 * Originally Released Under LGPL - original licence link has changed is not relivant.
11623 * <script type="text/javascript">
11627 * @class Roo.data.ArrayReader
11628 * @extends Roo.data.DataReader
11629 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11630 * Each element of that Array represents a row of data fields. The
11631 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11632 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11636 var RecordDef = Roo.data.Record.create([
11637 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11638 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11640 var myReader = new Roo.data.ArrayReader({
11641 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11645 * This would consume an Array like this:
11647 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11649 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11651 * Create a new JsonReader
11652 * @param {Object} meta Metadata configuration options.
11653 * @param {Object} recordType Either an Array of field definition objects
11654 * as specified to {@link Roo.data.Record#create},
11655 * or an {@link Roo.data.Record} object
11656 * created using {@link Roo.data.Record#create}.
11658 Roo.data.ArrayReader = function(meta, recordType){
11659 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11662 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11664 * Create a data block containing Roo.data.Records from an XML document.
11665 * @param {Object} o An Array of row objects which represents the dataset.
11666 * @return {Object} data A data block which is used by an Roo.data.Store object as
11667 * a cache of Roo.data.Records.
11669 readRecords : function(o){
11670 var sid = this.meta ? this.meta.id : null;
11671 var recordType = this.recordType, fields = recordType.prototype.fields;
11674 for(var i = 0; i < root.length; i++){
11677 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11678 for(var j = 0, jlen = fields.length; j < jlen; j++){
11679 var f = fields.items[j];
11680 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11681 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11683 values[f.name] = v;
11685 var record = new recordType(values, id);
11687 records[records.length] = record;
11691 totalRecords : records.length
11700 * @class Roo.bootstrap.ComboBox
11701 * @extends Roo.bootstrap.TriggerField
11702 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11703 * @cfg {Boolean} append (true|false) default false
11704 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11705 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11706 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11707 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11708 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11709 * @cfg {Boolean} animate default true
11710 * @cfg {Boolean} emptyResultText only for touch device
11711 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11713 * Create a new ComboBox.
11714 * @param {Object} config Configuration options
11716 Roo.bootstrap.ComboBox = function(config){
11717 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11721 * Fires when the dropdown list is expanded
11722 * @param {Roo.bootstrap.ComboBox} combo This combo box
11727 * Fires when the dropdown list is collapsed
11728 * @param {Roo.bootstrap.ComboBox} combo This combo box
11732 * @event beforeselect
11733 * Fires before a list item is selected. Return false to cancel the selection.
11734 * @param {Roo.bootstrap.ComboBox} combo This combo box
11735 * @param {Roo.data.Record} record The data record returned from the underlying store
11736 * @param {Number} index The index of the selected item in the dropdown list
11738 'beforeselect' : true,
11741 * Fires when a list item is selected
11742 * @param {Roo.bootstrap.ComboBox} combo This combo box
11743 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11744 * @param {Number} index The index of the selected item in the dropdown list
11748 * @event beforequery
11749 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11750 * The event object passed has these properties:
11751 * @param {Roo.bootstrap.ComboBox} combo This combo box
11752 * @param {String} query The query
11753 * @param {Boolean} forceAll true to force "all" query
11754 * @param {Boolean} cancel true to cancel the query
11755 * @param {Object} e The query event object
11757 'beforequery': true,
11760 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11761 * @param {Roo.bootstrap.ComboBox} combo This combo box
11766 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11767 * @param {Roo.bootstrap.ComboBox} combo This combo box
11768 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11773 * Fires when the remove value from the combobox array
11774 * @param {Roo.bootstrap.ComboBox} combo This combo box
11778 * @event afterremove
11779 * Fires when the remove value from the combobox array
11780 * @param {Roo.bootstrap.ComboBox} combo This combo box
11782 'afterremove' : true,
11784 * @event specialfilter
11785 * Fires when specialfilter
11786 * @param {Roo.bootstrap.ComboBox} combo This combo box
11788 'specialfilter' : true,
11791 * Fires when tick the element
11792 * @param {Roo.bootstrap.ComboBox} combo This combo box
11796 * @event touchviewdisplay
11797 * Fires when touch view require special display (default is using displayField)
11798 * @param {Roo.bootstrap.ComboBox} combo This combo box
11799 * @param {Object} cfg set html .
11801 'touchviewdisplay' : true
11806 this.tickItems = [];
11808 this.selectedIndex = -1;
11809 if(this.mode == 'local'){
11810 if(config.queryDelay === undefined){
11811 this.queryDelay = 10;
11813 if(config.minChars === undefined){
11819 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11822 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11823 * rendering into an Roo.Editor, defaults to false)
11826 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11827 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11830 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11833 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11834 * the dropdown list (defaults to undefined, with no header element)
11838 * @cfg {String/Roo.Template} tpl The template to use to render the output
11842 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11844 listWidth: undefined,
11846 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11847 * mode = 'remote' or 'text' if mode = 'local')
11849 displayField: undefined,
11852 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11853 * mode = 'remote' or 'value' if mode = 'local').
11854 * Note: use of a valueField requires the user make a selection
11855 * in order for a value to be mapped.
11857 valueField: undefined,
11861 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11862 * field's data value (defaults to the underlying DOM element's name)
11864 hiddenName: undefined,
11866 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11870 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11872 selectedClass: 'active',
11875 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11879 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11880 * anchor positions (defaults to 'tl-bl')
11882 listAlign: 'tl-bl?',
11884 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11888 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11889 * query specified by the allQuery config option (defaults to 'query')
11891 triggerAction: 'query',
11893 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11894 * (defaults to 4, does not apply if editable = false)
11898 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11899 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11903 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11904 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11908 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11909 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11913 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11914 * when editable = true (defaults to false)
11916 selectOnFocus:false,
11918 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11920 queryParam: 'query',
11922 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11923 * when mode = 'remote' (defaults to 'Loading...')
11925 loadingText: 'Loading...',
11927 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11931 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11935 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11936 * traditional select (defaults to true)
11940 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11944 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11948 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11949 * listWidth has a higher value)
11953 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11954 * allow the user to set arbitrary text into the field (defaults to false)
11956 forceSelection:false,
11958 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11959 * if typeAhead = true (defaults to 250)
11961 typeAheadDelay : 250,
11963 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11964 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11966 valueNotFoundText : undefined,
11968 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11970 blockFocus : false,
11973 * @cfg {Boolean} disableClear Disable showing of clear button.
11975 disableClear : false,
11977 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11979 alwaysQuery : false,
11982 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11987 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11989 invalidClass : "has-warning",
11992 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11994 validClass : "has-success",
11997 * @cfg {Boolean} specialFilter (true|false) special filter default false
11999 specialFilter : false,
12002 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12004 mobileTouchView : true,
12016 btnPosition : 'right',
12017 triggerList : true,
12018 showToggleBtn : true,
12020 emptyResultText: 'Empty',
12021 triggerText : 'Select',
12023 // element that contains real text value.. (when hidden is used..)
12025 getAutoCreate : function()
12033 if(Roo.isTouch && this.mobileTouchView){
12034 cfg = this.getAutoCreateTouchView();
12041 if(!this.tickable){
12042 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12047 * ComboBox with tickable selections
12050 var align = this.labelAlign || this.parentLabelAlign();
12053 cls : 'form-group roo-combobox-tickable' //input-group
12058 cls : 'tickable-buttons',
12063 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12064 html : this.triggerText
12070 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12077 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12084 buttons.cn.unshift({
12086 cls: 'roo-select2-search-field-input'
12092 Roo.each(buttons.cn, function(c){
12094 c.cls += ' btn-' + _this.size;
12097 if (_this.disabled) {
12108 cls: 'form-hidden-field'
12112 cls: 'roo-select2-choices',
12116 cls: 'roo-select2-search-field',
12128 cls: 'roo-select2-container input-group roo-select2-container-multi',
12133 // cls: 'typeahead typeahead-long dropdown-menu',
12134 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12139 if(this.hasFeedback && !this.allowBlank){
12143 cls: 'glyphicon form-control-feedback'
12146 combobox.cn.push(feedback);
12149 if (align ==='left' && this.fieldLabel.length) {
12151 // Roo.log("left and has label");
12157 cls : 'control-label col-sm-' + this.labelWidth,
12158 html : this.fieldLabel
12162 cls : "col-sm-" + (12 - this.labelWidth),
12169 } else if ( this.fieldLabel.length) {
12170 // Roo.log(" label");
12175 //cls : 'input-group-addon',
12176 html : this.fieldLabel
12186 // Roo.log(" no label && no align");
12193 ['xs','sm','md','lg'].map(function(size){
12194 if (settings[size]) {
12195 cfg.cls += ' col-' + size + '-' + settings[size];
12203 _initEventsCalled : false,
12206 initEvents: function()
12209 if (this._initEventsCalled) { // as we call render... prevent looping...
12212 this._initEventsCalled = true;
12215 throw "can not find store for combo";
12218 this.store = Roo.factory(this.store, Roo.data);
12220 // if we are building from html. then this element is so complex, that we can not really
12221 // use the rendered HTML.
12222 // so we have to trash and replace the previous code.
12223 if (Roo.XComponent.build_from_html) {
12225 // remove this element....
12226 var e = this.el.dom, k=0;
12227 while (e ) { e = e.previousSibling; ++k;}
12232 this.rendered = false;
12234 this.render(this.parent().getChildContainer(true), k);
12245 if(Roo.isTouch && this.mobileTouchView){
12246 this.initTouchView();
12251 this.initTickableEvents();
12255 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12257 if(this.hiddenName){
12259 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12261 this.hiddenField.dom.value =
12262 this.hiddenValue !== undefined ? this.hiddenValue :
12263 this.value !== undefined ? this.value : '';
12265 // prevent input submission
12266 this.el.dom.removeAttribute('name');
12267 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12272 // this.el.dom.setAttribute('autocomplete', 'off');
12275 var cls = 'x-combo-list';
12277 //this.list = new Roo.Layer({
12278 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12284 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12285 _this.list.setWidth(lw);
12288 this.list.on('mouseover', this.onViewOver, this);
12289 this.list.on('mousemove', this.onViewMove, this);
12291 this.list.on('scroll', this.onViewScroll, this);
12294 this.list.swallowEvent('mousewheel');
12295 this.assetHeight = 0;
12298 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12299 this.assetHeight += this.header.getHeight();
12302 this.innerList = this.list.createChild({cls:cls+'-inner'});
12303 this.innerList.on('mouseover', this.onViewOver, this);
12304 this.innerList.on('mousemove', this.onViewMove, this);
12305 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12307 if(this.allowBlank && !this.pageSize && !this.disableClear){
12308 this.footer = this.list.createChild({cls:cls+'-ft'});
12309 this.pageTb = new Roo.Toolbar(this.footer);
12313 this.footer = this.list.createChild({cls:cls+'-ft'});
12314 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12315 {pageSize: this.pageSize});
12319 if (this.pageTb && this.allowBlank && !this.disableClear) {
12321 this.pageTb.add(new Roo.Toolbar.Fill(), {
12322 cls: 'x-btn-icon x-btn-clear',
12324 handler: function()
12327 _this.clearValue();
12328 _this.onSelect(false, -1);
12333 this.assetHeight += this.footer.getHeight();
12338 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12341 this.view = new Roo.View(this.list, this.tpl, {
12342 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12344 //this.view.wrapEl.setDisplayed(false);
12345 this.view.on('click', this.onViewClick, this);
12349 this.store.on('beforeload', this.onBeforeLoad, this);
12350 this.store.on('load', this.onLoad, this);
12351 this.store.on('loadexception', this.onLoadException, this);
12353 if(this.resizable){
12354 this.resizer = new Roo.Resizable(this.list, {
12355 pinned:true, handles:'se'
12357 this.resizer.on('resize', function(r, w, h){
12358 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12359 this.listWidth = w;
12360 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12361 this.restrictHeight();
12363 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12366 if(!this.editable){
12367 this.editable = true;
12368 this.setEditable(false);
12373 if (typeof(this.events.add.listeners) != 'undefined') {
12375 this.addicon = this.wrap.createChild(
12376 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12378 this.addicon.on('click', function(e) {
12379 this.fireEvent('add', this);
12382 if (typeof(this.events.edit.listeners) != 'undefined') {
12384 this.editicon = this.wrap.createChild(
12385 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12386 if (this.addicon) {
12387 this.editicon.setStyle('margin-left', '40px');
12389 this.editicon.on('click', function(e) {
12391 // we fire even if inothing is selected..
12392 this.fireEvent('edit', this, this.lastData );
12398 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12399 "up" : function(e){
12400 this.inKeyMode = true;
12404 "down" : function(e){
12405 if(!this.isExpanded()){
12406 this.onTriggerClick();
12408 this.inKeyMode = true;
12413 "enter" : function(e){
12414 // this.onViewClick();
12418 if(this.fireEvent("specialkey", this, e)){
12419 this.onViewClick(false);
12425 "esc" : function(e){
12429 "tab" : function(e){
12432 if(this.fireEvent("specialkey", this, e)){
12433 this.onViewClick(false);
12441 doRelay : function(foo, bar, hname){
12442 if(hname == 'down' || this.scope.isExpanded()){
12443 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12452 this.queryDelay = Math.max(this.queryDelay || 10,
12453 this.mode == 'local' ? 10 : 250);
12456 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12458 if(this.typeAhead){
12459 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12461 if(this.editable !== false){
12462 this.inputEl().on("keyup", this.onKeyUp, this);
12464 if(this.forceSelection){
12465 this.inputEl().on('blur', this.doForce, this);
12469 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12470 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12474 initTickableEvents: function()
12478 if(this.hiddenName){
12480 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12482 this.hiddenField.dom.value =
12483 this.hiddenValue !== undefined ? this.hiddenValue :
12484 this.value !== undefined ? this.value : '';
12486 // prevent input submission
12487 this.el.dom.removeAttribute('name');
12488 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12493 // this.list = this.el.select('ul.dropdown-menu',true).first();
12495 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12496 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12497 if(this.triggerList){
12498 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12501 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12502 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12504 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12505 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12507 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12508 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12510 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12511 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12512 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12515 this.cancelBtn.hide();
12520 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12521 _this.list.setWidth(lw);
12524 this.list.on('mouseover', this.onViewOver, this);
12525 this.list.on('mousemove', this.onViewMove, this);
12527 this.list.on('scroll', this.onViewScroll, this);
12530 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>';
12533 this.view = new Roo.View(this.list, this.tpl, {
12534 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12537 //this.view.wrapEl.setDisplayed(false);
12538 this.view.on('click', this.onViewClick, this);
12542 this.store.on('beforeload', this.onBeforeLoad, this);
12543 this.store.on('load', this.onLoad, this);
12544 this.store.on('loadexception', this.onLoadException, this);
12547 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12548 "up" : function(e){
12549 this.inKeyMode = true;
12553 "down" : function(e){
12554 this.inKeyMode = true;
12558 "enter" : function(e){
12559 if(this.fireEvent("specialkey", this, e)){
12560 this.onViewClick(false);
12566 "esc" : function(e){
12567 this.onTickableFooterButtonClick(e, false, false);
12570 "tab" : function(e){
12571 this.fireEvent("specialkey", this, e);
12573 this.onTickableFooterButtonClick(e, false, false);
12580 doRelay : function(e, fn, key){
12581 if(this.scope.isExpanded()){
12582 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12591 this.queryDelay = Math.max(this.queryDelay || 10,
12592 this.mode == 'local' ? 10 : 250);
12595 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12597 if(this.typeAhead){
12598 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12601 if(this.editable !== false){
12602 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12607 onDestroy : function(){
12609 this.view.setStore(null);
12610 this.view.el.removeAllListeners();
12611 this.view.el.remove();
12612 this.view.purgeListeners();
12615 this.list.dom.innerHTML = '';
12619 this.store.un('beforeload', this.onBeforeLoad, this);
12620 this.store.un('load', this.onLoad, this);
12621 this.store.un('loadexception', this.onLoadException, this);
12623 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12627 fireKey : function(e){
12628 if(e.isNavKeyPress() && !this.list.isVisible()){
12629 this.fireEvent("specialkey", this, e);
12634 onResize: function(w, h){
12635 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12637 // if(typeof w != 'number'){
12638 // // we do not handle it!?!?
12641 // var tw = this.trigger.getWidth();
12642 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12643 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12645 // this.inputEl().setWidth( this.adjustWidth('input', x));
12647 // //this.trigger.setStyle('left', x+'px');
12649 // if(this.list && this.listWidth === undefined){
12650 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12651 // this.list.setWidth(lw);
12652 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12660 * Allow or prevent the user from directly editing the field text. If false is passed,
12661 * the user will only be able to select from the items defined in the dropdown list. This method
12662 * is the runtime equivalent of setting the 'editable' config option at config time.
12663 * @param {Boolean} value True to allow the user to directly edit the field text
12665 setEditable : function(value){
12666 if(value == this.editable){
12669 this.editable = value;
12671 this.inputEl().dom.setAttribute('readOnly', true);
12672 this.inputEl().on('mousedown', this.onTriggerClick, this);
12673 this.inputEl().addClass('x-combo-noedit');
12675 this.inputEl().dom.setAttribute('readOnly', false);
12676 this.inputEl().un('mousedown', this.onTriggerClick, this);
12677 this.inputEl().removeClass('x-combo-noedit');
12683 onBeforeLoad : function(combo,opts){
12684 if(!this.hasFocus){
12688 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12690 this.restrictHeight();
12691 this.selectedIndex = -1;
12695 onLoad : function(){
12697 this.hasQuery = false;
12699 if(!this.hasFocus){
12703 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12704 this.loading.hide();
12707 if(this.store.getCount() > 0){
12709 this.restrictHeight();
12710 if(this.lastQuery == this.allQuery){
12711 if(this.editable && !this.tickable){
12712 this.inputEl().dom.select();
12716 !this.selectByValue(this.value, true) &&
12719 !this.store.lastOptions ||
12720 typeof(this.store.lastOptions.add) == 'undefined' ||
12721 this.store.lastOptions.add != true
12724 this.select(0, true);
12727 if(this.autoFocus){
12730 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12731 this.taTask.delay(this.typeAheadDelay);
12735 this.onEmptyResults();
12741 onLoadException : function()
12743 this.hasQuery = false;
12745 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12746 this.loading.hide();
12749 if(this.tickable && this.editable){
12754 // only causes errors at present
12755 //Roo.log(this.store.reader.jsonData);
12756 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12758 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12764 onTypeAhead : function(){
12765 if(this.store.getCount() > 0){
12766 var r = this.store.getAt(0);
12767 var newValue = r.data[this.displayField];
12768 var len = newValue.length;
12769 var selStart = this.getRawValue().length;
12771 if(selStart != len){
12772 this.setRawValue(newValue);
12773 this.selectText(selStart, newValue.length);
12779 onSelect : function(record, index){
12781 if(this.fireEvent('beforeselect', this, record, index) !== false){
12783 this.setFromData(index > -1 ? record.data : false);
12786 this.fireEvent('select', this, record, index);
12791 * Returns the currently selected field value or empty string if no value is set.
12792 * @return {String} value The selected value
12794 getValue : function(){
12797 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12800 if(this.valueField){
12801 return typeof this.value != 'undefined' ? this.value : '';
12803 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12808 * Clears any text/value currently set in the field
12810 clearValue : function(){
12811 if(this.hiddenField){
12812 this.hiddenField.dom.value = '';
12815 this.setRawValue('');
12816 this.lastSelectionText = '';
12817 this.lastData = false;
12819 var close = this.closeTriggerEl();
12828 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12829 * will be displayed in the field. If the value does not match the data value of an existing item,
12830 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12831 * Otherwise the field will be blank (although the value will still be set).
12832 * @param {String} value The value to match
12834 setValue : function(v){
12841 if(this.valueField){
12842 var r = this.findRecord(this.valueField, v);
12844 text = r.data[this.displayField];
12845 }else if(this.valueNotFoundText !== undefined){
12846 text = this.valueNotFoundText;
12849 this.lastSelectionText = text;
12850 if(this.hiddenField){
12851 this.hiddenField.dom.value = v;
12853 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12856 var close = this.closeTriggerEl();
12859 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12863 * @property {Object} the last set data for the element
12868 * Sets the value of the field based on a object which is related to the record format for the store.
12869 * @param {Object} value the value to set as. or false on reset?
12871 setFromData : function(o){
12878 var dv = ''; // display value
12879 var vv = ''; // value value..
12881 if (this.displayField) {
12882 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12884 // this is an error condition!!!
12885 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12888 if(this.valueField){
12889 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12892 var close = this.closeTriggerEl();
12895 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12898 if(this.hiddenField){
12899 this.hiddenField.dom.value = vv;
12901 this.lastSelectionText = dv;
12902 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12906 // no hidden field.. - we store the value in 'value', but still display
12907 // display field!!!!
12908 this.lastSelectionText = dv;
12909 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12916 reset : function(){
12917 // overridden so that last data is reset..
12924 this.setValue(this.originalValue);
12925 this.clearInvalid();
12926 this.lastData = false;
12928 this.view.clearSelections();
12932 findRecord : function(prop, value){
12934 if(this.store.getCount() > 0){
12935 this.store.each(function(r){
12936 if(r.data[prop] == value){
12946 getName: function()
12948 // returns hidden if it's set..
12949 if (!this.rendered) {return ''};
12950 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12954 onViewMove : function(e, t){
12955 this.inKeyMode = false;
12959 onViewOver : function(e, t){
12960 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12963 var item = this.view.findItemFromChild(t);
12966 var index = this.view.indexOf(item);
12967 this.select(index, false);
12972 onViewClick : function(view, doFocus, el, e)
12974 var index = this.view.getSelectedIndexes()[0];
12976 var r = this.store.getAt(index);
12980 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12987 Roo.each(this.tickItems, function(v,k){
12989 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12991 _this.tickItems.splice(k, 1);
12993 if(typeof(e) == 'undefined' && view == false){
12994 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13006 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13007 this.tickItems.push(r.data);
13010 if(typeof(e) == 'undefined' && view == false){
13011 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13018 this.onSelect(r, index);
13020 if(doFocus !== false && !this.blockFocus){
13021 this.inputEl().focus();
13026 restrictHeight : function(){
13027 //this.innerList.dom.style.height = '';
13028 //var inner = this.innerList.dom;
13029 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13030 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13031 //this.list.beginUpdate();
13032 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13033 this.list.alignTo(this.inputEl(), this.listAlign);
13034 this.list.alignTo(this.inputEl(), this.listAlign);
13035 //this.list.endUpdate();
13039 onEmptyResults : function(){
13041 if(this.tickable && this.editable){
13042 this.restrictHeight();
13050 * Returns true if the dropdown list is expanded, else false.
13052 isExpanded : function(){
13053 return this.list.isVisible();
13057 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13058 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13059 * @param {String} value The data value of the item to select
13060 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13061 * selected item if it is not currently in view (defaults to true)
13062 * @return {Boolean} True if the value matched an item in the list, else false
13064 selectByValue : function(v, scrollIntoView){
13065 if(v !== undefined && v !== null){
13066 var r = this.findRecord(this.valueField || this.displayField, v);
13068 this.select(this.store.indexOf(r), scrollIntoView);
13076 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13077 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13078 * @param {Number} index The zero-based index of the list item to select
13079 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13080 * selected item if it is not currently in view (defaults to true)
13082 select : function(index, scrollIntoView){
13083 this.selectedIndex = index;
13084 this.view.select(index);
13085 if(scrollIntoView !== false){
13086 var el = this.view.getNode(index);
13088 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13091 this.list.scrollChildIntoView(el, false);
13097 selectNext : function(){
13098 var ct = this.store.getCount();
13100 if(this.selectedIndex == -1){
13102 }else if(this.selectedIndex < ct-1){
13103 this.select(this.selectedIndex+1);
13109 selectPrev : function(){
13110 var ct = this.store.getCount();
13112 if(this.selectedIndex == -1){
13114 }else if(this.selectedIndex != 0){
13115 this.select(this.selectedIndex-1);
13121 onKeyUp : function(e){
13122 if(this.editable !== false && !e.isSpecialKey()){
13123 this.lastKey = e.getKey();
13124 this.dqTask.delay(this.queryDelay);
13129 validateBlur : function(){
13130 return !this.list || !this.list.isVisible();
13134 initQuery : function(){
13136 var v = this.getRawValue();
13138 if(this.tickable && this.editable){
13139 v = this.tickableInputEl().getValue();
13146 doForce : function(){
13147 if(this.inputEl().dom.value.length > 0){
13148 this.inputEl().dom.value =
13149 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13155 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13156 * query allowing the query action to be canceled if needed.
13157 * @param {String} query The SQL query to execute
13158 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13159 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13160 * saved in the current store (defaults to false)
13162 doQuery : function(q, forceAll){
13164 if(q === undefined || q === null){
13169 forceAll: forceAll,
13173 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13178 forceAll = qe.forceAll;
13179 if(forceAll === true || (q.length >= this.minChars)){
13181 this.hasQuery = true;
13183 if(this.lastQuery != q || this.alwaysQuery){
13184 this.lastQuery = q;
13185 if(this.mode == 'local'){
13186 this.selectedIndex = -1;
13188 this.store.clearFilter();
13191 if(this.specialFilter){
13192 this.fireEvent('specialfilter', this);
13197 this.store.filter(this.displayField, q);
13200 this.store.fireEvent("datachanged", this.store);
13207 this.store.baseParams[this.queryParam] = q;
13209 var options = {params : this.getParams(q)};
13212 options.add = true;
13213 options.params.start = this.page * this.pageSize;
13216 this.store.load(options);
13219 * this code will make the page width larger, at the beginning, the list not align correctly,
13220 * we should expand the list on onLoad
13221 * so command out it
13226 this.selectedIndex = -1;
13231 this.loadNext = false;
13235 getParams : function(q){
13237 //p[this.queryParam] = q;
13241 p.limit = this.pageSize;
13247 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13249 collapse : function(){
13250 if(!this.isExpanded()){
13257 this.hasFocus = false;
13259 this.cancelBtn.hide();
13260 this.trigger.show();
13263 this.tickableInputEl().dom.value = '';
13264 this.tickableInputEl().blur();
13269 Roo.get(document).un('mousedown', this.collapseIf, this);
13270 Roo.get(document).un('mousewheel', this.collapseIf, this);
13271 if (!this.editable) {
13272 Roo.get(document).un('keydown', this.listKeyPress, this);
13274 this.fireEvent('collapse', this);
13278 collapseIf : function(e){
13279 var in_combo = e.within(this.el);
13280 var in_list = e.within(this.list);
13281 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13283 if (in_combo || in_list || is_list) {
13284 //e.stopPropagation();
13289 this.onTickableFooterButtonClick(e, false, false);
13297 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13299 expand : function(){
13301 if(this.isExpanded() || !this.hasFocus){
13305 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13306 this.list.setWidth(lw);
13313 this.restrictHeight();
13317 this.tickItems = Roo.apply([], this.item);
13320 this.cancelBtn.show();
13321 this.trigger.hide();
13324 this.tickableInputEl().focus();
13329 Roo.get(document).on('mousedown', this.collapseIf, this);
13330 Roo.get(document).on('mousewheel', this.collapseIf, this);
13331 if (!this.editable) {
13332 Roo.get(document).on('keydown', this.listKeyPress, this);
13335 this.fireEvent('expand', this);
13339 // Implements the default empty TriggerField.onTriggerClick function
13340 onTriggerClick : function(e)
13342 Roo.log('trigger click');
13344 if(this.disabled || !this.triggerList){
13349 this.loadNext = false;
13351 if(this.isExpanded()){
13353 if (!this.blockFocus) {
13354 this.inputEl().focus();
13358 this.hasFocus = true;
13359 if(this.triggerAction == 'all') {
13360 this.doQuery(this.allQuery, true);
13362 this.doQuery(this.getRawValue());
13364 if (!this.blockFocus) {
13365 this.inputEl().focus();
13370 onTickableTriggerClick : function(e)
13377 this.loadNext = false;
13378 this.hasFocus = true;
13380 if(this.triggerAction == 'all') {
13381 this.doQuery(this.allQuery, true);
13383 this.doQuery(this.getRawValue());
13387 onSearchFieldClick : function(e)
13389 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13390 this.onTickableFooterButtonClick(e, false, false);
13394 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13399 this.loadNext = false;
13400 this.hasFocus = true;
13402 if(this.triggerAction == 'all') {
13403 this.doQuery(this.allQuery, true);
13405 this.doQuery(this.getRawValue());
13409 listKeyPress : function(e)
13411 //Roo.log('listkeypress');
13412 // scroll to first matching element based on key pres..
13413 if (e.isSpecialKey()) {
13416 var k = String.fromCharCode(e.getKey()).toUpperCase();
13419 var csel = this.view.getSelectedNodes();
13420 var cselitem = false;
13422 var ix = this.view.indexOf(csel[0]);
13423 cselitem = this.store.getAt(ix);
13424 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13430 this.store.each(function(v) {
13432 // start at existing selection.
13433 if (cselitem.id == v.id) {
13439 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13440 match = this.store.indexOf(v);
13446 if (match === false) {
13447 return true; // no more action?
13450 this.view.select(match);
13451 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13452 sn.scrollIntoView(sn.dom.parentNode, false);
13455 onViewScroll : function(e, t){
13457 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){
13461 this.hasQuery = true;
13463 this.loading = this.list.select('.loading', true).first();
13465 if(this.loading === null){
13466 this.list.createChild({
13468 cls: 'loading roo-select2-more-results roo-select2-active',
13469 html: 'Loading more results...'
13472 this.loading = this.list.select('.loading', true).first();
13474 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13476 this.loading.hide();
13479 this.loading.show();
13484 this.loadNext = true;
13486 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13491 addItem : function(o)
13493 var dv = ''; // display value
13495 if (this.displayField) {
13496 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13498 // this is an error condition!!!
13499 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13506 var choice = this.choices.createChild({
13508 cls: 'roo-select2-search-choice',
13517 cls: 'roo-select2-search-choice-close',
13522 }, this.searchField);
13524 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13526 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13534 this.inputEl().dom.value = '';
13539 onRemoveItem : function(e, _self, o)
13541 e.preventDefault();
13543 this.lastItem = Roo.apply([], this.item);
13545 var index = this.item.indexOf(o.data) * 1;
13548 Roo.log('not this item?!');
13552 this.item.splice(index, 1);
13557 this.fireEvent('remove', this, e);
13563 syncValue : function()
13565 if(!this.item.length){
13572 Roo.each(this.item, function(i){
13573 if(_this.valueField){
13574 value.push(i[_this.valueField]);
13581 this.value = value.join(',');
13583 if(this.hiddenField){
13584 this.hiddenField.dom.value = this.value;
13587 this.store.fireEvent("datachanged", this.store);
13590 clearItem : function()
13592 if(!this.multiple){
13598 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13606 if(this.tickable && !Roo.isTouch){
13607 this.view.refresh();
13611 inputEl: function ()
13613 if(Roo.isTouch && this.mobileTouchView){
13614 return this.el.select('input.form-control',true).first();
13618 return this.searchField;
13621 return this.el.select('input.form-control',true).first();
13625 onTickableFooterButtonClick : function(e, btn, el)
13627 e.preventDefault();
13629 this.lastItem = Roo.apply([], this.item);
13631 if(btn && btn.name == 'cancel'){
13632 this.tickItems = Roo.apply([], this.item);
13641 Roo.each(this.tickItems, function(o){
13649 validate : function()
13651 var v = this.getRawValue();
13654 v = this.getValue();
13657 if(this.disabled || this.allowBlank || v.length){
13662 this.markInvalid();
13666 tickableInputEl : function()
13668 if(!this.tickable || !this.editable){
13669 return this.inputEl();
13672 return this.inputEl().select('.roo-select2-search-field-input', true).first();
13676 getAutoCreateTouchView : function()
13681 cls: 'form-group' //input-group
13687 type : this.inputType,
13688 cls : 'form-control x-combo-noedit',
13689 autocomplete: 'new-password',
13690 placeholder : this.placeholder || '',
13695 input.name = this.name;
13699 input.cls += ' input-' + this.size;
13702 if (this.disabled) {
13703 input.disabled = true;
13714 inputblock.cls += ' input-group';
13716 inputblock.cn.unshift({
13718 cls : 'input-group-addon',
13723 if(this.removable && !this.multiple){
13724 inputblock.cls += ' roo-removable';
13726 inputblock.cn.push({
13729 cls : 'roo-combo-removable-btn close'
13733 if(this.hasFeedback && !this.allowBlank){
13735 inputblock.cls += ' has-feedback';
13737 inputblock.cn.push({
13739 cls: 'glyphicon form-control-feedback'
13746 inputblock.cls += (this.before) ? '' : ' input-group';
13748 inputblock.cn.push({
13750 cls : 'input-group-addon',
13761 cls: 'form-hidden-field'
13775 cls: 'form-hidden-field'
13779 cls: 'roo-select2-choices',
13783 cls: 'roo-select2-search-field',
13796 cls: 'roo-select2-container input-group',
13803 combobox.cls += ' roo-select2-container-multi';
13806 var align = this.labelAlign || this.parentLabelAlign();
13810 if(this.fieldLabel.length){
13812 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13813 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13818 cls : 'control-label ' + lw,
13819 html : this.fieldLabel
13831 var settings = this;
13833 ['xs','sm','md','lg'].map(function(size){
13834 if (settings[size]) {
13835 cfg.cls += ' col-' + size + '-' + settings[size];
13842 initTouchView : function()
13844 this.renderTouchView();
13846 this.touchViewEl.on('scroll', function(){
13847 this.el.dom.scrollTop = 0;
13850 this.originalValue = this.getValue();
13852 this.inputEl().on("click", this.showTouchView, this);
13854 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13855 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13857 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13859 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13860 this.store.on('load', this.onTouchViewLoad, this);
13861 this.store.on('loadexception', this.onTouchViewLoadException, this);
13863 if(this.hiddenName){
13865 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13867 this.hiddenField.dom.value =
13868 this.hiddenValue !== undefined ? this.hiddenValue :
13869 this.value !== undefined ? this.value : '';
13871 this.el.dom.removeAttribute('name');
13872 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13876 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13877 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13880 if(this.removable && !this.multiple){
13881 var close = this.closeTriggerEl();
13883 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13884 close.on('click', this.removeBtnClick, this, close);
13888 * fix the bug in Safari iOS8
13890 this.inputEl().on("focus", function(e){
13891 document.activeElement.blur();
13899 renderTouchView : function()
13901 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13902 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13904 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13905 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13907 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13908 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13909 this.touchViewBodyEl.setStyle('overflow', 'auto');
13911 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13912 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13914 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13915 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13919 showTouchView : function()
13925 this.touchViewHeaderEl.hide();
13927 if(this.fieldLabel.length){
13928 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13929 this.touchViewHeaderEl.show();
13932 this.touchViewEl.show();
13934 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13935 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13937 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13939 if(this.fieldLabel.length){
13940 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13943 this.touchViewBodyEl.setHeight(bodyHeight);
13947 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13949 this.touchViewEl.addClass('in');
13952 this.doTouchViewQuery();
13956 hideTouchView : function()
13958 this.touchViewEl.removeClass('in');
13962 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13964 this.touchViewEl.setStyle('display', 'none');
13969 setTouchViewValue : function()
13976 Roo.each(this.tickItems, function(o){
13981 this.hideTouchView();
13984 doTouchViewQuery : function()
13993 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
13997 if(!this.alwaysQuery || this.mode == 'local'){
13998 this.onTouchViewLoad();
14005 onTouchViewBeforeLoad : function(combo,opts)
14011 onTouchViewLoad : function()
14013 if(this.store.getCount() < 1){
14014 this.onTouchViewEmptyResults();
14018 this.clearTouchView();
14020 var rawValue = this.getRawValue();
14022 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14024 this.tickItems = [];
14026 this.store.data.each(function(d, rowIndex){
14027 var row = this.touchViewListGroup.createChild(template);
14029 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14030 row.addClass(d.data.cls);
14033 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14036 html : d.data[this.displayField]
14039 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14040 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14044 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
14045 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14048 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
14049 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14050 this.tickItems.push(d.data);
14053 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14057 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14059 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14061 if(this.fieldLabel.length){
14062 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14065 var listHeight = this.touchViewListGroup.getHeight();
14069 if(firstChecked && listHeight > bodyHeight){
14070 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14075 onTouchViewLoadException : function()
14077 this.hideTouchView();
14080 onTouchViewEmptyResults : function()
14082 this.clearTouchView();
14084 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14086 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14090 clearTouchView : function()
14092 this.touchViewListGroup.dom.innerHTML = '';
14095 onTouchViewClick : function(e, el, o)
14097 e.preventDefault();
14100 var rowIndex = o.rowIndex;
14102 var r = this.store.getAt(rowIndex);
14104 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14106 if(!this.multiple){
14107 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14108 c.dom.removeAttribute('checked');
14111 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14113 this.setFromData(r.data);
14115 var close = this.closeTriggerEl();
14121 this.hideTouchView();
14123 this.fireEvent('select', this, r, rowIndex);
14128 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14129 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14130 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14134 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14135 this.addItem(r.data);
14136 this.tickItems.push(r.data);
14142 * @cfg {Boolean} grow
14146 * @cfg {Number} growMin
14150 * @cfg {Number} growMax
14159 Roo.apply(Roo.bootstrap.ComboBox, {
14163 cls: 'modal-header',
14185 cls: 'list-group-item',
14189 cls: 'roo-combobox-list-group-item-value'
14193 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14207 listItemCheckbox : {
14209 cls: 'list-group-item',
14213 cls: 'roo-combobox-list-group-item-value'
14217 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14233 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14238 cls: 'modal-footer',
14246 cls: 'col-xs-6 text-left',
14249 cls: 'btn btn-danger roo-touch-view-cancel',
14255 cls: 'col-xs-6 text-right',
14258 cls: 'btn btn-success roo-touch-view-ok',
14269 Roo.apply(Roo.bootstrap.ComboBox, {
14271 touchViewTemplate : {
14273 cls: 'modal fade roo-combobox-touch-view',
14277 cls: 'modal-dialog',
14278 style : 'position:fixed', // we have to fix position....
14282 cls: 'modal-content',
14284 Roo.bootstrap.ComboBox.header,
14285 Roo.bootstrap.ComboBox.body,
14286 Roo.bootstrap.ComboBox.footer
14295 * Ext JS Library 1.1.1
14296 * Copyright(c) 2006-2007, Ext JS, LLC.
14298 * Originally Released Under LGPL - original licence link has changed is not relivant.
14301 * <script type="text/javascript">
14306 * @extends Roo.util.Observable
14307 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14308 * This class also supports single and multi selection modes. <br>
14309 * Create a data model bound view:
14311 var store = new Roo.data.Store(...);
14313 var view = new Roo.View({
14315 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14317 singleSelect: true,
14318 selectedClass: "ydataview-selected",
14322 // listen for node click?
14323 view.on("click", function(vw, index, node, e){
14324 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14328 dataModel.load("foobar.xml");
14330 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14332 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14333 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14335 * Note: old style constructor is still suported (container, template, config)
14338 * Create a new View
14339 * @param {Object} config The config object
14342 Roo.View = function(config, depreciated_tpl, depreciated_config){
14344 this.parent = false;
14346 if (typeof(depreciated_tpl) == 'undefined') {
14347 // new way.. - universal constructor.
14348 Roo.apply(this, config);
14349 this.el = Roo.get(this.el);
14352 this.el = Roo.get(config);
14353 this.tpl = depreciated_tpl;
14354 Roo.apply(this, depreciated_config);
14356 this.wrapEl = this.el.wrap().wrap();
14357 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14360 if(typeof(this.tpl) == "string"){
14361 this.tpl = new Roo.Template(this.tpl);
14363 // support xtype ctors..
14364 this.tpl = new Roo.factory(this.tpl, Roo);
14368 this.tpl.compile();
14373 * @event beforeclick
14374 * Fires before a click is processed. Returns false to cancel the default action.
14375 * @param {Roo.View} this
14376 * @param {Number} index The index of the target node
14377 * @param {HTMLElement} node The target node
14378 * @param {Roo.EventObject} e The raw event object
14380 "beforeclick" : true,
14383 * Fires when a template node is clicked.
14384 * @param {Roo.View} this
14385 * @param {Number} index The index of the target node
14386 * @param {HTMLElement} node The target node
14387 * @param {Roo.EventObject} e The raw event object
14392 * Fires when a template node is double clicked.
14393 * @param {Roo.View} this
14394 * @param {Number} index The index of the target node
14395 * @param {HTMLElement} node The target node
14396 * @param {Roo.EventObject} e The raw event object
14400 * @event contextmenu
14401 * Fires when a template node is right clicked.
14402 * @param {Roo.View} this
14403 * @param {Number} index The index of the target node
14404 * @param {HTMLElement} node The target node
14405 * @param {Roo.EventObject} e The raw event object
14407 "contextmenu" : true,
14409 * @event selectionchange
14410 * Fires when the selected nodes change.
14411 * @param {Roo.View} this
14412 * @param {Array} selections Array of the selected nodes
14414 "selectionchange" : true,
14417 * @event beforeselect
14418 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14419 * @param {Roo.View} this
14420 * @param {HTMLElement} node The node to be selected
14421 * @param {Array} selections Array of currently selected nodes
14423 "beforeselect" : true,
14425 * @event preparedata
14426 * Fires on every row to render, to allow you to change the data.
14427 * @param {Roo.View} this
14428 * @param {Object} data to be rendered (change this)
14430 "preparedata" : true
14438 "click": this.onClick,
14439 "dblclick": this.onDblClick,
14440 "contextmenu": this.onContextMenu,
14444 this.selections = [];
14446 this.cmp = new Roo.CompositeElementLite([]);
14448 this.store = Roo.factory(this.store, Roo.data);
14449 this.setStore(this.store, true);
14452 if ( this.footer && this.footer.xtype) {
14454 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14456 this.footer.dataSource = this.store;
14457 this.footer.container = fctr;
14458 this.footer = Roo.factory(this.footer, Roo);
14459 fctr.insertFirst(this.el);
14461 // this is a bit insane - as the paging toolbar seems to detach the el..
14462 // dom.parentNode.parentNode.parentNode
14463 // they get detached?
14467 Roo.View.superclass.constructor.call(this);
14472 Roo.extend(Roo.View, Roo.util.Observable, {
14475 * @cfg {Roo.data.Store} store Data store to load data from.
14480 * @cfg {String|Roo.Element} el The container element.
14485 * @cfg {String|Roo.Template} tpl The template used by this View
14489 * @cfg {String} dataName the named area of the template to use as the data area
14490 * Works with domtemplates roo-name="name"
14494 * @cfg {String} selectedClass The css class to add to selected nodes
14496 selectedClass : "x-view-selected",
14498 * @cfg {String} emptyText The empty text to show when nothing is loaded.
14503 * @cfg {String} text to display on mask (default Loading)
14507 * @cfg {Boolean} multiSelect Allow multiple selection
14509 multiSelect : false,
14511 * @cfg {Boolean} singleSelect Allow single selection
14513 singleSelect: false,
14516 * @cfg {Boolean} toggleSelect - selecting
14518 toggleSelect : false,
14521 * @cfg {Boolean} tickable - selecting
14526 * Returns the element this view is bound to.
14527 * @return {Roo.Element}
14529 getEl : function(){
14530 return this.wrapEl;
14536 * Refreshes the view. - called by datachanged on the store. - do not call directly.
14538 refresh : function(){
14539 //Roo.log('refresh');
14542 // if we are using something like 'domtemplate', then
14543 // the what gets used is:
14544 // t.applySubtemplate(NAME, data, wrapping data..)
14545 // the outer template then get' applied with
14546 // the store 'extra data'
14547 // and the body get's added to the
14548 // roo-name="data" node?
14549 // <span class='roo-tpl-{name}'></span> ?????
14553 this.clearSelections();
14554 this.el.update("");
14556 var records = this.store.getRange();
14557 if(records.length < 1) {
14559 // is this valid?? = should it render a template??
14561 this.el.update(this.emptyText);
14565 if (this.dataName) {
14566 this.el.update(t.apply(this.store.meta)); //????
14567 el = this.el.child('.roo-tpl-' + this.dataName);
14570 for(var i = 0, len = records.length; i < len; i++){
14571 var data = this.prepareData(records[i].data, i, records[i]);
14572 this.fireEvent("preparedata", this, data, i, records[i]);
14574 var d = Roo.apply({}, data);
14577 Roo.apply(d, {'roo-id' : Roo.id()});
14581 Roo.each(this.parent.item, function(item){
14582 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
14585 Roo.apply(d, {'roo-data-checked' : 'checked'});
14589 html[html.length] = Roo.util.Format.trim(
14591 t.applySubtemplate(this.dataName, d, this.store.meta) :
14598 el.update(html.join(""));
14599 this.nodes = el.dom.childNodes;
14600 this.updateIndexes(0);
14605 * Function to override to reformat the data that is sent to
14606 * the template for each node.
14607 * DEPRICATED - use the preparedata event handler.
14608 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
14609 * a JSON object for an UpdateManager bound view).
14611 prepareData : function(data, index, record)
14613 this.fireEvent("preparedata", this, data, index, record);
14617 onUpdate : function(ds, record){
14618 // Roo.log('on update');
14619 this.clearSelections();
14620 var index = this.store.indexOf(record);
14621 var n = this.nodes[index];
14622 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
14623 n.parentNode.removeChild(n);
14624 this.updateIndexes(index, index);
14630 onAdd : function(ds, records, index)
14632 //Roo.log(['on Add', ds, records, index] );
14633 this.clearSelections();
14634 if(this.nodes.length == 0){
14638 var n = this.nodes[index];
14639 for(var i = 0, len = records.length; i < len; i++){
14640 var d = this.prepareData(records[i].data, i, records[i]);
14642 this.tpl.insertBefore(n, d);
14645 this.tpl.append(this.el, d);
14648 this.updateIndexes(index);
14651 onRemove : function(ds, record, index){
14652 // Roo.log('onRemove');
14653 this.clearSelections();
14654 var el = this.dataName ?
14655 this.el.child('.roo-tpl-' + this.dataName) :
14658 el.dom.removeChild(this.nodes[index]);
14659 this.updateIndexes(index);
14663 * Refresh an individual node.
14664 * @param {Number} index
14666 refreshNode : function(index){
14667 this.onUpdate(this.store, this.store.getAt(index));
14670 updateIndexes : function(startIndex, endIndex){
14671 var ns = this.nodes;
14672 startIndex = startIndex || 0;
14673 endIndex = endIndex || ns.length - 1;
14674 for(var i = startIndex; i <= endIndex; i++){
14675 ns[i].nodeIndex = i;
14680 * Changes the data store this view uses and refresh the view.
14681 * @param {Store} store
14683 setStore : function(store, initial){
14684 if(!initial && this.store){
14685 this.store.un("datachanged", this.refresh);
14686 this.store.un("add", this.onAdd);
14687 this.store.un("remove", this.onRemove);
14688 this.store.un("update", this.onUpdate);
14689 this.store.un("clear", this.refresh);
14690 this.store.un("beforeload", this.onBeforeLoad);
14691 this.store.un("load", this.onLoad);
14692 this.store.un("loadexception", this.onLoad);
14696 store.on("datachanged", this.refresh, this);
14697 store.on("add", this.onAdd, this);
14698 store.on("remove", this.onRemove, this);
14699 store.on("update", this.onUpdate, this);
14700 store.on("clear", this.refresh, this);
14701 store.on("beforeload", this.onBeforeLoad, this);
14702 store.on("load", this.onLoad, this);
14703 store.on("loadexception", this.onLoad, this);
14711 * onbeforeLoad - masks the loading area.
14714 onBeforeLoad : function(store,opts)
14716 //Roo.log('onBeforeLoad');
14718 this.el.update("");
14720 this.el.mask(this.mask ? this.mask : "Loading" );
14722 onLoad : function ()
14729 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
14730 * @param {HTMLElement} node
14731 * @return {HTMLElement} The template node
14733 findItemFromChild : function(node){
14734 var el = this.dataName ?
14735 this.el.child('.roo-tpl-' + this.dataName,true) :
14738 if(!node || node.parentNode == el){
14741 var p = node.parentNode;
14742 while(p && p != el){
14743 if(p.parentNode == el){
14752 onClick : function(e){
14753 var item = this.findItemFromChild(e.getTarget());
14755 var index = this.indexOf(item);
14756 if(this.onItemClick(item, index, e) !== false){
14757 this.fireEvent("click", this, index, item, e);
14760 this.clearSelections();
14765 onContextMenu : function(e){
14766 var item = this.findItemFromChild(e.getTarget());
14768 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14773 onDblClick : function(e){
14774 var item = this.findItemFromChild(e.getTarget());
14776 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14780 onItemClick : function(item, index, e)
14782 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14785 if (this.toggleSelect) {
14786 var m = this.isSelected(item) ? 'unselect' : 'select';
14789 _t[m](item, true, false);
14792 if(this.multiSelect || this.singleSelect){
14793 if(this.multiSelect && e.shiftKey && this.lastSelection){
14794 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14796 this.select(item, this.multiSelect && e.ctrlKey);
14797 this.lastSelection = item;
14800 if(!this.tickable){
14801 e.preventDefault();
14809 * Get the number of selected nodes.
14812 getSelectionCount : function(){
14813 return this.selections.length;
14817 * Get the currently selected nodes.
14818 * @return {Array} An array of HTMLElements
14820 getSelectedNodes : function(){
14821 return this.selections;
14825 * Get the indexes of the selected nodes.
14828 getSelectedIndexes : function(){
14829 var indexes = [], s = this.selections;
14830 for(var i = 0, len = s.length; i < len; i++){
14831 indexes.push(s[i].nodeIndex);
14837 * Clear all selections
14838 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14840 clearSelections : function(suppressEvent){
14841 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14842 this.cmp.elements = this.selections;
14843 this.cmp.removeClass(this.selectedClass);
14844 this.selections = [];
14845 if(!suppressEvent){
14846 this.fireEvent("selectionchange", this, this.selections);
14852 * Returns true if the passed node is selected
14853 * @param {HTMLElement/Number} node The node or node index
14854 * @return {Boolean}
14856 isSelected : function(node){
14857 var s = this.selections;
14861 node = this.getNode(node);
14862 return s.indexOf(node) !== -1;
14867 * @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
14868 * @param {Boolean} keepExisting (optional) true to keep existing selections
14869 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14871 select : function(nodeInfo, keepExisting, suppressEvent){
14872 if(nodeInfo instanceof Array){
14874 this.clearSelections(true);
14876 for(var i = 0, len = nodeInfo.length; i < len; i++){
14877 this.select(nodeInfo[i], true, true);
14881 var node = this.getNode(nodeInfo);
14882 if(!node || this.isSelected(node)){
14883 return; // already selected.
14886 this.clearSelections(true);
14889 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14890 Roo.fly(node).addClass(this.selectedClass);
14891 this.selections.push(node);
14892 if(!suppressEvent){
14893 this.fireEvent("selectionchange", this, this.selections);
14901 * @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
14902 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14903 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14905 unselect : function(nodeInfo, keepExisting, suppressEvent)
14907 if(nodeInfo instanceof Array){
14908 Roo.each(this.selections, function(s) {
14909 this.unselect(s, nodeInfo);
14913 var node = this.getNode(nodeInfo);
14914 if(!node || !this.isSelected(node)){
14915 //Roo.log("not selected");
14916 return; // not selected.
14920 Roo.each(this.selections, function(s) {
14922 Roo.fly(node).removeClass(this.selectedClass);
14929 this.selections= ns;
14930 this.fireEvent("selectionchange", this, this.selections);
14934 * Gets a template node.
14935 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14936 * @return {HTMLElement} The node or null if it wasn't found
14938 getNode : function(nodeInfo){
14939 if(typeof nodeInfo == "string"){
14940 return document.getElementById(nodeInfo);
14941 }else if(typeof nodeInfo == "number"){
14942 return this.nodes[nodeInfo];
14948 * Gets a range template nodes.
14949 * @param {Number} startIndex
14950 * @param {Number} endIndex
14951 * @return {Array} An array of nodes
14953 getNodes : function(start, end){
14954 var ns = this.nodes;
14955 start = start || 0;
14956 end = typeof end == "undefined" ? ns.length - 1 : end;
14959 for(var i = start; i <= end; i++){
14963 for(var i = start; i >= end; i--){
14971 * Finds the index of the passed node
14972 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14973 * @return {Number} The index of the node or -1
14975 indexOf : function(node){
14976 node = this.getNode(node);
14977 if(typeof node.nodeIndex == "number"){
14978 return node.nodeIndex;
14980 var ns = this.nodes;
14981 for(var i = 0, len = ns.length; i < len; i++){
14992 * based on jquery fullcalendar
14996 Roo.bootstrap = Roo.bootstrap || {};
14998 * @class Roo.bootstrap.Calendar
14999 * @extends Roo.bootstrap.Component
15000 * Bootstrap Calendar class
15001 * @cfg {Boolean} loadMask (true|false) default false
15002 * @cfg {Object} header generate the user specific header of the calendar, default false
15005 * Create a new Container
15006 * @param {Object} config The config object
15011 Roo.bootstrap.Calendar = function(config){
15012 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15016 * Fires when a date is selected
15017 * @param {DatePicker} this
15018 * @param {Date} date The selected date
15022 * @event monthchange
15023 * Fires when the displayed month changes
15024 * @param {DatePicker} this
15025 * @param {Date} date The selected month
15027 'monthchange': true,
15029 * @event evententer
15030 * Fires when mouse over an event
15031 * @param {Calendar} this
15032 * @param {event} Event
15034 'evententer': true,
15036 * @event eventleave
15037 * Fires when the mouse leaves an
15038 * @param {Calendar} this
15041 'eventleave': true,
15043 * @event eventclick
15044 * Fires when the mouse click an
15045 * @param {Calendar} this
15054 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15057 * @cfg {Number} startDay
15058 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15066 getAutoCreate : function(){
15069 var fc_button = function(name, corner, style, content ) {
15070 return Roo.apply({},{
15072 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15074 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15077 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15088 style : 'width:100%',
15095 cls : 'fc-header-left',
15097 fc_button('prev', 'left', 'arrow', '‹' ),
15098 fc_button('next', 'right', 'arrow', '›' ),
15099 { tag: 'span', cls: 'fc-header-space' },
15100 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15108 cls : 'fc-header-center',
15112 cls: 'fc-header-title',
15115 html : 'month / year'
15123 cls : 'fc-header-right',
15125 /* fc_button('month', 'left', '', 'month' ),
15126 fc_button('week', '', '', 'week' ),
15127 fc_button('day', 'right', '', 'day' )
15139 header = this.header;
15142 var cal_heads = function() {
15144 // fixme - handle this.
15146 for (var i =0; i < Date.dayNames.length; i++) {
15147 var d = Date.dayNames[i];
15150 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15151 html : d.substring(0,3)
15155 ret[0].cls += ' fc-first';
15156 ret[6].cls += ' fc-last';
15159 var cal_cell = function(n) {
15162 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15167 cls: 'fc-day-number',
15171 cls: 'fc-day-content',
15175 style: 'position: relative;' // height: 17px;
15187 var cal_rows = function() {
15190 for (var r = 0; r < 6; r++) {
15197 for (var i =0; i < Date.dayNames.length; i++) {
15198 var d = Date.dayNames[i];
15199 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15202 row.cn[0].cls+=' fc-first';
15203 row.cn[0].cn[0].style = 'min-height:90px';
15204 row.cn[6].cls+=' fc-last';
15208 ret[0].cls += ' fc-first';
15209 ret[4].cls += ' fc-prev-last';
15210 ret[5].cls += ' fc-last';
15217 cls: 'fc-border-separate',
15218 style : 'width:100%',
15226 cls : 'fc-first fc-last',
15244 cls : 'fc-content',
15245 style : "position: relative;",
15248 cls : 'fc-view fc-view-month fc-grid',
15249 style : 'position: relative',
15250 unselectable : 'on',
15253 cls : 'fc-event-container',
15254 style : 'position:absolute;z-index:8;top:0;left:0;'
15272 initEvents : function()
15275 throw "can not find store for calendar";
15281 style: "text-align:center",
15285 style: "background-color:white;width:50%;margin:250 auto",
15289 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15300 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15302 var size = this.el.select('.fc-content', true).first().getSize();
15303 this.maskEl.setSize(size.width, size.height);
15304 this.maskEl.enableDisplayMode("block");
15305 if(!this.loadMask){
15306 this.maskEl.hide();
15309 this.store = Roo.factory(this.store, Roo.data);
15310 this.store.on('load', this.onLoad, this);
15311 this.store.on('beforeload', this.onBeforeLoad, this);
15315 this.cells = this.el.select('.fc-day',true);
15316 //Roo.log(this.cells);
15317 this.textNodes = this.el.query('.fc-day-number');
15318 this.cells.addClassOnOver('fc-state-hover');
15320 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15321 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15322 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15323 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15325 this.on('monthchange', this.onMonthChange, this);
15327 this.update(new Date().clearTime());
15330 resize : function() {
15331 var sz = this.el.getSize();
15333 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15334 this.el.select('.fc-day-content div',true).setHeight(34);
15339 showPrevMonth : function(e){
15340 this.update(this.activeDate.add("mo", -1));
15342 showToday : function(e){
15343 this.update(new Date().clearTime());
15346 showNextMonth : function(e){
15347 this.update(this.activeDate.add("mo", 1));
15351 showPrevYear : function(){
15352 this.update(this.activeDate.add("y", -1));
15356 showNextYear : function(){
15357 this.update(this.activeDate.add("y", 1));
15362 update : function(date)
15364 var vd = this.activeDate;
15365 this.activeDate = date;
15366 // if(vd && this.el){
15367 // var t = date.getTime();
15368 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15369 // Roo.log('using add remove');
15371 // this.fireEvent('monthchange', this, date);
15373 // this.cells.removeClass("fc-state-highlight");
15374 // this.cells.each(function(c){
15375 // if(c.dateValue == t){
15376 // c.addClass("fc-state-highlight");
15377 // setTimeout(function(){
15378 // try{c.dom.firstChild.focus();}catch(e){}
15388 var days = date.getDaysInMonth();
15390 var firstOfMonth = date.getFirstDateOfMonth();
15391 var startingPos = firstOfMonth.getDay()-this.startDay;
15393 if(startingPos < this.startDay){
15397 var pm = date.add(Date.MONTH, -1);
15398 var prevStart = pm.getDaysInMonth()-startingPos;
15400 this.cells = this.el.select('.fc-day',true);
15401 this.textNodes = this.el.query('.fc-day-number');
15402 this.cells.addClassOnOver('fc-state-hover');
15404 var cells = this.cells.elements;
15405 var textEls = this.textNodes;
15407 Roo.each(cells, function(cell){
15408 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15411 days += startingPos;
15413 // convert everything to numbers so it's fast
15414 var day = 86400000;
15415 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15418 //Roo.log(prevStart);
15420 var today = new Date().clearTime().getTime();
15421 var sel = date.clearTime().getTime();
15422 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15423 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15424 var ddMatch = this.disabledDatesRE;
15425 var ddText = this.disabledDatesText;
15426 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15427 var ddaysText = this.disabledDaysText;
15428 var format = this.format;
15430 var setCellClass = function(cal, cell){
15434 //Roo.log('set Cell Class');
15436 var t = d.getTime();
15440 cell.dateValue = t;
15442 cell.className += " fc-today";
15443 cell.className += " fc-state-highlight";
15444 cell.title = cal.todayText;
15447 // disable highlight in other month..
15448 //cell.className += " fc-state-highlight";
15453 cell.className = " fc-state-disabled";
15454 cell.title = cal.minText;
15458 cell.className = " fc-state-disabled";
15459 cell.title = cal.maxText;
15463 if(ddays.indexOf(d.getDay()) != -1){
15464 cell.title = ddaysText;
15465 cell.className = " fc-state-disabled";
15468 if(ddMatch && format){
15469 var fvalue = d.dateFormat(format);
15470 if(ddMatch.test(fvalue)){
15471 cell.title = ddText.replace("%0", fvalue);
15472 cell.className = " fc-state-disabled";
15476 if (!cell.initialClassName) {
15477 cell.initialClassName = cell.dom.className;
15480 cell.dom.className = cell.initialClassName + ' ' + cell.className;
15485 for(; i < startingPos; i++) {
15486 textEls[i].innerHTML = (++prevStart);
15487 d.setDate(d.getDate()+1);
15489 cells[i].className = "fc-past fc-other-month";
15490 setCellClass(this, cells[i]);
15495 for(; i < days; i++){
15496 intDay = i - startingPos + 1;
15497 textEls[i].innerHTML = (intDay);
15498 d.setDate(d.getDate()+1);
15500 cells[i].className = ''; // "x-date-active";
15501 setCellClass(this, cells[i]);
15505 for(; i < 42; i++) {
15506 textEls[i].innerHTML = (++extraDays);
15507 d.setDate(d.getDate()+1);
15509 cells[i].className = "fc-future fc-other-month";
15510 setCellClass(this, cells[i]);
15513 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
15515 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
15517 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
15518 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
15520 if(totalRows != 6){
15521 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
15522 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
15525 this.fireEvent('monthchange', this, date);
15529 if(!this.internalRender){
15530 var main = this.el.dom.firstChild;
15531 var w = main.offsetWidth;
15532 this.el.setWidth(w + this.el.getBorderWidth("lr"));
15533 Roo.fly(main).setWidth(w);
15534 this.internalRender = true;
15535 // opera does not respect the auto grow header center column
15536 // then, after it gets a width opera refuses to recalculate
15537 // without a second pass
15538 if(Roo.isOpera && !this.secondPass){
15539 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
15540 this.secondPass = true;
15541 this.update.defer(10, this, [date]);
15548 findCell : function(dt) {
15549 dt = dt.clearTime().getTime();
15551 this.cells.each(function(c){
15552 //Roo.log("check " +c.dateValue + '?=' + dt);
15553 if(c.dateValue == dt){
15563 findCells : function(ev) {
15564 var s = ev.start.clone().clearTime().getTime();
15566 var e= ev.end.clone().clearTime().getTime();
15569 this.cells.each(function(c){
15570 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
15572 if(c.dateValue > e){
15575 if(c.dateValue < s){
15584 // findBestRow: function(cells)
15588 // for (var i =0 ; i < cells.length;i++) {
15589 // ret = Math.max(cells[i].rows || 0,ret);
15596 addItem : function(ev)
15598 // look for vertical location slot in
15599 var cells = this.findCells(ev);
15601 // ev.row = this.findBestRow(cells);
15603 // work out the location.
15607 for(var i =0; i < cells.length; i++) {
15609 cells[i].row = cells[0].row;
15612 cells[i].row = cells[i].row + 1;
15622 if (crow.start.getY() == cells[i].getY()) {
15624 crow.end = cells[i];
15641 cells[0].events.push(ev);
15643 this.calevents.push(ev);
15646 clearEvents: function() {
15648 if(!this.calevents){
15652 Roo.each(this.cells.elements, function(c){
15658 Roo.each(this.calevents, function(e) {
15659 Roo.each(e.els, function(el) {
15660 el.un('mouseenter' ,this.onEventEnter, this);
15661 el.un('mouseleave' ,this.onEventLeave, this);
15666 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
15672 renderEvents: function()
15676 this.cells.each(function(c) {
15685 if(c.row != c.events.length){
15686 r = 4 - (4 - (c.row - c.events.length));
15689 c.events = ev.slice(0, r);
15690 c.more = ev.slice(r);
15692 if(c.more.length && c.more.length == 1){
15693 c.events.push(c.more.pop());
15696 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
15700 this.cells.each(function(c) {
15702 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
15705 for (var e = 0; e < c.events.length; e++){
15706 var ev = c.events[e];
15707 var rows = ev.rows;
15709 for(var i = 0; i < rows.length; i++) {
15711 // how many rows should it span..
15714 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
15715 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
15717 unselectable : "on",
15720 cls: 'fc-event-inner',
15724 // cls: 'fc-event-time',
15725 // html : cells.length > 1 ? '' : ev.time
15729 cls: 'fc-event-title',
15730 html : String.format('{0}', ev.title)
15737 cls: 'ui-resizable-handle ui-resizable-e',
15738 html : '  '
15745 cfg.cls += ' fc-event-start';
15747 if ((i+1) == rows.length) {
15748 cfg.cls += ' fc-event-end';
15751 var ctr = _this.el.select('.fc-event-container',true).first();
15752 var cg = ctr.createChild(cfg);
15754 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
15755 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
15757 var r = (c.more.length) ? 1 : 0;
15758 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
15759 cg.setWidth(ebox.right - sbox.x -2);
15761 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
15762 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
15763 cg.on('click', _this.onEventClick, _this, ev);
15774 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15775 style : 'position: absolute',
15776 unselectable : "on",
15779 cls: 'fc-event-inner',
15783 cls: 'fc-event-title',
15791 cls: 'ui-resizable-handle ui-resizable-e',
15792 html : '  '
15798 var ctr = _this.el.select('.fc-event-container',true).first();
15799 var cg = ctr.createChild(cfg);
15801 var sbox = c.select('.fc-day-content',true).first().getBox();
15802 var ebox = c.select('.fc-day-content',true).first().getBox();
15804 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15805 cg.setWidth(ebox.right - sbox.x -2);
15807 cg.on('click', _this.onMoreEventClick, _this, c.more);
15817 onEventEnter: function (e, el,event,d) {
15818 this.fireEvent('evententer', this, el, event);
15821 onEventLeave: function (e, el,event,d) {
15822 this.fireEvent('eventleave', this, el, event);
15825 onEventClick: function (e, el,event,d) {
15826 this.fireEvent('eventclick', this, el, event);
15829 onMonthChange: function () {
15833 onMoreEventClick: function(e, el, more)
15837 this.calpopover.placement = 'right';
15838 this.calpopover.setTitle('More');
15840 this.calpopover.setContent('');
15842 var ctr = this.calpopover.el.select('.popover-content', true).first();
15844 Roo.each(more, function(m){
15846 cls : 'fc-event-hori fc-event-draggable',
15849 var cg = ctr.createChild(cfg);
15851 cg.on('click', _this.onEventClick, _this, m);
15854 this.calpopover.show(el);
15859 onLoad: function ()
15861 this.calevents = [];
15864 if(this.store.getCount() > 0){
15865 this.store.data.each(function(d){
15868 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15869 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15870 time : d.data.start_time,
15871 title : d.data.title,
15872 description : d.data.description,
15873 venue : d.data.venue
15878 this.renderEvents();
15880 if(this.calevents.length && this.loadMask){
15881 this.maskEl.hide();
15885 onBeforeLoad: function()
15887 this.clearEvents();
15889 this.maskEl.show();
15903 * @class Roo.bootstrap.Popover
15904 * @extends Roo.bootstrap.Component
15905 * Bootstrap Popover class
15906 * @cfg {String} html contents of the popover (or false to use children..)
15907 * @cfg {String} title of popover (or false to hide)
15908 * @cfg {String} placement how it is placed
15909 * @cfg {String} trigger click || hover (or false to trigger manually)
15910 * @cfg {String} over what (parent or false to trigger manually.)
15911 * @cfg {Number} delay - delay before showing
15914 * Create a new Popover
15915 * @param {Object} config The config object
15918 Roo.bootstrap.Popover = function(config){
15919 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15925 * After the popover show
15927 * @param {Roo.bootstrap.Popover} this
15932 * After the popover hide
15934 * @param {Roo.bootstrap.Popover} this
15940 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
15942 title: 'Fill in a title',
15945 placement : 'right',
15946 trigger : 'hover', // hover
15952 can_build_overlaid : false,
15954 getChildContainer : function()
15956 return this.el.select('.popover-content',true).first();
15959 getAutoCreate : function(){
15962 cls : 'popover roo-dynamic',
15963 style: 'display:block',
15969 cls : 'popover-inner',
15973 cls: 'popover-title',
15977 cls : 'popover-content',
15988 setTitle: function(str)
15991 this.el.select('.popover-title',true).first().dom.innerHTML = str;
15993 setContent: function(str)
15996 this.el.select('.popover-content',true).first().dom.innerHTML = str;
15998 // as it get's added to the bottom of the page.
15999 onRender : function(ct, position)
16001 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16003 var cfg = Roo.apply({}, this.getAutoCreate());
16007 cfg.cls += ' ' + this.cls;
16010 cfg.style = this.style;
16012 //Roo.log("adding to ");
16013 this.el = Roo.get(document.body).createChild(cfg, position);
16014 // Roo.log(this.el);
16019 initEvents : function()
16021 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16022 this.el.enableDisplayMode('block');
16024 if (this.over === false) {
16027 if (this.triggers === false) {
16030 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16031 var triggers = this.trigger ? this.trigger.split(' ') : [];
16032 Roo.each(triggers, function(trigger) {
16034 if (trigger == 'click') {
16035 on_el.on('click', this.toggle, this);
16036 } else if (trigger != 'manual') {
16037 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16038 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16040 on_el.on(eventIn ,this.enter, this);
16041 on_el.on(eventOut, this.leave, this);
16052 toggle : function () {
16053 this.hoverState == 'in' ? this.leave() : this.enter();
16056 enter : function () {
16058 clearTimeout(this.timeout);
16060 this.hoverState = 'in';
16062 if (!this.delay || !this.delay.show) {
16067 this.timeout = setTimeout(function () {
16068 if (_t.hoverState == 'in') {
16071 }, this.delay.show)
16074 leave : function() {
16075 clearTimeout(this.timeout);
16077 this.hoverState = 'out';
16079 if (!this.delay || !this.delay.hide) {
16084 this.timeout = setTimeout(function () {
16085 if (_t.hoverState == 'out') {
16088 }, this.delay.hide)
16091 show : function (on_el)
16094 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16098 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16099 if (this.html !== false) {
16100 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16102 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16103 if (!this.title.length) {
16104 this.el.select('.popover-title',true).hide();
16107 var placement = typeof this.placement == 'function' ?
16108 this.placement.call(this, this.el, on_el) :
16111 var autoToken = /\s?auto?\s?/i;
16112 var autoPlace = autoToken.test(placement);
16114 placement = placement.replace(autoToken, '') || 'top';
16118 //this.el.setXY([0,0]);
16120 this.el.dom.style.display='block';
16121 this.el.addClass(placement);
16123 //this.el.appendTo(on_el);
16125 var p = this.getPosition();
16126 var box = this.el.getBox();
16131 var align = Roo.bootstrap.Popover.alignment[placement];
16132 this.el.alignTo(on_el, align[0],align[1]);
16133 //var arrow = this.el.select('.arrow',true).first();
16134 //arrow.set(align[2],
16136 this.el.addClass('in');
16139 if (this.el.hasClass('fade')) {
16143 this.hoverState = 'in';
16145 this.fireEvent('show', this);
16150 this.el.setXY([0,0]);
16151 this.el.removeClass('in');
16153 this.hoverState = null;
16155 this.fireEvent('hide', this);
16160 Roo.bootstrap.Popover.alignment = {
16161 'left' : ['r-l', [-10,0], 'right'],
16162 'right' : ['l-r', [10,0], 'left'],
16163 'bottom' : ['t-b', [0,10], 'top'],
16164 'top' : [ 'b-t', [0,-10], 'bottom']
16175 * @class Roo.bootstrap.Progress
16176 * @extends Roo.bootstrap.Component
16177 * Bootstrap Progress class
16178 * @cfg {Boolean} striped striped of the progress bar
16179 * @cfg {Boolean} active animated of the progress bar
16183 * Create a new Progress
16184 * @param {Object} config The config object
16187 Roo.bootstrap.Progress = function(config){
16188 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16191 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16196 getAutoCreate : function(){
16204 cfg.cls += ' progress-striped';
16208 cfg.cls += ' active';
16227 * @class Roo.bootstrap.ProgressBar
16228 * @extends Roo.bootstrap.Component
16229 * Bootstrap ProgressBar class
16230 * @cfg {Number} aria_valuenow aria-value now
16231 * @cfg {Number} aria_valuemin aria-value min
16232 * @cfg {Number} aria_valuemax aria-value max
16233 * @cfg {String} label label for the progress bar
16234 * @cfg {String} panel (success | info | warning | danger )
16235 * @cfg {String} role role of the progress bar
16236 * @cfg {String} sr_only text
16240 * Create a new ProgressBar
16241 * @param {Object} config The config object
16244 Roo.bootstrap.ProgressBar = function(config){
16245 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16248 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16252 aria_valuemax : 100,
16258 getAutoCreate : function()
16263 cls: 'progress-bar',
16264 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16276 cfg.role = this.role;
16279 if(this.aria_valuenow){
16280 cfg['aria-valuenow'] = this.aria_valuenow;
16283 if(this.aria_valuemin){
16284 cfg['aria-valuemin'] = this.aria_valuemin;
16287 if(this.aria_valuemax){
16288 cfg['aria-valuemax'] = this.aria_valuemax;
16291 if(this.label && !this.sr_only){
16292 cfg.html = this.label;
16296 cfg.cls += ' progress-bar-' + this.panel;
16302 update : function(aria_valuenow)
16304 this.aria_valuenow = aria_valuenow;
16306 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16321 * @class Roo.bootstrap.TabGroup
16322 * @extends Roo.bootstrap.Column
16323 * Bootstrap Column class
16324 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16325 * @cfg {Boolean} carousel true to make the group behave like a carousel
16326 * @cfg {Boolean} bullets show bullets for the panels
16327 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16328 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16329 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16332 * Create a new TabGroup
16333 * @param {Object} config The config object
16336 Roo.bootstrap.TabGroup = function(config){
16337 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16339 this.navId = Roo.id();
16342 Roo.bootstrap.TabGroup.register(this);
16346 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16349 transition : false,
16354 slideOnTouch : false,
16356 getAutoCreate : function()
16358 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16360 cfg.cls += ' tab-content';
16362 if (this.carousel) {
16363 cfg.cls += ' carousel slide';
16366 cls : 'carousel-inner'
16369 if(this.bullets && !Roo.isTouch){
16372 cls : 'carousel-bullets',
16376 if(this.bullets_cls){
16377 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16380 for (var i = 0; i < this.bullets; i++){
16382 cls : 'bullet bullet-' + i
16390 cfg.cn[0].cn = bullets;
16397 initEvents: function()
16399 if(Roo.isTouch && this.slideOnTouch){
16400 this.el.on("touchstart", this.onTouchStart, this);
16403 if(this.autoslide){
16406 this.slideFn = window.setInterval(function() {
16407 _this.showPanelNext();
16413 onTouchStart : function(e, el, o)
16415 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16419 this.showPanelNext();
16422 getChildContainer : function()
16424 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
16428 * register a Navigation item
16429 * @param {Roo.bootstrap.NavItem} the navitem to add
16431 register : function(item)
16433 this.tabs.push( item);
16434 item.navId = this.navId; // not really needed..
16439 getActivePanel : function()
16442 Roo.each(this.tabs, function(t) {
16452 getPanelByName : function(n)
16455 Roo.each(this.tabs, function(t) {
16456 if (t.tabId == n) {
16464 indexOfPanel : function(p)
16467 Roo.each(this.tabs, function(t,i) {
16468 if (t.tabId == p.tabId) {
16477 * show a specific panel
16478 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
16479 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
16481 showPanel : function (pan)
16483 if(this.transition || typeof(pan) == 'undefined'){
16484 Roo.log("waiting for the transitionend");
16488 if (typeof(pan) == 'number') {
16489 pan = this.tabs[pan];
16492 if (typeof(pan) == 'string') {
16493 pan = this.getPanelByName(pan);
16496 var cur = this.getActivePanel();
16499 Roo.log('pan or acitve pan is undefined');
16503 if (pan.tabId == this.getActivePanel().tabId) {
16507 if (false === cur.fireEvent('beforedeactivate')) {
16511 if(this.bullets > 0 && !Roo.isTouch){
16512 this.setActiveBullet(this.indexOfPanel(pan));
16515 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
16517 this.transition = true;
16518 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
16519 var lr = dir == 'next' ? 'left' : 'right';
16520 pan.el.addClass(dir); // or prev
16521 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
16522 cur.el.addClass(lr); // or right
16523 pan.el.addClass(lr);
16526 cur.el.on('transitionend', function() {
16527 Roo.log("trans end?");
16529 pan.el.removeClass([lr,dir]);
16530 pan.setActive(true);
16532 cur.el.removeClass([lr]);
16533 cur.setActive(false);
16535 _this.transition = false;
16537 }, this, { single: true } );
16542 cur.setActive(false);
16543 pan.setActive(true);
16548 showPanelNext : function()
16550 var i = this.indexOfPanel(this.getActivePanel());
16552 if (i >= this.tabs.length - 1 && !this.autoslide) {
16556 if (i >= this.tabs.length - 1 && this.autoslide) {
16560 this.showPanel(this.tabs[i+1]);
16563 showPanelPrev : function()
16565 var i = this.indexOfPanel(this.getActivePanel());
16567 if (i < 1 && !this.autoslide) {
16571 if (i < 1 && this.autoslide) {
16572 i = this.tabs.length;
16575 this.showPanel(this.tabs[i-1]);
16579 addBullet: function()
16581 if(!this.bullets || Roo.isTouch){
16584 var ctr = this.el.select('.carousel-bullets',true).first();
16585 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
16586 var bullet = ctr.createChild({
16587 cls : 'bullet bullet-' + i
16588 },ctr.dom.lastChild);
16593 bullet.on('click', (function(e, el, o, ii, t){
16595 e.preventDefault();
16597 this.showPanel(ii);
16599 if(this.autoslide && this.slideFn){
16600 clearInterval(this.slideFn);
16601 this.slideFn = window.setInterval(function() {
16602 _this.showPanelNext();
16606 }).createDelegate(this, [i, bullet], true));
16611 setActiveBullet : function(i)
16617 Roo.each(this.el.select('.bullet', true).elements, function(el){
16618 el.removeClass('selected');
16621 var bullet = this.el.select('.bullet-' + i, true).first();
16627 bullet.addClass('selected');
16638 Roo.apply(Roo.bootstrap.TabGroup, {
16642 * register a Navigation Group
16643 * @param {Roo.bootstrap.NavGroup} the navgroup to add
16645 register : function(navgrp)
16647 this.groups[navgrp.navId] = navgrp;
16651 * fetch a Navigation Group based on the navigation ID
16652 * if one does not exist , it will get created.
16653 * @param {string} the navgroup to add
16654 * @returns {Roo.bootstrap.NavGroup} the navgroup
16656 get: function(navId) {
16657 if (typeof(this.groups[navId]) == 'undefined') {
16658 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
16660 return this.groups[navId] ;
16675 * @class Roo.bootstrap.TabPanel
16676 * @extends Roo.bootstrap.Component
16677 * Bootstrap TabPanel class
16678 * @cfg {Boolean} active panel active
16679 * @cfg {String} html panel content
16680 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
16681 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
16685 * Create a new TabPanel
16686 * @param {Object} config The config object
16689 Roo.bootstrap.TabPanel = function(config){
16690 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
16694 * Fires when the active status changes
16695 * @param {Roo.bootstrap.TabPanel} this
16696 * @param {Boolean} state the new state
16701 * @event beforedeactivate
16702 * Fires before a tab is de-activated - can be used to do validation on a form.
16703 * @param {Roo.bootstrap.TabPanel} this
16704 * @return {Boolean} false if there is an error
16707 'beforedeactivate': true
16710 this.tabId = this.tabId || Roo.id();
16714 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
16721 getAutoCreate : function(){
16724 // item is needed for carousel - not sure if it has any effect otherwise
16725 cls: 'tab-pane item',
16726 html: this.html || ''
16730 cfg.cls += ' active';
16734 cfg.tabId = this.tabId;
16741 initEvents: function()
16743 var p = this.parent();
16744 this.navId = this.navId || p.navId;
16746 if (typeof(this.navId) != 'undefined') {
16747 // not really needed.. but just in case.. parent should be a NavGroup.
16748 var tg = Roo.bootstrap.TabGroup.get(this.navId);
16752 var i = tg.tabs.length - 1;
16754 if(this.active && tg.bullets > 0 && i < tg.bullets){
16755 tg.setActiveBullet(i);
16762 onRender : function(ct, position)
16764 // Roo.log("Call onRender: " + this.xtype);
16766 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
16774 setActive: function(state)
16776 Roo.log("panel - set active " + this.tabId + "=" + state);
16778 this.active = state;
16780 this.el.removeClass('active');
16782 } else if (!this.el.hasClass('active')) {
16783 this.el.addClass('active');
16786 this.fireEvent('changed', this, state);
16803 * @class Roo.bootstrap.DateField
16804 * @extends Roo.bootstrap.Input
16805 * Bootstrap DateField class
16806 * @cfg {Number} weekStart default 0
16807 * @cfg {String} viewMode default empty, (months|years)
16808 * @cfg {String} minViewMode default empty, (months|years)
16809 * @cfg {Number} startDate default -Infinity
16810 * @cfg {Number} endDate default Infinity
16811 * @cfg {Boolean} todayHighlight default false
16812 * @cfg {Boolean} todayBtn default false
16813 * @cfg {Boolean} calendarWeeks default false
16814 * @cfg {Object} daysOfWeekDisabled default empty
16815 * @cfg {Boolean} singleMode default false (true | false)
16817 * @cfg {Boolean} keyboardNavigation default true
16818 * @cfg {String} language default en
16821 * Create a new DateField
16822 * @param {Object} config The config object
16825 Roo.bootstrap.DateField = function(config){
16826 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16830 * Fires when this field show.
16831 * @param {Roo.bootstrap.DateField} this
16832 * @param {Mixed} date The date value
16837 * Fires when this field hide.
16838 * @param {Roo.bootstrap.DateField} this
16839 * @param {Mixed} date The date value
16844 * Fires when select a date.
16845 * @param {Roo.bootstrap.DateField} this
16846 * @param {Mixed} date The date value
16850 * @event beforeselect
16851 * Fires when before select a date.
16852 * @param {Roo.bootstrap.DateField} this
16853 * @param {Mixed} date The date value
16855 beforeselect : true
16859 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16862 * @cfg {String} format
16863 * The default date format string which can be overriden for localization support. The format must be
16864 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16868 * @cfg {String} altFormats
16869 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16870 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16872 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16880 todayHighlight : false,
16886 keyboardNavigation: true,
16888 calendarWeeks: false,
16890 startDate: -Infinity,
16894 daysOfWeekDisabled: [],
16898 singleMode : false,
16900 UTCDate: function()
16902 return new Date(Date.UTC.apply(Date, arguments));
16905 UTCToday: function()
16907 var today = new Date();
16908 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16911 getDate: function() {
16912 var d = this.getUTCDate();
16913 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16916 getUTCDate: function() {
16920 setDate: function(d) {
16921 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16924 setUTCDate: function(d) {
16926 this.setValue(this.formatDate(this.date));
16929 onRender: function(ct, position)
16932 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16934 this.language = this.language || 'en';
16935 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16936 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16938 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16939 this.format = this.format || 'm/d/y';
16940 this.isInline = false;
16941 this.isInput = true;
16942 this.component = this.el.select('.add-on', true).first() || false;
16943 this.component = (this.component && this.component.length === 0) ? false : this.component;
16944 this.hasInput = this.component && this.inputEL().length;
16946 if (typeof(this.minViewMode === 'string')) {
16947 switch (this.minViewMode) {
16949 this.minViewMode = 1;
16952 this.minViewMode = 2;
16955 this.minViewMode = 0;
16960 if (typeof(this.viewMode === 'string')) {
16961 switch (this.viewMode) {
16974 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
16976 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
16978 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16980 this.picker().on('mousedown', this.onMousedown, this);
16981 this.picker().on('click', this.onClick, this);
16983 this.picker().addClass('datepicker-dropdown');
16985 this.startViewMode = this.viewMode;
16987 if(this.singleMode){
16988 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
16989 v.setVisibilityMode(Roo.Element.DISPLAY);
16993 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16994 v.setStyle('width', '189px');
16998 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
16999 if(!this.calendarWeeks){
17004 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17005 v.attr('colspan', function(i, val){
17006 return parseInt(val) + 1;
17011 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17013 this.setStartDate(this.startDate);
17014 this.setEndDate(this.endDate);
17016 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17023 if(this.isInline) {
17028 picker : function()
17030 return this.pickerEl;
17031 // return this.el.select('.datepicker', true).first();
17034 fillDow: function()
17036 var dowCnt = this.weekStart;
17045 if(this.calendarWeeks){
17053 while (dowCnt < this.weekStart + 7) {
17057 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17061 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17064 fillMonths: function()
17067 var months = this.picker().select('>.datepicker-months td', true).first();
17069 months.dom.innerHTML = '';
17075 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17078 months.createChild(month);
17085 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;
17087 if (this.date < this.startDate) {
17088 this.viewDate = new Date(this.startDate);
17089 } else if (this.date > this.endDate) {
17090 this.viewDate = new Date(this.endDate);
17092 this.viewDate = new Date(this.date);
17100 var d = new Date(this.viewDate),
17101 year = d.getUTCFullYear(),
17102 month = d.getUTCMonth(),
17103 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17104 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17105 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17106 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17107 currentDate = this.date && this.date.valueOf(),
17108 today = this.UTCToday();
17110 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17112 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17114 // this.picker.select('>tfoot th.today').
17115 // .text(dates[this.language].today)
17116 // .toggle(this.todayBtn !== false);
17118 this.updateNavArrows();
17121 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17123 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17125 prevMonth.setUTCDate(day);
17127 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17129 var nextMonth = new Date(prevMonth);
17131 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17133 nextMonth = nextMonth.valueOf();
17135 var fillMonths = false;
17137 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17139 while(prevMonth.valueOf() < nextMonth) {
17142 if (prevMonth.getUTCDay() === this.weekStart) {
17144 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17152 if(this.calendarWeeks){
17153 // ISO 8601: First week contains first thursday.
17154 // ISO also states week starts on Monday, but we can be more abstract here.
17156 // Start of current week: based on weekstart/current date
17157 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17158 // Thursday of this week
17159 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17160 // First Thursday of year, year from thursday
17161 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17162 // Calendar week: ms between thursdays, div ms per day, div 7 days
17163 calWeek = (th - yth) / 864e5 / 7 + 1;
17165 fillMonths.cn.push({
17173 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17175 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17178 if (this.todayHighlight &&
17179 prevMonth.getUTCFullYear() == today.getFullYear() &&
17180 prevMonth.getUTCMonth() == today.getMonth() &&
17181 prevMonth.getUTCDate() == today.getDate()) {
17182 clsName += ' today';
17185 if (currentDate && prevMonth.valueOf() === currentDate) {
17186 clsName += ' active';
17189 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17190 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17191 clsName += ' disabled';
17194 fillMonths.cn.push({
17196 cls: 'day ' + clsName,
17197 html: prevMonth.getDate()
17200 prevMonth.setDate(prevMonth.getDate()+1);
17203 var currentYear = this.date && this.date.getUTCFullYear();
17204 var currentMonth = this.date && this.date.getUTCMonth();
17206 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17208 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17209 v.removeClass('active');
17211 if(currentYear === year && k === currentMonth){
17212 v.addClass('active');
17215 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17216 v.addClass('disabled');
17222 year = parseInt(year/10, 10) * 10;
17224 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17226 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17229 for (var i = -1; i < 11; i++) {
17230 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17232 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17240 showMode: function(dir)
17243 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17246 Roo.each(this.picker().select('>div',true).elements, function(v){
17247 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17250 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17255 if(this.isInline) {
17259 this.picker().removeClass(['bottom', 'top']);
17261 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17263 * place to the top of element!
17267 this.picker().addClass('top');
17268 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17273 this.picker().addClass('bottom');
17275 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17278 parseDate : function(value)
17280 if(!value || value instanceof Date){
17283 var v = Date.parseDate(value, this.format);
17284 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17285 v = Date.parseDate(value, 'Y-m-d');
17287 if(!v && this.altFormats){
17288 if(!this.altFormatsArray){
17289 this.altFormatsArray = this.altFormats.split("|");
17291 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17292 v = Date.parseDate(value, this.altFormatsArray[i]);
17298 formatDate : function(date, fmt)
17300 return (!date || !(date instanceof Date)) ?
17301 date : date.dateFormat(fmt || this.format);
17304 onFocus : function()
17306 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17310 onBlur : function()
17312 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17314 var d = this.inputEl().getValue();
17323 this.picker().show();
17327 this.fireEvent('show', this, this.date);
17332 if(this.isInline) {
17335 this.picker().hide();
17336 this.viewMode = this.startViewMode;
17339 this.fireEvent('hide', this, this.date);
17343 onMousedown: function(e)
17345 e.stopPropagation();
17346 e.preventDefault();
17351 Roo.bootstrap.DateField.superclass.keyup.call(this);
17355 setValue: function(v)
17357 if(this.fireEvent('beforeselect', this, v) !== false){
17358 var d = new Date(this.parseDate(v) ).clearTime();
17360 if(isNaN(d.getTime())){
17361 this.date = this.viewDate = '';
17362 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17366 v = this.formatDate(d);
17368 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17370 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17374 this.fireEvent('select', this, this.date);
17378 getValue: function()
17380 return this.formatDate(this.date);
17383 fireKey: function(e)
17385 if (!this.picker().isVisible()){
17386 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17392 var dateChanged = false,
17394 newDate, newViewDate;
17399 e.preventDefault();
17403 if (!this.keyboardNavigation) {
17406 dir = e.keyCode == 37 ? -1 : 1;
17409 newDate = this.moveYear(this.date, dir);
17410 newViewDate = this.moveYear(this.viewDate, dir);
17411 } else if (e.shiftKey){
17412 newDate = this.moveMonth(this.date, dir);
17413 newViewDate = this.moveMonth(this.viewDate, dir);
17415 newDate = new Date(this.date);
17416 newDate.setUTCDate(this.date.getUTCDate() + dir);
17417 newViewDate = new Date(this.viewDate);
17418 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
17420 if (this.dateWithinRange(newDate)){
17421 this.date = newDate;
17422 this.viewDate = newViewDate;
17423 this.setValue(this.formatDate(this.date));
17425 e.preventDefault();
17426 dateChanged = true;
17431 if (!this.keyboardNavigation) {
17434 dir = e.keyCode == 38 ? -1 : 1;
17436 newDate = this.moveYear(this.date, dir);
17437 newViewDate = this.moveYear(this.viewDate, dir);
17438 } else if (e.shiftKey){
17439 newDate = this.moveMonth(this.date, dir);
17440 newViewDate = this.moveMonth(this.viewDate, dir);
17442 newDate = new Date(this.date);
17443 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
17444 newViewDate = new Date(this.viewDate);
17445 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
17447 if (this.dateWithinRange(newDate)){
17448 this.date = newDate;
17449 this.viewDate = newViewDate;
17450 this.setValue(this.formatDate(this.date));
17452 e.preventDefault();
17453 dateChanged = true;
17457 this.setValue(this.formatDate(this.date));
17459 e.preventDefault();
17462 this.setValue(this.formatDate(this.date));
17476 onClick: function(e)
17478 e.stopPropagation();
17479 e.preventDefault();
17481 var target = e.getTarget();
17483 if(target.nodeName.toLowerCase() === 'i'){
17484 target = Roo.get(target).dom.parentNode;
17487 var nodeName = target.nodeName;
17488 var className = target.className;
17489 var html = target.innerHTML;
17490 //Roo.log(nodeName);
17492 switch(nodeName.toLowerCase()) {
17494 switch(className) {
17500 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
17501 switch(this.viewMode){
17503 this.viewDate = this.moveMonth(this.viewDate, dir);
17507 this.viewDate = this.moveYear(this.viewDate, dir);
17513 var date = new Date();
17514 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
17516 this.setValue(this.formatDate(this.date));
17523 if (className.indexOf('disabled') < 0) {
17524 this.viewDate.setUTCDate(1);
17525 if (className.indexOf('month') > -1) {
17526 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
17528 var year = parseInt(html, 10) || 0;
17529 this.viewDate.setUTCFullYear(year);
17533 if(this.singleMode){
17534 this.setValue(this.formatDate(this.viewDate));
17545 //Roo.log(className);
17546 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
17547 var day = parseInt(html, 10) || 1;
17548 var year = this.viewDate.getUTCFullYear(),
17549 month = this.viewDate.getUTCMonth();
17551 if (className.indexOf('old') > -1) {
17558 } else if (className.indexOf('new') > -1) {
17566 //Roo.log([year,month,day]);
17567 this.date = this.UTCDate(year, month, day,0,0,0,0);
17568 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
17570 //Roo.log(this.formatDate(this.date));
17571 this.setValue(this.formatDate(this.date));
17578 setStartDate: function(startDate)
17580 this.startDate = startDate || -Infinity;
17581 if (this.startDate !== -Infinity) {
17582 this.startDate = this.parseDate(this.startDate);
17585 this.updateNavArrows();
17588 setEndDate: function(endDate)
17590 this.endDate = endDate || Infinity;
17591 if (this.endDate !== Infinity) {
17592 this.endDate = this.parseDate(this.endDate);
17595 this.updateNavArrows();
17598 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
17600 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
17601 if (typeof(this.daysOfWeekDisabled) !== 'object') {
17602 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
17604 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
17605 return parseInt(d, 10);
17608 this.updateNavArrows();
17611 updateNavArrows: function()
17613 if(this.singleMode){
17617 var d = new Date(this.viewDate),
17618 year = d.getUTCFullYear(),
17619 month = d.getUTCMonth();
17621 Roo.each(this.picker().select('.prev', true).elements, function(v){
17623 switch (this.viewMode) {
17626 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
17632 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
17639 Roo.each(this.picker().select('.next', true).elements, function(v){
17641 switch (this.viewMode) {
17644 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
17650 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
17658 moveMonth: function(date, dir)
17663 var new_date = new Date(date.valueOf()),
17664 day = new_date.getUTCDate(),
17665 month = new_date.getUTCMonth(),
17666 mag = Math.abs(dir),
17668 dir = dir > 0 ? 1 : -1;
17671 // If going back one month, make sure month is not current month
17672 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
17674 return new_date.getUTCMonth() == month;
17676 // If going forward one month, make sure month is as expected
17677 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
17679 return new_date.getUTCMonth() != new_month;
17681 new_month = month + dir;
17682 new_date.setUTCMonth(new_month);
17683 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
17684 if (new_month < 0 || new_month > 11) {
17685 new_month = (new_month + 12) % 12;
17688 // For magnitudes >1, move one month at a time...
17689 for (var i=0; i<mag; i++) {
17690 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
17691 new_date = this.moveMonth(new_date, dir);
17693 // ...then reset the day, keeping it in the new month
17694 new_month = new_date.getUTCMonth();
17695 new_date.setUTCDate(day);
17697 return new_month != new_date.getUTCMonth();
17700 // Common date-resetting loop -- if date is beyond end of month, make it
17703 new_date.setUTCDate(--day);
17704 new_date.setUTCMonth(new_month);
17709 moveYear: function(date, dir)
17711 return this.moveMonth(date, dir*12);
17714 dateWithinRange: function(date)
17716 return date >= this.startDate && date <= this.endDate;
17722 this.picker().remove();
17727 Roo.apply(Roo.bootstrap.DateField, {
17738 html: '<i class="fa fa-arrow-left"/>'
17748 html: '<i class="fa fa-arrow-right"/>'
17790 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
17791 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17792 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
17793 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17794 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17807 navFnc: 'FullYear',
17812 navFnc: 'FullYear',
17817 Roo.apply(Roo.bootstrap.DateField, {
17821 cls: 'datepicker dropdown-menu roo-dynamic',
17825 cls: 'datepicker-days',
17829 cls: 'table-condensed',
17831 Roo.bootstrap.DateField.head,
17835 Roo.bootstrap.DateField.footer
17842 cls: 'datepicker-months',
17846 cls: 'table-condensed',
17848 Roo.bootstrap.DateField.head,
17849 Roo.bootstrap.DateField.content,
17850 Roo.bootstrap.DateField.footer
17857 cls: 'datepicker-years',
17861 cls: 'table-condensed',
17863 Roo.bootstrap.DateField.head,
17864 Roo.bootstrap.DateField.content,
17865 Roo.bootstrap.DateField.footer
17884 * @class Roo.bootstrap.TimeField
17885 * @extends Roo.bootstrap.Input
17886 * Bootstrap DateField class
17890 * Create a new TimeField
17891 * @param {Object} config The config object
17894 Roo.bootstrap.TimeField = function(config){
17895 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17899 * Fires when this field show.
17900 * @param {Roo.bootstrap.DateField} thisthis
17901 * @param {Mixed} date The date value
17906 * Fires when this field hide.
17907 * @param {Roo.bootstrap.DateField} this
17908 * @param {Mixed} date The date value
17913 * Fires when select a date.
17914 * @param {Roo.bootstrap.DateField} this
17915 * @param {Mixed} date The date value
17921 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17924 * @cfg {String} format
17925 * The default time format string which can be overriden for localization support. The format must be
17926 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17930 onRender: function(ct, position)
17933 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17935 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17937 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17939 this.pop = this.picker().select('>.datepicker-time',true).first();
17940 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17942 this.picker().on('mousedown', this.onMousedown, this);
17943 this.picker().on('click', this.onClick, this);
17945 this.picker().addClass('datepicker-dropdown');
17950 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17951 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17952 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17953 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17954 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17955 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17959 fireKey: function(e){
17960 if (!this.picker().isVisible()){
17961 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17967 e.preventDefault();
17975 this.onTogglePeriod();
17978 this.onIncrementMinutes();
17981 this.onDecrementMinutes();
17990 onClick: function(e) {
17991 e.stopPropagation();
17992 e.preventDefault();
17995 picker : function()
17997 return this.el.select('.datepicker', true).first();
18000 fillTime: function()
18002 var time = this.pop.select('tbody', true).first();
18004 time.dom.innerHTML = '';
18019 cls: 'hours-up glyphicon glyphicon-chevron-up'
18039 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18060 cls: 'timepicker-hour',
18075 cls: 'timepicker-minute',
18090 cls: 'btn btn-primary period',
18112 cls: 'hours-down glyphicon glyphicon-chevron-down'
18132 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18150 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18157 var hours = this.time.getHours();
18158 var minutes = this.time.getMinutes();
18171 hours = hours - 12;
18175 hours = '0' + hours;
18179 minutes = '0' + minutes;
18182 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18183 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18184 this.pop.select('button', true).first().dom.innerHTML = period;
18190 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18192 var cls = ['bottom'];
18194 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18201 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18206 this.picker().addClass(cls.join('-'));
18210 Roo.each(cls, function(c){
18212 _this.picker().setTop(_this.inputEl().getHeight());
18216 _this.picker().setTop(0 - _this.picker().getHeight());
18221 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18225 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18232 onFocus : function()
18234 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18238 onBlur : function()
18240 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18246 this.picker().show();
18251 this.fireEvent('show', this, this.date);
18256 this.picker().hide();
18259 this.fireEvent('hide', this, this.date);
18262 setTime : function()
18265 this.setValue(this.time.format(this.format));
18267 this.fireEvent('select', this, this.date);
18272 onMousedown: function(e){
18273 e.stopPropagation();
18274 e.preventDefault();
18277 onIncrementHours: function()
18279 Roo.log('onIncrementHours');
18280 this.time = this.time.add(Date.HOUR, 1);
18285 onDecrementHours: function()
18287 Roo.log('onDecrementHours');
18288 this.time = this.time.add(Date.HOUR, -1);
18292 onIncrementMinutes: function()
18294 Roo.log('onIncrementMinutes');
18295 this.time = this.time.add(Date.MINUTE, 1);
18299 onDecrementMinutes: function()
18301 Roo.log('onDecrementMinutes');
18302 this.time = this.time.add(Date.MINUTE, -1);
18306 onTogglePeriod: function()
18308 Roo.log('onTogglePeriod');
18309 this.time = this.time.add(Date.HOUR, 12);
18316 Roo.apply(Roo.bootstrap.TimeField, {
18346 cls: 'btn btn-info ok',
18358 Roo.apply(Roo.bootstrap.TimeField, {
18362 cls: 'datepicker dropdown-menu',
18366 cls: 'datepicker-time',
18370 cls: 'table-condensed',
18372 Roo.bootstrap.TimeField.content,
18373 Roo.bootstrap.TimeField.footer
18392 * @class Roo.bootstrap.MonthField
18393 * @extends Roo.bootstrap.Input
18394 * Bootstrap MonthField class
18396 * @cfg {String} language default en
18399 * Create a new MonthField
18400 * @param {Object} config The config object
18403 Roo.bootstrap.MonthField = function(config){
18404 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
18409 * Fires when this field show.
18410 * @param {Roo.bootstrap.MonthField} this
18411 * @param {Mixed} date The date value
18416 * Fires when this field hide.
18417 * @param {Roo.bootstrap.MonthField} this
18418 * @param {Mixed} date The date value
18423 * Fires when select a date.
18424 * @param {Roo.bootstrap.MonthField} this
18425 * @param {String} oldvalue The old value
18426 * @param {String} newvalue The new value
18432 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
18434 onRender: function(ct, position)
18437 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
18439 this.language = this.language || 'en';
18440 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
18441 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
18443 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
18444 this.isInline = false;
18445 this.isInput = true;
18446 this.component = this.el.select('.add-on', true).first() || false;
18447 this.component = (this.component && this.component.length === 0) ? false : this.component;
18448 this.hasInput = this.component && this.inputEL().length;
18450 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
18452 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18454 this.picker().on('mousedown', this.onMousedown, this);
18455 this.picker().on('click', this.onClick, this);
18457 this.picker().addClass('datepicker-dropdown');
18459 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18460 v.setStyle('width', '189px');
18467 if(this.isInline) {
18473 setValue: function(v, suppressEvent)
18475 var o = this.getValue();
18477 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
18481 if(suppressEvent !== true){
18482 this.fireEvent('select', this, o, v);
18487 getValue: function()
18492 onClick: function(e)
18494 e.stopPropagation();
18495 e.preventDefault();
18497 var target = e.getTarget();
18499 if(target.nodeName.toLowerCase() === 'i'){
18500 target = Roo.get(target).dom.parentNode;
18503 var nodeName = target.nodeName;
18504 var className = target.className;
18505 var html = target.innerHTML;
18507 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
18511 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
18513 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18519 picker : function()
18521 return this.pickerEl;
18524 fillMonths: function()
18527 var months = this.picker().select('>.datepicker-months td', true).first();
18529 months.dom.innerHTML = '';
18535 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
18538 months.createChild(month);
18547 if(typeof(this.vIndex) == 'undefined' && this.value.length){
18548 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
18551 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
18552 e.removeClass('active');
18554 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
18555 e.addClass('active');
18562 if(this.isInline) {
18566 this.picker().removeClass(['bottom', 'top']);
18568 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18570 * place to the top of element!
18574 this.picker().addClass('top');
18575 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18580 this.picker().addClass('bottom');
18582 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18585 onFocus : function()
18587 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
18591 onBlur : function()
18593 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
18595 var d = this.inputEl().getValue();
18604 this.picker().show();
18605 this.picker().select('>.datepicker-months', true).first().show();
18609 this.fireEvent('show', this, this.date);
18614 if(this.isInline) {
18617 this.picker().hide();
18618 this.fireEvent('hide', this, this.date);
18622 onMousedown: function(e)
18624 e.stopPropagation();
18625 e.preventDefault();
18630 Roo.bootstrap.MonthField.superclass.keyup.call(this);
18634 fireKey: function(e)
18636 if (!this.picker().isVisible()){
18637 if (e.keyCode == 27) {// allow escape to hide and re-show picker
18648 e.preventDefault();
18652 dir = e.keyCode == 37 ? -1 : 1;
18654 this.vIndex = this.vIndex + dir;
18656 if(this.vIndex < 0){
18660 if(this.vIndex > 11){
18664 if(isNaN(this.vIndex)){
18668 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18674 dir = e.keyCode == 38 ? -1 : 1;
18676 this.vIndex = this.vIndex + dir * 4;
18678 if(this.vIndex < 0){
18682 if(this.vIndex > 11){
18686 if(isNaN(this.vIndex)){
18690 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18695 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18696 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18700 e.preventDefault();
18703 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18704 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18720 this.picker().remove();
18725 Roo.apply(Roo.bootstrap.MonthField, {
18744 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18745 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
18750 Roo.apply(Roo.bootstrap.MonthField, {
18754 cls: 'datepicker dropdown-menu roo-dynamic',
18758 cls: 'datepicker-months',
18762 cls: 'table-condensed',
18764 Roo.bootstrap.DateField.content
18784 * @class Roo.bootstrap.CheckBox
18785 * @extends Roo.bootstrap.Input
18786 * Bootstrap CheckBox class
18788 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
18789 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
18790 * @cfg {String} boxLabel The text that appears beside the checkbox
18791 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
18792 * @cfg {Boolean} checked initnal the element
18793 * @cfg {Boolean} inline inline the element (default false)
18794 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
18797 * Create a new CheckBox
18798 * @param {Object} config The config object
18801 Roo.bootstrap.CheckBox = function(config){
18802 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18807 * Fires when the element is checked or unchecked.
18808 * @param {Roo.bootstrap.CheckBox} this This input
18809 * @param {Boolean} checked The new checked value
18816 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18818 inputType: 'checkbox',
18826 getAutoCreate : function()
18828 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18834 cfg.cls = 'form-group ' + this.inputType; //input-group
18837 cfg.cls += ' ' + this.inputType + '-inline';
18843 type : this.inputType,
18844 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18845 cls : 'roo-' + this.inputType, //'form-box',
18846 placeholder : this.placeholder || ''
18850 if (this.weight) { // Validity check?
18851 cfg.cls += " " + this.inputType + "-" + this.weight;
18854 if (this.disabled) {
18855 input.disabled=true;
18859 input.checked = this.checked;
18863 input.name = this.name;
18867 input.cls += ' input-' + this.size;
18872 ['xs','sm','md','lg'].map(function(size){
18873 if (settings[size]) {
18874 cfg.cls += ' col-' + size + '-' + settings[size];
18878 var inputblock = input;
18880 if (this.before || this.after) {
18883 cls : 'input-group',
18888 inputblock.cn.push({
18890 cls : 'input-group-addon',
18895 inputblock.cn.push(input);
18898 inputblock.cn.push({
18900 cls : 'input-group-addon',
18907 if (align ==='left' && this.fieldLabel.length) {
18908 // Roo.log("left and has label");
18914 cls : 'control-label col-md-' + this.labelWidth,
18915 html : this.fieldLabel
18919 cls : "col-md-" + (12 - this.labelWidth),
18926 } else if ( this.fieldLabel.length) {
18927 // Roo.log(" label");
18931 tag: this.boxLabel ? 'span' : 'label',
18933 cls: 'control-label box-input-label',
18934 //cls : 'input-group-addon',
18935 html : this.fieldLabel
18945 // Roo.log(" no label && no align");
18946 cfg.cn = [ inputblock ] ;
18952 var boxLabelCfg = {
18954 //'for': id, // box label is handled by onclick - so no for...
18956 html: this.boxLabel
18960 boxLabelCfg.tooltip = this.tooltip;
18963 cfg.cn.push(boxLabelCfg);
18973 * return the real input element.
18975 inputEl: function ()
18977 return this.el.select('input.roo-' + this.inputType,true).first();
18980 labelEl: function()
18982 return this.el.select('label.control-label',true).first();
18984 /* depricated... */
18988 return this.labelEl();
18991 boxLabelEl: function()
18993 return this.el.select('label.box-label',true).first();
18996 initEvents : function()
18998 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19000 this.inputEl().on('click', this.onClick, this);
19002 if (this.boxLabel) {
19003 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19006 this.startValue = this.getValue();
19009 Roo.bootstrap.CheckBox.register(this);
19013 onClick : function()
19015 this.setChecked(!this.checked);
19018 setChecked : function(state,suppressEvent)
19020 this.startValue = this.getValue();
19022 if(this.inputType == 'radio'){
19024 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19025 e.dom.checked = false;
19028 this.inputEl().dom.checked = true;
19030 this.inputEl().dom.value = this.inputValue;
19032 if(suppressEvent !== true){
19033 this.fireEvent('check', this, true);
19041 this.checked = state;
19043 this.inputEl().dom.checked = state;
19045 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19047 if(suppressEvent !== true){
19048 this.fireEvent('check', this, state);
19054 getValue : function()
19056 if(this.inputType == 'radio'){
19057 return this.getGroupValue();
19060 return this.inputEl().getValue();
19064 getGroupValue : function()
19066 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19070 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19073 setValue : function(v,suppressEvent)
19075 if(this.inputType == 'radio'){
19076 this.setGroupValue(v, suppressEvent);
19080 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19085 setGroupValue : function(v, suppressEvent)
19087 this.startValue = this.getValue();
19089 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19090 e.dom.checked = false;
19092 if(e.dom.value == v){
19093 e.dom.checked = true;
19097 if(suppressEvent !== true){
19098 this.fireEvent('check', this, true);
19106 validate : function()
19110 (this.inputType == 'radio' && this.validateRadio()) ||
19111 (this.inputType == 'checkbox' && this.validateCheckbox())
19117 this.markInvalid();
19121 validateRadio : function()
19125 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19126 if(!e.dom.checked){
19138 validateCheckbox : function()
19141 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19144 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19152 for(var i in group){
19157 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19164 * Mark this field as valid
19166 markValid : function()
19168 if(this.allowBlank){
19174 this.fireEvent('valid', this);
19176 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19179 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19186 if(this.inputType == 'radio'){
19187 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19188 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19189 e.findParent('.form-group', false, true).addClass(_this.validClass);
19196 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19197 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19201 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19207 for(var i in group){
19208 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19209 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19214 * Mark this field as invalid
19215 * @param {String} msg The validation message
19217 markInvalid : function(msg)
19219 if(this.allowBlank){
19225 this.fireEvent('invalid', this, msg);
19227 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19230 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19234 label.markInvalid();
19237 if(this.inputType == 'radio'){
19238 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19239 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19240 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19247 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19248 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19252 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19258 for(var i in group){
19259 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19260 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19267 Roo.apply(Roo.bootstrap.CheckBox, {
19272 * register a CheckBox Group
19273 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19275 register : function(checkbox)
19277 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19278 this.groups[checkbox.groupId] = {};
19281 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19285 this.groups[checkbox.groupId][checkbox.name] = checkbox;
19289 * fetch a CheckBox Group based on the group ID
19290 * @param {string} the group ID
19291 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
19293 get: function(groupId) {
19294 if (typeof(this.groups[groupId]) == 'undefined') {
19298 return this.groups[groupId] ;
19310 *<div class="radio">
19312 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
19313 Option one is this and that—be sure to include why it's great
19320 *<label class="radio-inline">fieldLabel</label>
19321 *<label class="radio-inline">
19322 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
19330 * @class Roo.bootstrap.Radio
19331 * @extends Roo.bootstrap.CheckBox
19332 * Bootstrap Radio class
19335 * Create a new Radio
19336 * @param {Object} config The config object
19339 Roo.bootstrap.Radio = function(config){
19340 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
19344 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
19346 inputType: 'radio',
19350 getAutoCreate : function()
19352 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19353 align = align || 'left'; // default...
19360 tag : this.inline ? 'span' : 'div',
19365 var inline = this.inline ? ' radio-inline' : '';
19369 // does not need for, as we wrap the input with it..
19371 cls : 'control-label box-label' + inline,
19374 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
19378 //cls : 'control-label' + inline,
19379 html : this.fieldLabel,
19380 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
19389 type : this.inputType,
19390 //value : (!this.checked) ? this.valueOff : this.inputValue,
19391 value : this.inputValue,
19393 placeholder : this.placeholder || '' // ?? needed????
19396 if (this.weight) { // Validity check?
19397 input.cls += " radio-" + this.weight;
19399 if (this.disabled) {
19400 input.disabled=true;
19404 input.checked = this.checked;
19408 input.name = this.name;
19412 input.cls += ' input-' + this.size;
19415 //?? can span's inline have a width??
19418 ['xs','sm','md','lg'].map(function(size){
19419 if (settings[size]) {
19420 cfg.cls += ' col-' + size + '-' + settings[size];
19424 var inputblock = input;
19426 if (this.before || this.after) {
19429 cls : 'input-group',
19434 inputblock.cn.push({
19436 cls : 'input-group-addon',
19440 inputblock.cn.push(input);
19442 inputblock.cn.push({
19444 cls : 'input-group-addon',
19452 if (this.fieldLabel && this.fieldLabel.length) {
19453 cfg.cn.push(fieldLabel);
19456 // normal bootstrap puts the input inside the label.
19457 // however with our styled version - it has to go after the input.
19459 //lbl.cn.push(inputblock);
19463 cls: 'radio' + inline,
19470 cfg.cn.push( lblwrap);
19475 html: this.boxLabel
19484 initEvents : function()
19486 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19488 this.inputEl().on('click', this.onClick, this);
19489 if (this.boxLabel) {
19490 //Roo.log('find label');
19491 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
19496 inputEl: function ()
19498 return this.el.select('input.roo-radio',true).first();
19500 onClick : function()
19503 this.setChecked(true);
19506 setChecked : function(state,suppressEvent)
19509 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19510 v.dom.checked = false;
19513 Roo.log(this.inputEl().dom);
19514 this.checked = state;
19515 this.inputEl().dom.checked = state;
19517 if(suppressEvent !== true){
19518 this.fireEvent('check', this, state);
19521 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19525 getGroupValue : function()
19528 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19529 if(v.dom.checked == true){
19530 value = v.dom.value;
19538 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19539 * @return {Mixed} value The field value
19541 getValue : function(){
19542 return this.getGroupValue();
19548 //<script type="text/javascript">
19551 * Based Ext JS Library 1.1.1
19552 * Copyright(c) 2006-2007, Ext JS, LLC.
19558 * @class Roo.HtmlEditorCore
19559 * @extends Roo.Component
19560 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
19562 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
19565 Roo.HtmlEditorCore = function(config){
19568 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
19573 * @event initialize
19574 * Fires when the editor is fully initialized (including the iframe)
19575 * @param {Roo.HtmlEditorCore} this
19580 * Fires when the editor is first receives the focus. Any insertion must wait
19581 * until after this event.
19582 * @param {Roo.HtmlEditorCore} this
19586 * @event beforesync
19587 * Fires before the textarea is updated with content from the editor iframe. Return false
19588 * to cancel the sync.
19589 * @param {Roo.HtmlEditorCore} this
19590 * @param {String} html
19594 * @event beforepush
19595 * Fires before the iframe editor is updated with content from the textarea. Return false
19596 * to cancel the push.
19597 * @param {Roo.HtmlEditorCore} this
19598 * @param {String} html
19603 * Fires when the textarea is updated with content from the editor iframe.
19604 * @param {Roo.HtmlEditorCore} this
19605 * @param {String} html
19610 * Fires when the iframe editor is updated with content from the textarea.
19611 * @param {Roo.HtmlEditorCore} this
19612 * @param {String} html
19617 * @event editorevent
19618 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19619 * @param {Roo.HtmlEditorCore} this
19625 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
19627 // defaults : white / black...
19628 this.applyBlacklists();
19635 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
19639 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
19645 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19650 * @cfg {Number} height (in pixels)
19654 * @cfg {Number} width (in pixels)
19659 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19662 stylesheets: false,
19667 // private properties
19668 validationEvent : false,
19670 initialized : false,
19672 sourceEditMode : false,
19673 onFocus : Roo.emptyFn,
19675 hideMode:'offsets',
19679 // blacklist + whitelisted elements..
19686 * Protected method that will not generally be called directly. It
19687 * is called when the editor initializes the iframe with HTML contents. Override this method if you
19688 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
19690 getDocMarkup : function(){
19694 // inherit styels from page...??
19695 if (this.stylesheets === false) {
19697 Roo.get(document.head).select('style').each(function(node) {
19698 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19701 Roo.get(document.head).select('link').each(function(node) {
19702 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19705 } else if (!this.stylesheets.length) {
19707 st = '<style type="text/css">' +
19708 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19714 st += '<style type="text/css">' +
19715 'IMG { cursor: pointer } ' +
19719 return '<html><head>' + st +
19720 //<style type="text/css">' +
19721 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19723 ' </head><body class="roo-htmleditor-body"></body></html>';
19727 onRender : function(ct, position)
19730 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
19731 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
19734 this.el.dom.style.border = '0 none';
19735 this.el.dom.setAttribute('tabIndex', -1);
19736 this.el.addClass('x-hidden hide');
19740 if(Roo.isIE){ // fix IE 1px bogus margin
19741 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
19745 this.frameId = Roo.id();
19749 var iframe = this.owner.wrap.createChild({
19751 cls: 'form-control', // bootstrap..
19753 name: this.frameId,
19754 frameBorder : 'no',
19755 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
19760 this.iframe = iframe.dom;
19762 this.assignDocWin();
19764 this.doc.designMode = 'on';
19767 this.doc.write(this.getDocMarkup());
19771 var task = { // must defer to wait for browser to be ready
19773 //console.log("run task?" + this.doc.readyState);
19774 this.assignDocWin();
19775 if(this.doc.body || this.doc.readyState == 'complete'){
19777 this.doc.designMode="on";
19781 Roo.TaskMgr.stop(task);
19782 this.initEditor.defer(10, this);
19789 Roo.TaskMgr.start(task);
19794 onResize : function(w, h)
19796 Roo.log('resize: ' +w + ',' + h );
19797 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
19801 if(typeof w == 'number'){
19803 this.iframe.style.width = w + 'px';
19805 if(typeof h == 'number'){
19807 this.iframe.style.height = h + 'px';
19809 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
19816 * Toggles the editor between standard and source edit mode.
19817 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19819 toggleSourceEdit : function(sourceEditMode){
19821 this.sourceEditMode = sourceEditMode === true;
19823 if(this.sourceEditMode){
19825 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19828 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19829 //this.iframe.className = '';
19832 //this.setSize(this.owner.wrap.getSize());
19833 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19840 * Protected method that will not generally be called directly. If you need/want
19841 * custom HTML cleanup, this is the method you should override.
19842 * @param {String} html The HTML to be cleaned
19843 * return {String} The cleaned HTML
19845 cleanHtml : function(html){
19846 html = String(html);
19847 if(html.length > 5){
19848 if(Roo.isSafari){ // strip safari nonsense
19849 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19852 if(html == ' '){
19859 * HTML Editor -> Textarea
19860 * Protected method that will not generally be called directly. Syncs the contents
19861 * of the editor iframe with the textarea.
19863 syncValue : function(){
19864 if(this.initialized){
19865 var bd = (this.doc.body || this.doc.documentElement);
19866 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19867 var html = bd.innerHTML;
19869 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19870 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19872 html = '<div style="'+m[0]+'">' + html + '</div>';
19875 html = this.cleanHtml(html);
19876 // fix up the special chars.. normaly like back quotes in word...
19877 // however we do not want to do this with chinese..
19878 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19879 var cc = b.charCodeAt();
19881 (cc >= 0x4E00 && cc < 0xA000 ) ||
19882 (cc >= 0x3400 && cc < 0x4E00 ) ||
19883 (cc >= 0xf900 && cc < 0xfb00 )
19889 if(this.owner.fireEvent('beforesync', this, html) !== false){
19890 this.el.dom.value = html;
19891 this.owner.fireEvent('sync', this, html);
19897 * Protected method that will not generally be called directly. Pushes the value of the textarea
19898 * into the iframe editor.
19900 pushValue : function(){
19901 if(this.initialized){
19902 var v = this.el.dom.value.trim();
19904 // if(v.length < 1){
19908 if(this.owner.fireEvent('beforepush', this, v) !== false){
19909 var d = (this.doc.body || this.doc.documentElement);
19911 this.cleanUpPaste();
19912 this.el.dom.value = d.innerHTML;
19913 this.owner.fireEvent('push', this, v);
19919 deferFocus : function(){
19920 this.focus.defer(10, this);
19924 focus : function(){
19925 if(this.win && !this.sourceEditMode){
19932 assignDocWin: function()
19934 var iframe = this.iframe;
19937 this.doc = iframe.contentWindow.document;
19938 this.win = iframe.contentWindow;
19940 // if (!Roo.get(this.frameId)) {
19943 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19944 // this.win = Roo.get(this.frameId).dom.contentWindow;
19946 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19950 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19951 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19956 initEditor : function(){
19957 //console.log("INIT EDITOR");
19958 this.assignDocWin();
19962 this.doc.designMode="on";
19964 this.doc.write(this.getDocMarkup());
19967 var dbody = (this.doc.body || this.doc.documentElement);
19968 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
19969 // this copies styles from the containing element into thsi one..
19970 // not sure why we need all of this..
19971 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
19973 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
19974 //ss['background-attachment'] = 'fixed'; // w3c
19975 dbody.bgProperties = 'fixed'; // ie
19976 //Roo.DomHelper.applyStyles(dbody, ss);
19977 Roo.EventManager.on(this.doc, {
19978 //'mousedown': this.onEditorEvent,
19979 'mouseup': this.onEditorEvent,
19980 'dblclick': this.onEditorEvent,
19981 'click': this.onEditorEvent,
19982 'keyup': this.onEditorEvent,
19987 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
19989 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
19990 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
19992 this.initialized = true;
19994 this.owner.fireEvent('initialize', this);
19999 onDestroy : function(){
20005 //for (var i =0; i < this.toolbars.length;i++) {
20006 // // fixme - ask toolbars for heights?
20007 // this.toolbars[i].onDestroy();
20010 //this.wrap.dom.innerHTML = '';
20011 //this.wrap.remove();
20016 onFirstFocus : function(){
20018 this.assignDocWin();
20021 this.activated = true;
20024 if(Roo.isGecko){ // prevent silly gecko errors
20026 var s = this.win.getSelection();
20027 if(!s.focusNode || s.focusNode.nodeType != 3){
20028 var r = s.getRangeAt(0);
20029 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20034 this.execCmd('useCSS', true);
20035 this.execCmd('styleWithCSS', false);
20038 this.owner.fireEvent('activate', this);
20042 adjustFont: function(btn){
20043 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20044 //if(Roo.isSafari){ // safari
20047 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20048 if(Roo.isSafari){ // safari
20049 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20050 v = (v < 10) ? 10 : v;
20051 v = (v > 48) ? 48 : v;
20052 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20057 v = Math.max(1, v+adjust);
20059 this.execCmd('FontSize', v );
20062 onEditorEvent : function(e)
20064 this.owner.fireEvent('editorevent', this, e);
20065 // this.updateToolbar();
20066 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20069 insertTag : function(tg)
20071 // could be a bit smarter... -> wrap the current selected tRoo..
20072 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20074 range = this.createRange(this.getSelection());
20075 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20076 wrappingNode.appendChild(range.extractContents());
20077 range.insertNode(wrappingNode);
20084 this.execCmd("formatblock", tg);
20088 insertText : function(txt)
20092 var range = this.createRange();
20093 range.deleteContents();
20094 //alert(Sender.getAttribute('label'));
20096 range.insertNode(this.doc.createTextNode(txt));
20102 * Executes a Midas editor command on the editor document and performs necessary focus and
20103 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20104 * @param {String} cmd The Midas command
20105 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20107 relayCmd : function(cmd, value){
20109 this.execCmd(cmd, value);
20110 this.owner.fireEvent('editorevent', this);
20111 //this.updateToolbar();
20112 this.owner.deferFocus();
20116 * Executes a Midas editor command directly on the editor document.
20117 * For visual commands, you should use {@link #relayCmd} instead.
20118 * <b>This should only be called after the editor is initialized.</b>
20119 * @param {String} cmd The Midas command
20120 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20122 execCmd : function(cmd, value){
20123 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20130 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20132 * @param {String} text | dom node..
20134 insertAtCursor : function(text)
20139 if(!this.activated){
20145 var r = this.doc.selection.createRange();
20156 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20160 // from jquery ui (MIT licenced)
20162 var win = this.win;
20164 if (win.getSelection && win.getSelection().getRangeAt) {
20165 range = win.getSelection().getRangeAt(0);
20166 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20167 range.insertNode(node);
20168 } else if (win.document.selection && win.document.selection.createRange) {
20169 // no firefox support
20170 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20171 win.document.selection.createRange().pasteHTML(txt);
20173 // no firefox support
20174 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20175 this.execCmd('InsertHTML', txt);
20184 mozKeyPress : function(e){
20186 var c = e.getCharCode(), cmd;
20189 c = String.fromCharCode(c).toLowerCase();
20203 this.cleanUpPaste.defer(100, this);
20211 e.preventDefault();
20219 fixKeys : function(){ // load time branching for fastest keydown performance
20221 return function(e){
20222 var k = e.getKey(), r;
20225 r = this.doc.selection.createRange();
20228 r.pasteHTML('    ');
20235 r = this.doc.selection.createRange();
20237 var target = r.parentElement();
20238 if(!target || target.tagName.toLowerCase() != 'li'){
20240 r.pasteHTML('<br />');
20246 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20247 this.cleanUpPaste.defer(100, this);
20253 }else if(Roo.isOpera){
20254 return function(e){
20255 var k = e.getKey();
20259 this.execCmd('InsertHTML','    ');
20262 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20263 this.cleanUpPaste.defer(100, this);
20268 }else if(Roo.isSafari){
20269 return function(e){
20270 var k = e.getKey();
20274 this.execCmd('InsertText','\t');
20278 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20279 this.cleanUpPaste.defer(100, this);
20287 getAllAncestors: function()
20289 var p = this.getSelectedNode();
20292 a.push(p); // push blank onto stack..
20293 p = this.getParentElement();
20297 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
20301 a.push(this.doc.body);
20305 lastSelNode : false,
20308 getSelection : function()
20310 this.assignDocWin();
20311 return Roo.isIE ? this.doc.selection : this.win.getSelection();
20314 getSelectedNode: function()
20316 // this may only work on Gecko!!!
20318 // should we cache this!!!!
20323 var range = this.createRange(this.getSelection()).cloneRange();
20326 var parent = range.parentElement();
20328 var testRange = range.duplicate();
20329 testRange.moveToElementText(parent);
20330 if (testRange.inRange(range)) {
20333 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
20336 parent = parent.parentElement;
20341 // is ancestor a text element.
20342 var ac = range.commonAncestorContainer;
20343 if (ac.nodeType == 3) {
20344 ac = ac.parentNode;
20347 var ar = ac.childNodes;
20350 var other_nodes = [];
20351 var has_other_nodes = false;
20352 for (var i=0;i<ar.length;i++) {
20353 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
20356 // fullly contained node.
20358 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
20363 // probably selected..
20364 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
20365 other_nodes.push(ar[i]);
20369 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
20374 has_other_nodes = true;
20376 if (!nodes.length && other_nodes.length) {
20377 nodes= other_nodes;
20379 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
20385 createRange: function(sel)
20387 // this has strange effects when using with
20388 // top toolbar - not sure if it's a great idea.
20389 //this.editor.contentWindow.focus();
20390 if (typeof sel != "undefined") {
20392 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
20394 return this.doc.createRange();
20397 return this.doc.createRange();
20400 getParentElement: function()
20403 this.assignDocWin();
20404 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
20406 var range = this.createRange(sel);
20409 var p = range.commonAncestorContainer;
20410 while (p.nodeType == 3) { // text node
20421 * Range intersection.. the hard stuff...
20425 * [ -- selected range --- ]
20429 * if end is before start or hits it. fail.
20430 * if start is after end or hits it fail.
20432 * if either hits (but other is outside. - then it's not
20438 // @see http://www.thismuchiknow.co.uk/?p=64.
20439 rangeIntersectsNode : function(range, node)
20441 var nodeRange = node.ownerDocument.createRange();
20443 nodeRange.selectNode(node);
20445 nodeRange.selectNodeContents(node);
20448 var rangeStartRange = range.cloneRange();
20449 rangeStartRange.collapse(true);
20451 var rangeEndRange = range.cloneRange();
20452 rangeEndRange.collapse(false);
20454 var nodeStartRange = nodeRange.cloneRange();
20455 nodeStartRange.collapse(true);
20457 var nodeEndRange = nodeRange.cloneRange();
20458 nodeEndRange.collapse(false);
20460 return rangeStartRange.compareBoundaryPoints(
20461 Range.START_TO_START, nodeEndRange) == -1 &&
20462 rangeEndRange.compareBoundaryPoints(
20463 Range.START_TO_START, nodeStartRange) == 1;
20467 rangeCompareNode : function(range, node)
20469 var nodeRange = node.ownerDocument.createRange();
20471 nodeRange.selectNode(node);
20473 nodeRange.selectNodeContents(node);
20477 range.collapse(true);
20479 nodeRange.collapse(true);
20481 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
20482 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
20484 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
20486 var nodeIsBefore = ss == 1;
20487 var nodeIsAfter = ee == -1;
20489 if (nodeIsBefore && nodeIsAfter) {
20492 if (!nodeIsBefore && nodeIsAfter) {
20493 return 1; //right trailed.
20496 if (nodeIsBefore && !nodeIsAfter) {
20497 return 2; // left trailed.
20503 // private? - in a new class?
20504 cleanUpPaste : function()
20506 // cleans up the whole document..
20507 Roo.log('cleanuppaste');
20509 this.cleanUpChildren(this.doc.body);
20510 var clean = this.cleanWordChars(this.doc.body.innerHTML);
20511 if (clean != this.doc.body.innerHTML) {
20512 this.doc.body.innerHTML = clean;
20517 cleanWordChars : function(input) {// change the chars to hex code
20518 var he = Roo.HtmlEditorCore;
20520 var output = input;
20521 Roo.each(he.swapCodes, function(sw) {
20522 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
20524 output = output.replace(swapper, sw[1]);
20531 cleanUpChildren : function (n)
20533 if (!n.childNodes.length) {
20536 for (var i = n.childNodes.length-1; i > -1 ; i--) {
20537 this.cleanUpChild(n.childNodes[i]);
20544 cleanUpChild : function (node)
20547 //console.log(node);
20548 if (node.nodeName == "#text") {
20549 // clean up silly Windows -- stuff?
20552 if (node.nodeName == "#comment") {
20553 node.parentNode.removeChild(node);
20554 // clean up silly Windows -- stuff?
20557 var lcname = node.tagName.toLowerCase();
20558 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
20559 // whitelist of tags..
20561 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
20563 node.parentNode.removeChild(node);
20568 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
20570 // remove <a name=....> as rendering on yahoo mailer is borked with this.
20571 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
20573 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
20574 // remove_keep_children = true;
20577 if (remove_keep_children) {
20578 this.cleanUpChildren(node);
20579 // inserts everything just before this node...
20580 while (node.childNodes.length) {
20581 var cn = node.childNodes[0];
20582 node.removeChild(cn);
20583 node.parentNode.insertBefore(cn, node);
20585 node.parentNode.removeChild(node);
20589 if (!node.attributes || !node.attributes.length) {
20590 this.cleanUpChildren(node);
20594 function cleanAttr(n,v)
20597 if (v.match(/^\./) || v.match(/^\//)) {
20600 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
20603 if (v.match(/^#/)) {
20606 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
20607 node.removeAttribute(n);
20611 var cwhite = this.cwhite;
20612 var cblack = this.cblack;
20614 function cleanStyle(n,v)
20616 if (v.match(/expression/)) { //XSS?? should we even bother..
20617 node.removeAttribute(n);
20621 var parts = v.split(/;/);
20624 Roo.each(parts, function(p) {
20625 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
20629 var l = p.split(':').shift().replace(/\s+/g,'');
20630 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
20632 if ( cwhite.length && cblack.indexOf(l) > -1) {
20633 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20634 //node.removeAttribute(n);
20638 // only allow 'c whitelisted system attributes'
20639 if ( cwhite.length && cwhite.indexOf(l) < 0) {
20640 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20641 //node.removeAttribute(n);
20651 if (clean.length) {
20652 node.setAttribute(n, clean.join(';'));
20654 node.removeAttribute(n);
20660 for (var i = node.attributes.length-1; i > -1 ; i--) {
20661 var a = node.attributes[i];
20664 if (a.name.toLowerCase().substr(0,2)=='on') {
20665 node.removeAttribute(a.name);
20668 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
20669 node.removeAttribute(a.name);
20672 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
20673 cleanAttr(a.name,a.value); // fixme..
20676 if (a.name == 'style') {
20677 cleanStyle(a.name,a.value);
20680 /// clean up MS crap..
20681 // tecnically this should be a list of valid class'es..
20684 if (a.name == 'class') {
20685 if (a.value.match(/^Mso/)) {
20686 node.className = '';
20689 if (a.value.match(/body/)) {
20690 node.className = '';
20701 this.cleanUpChildren(node);
20707 * Clean up MS wordisms...
20709 cleanWord : function(node)
20714 this.cleanWord(this.doc.body);
20717 if (node.nodeName == "#text") {
20718 // clean up silly Windows -- stuff?
20721 if (node.nodeName == "#comment") {
20722 node.parentNode.removeChild(node);
20723 // clean up silly Windows -- stuff?
20727 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
20728 node.parentNode.removeChild(node);
20732 // remove - but keep children..
20733 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
20734 while (node.childNodes.length) {
20735 var cn = node.childNodes[0];
20736 node.removeChild(cn);
20737 node.parentNode.insertBefore(cn, node);
20739 node.parentNode.removeChild(node);
20740 this.iterateChildren(node, this.cleanWord);
20744 if (node.className.length) {
20746 var cn = node.className.split(/\W+/);
20748 Roo.each(cn, function(cls) {
20749 if (cls.match(/Mso[a-zA-Z]+/)) {
20754 node.className = cna.length ? cna.join(' ') : '';
20756 node.removeAttribute("class");
20760 if (node.hasAttribute("lang")) {
20761 node.removeAttribute("lang");
20764 if (node.hasAttribute("style")) {
20766 var styles = node.getAttribute("style").split(";");
20768 Roo.each(styles, function(s) {
20769 if (!s.match(/:/)) {
20772 var kv = s.split(":");
20773 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
20776 // what ever is left... we allow.
20779 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20780 if (!nstyle.length) {
20781 node.removeAttribute('style');
20784 this.iterateChildren(node, this.cleanWord);
20790 * iterateChildren of a Node, calling fn each time, using this as the scole..
20791 * @param {DomNode} node node to iterate children of.
20792 * @param {Function} fn method of this class to call on each item.
20794 iterateChildren : function(node, fn)
20796 if (!node.childNodes.length) {
20799 for (var i = node.childNodes.length-1; i > -1 ; i--) {
20800 fn.call(this, node.childNodes[i])
20806 * cleanTableWidths.
20808 * Quite often pasting from word etc.. results in tables with column and widths.
20809 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
20812 cleanTableWidths : function(node)
20817 this.cleanTableWidths(this.doc.body);
20822 if (node.nodeName == "#text" || node.nodeName == "#comment") {
20825 Roo.log(node.tagName);
20826 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
20827 this.iterateChildren(node, this.cleanTableWidths);
20830 if (node.hasAttribute('width')) {
20831 node.removeAttribute('width');
20835 if (node.hasAttribute("style")) {
20838 var styles = node.getAttribute("style").split(";");
20840 Roo.each(styles, function(s) {
20841 if (!s.match(/:/)) {
20844 var kv = s.split(":");
20845 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20848 // what ever is left... we allow.
20851 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20852 if (!nstyle.length) {
20853 node.removeAttribute('style');
20857 this.iterateChildren(node, this.cleanTableWidths);
20865 domToHTML : function(currentElement, depth, nopadtext) {
20867 depth = depth || 0;
20868 nopadtext = nopadtext || false;
20870 if (!currentElement) {
20871 return this.domToHTML(this.doc.body);
20874 //Roo.log(currentElement);
20876 var allText = false;
20877 var nodeName = currentElement.nodeName;
20878 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20880 if (nodeName == '#text') {
20882 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20887 if (nodeName != 'BODY') {
20890 // Prints the node tagName, such as <A>, <IMG>, etc
20893 for(i = 0; i < currentElement.attributes.length;i++) {
20895 var aname = currentElement.attributes.item(i).name;
20896 if (!currentElement.attributes.item(i).value.length) {
20899 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20902 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20911 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20914 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20919 // Traverse the tree
20921 var currentElementChild = currentElement.childNodes.item(i);
20922 var allText = true;
20923 var innerHTML = '';
20925 while (currentElementChild) {
20926 // Formatting code (indent the tree so it looks nice on the screen)
20927 var nopad = nopadtext;
20928 if (lastnode == 'SPAN') {
20932 if (currentElementChild.nodeName == '#text') {
20933 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20934 toadd = nopadtext ? toadd : toadd.trim();
20935 if (!nopad && toadd.length > 80) {
20936 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20938 innerHTML += toadd;
20941 currentElementChild = currentElement.childNodes.item(i);
20947 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20949 // Recursively traverse the tree structure of the child node
20950 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20951 lastnode = currentElementChild.nodeName;
20953 currentElementChild=currentElement.childNodes.item(i);
20959 // The remaining code is mostly for formatting the tree
20960 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20965 ret+= "</"+tagName+">";
20971 applyBlacklists : function()
20973 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
20974 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
20978 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
20979 if (b.indexOf(tag) > -1) {
20982 this.white.push(tag);
20986 Roo.each(w, function(tag) {
20987 if (b.indexOf(tag) > -1) {
20990 if (this.white.indexOf(tag) > -1) {
20993 this.white.push(tag);
20998 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
20999 if (w.indexOf(tag) > -1) {
21002 this.black.push(tag);
21006 Roo.each(b, function(tag) {
21007 if (w.indexOf(tag) > -1) {
21010 if (this.black.indexOf(tag) > -1) {
21013 this.black.push(tag);
21018 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21019 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21023 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21024 if (b.indexOf(tag) > -1) {
21027 this.cwhite.push(tag);
21031 Roo.each(w, function(tag) {
21032 if (b.indexOf(tag) > -1) {
21035 if (this.cwhite.indexOf(tag) > -1) {
21038 this.cwhite.push(tag);
21043 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21044 if (w.indexOf(tag) > -1) {
21047 this.cblack.push(tag);
21051 Roo.each(b, function(tag) {
21052 if (w.indexOf(tag) > -1) {
21055 if (this.cblack.indexOf(tag) > -1) {
21058 this.cblack.push(tag);
21063 setStylesheets : function(stylesheets)
21065 if(typeof(stylesheets) == 'string'){
21066 Roo.get(this.iframe.contentDocument.head).createChild({
21068 rel : 'stylesheet',
21077 Roo.each(stylesheets, function(s) {
21082 Roo.get(_this.iframe.contentDocument.head).createChild({
21084 rel : 'stylesheet',
21093 removeStylesheets : function()
21097 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21102 // hide stuff that is not compatible
21116 * @event specialkey
21120 * @cfg {String} fieldClass @hide
21123 * @cfg {String} focusClass @hide
21126 * @cfg {String} autoCreate @hide
21129 * @cfg {String} inputType @hide
21132 * @cfg {String} invalidClass @hide
21135 * @cfg {String} invalidText @hide
21138 * @cfg {String} msgFx @hide
21141 * @cfg {String} validateOnBlur @hide
21145 Roo.HtmlEditorCore.white = [
21146 'area', 'br', 'img', 'input', 'hr', 'wbr',
21148 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21149 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21150 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21151 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21152 'table', 'ul', 'xmp',
21154 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21157 'dir', 'menu', 'ol', 'ul', 'dl',
21163 Roo.HtmlEditorCore.black = [
21164 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21166 'base', 'basefont', 'bgsound', 'blink', 'body',
21167 'frame', 'frameset', 'head', 'html', 'ilayer',
21168 'iframe', 'layer', 'link', 'meta', 'object',
21169 'script', 'style' ,'title', 'xml' // clean later..
21171 Roo.HtmlEditorCore.clean = [
21172 'script', 'style', 'title', 'xml'
21174 Roo.HtmlEditorCore.remove = [
21179 Roo.HtmlEditorCore.ablack = [
21183 Roo.HtmlEditorCore.aclean = [
21184 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21188 Roo.HtmlEditorCore.pwhite= [
21189 'http', 'https', 'mailto'
21192 // white listed style attributes.
21193 Roo.HtmlEditorCore.cwhite= [
21194 // 'text-align', /// default is to allow most things..
21200 // black listed style attributes.
21201 Roo.HtmlEditorCore.cblack= [
21202 // 'font-size' -- this can be set by the project
21206 Roo.HtmlEditorCore.swapCodes =[
21225 * @class Roo.bootstrap.HtmlEditor
21226 * @extends Roo.bootstrap.TextArea
21227 * Bootstrap HtmlEditor class
21230 * Create a new HtmlEditor
21231 * @param {Object} config The config object
21234 Roo.bootstrap.HtmlEditor = function(config){
21235 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21236 if (!this.toolbars) {
21237 this.toolbars = [];
21239 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21242 * @event initialize
21243 * Fires when the editor is fully initialized (including the iframe)
21244 * @param {HtmlEditor} this
21249 * Fires when the editor is first receives the focus. Any insertion must wait
21250 * until after this event.
21251 * @param {HtmlEditor} this
21255 * @event beforesync
21256 * Fires before the textarea is updated with content from the editor iframe. Return false
21257 * to cancel the sync.
21258 * @param {HtmlEditor} this
21259 * @param {String} html
21263 * @event beforepush
21264 * Fires before the iframe editor is updated with content from the textarea. Return false
21265 * to cancel the push.
21266 * @param {HtmlEditor} this
21267 * @param {String} html
21272 * Fires when the textarea is updated with content from the editor iframe.
21273 * @param {HtmlEditor} this
21274 * @param {String} html
21279 * Fires when the iframe editor is updated with content from the textarea.
21280 * @param {HtmlEditor} this
21281 * @param {String} html
21285 * @event editmodechange
21286 * Fires when the editor switches edit modes
21287 * @param {HtmlEditor} this
21288 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21290 editmodechange: true,
21292 * @event editorevent
21293 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21294 * @param {HtmlEditor} this
21298 * @event firstfocus
21299 * Fires when on first focus - needed by toolbars..
21300 * @param {HtmlEditor} this
21305 * Auto save the htmlEditor value as a file into Events
21306 * @param {HtmlEditor} this
21310 * @event savedpreview
21311 * preview the saved version of htmlEditor
21312 * @param {HtmlEditor} this
21319 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
21323 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
21328 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21333 * @cfg {Number} height (in pixels)
21337 * @cfg {Number} width (in pixels)
21342 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21345 stylesheets: false,
21350 // private properties
21351 validationEvent : false,
21353 initialized : false,
21356 onFocus : Roo.emptyFn,
21358 hideMode:'offsets',
21361 tbContainer : false,
21363 toolbarContainer :function() {
21364 return this.wrap.select('.x-html-editor-tb',true).first();
21368 * Protected method that will not generally be called directly. It
21369 * is called when the editor creates its toolbar. Override this method if you need to
21370 * add custom toolbar buttons.
21371 * @param {HtmlEditor} editor
21373 createToolbar : function(){
21375 Roo.log("create toolbars");
21377 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
21378 this.toolbars[0].render(this.toolbarContainer());
21382 // if (!editor.toolbars || !editor.toolbars.length) {
21383 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
21386 // for (var i =0 ; i < editor.toolbars.length;i++) {
21387 // editor.toolbars[i] = Roo.factory(
21388 // typeof(editor.toolbars[i]) == 'string' ?
21389 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
21390 // Roo.bootstrap.HtmlEditor);
21391 // editor.toolbars[i].init(editor);
21397 onRender : function(ct, position)
21399 // Roo.log("Call onRender: " + this.xtype);
21401 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
21403 this.wrap = this.inputEl().wrap({
21404 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
21407 this.editorcore.onRender(ct, position);
21409 if (this.resizable) {
21410 this.resizeEl = new Roo.Resizable(this.wrap, {
21414 minHeight : this.height,
21415 height: this.height,
21416 handles : this.resizable,
21419 resize : function(r, w, h) {
21420 _t.onResize(w,h); // -something
21426 this.createToolbar(this);
21429 if(!this.width && this.resizable){
21430 this.setSize(this.wrap.getSize());
21432 if (this.resizeEl) {
21433 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
21434 // should trigger onReize..
21440 onResize : function(w, h)
21442 Roo.log('resize: ' +w + ',' + h );
21443 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
21447 if(this.inputEl() ){
21448 if(typeof w == 'number'){
21449 var aw = w - this.wrap.getFrameWidth('lr');
21450 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
21453 if(typeof h == 'number'){
21454 var tbh = -11; // fixme it needs to tool bar size!
21455 for (var i =0; i < this.toolbars.length;i++) {
21456 // fixme - ask toolbars for heights?
21457 tbh += this.toolbars[i].el.getHeight();
21458 //if (this.toolbars[i].footer) {
21459 // tbh += this.toolbars[i].footer.el.getHeight();
21467 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
21468 ah -= 5; // knock a few pixes off for look..
21469 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
21473 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
21474 this.editorcore.onResize(ew,eh);
21479 * Toggles the editor between standard and source edit mode.
21480 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21482 toggleSourceEdit : function(sourceEditMode)
21484 this.editorcore.toggleSourceEdit(sourceEditMode);
21486 if(this.editorcore.sourceEditMode){
21487 Roo.log('editor - showing textarea');
21490 // Roo.log(this.syncValue());
21492 this.inputEl().removeClass(['hide', 'x-hidden']);
21493 this.inputEl().dom.removeAttribute('tabIndex');
21494 this.inputEl().focus();
21496 Roo.log('editor - hiding textarea');
21498 // Roo.log(this.pushValue());
21501 this.inputEl().addClass(['hide', 'x-hidden']);
21502 this.inputEl().dom.setAttribute('tabIndex', -1);
21503 //this.deferFocus();
21506 if(this.resizable){
21507 this.setSize(this.wrap.getSize());
21510 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
21513 // private (for BoxComponent)
21514 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21516 // private (for BoxComponent)
21517 getResizeEl : function(){
21521 // private (for BoxComponent)
21522 getPositionEl : function(){
21527 initEvents : function(){
21528 this.originalValue = this.getValue();
21532 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21535 // markInvalid : Roo.emptyFn,
21537 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21540 // clearInvalid : Roo.emptyFn,
21542 setValue : function(v){
21543 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
21544 this.editorcore.pushValue();
21549 deferFocus : function(){
21550 this.focus.defer(10, this);
21554 focus : function(){
21555 this.editorcore.focus();
21561 onDestroy : function(){
21567 for (var i =0; i < this.toolbars.length;i++) {
21568 // fixme - ask toolbars for heights?
21569 this.toolbars[i].onDestroy();
21572 this.wrap.dom.innerHTML = '';
21573 this.wrap.remove();
21578 onFirstFocus : function(){
21579 //Roo.log("onFirstFocus");
21580 this.editorcore.onFirstFocus();
21581 for (var i =0; i < this.toolbars.length;i++) {
21582 this.toolbars[i].onFirstFocus();
21588 syncValue : function()
21590 this.editorcore.syncValue();
21593 pushValue : function()
21595 this.editorcore.pushValue();
21599 // hide stuff that is not compatible
21613 * @event specialkey
21617 * @cfg {String} fieldClass @hide
21620 * @cfg {String} focusClass @hide
21623 * @cfg {String} autoCreate @hide
21626 * @cfg {String} inputType @hide
21629 * @cfg {String} invalidClass @hide
21632 * @cfg {String} invalidText @hide
21635 * @cfg {String} msgFx @hide
21638 * @cfg {String} validateOnBlur @hide
21647 Roo.namespace('Roo.bootstrap.htmleditor');
21649 * @class Roo.bootstrap.HtmlEditorToolbar1
21654 new Roo.bootstrap.HtmlEditor({
21657 new Roo.bootstrap.HtmlEditorToolbar1({
21658 disable : { fonts: 1 , format: 1, ..., ... , ...],
21664 * @cfg {Object} disable List of elements to disable..
21665 * @cfg {Array} btns List of additional buttons.
21669 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
21672 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
21675 Roo.apply(this, config);
21677 // default disabled, based on 'good practice'..
21678 this.disable = this.disable || {};
21679 Roo.applyIf(this.disable, {
21682 specialElements : true
21684 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
21686 this.editor = config.editor;
21687 this.editorcore = config.editor.editorcore;
21689 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
21691 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
21692 // dont call parent... till later.
21694 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
21699 editorcore : false,
21704 "h1","h2","h3","h4","h5","h6",
21706 "abbr", "acronym", "address", "cite", "samp", "var",
21710 onRender : function(ct, position)
21712 // Roo.log("Call onRender: " + this.xtype);
21714 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
21716 this.el.dom.style.marginBottom = '0';
21718 var editorcore = this.editorcore;
21719 var editor= this.editor;
21722 var btn = function(id,cmd , toggle, handler){
21724 var event = toggle ? 'toggle' : 'click';
21729 xns: Roo.bootstrap,
21732 enableToggle:toggle !== false,
21734 pressed : toggle ? false : null,
21737 a.listeners[toggle ? 'toggle' : 'click'] = function() {
21738 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
21747 xns: Roo.bootstrap,
21748 glyphicon : 'font',
21752 xns: Roo.bootstrap,
21756 Roo.each(this.formats, function(f) {
21757 style.menu.items.push({
21759 xns: Roo.bootstrap,
21760 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
21765 editorcore.insertTag(this.tagname);
21772 children.push(style);
21775 btn('bold',false,true);
21776 btn('italic',false,true);
21777 btn('align-left', 'justifyleft',true);
21778 btn('align-center', 'justifycenter',true);
21779 btn('align-right' , 'justifyright',true);
21780 btn('link', false, false, function(btn) {
21781 //Roo.log("create link?");
21782 var url = prompt(this.createLinkText, this.defaultLinkValue);
21783 if(url && url != 'http:/'+'/'){
21784 this.editorcore.relayCmd('createlink', url);
21787 btn('list','insertunorderedlist',true);
21788 btn('pencil', false,true, function(btn){
21791 this.toggleSourceEdit(btn.pressed);
21797 xns: Roo.bootstrap,
21802 xns: Roo.bootstrap,
21807 cog.menu.items.push({
21809 xns: Roo.bootstrap,
21810 html : Clean styles,
21815 editorcore.insertTag(this.tagname);
21824 this.xtype = 'NavSimplebar';
21826 for(var i=0;i< children.length;i++) {
21828 this.buttons.add(this.addxtypeChild(children[i]));
21832 editor.on('editorevent', this.updateToolbar, this);
21834 onBtnClick : function(id)
21836 this.editorcore.relayCmd(id);
21837 this.editorcore.focus();
21841 * Protected method that will not generally be called directly. It triggers
21842 * a toolbar update by reading the markup state of the current selection in the editor.
21844 updateToolbar: function(){
21846 if(!this.editorcore.activated){
21847 this.editor.onFirstFocus(); // is this neeed?
21851 var btns = this.buttons;
21852 var doc = this.editorcore.doc;
21853 btns.get('bold').setActive(doc.queryCommandState('bold'));
21854 btns.get('italic').setActive(doc.queryCommandState('italic'));
21855 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21857 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21858 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21859 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21861 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21862 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21865 var ans = this.editorcore.getAllAncestors();
21866 if (this.formatCombo) {
21869 var store = this.formatCombo.store;
21870 this.formatCombo.setValue("");
21871 for (var i =0; i < ans.length;i++) {
21872 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21874 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21882 // hides menus... - so this cant be on a menu...
21883 Roo.bootstrap.MenuMgr.hideAll();
21885 Roo.bootstrap.MenuMgr.hideAll();
21886 //this.editorsyncValue();
21888 onFirstFocus: function() {
21889 this.buttons.each(function(item){
21893 toggleSourceEdit : function(sourceEditMode){
21896 if(sourceEditMode){
21897 Roo.log("disabling buttons");
21898 this.buttons.each( function(item){
21899 if(item.cmd != 'pencil'){
21905 Roo.log("enabling buttons");
21906 if(this.editorcore.initialized){
21907 this.buttons.each( function(item){
21913 Roo.log("calling toggole on editor");
21914 // tell the editor that it's been pressed..
21915 this.editor.toggleSourceEdit(sourceEditMode);
21925 * @class Roo.bootstrap.Table.AbstractSelectionModel
21926 * @extends Roo.util.Observable
21927 * Abstract base class for grid SelectionModels. It provides the interface that should be
21928 * implemented by descendant classes. This class should not be directly instantiated.
21931 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21932 this.locked = false;
21933 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21937 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21938 /** @ignore Called by the grid automatically. Do not call directly. */
21939 init : function(grid){
21945 * Locks the selections.
21948 this.locked = true;
21952 * Unlocks the selections.
21954 unlock : function(){
21955 this.locked = false;
21959 * Returns true if the selections are locked.
21960 * @return {Boolean}
21962 isLocked : function(){
21963 return this.locked;
21967 * @extends Roo.bootstrap.Table.AbstractSelectionModel
21968 * @class Roo.bootstrap.Table.RowSelectionModel
21969 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
21970 * It supports multiple selections and keyboard selection/navigation.
21972 * @param {Object} config
21975 Roo.bootstrap.Table.RowSelectionModel = function(config){
21976 Roo.apply(this, config);
21977 this.selections = new Roo.util.MixedCollection(false, function(o){
21982 this.lastActive = false;
21986 * @event selectionchange
21987 * Fires when the selection changes
21988 * @param {SelectionModel} this
21990 "selectionchange" : true,
21992 * @event afterselectionchange
21993 * Fires after the selection changes (eg. by key press or clicking)
21994 * @param {SelectionModel} this
21996 "afterselectionchange" : true,
21998 * @event beforerowselect
21999 * Fires when a row is selected being selected, return false to cancel.
22000 * @param {SelectionModel} this
22001 * @param {Number} rowIndex The selected index
22002 * @param {Boolean} keepExisting False if other selections will be cleared
22004 "beforerowselect" : true,
22007 * Fires when a row is selected.
22008 * @param {SelectionModel} this
22009 * @param {Number} rowIndex The selected index
22010 * @param {Roo.data.Record} r The record
22012 "rowselect" : true,
22014 * @event rowdeselect
22015 * Fires when a row is deselected.
22016 * @param {SelectionModel} this
22017 * @param {Number} rowIndex The selected index
22019 "rowdeselect" : true
22021 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22022 this.locked = false;
22025 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22027 * @cfg {Boolean} singleSelect
22028 * True to allow selection of only one row at a time (defaults to false)
22030 singleSelect : false,
22033 initEvents : function(){
22035 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22036 this.grid.on("mousedown", this.handleMouseDown, this);
22037 }else{ // allow click to work like normal
22038 this.grid.on("rowclick", this.handleDragableRowClick, this);
22041 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22042 "up" : function(e){
22044 this.selectPrevious(e.shiftKey);
22045 }else if(this.last !== false && this.lastActive !== false){
22046 var last = this.last;
22047 this.selectRange(this.last, this.lastActive-1);
22048 this.grid.getView().focusRow(this.lastActive);
22049 if(last !== false){
22053 this.selectFirstRow();
22055 this.fireEvent("afterselectionchange", this);
22057 "down" : function(e){
22059 this.selectNext(e.shiftKey);
22060 }else if(this.last !== false && this.lastActive !== false){
22061 var last = this.last;
22062 this.selectRange(this.last, this.lastActive+1);
22063 this.grid.getView().focusRow(this.lastActive);
22064 if(last !== false){
22068 this.selectFirstRow();
22070 this.fireEvent("afterselectionchange", this);
22075 var view = this.grid.view;
22076 view.on("refresh", this.onRefresh, this);
22077 view.on("rowupdated", this.onRowUpdated, this);
22078 view.on("rowremoved", this.onRemove, this);
22082 onRefresh : function(){
22083 var ds = this.grid.dataSource, i, v = this.grid.view;
22084 var s = this.selections;
22085 s.each(function(r){
22086 if((i = ds.indexOfId(r.id)) != -1){
22095 onRemove : function(v, index, r){
22096 this.selections.remove(r);
22100 onRowUpdated : function(v, index, r){
22101 if(this.isSelected(r)){
22102 v.onRowSelect(index);
22108 * @param {Array} records The records to select
22109 * @param {Boolean} keepExisting (optional) True to keep existing selections
22111 selectRecords : function(records, keepExisting){
22113 this.clearSelections();
22115 var ds = this.grid.dataSource;
22116 for(var i = 0, len = records.length; i < len; i++){
22117 this.selectRow(ds.indexOf(records[i]), true);
22122 * Gets the number of selected rows.
22125 getCount : function(){
22126 return this.selections.length;
22130 * Selects the first row in the grid.
22132 selectFirstRow : function(){
22137 * Select the last row.
22138 * @param {Boolean} keepExisting (optional) True to keep existing selections
22140 selectLastRow : function(keepExisting){
22141 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22145 * Selects the row immediately following the last selected row.
22146 * @param {Boolean} keepExisting (optional) True to keep existing selections
22148 selectNext : function(keepExisting){
22149 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
22150 this.selectRow(this.last+1, keepExisting);
22151 this.grid.getView().focusRow(this.last);
22156 * Selects the row that precedes the last selected row.
22157 * @param {Boolean} keepExisting (optional) True to keep existing selections
22159 selectPrevious : function(keepExisting){
22161 this.selectRow(this.last-1, keepExisting);
22162 this.grid.getView().focusRow(this.last);
22167 * Returns the selected records
22168 * @return {Array} Array of selected records
22170 getSelections : function(){
22171 return [].concat(this.selections.items);
22175 * Returns the first selected record.
22178 getSelected : function(){
22179 return this.selections.itemAt(0);
22184 * Clears all selections.
22186 clearSelections : function(fast){
22191 var ds = this.grid.dataSource;
22192 var s = this.selections;
22193 s.each(function(r){
22194 this.deselectRow(ds.indexOfId(r.id));
22198 this.selections.clear();
22205 * Selects all rows.
22207 selectAll : function(){
22211 this.selections.clear();
22212 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
22213 this.selectRow(i, true);
22218 * Returns True if there is a selection.
22219 * @return {Boolean}
22221 hasSelection : function(){
22222 return this.selections.length > 0;
22226 * Returns True if the specified row is selected.
22227 * @param {Number/Record} record The record or index of the record to check
22228 * @return {Boolean}
22230 isSelected : function(index){
22231 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
22232 return (r && this.selections.key(r.id) ? true : false);
22236 * Returns True if the specified record id is selected.
22237 * @param {String} id The id of record to check
22238 * @return {Boolean}
22240 isIdSelected : function(id){
22241 return (this.selections.key(id) ? true : false);
22245 handleMouseDown : function(e, t){
22246 var view = this.grid.getView(), rowIndex;
22247 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
22250 if(e.shiftKey && this.last !== false){
22251 var last = this.last;
22252 this.selectRange(last, rowIndex, e.ctrlKey);
22253 this.last = last; // reset the last
22254 view.focusRow(rowIndex);
22256 var isSelected = this.isSelected(rowIndex);
22257 if(e.button !== 0 && isSelected){
22258 view.focusRow(rowIndex);
22259 }else if(e.ctrlKey && isSelected){
22260 this.deselectRow(rowIndex);
22261 }else if(!isSelected){
22262 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22263 view.focusRow(rowIndex);
22266 this.fireEvent("afterselectionchange", this);
22269 handleDragableRowClick : function(grid, rowIndex, e)
22271 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
22272 this.selectRow(rowIndex, false);
22273 grid.view.focusRow(rowIndex);
22274 this.fireEvent("afterselectionchange", this);
22279 * Selects multiple rows.
22280 * @param {Array} rows Array of the indexes of the row to select
22281 * @param {Boolean} keepExisting (optional) True to keep existing selections
22283 selectRows : function(rows, keepExisting){
22285 this.clearSelections();
22287 for(var i = 0, len = rows.length; i < len; i++){
22288 this.selectRow(rows[i], true);
22293 * Selects a range of rows. All rows in between startRow and endRow are also selected.
22294 * @param {Number} startRow The index of the first row in the range
22295 * @param {Number} endRow The index of the last row in the range
22296 * @param {Boolean} keepExisting (optional) True to retain existing selections
22298 selectRange : function(startRow, endRow, keepExisting){
22303 this.clearSelections();
22305 if(startRow <= endRow){
22306 for(var i = startRow; i <= endRow; i++){
22307 this.selectRow(i, true);
22310 for(var i = startRow; i >= endRow; i--){
22311 this.selectRow(i, true);
22317 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
22318 * @param {Number} startRow The index of the first row in the range
22319 * @param {Number} endRow The index of the last row in the range
22321 deselectRange : function(startRow, endRow, preventViewNotify){
22325 for(var i = startRow; i <= endRow; i++){
22326 this.deselectRow(i, preventViewNotify);
22332 * @param {Number} row The index of the row to select
22333 * @param {Boolean} keepExisting (optional) True to keep existing selections
22335 selectRow : function(index, keepExisting, preventViewNotify){
22336 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
22339 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
22340 if(!keepExisting || this.singleSelect){
22341 this.clearSelections();
22343 var r = this.grid.dataSource.getAt(index);
22344 this.selections.add(r);
22345 this.last = this.lastActive = index;
22346 if(!preventViewNotify){
22347 this.grid.getView().onRowSelect(index);
22349 this.fireEvent("rowselect", this, index, r);
22350 this.fireEvent("selectionchange", this);
22356 * @param {Number} row The index of the row to deselect
22358 deselectRow : function(index, preventViewNotify){
22362 if(this.last == index){
22365 if(this.lastActive == index){
22366 this.lastActive = false;
22368 var r = this.grid.dataSource.getAt(index);
22369 this.selections.remove(r);
22370 if(!preventViewNotify){
22371 this.grid.getView().onRowDeselect(index);
22373 this.fireEvent("rowdeselect", this, index);
22374 this.fireEvent("selectionchange", this);
22378 restoreLast : function(){
22380 this.last = this._last;
22385 acceptsNav : function(row, col, cm){
22386 return !cm.isHidden(col) && cm.isCellEditable(col, row);
22390 onEditorKey : function(field, e){
22391 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
22396 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
22398 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
22400 }else if(k == e.ENTER && !e.ctrlKey){
22404 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
22406 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
22408 }else if(k == e.ESC){
22412 g.startEditing(newCell[0], newCell[1]);
22417 * Ext JS Library 1.1.1
22418 * Copyright(c) 2006-2007, Ext JS, LLC.
22420 * Originally Released Under LGPL - original licence link has changed is not relivant.
22423 * <script type="text/javascript">
22427 * @class Roo.bootstrap.PagingToolbar
22428 * @extends Roo.bootstrap.NavSimplebar
22429 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
22431 * Create a new PagingToolbar
22432 * @param {Object} config The config object
22433 * @param {Roo.data.Store} store
22435 Roo.bootstrap.PagingToolbar = function(config)
22437 // old args format still supported... - xtype is prefered..
22438 // created from xtype...
22440 this.ds = config.dataSource;
22442 if (config.store && !this.ds) {
22443 this.store= Roo.factory(config.store, Roo.data);
22444 this.ds = this.store;
22445 this.ds.xmodule = this.xmodule || false;
22448 this.toolbarItems = [];
22449 if (config.items) {
22450 this.toolbarItems = config.items;
22453 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
22458 this.bind(this.ds);
22461 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
22465 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
22467 * @cfg {Roo.data.Store} dataSource
22468 * The underlying data store providing the paged data
22471 * @cfg {String/HTMLElement/Element} container
22472 * container The id or element that will contain the toolbar
22475 * @cfg {Boolean} displayInfo
22476 * True to display the displayMsg (defaults to false)
22479 * @cfg {Number} pageSize
22480 * The number of records to display per page (defaults to 20)
22484 * @cfg {String} displayMsg
22485 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
22487 displayMsg : 'Displaying {0} - {1} of {2}',
22489 * @cfg {String} emptyMsg
22490 * The message to display when no records are found (defaults to "No data to display")
22492 emptyMsg : 'No data to display',
22494 * Customizable piece of the default paging text (defaults to "Page")
22497 beforePageText : "Page",
22499 * Customizable piece of the default paging text (defaults to "of %0")
22502 afterPageText : "of {0}",
22504 * Customizable piece of the default paging text (defaults to "First Page")
22507 firstText : "First Page",
22509 * Customizable piece of the default paging text (defaults to "Previous Page")
22512 prevText : "Previous Page",
22514 * Customizable piece of the default paging text (defaults to "Next Page")
22517 nextText : "Next Page",
22519 * Customizable piece of the default paging text (defaults to "Last Page")
22522 lastText : "Last Page",
22524 * Customizable piece of the default paging text (defaults to "Refresh")
22527 refreshText : "Refresh",
22531 onRender : function(ct, position)
22533 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
22534 this.navgroup.parentId = this.id;
22535 this.navgroup.onRender(this.el, null);
22536 // add the buttons to the navgroup
22538 if(this.displayInfo){
22539 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
22540 this.displayEl = this.el.select('.x-paging-info', true).first();
22541 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
22542 // this.displayEl = navel.el.select('span',true).first();
22548 Roo.each(_this.buttons, function(e){ // this might need to use render????
22549 Roo.factory(e).onRender(_this.el, null);
22553 Roo.each(_this.toolbarItems, function(e) {
22554 _this.navgroup.addItem(e);
22558 this.first = this.navgroup.addItem({
22559 tooltip: this.firstText,
22561 icon : 'fa fa-backward',
22563 preventDefault: true,
22564 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
22567 this.prev = this.navgroup.addItem({
22568 tooltip: this.prevText,
22570 icon : 'fa fa-step-backward',
22572 preventDefault: true,
22573 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
22575 //this.addSeparator();
22578 var field = this.navgroup.addItem( {
22580 cls : 'x-paging-position',
22582 html : this.beforePageText +
22583 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
22584 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
22587 this.field = field.el.select('input', true).first();
22588 this.field.on("keydown", this.onPagingKeydown, this);
22589 this.field.on("focus", function(){this.dom.select();});
22592 this.afterTextEl = field.el.select('.x-paging-after',true).first();
22593 //this.field.setHeight(18);
22594 //this.addSeparator();
22595 this.next = this.navgroup.addItem({
22596 tooltip: this.nextText,
22598 html : ' <i class="fa fa-step-forward">',
22600 preventDefault: true,
22601 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
22603 this.last = this.navgroup.addItem({
22604 tooltip: this.lastText,
22605 icon : 'fa fa-forward',
22608 preventDefault: true,
22609 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
22611 //this.addSeparator();
22612 this.loading = this.navgroup.addItem({
22613 tooltip: this.refreshText,
22614 icon: 'fa fa-refresh',
22615 preventDefault: true,
22616 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
22622 updateInfo : function(){
22623 if(this.displayEl){
22624 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
22625 var msg = count == 0 ?
22629 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
22631 this.displayEl.update(msg);
22636 onLoad : function(ds, r, o){
22637 this.cursor = o.params ? o.params.start : 0;
22638 var d = this.getPageData(),
22642 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
22643 this.field.dom.value = ap;
22644 this.first.setDisabled(ap == 1);
22645 this.prev.setDisabled(ap == 1);
22646 this.next.setDisabled(ap == ps);
22647 this.last.setDisabled(ap == ps);
22648 this.loading.enable();
22653 getPageData : function(){
22654 var total = this.ds.getTotalCount();
22657 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
22658 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
22663 onLoadError : function(){
22664 this.loading.enable();
22668 onPagingKeydown : function(e){
22669 var k = e.getKey();
22670 var d = this.getPageData();
22672 var v = this.field.dom.value, pageNum;
22673 if(!v || isNaN(pageNum = parseInt(v, 10))){
22674 this.field.dom.value = d.activePage;
22677 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
22678 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22681 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))
22683 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
22684 this.field.dom.value = pageNum;
22685 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
22688 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
22690 var v = this.field.dom.value, pageNum;
22691 var increment = (e.shiftKey) ? 10 : 1;
22692 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
22695 if(!v || isNaN(pageNum = parseInt(v, 10))) {
22696 this.field.dom.value = d.activePage;
22699 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
22701 this.field.dom.value = parseInt(v, 10) + increment;
22702 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
22703 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22710 beforeLoad : function(){
22712 this.loading.disable();
22717 onClick : function(which){
22726 ds.load({params:{start: 0, limit: this.pageSize}});
22729 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
22732 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
22735 var total = ds.getTotalCount();
22736 var extra = total % this.pageSize;
22737 var lastStart = extra ? (total - extra) : total-this.pageSize;
22738 ds.load({params:{start: lastStart, limit: this.pageSize}});
22741 ds.load({params:{start: this.cursor, limit: this.pageSize}});
22747 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
22748 * @param {Roo.data.Store} store The data store to unbind
22750 unbind : function(ds){
22751 ds.un("beforeload", this.beforeLoad, this);
22752 ds.un("load", this.onLoad, this);
22753 ds.un("loadexception", this.onLoadError, this);
22754 ds.un("remove", this.updateInfo, this);
22755 ds.un("add", this.updateInfo, this);
22756 this.ds = undefined;
22760 * Binds the paging toolbar to the specified {@link Roo.data.Store}
22761 * @param {Roo.data.Store} store The data store to bind
22763 bind : function(ds){
22764 ds.on("beforeload", this.beforeLoad, this);
22765 ds.on("load", this.onLoad, this);
22766 ds.on("loadexception", this.onLoadError, this);
22767 ds.on("remove", this.updateInfo, this);
22768 ds.on("add", this.updateInfo, this);
22779 * @class Roo.bootstrap.MessageBar
22780 * @extends Roo.bootstrap.Component
22781 * Bootstrap MessageBar class
22782 * @cfg {String} html contents of the MessageBar
22783 * @cfg {String} weight (info | success | warning | danger) default info
22784 * @cfg {String} beforeClass insert the bar before the given class
22785 * @cfg {Boolean} closable (true | false) default false
22786 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
22789 * Create a new Element
22790 * @param {Object} config The config object
22793 Roo.bootstrap.MessageBar = function(config){
22794 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
22797 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
22803 beforeClass: 'bootstrap-sticky-wrap',
22805 getAutoCreate : function(){
22809 cls: 'alert alert-dismissable alert-' + this.weight,
22814 html: this.html || ''
22820 cfg.cls += ' alert-messages-fixed';
22834 onRender : function(ct, position)
22836 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
22839 var cfg = Roo.apply({}, this.getAutoCreate());
22843 cfg.cls += ' ' + this.cls;
22846 cfg.style = this.style;
22848 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22850 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22853 this.el.select('>button.close').on('click', this.hide, this);
22859 if (!this.rendered) {
22865 this.fireEvent('show', this);
22871 if (!this.rendered) {
22877 this.fireEvent('hide', this);
22880 update : function()
22882 // var e = this.el.dom.firstChild;
22884 // if(this.closable){
22885 // e = e.nextSibling;
22888 // e.data = this.html || '';
22890 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22906 * @class Roo.bootstrap.Graph
22907 * @extends Roo.bootstrap.Component
22908 * Bootstrap Graph class
22912 @cfg {String} graphtype bar | vbar | pie
22913 @cfg {number} g_x coodinator | centre x (pie)
22914 @cfg {number} g_y coodinator | centre y (pie)
22915 @cfg {number} g_r radius (pie)
22916 @cfg {number} g_height height of the chart (respected by all elements in the set)
22917 @cfg {number} g_width width of the chart (respected by all elements in the set)
22918 @cfg {Object} title The title of the chart
22921 -opts (object) options for the chart
22923 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22924 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22926 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.
22927 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22929 o stretch (boolean)
22931 -opts (object) options for the pie
22934 o startAngle (number)
22935 o endAngle (number)
22939 * Create a new Input
22940 * @param {Object} config The config object
22943 Roo.bootstrap.Graph = function(config){
22944 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22950 * The img click event for the img.
22951 * @param {Roo.EventObject} e
22957 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
22968 //g_colors: this.colors,
22975 getAutoCreate : function(){
22986 onRender : function(ct,position){
22989 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
22991 if (typeof(Raphael) == 'undefined') {
22992 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
22996 this.raphael = Raphael(this.el.dom);
22998 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
22999 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23000 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23001 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23003 r.text(160, 10, "Single Series Chart").attr(txtattr);
23004 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23005 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23006 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23008 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23009 r.barchart(330, 10, 300, 220, data1);
23010 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23011 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23014 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23015 // r.barchart(30, 30, 560, 250, xdata, {
23016 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23017 // axis : "0 0 1 1",
23018 // axisxlabels : xdata
23019 // //yvalues : cols,
23022 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23024 // this.load(null,xdata,{
23025 // axis : "0 0 1 1",
23026 // axisxlabels : xdata
23031 load : function(graphtype,xdata,opts)
23033 this.raphael.clear();
23035 graphtype = this.graphtype;
23040 var r = this.raphael,
23041 fin = function () {
23042 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23044 fout = function () {
23045 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23047 pfin = function() {
23048 this.sector.stop();
23049 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23052 this.label[0].stop();
23053 this.label[0].attr({ r: 7.5 });
23054 this.label[1].attr({ "font-weight": 800 });
23057 pfout = function() {
23058 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23061 this.label[0].animate({ r: 5 }, 500, "bounce");
23062 this.label[1].attr({ "font-weight": 400 });
23068 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23071 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23074 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23075 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23077 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23084 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23089 setTitle: function(o)
23094 initEvents: function() {
23097 this.el.on('click', this.onClick, this);
23101 onClick : function(e)
23103 Roo.log('img onclick');
23104 this.fireEvent('click', this, e);
23116 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23119 * @class Roo.bootstrap.dash.NumberBox
23120 * @extends Roo.bootstrap.Component
23121 * Bootstrap NumberBox class
23122 * @cfg {String} headline Box headline
23123 * @cfg {String} content Box content
23124 * @cfg {String} icon Box icon
23125 * @cfg {String} footer Footer text
23126 * @cfg {String} fhref Footer href
23129 * Create a new NumberBox
23130 * @param {Object} config The config object
23134 Roo.bootstrap.dash.NumberBox = function(config){
23135 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23139 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23148 getAutoCreate : function(){
23152 cls : 'small-box ',
23160 cls : 'roo-headline',
23161 html : this.headline
23165 cls : 'roo-content',
23166 html : this.content
23180 cls : 'ion ' + this.icon
23189 cls : 'small-box-footer',
23190 href : this.fhref || '#',
23194 cfg.cn.push(footer);
23201 onRender : function(ct,position){
23202 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23209 setHeadline: function (value)
23211 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23214 setFooter: function (value, href)
23216 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23219 this.el.select('a.small-box-footer',true).first().attr('href', href);
23224 setContent: function (value)
23226 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23229 initEvents: function()
23243 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23246 * @class Roo.bootstrap.dash.TabBox
23247 * @extends Roo.bootstrap.Component
23248 * Bootstrap TabBox class
23249 * @cfg {String} title Title of the TabBox
23250 * @cfg {String} icon Icon of the TabBox
23251 * @cfg {Boolean} showtabs (true|false) show the tabs default true
23252 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
23255 * Create a new TabBox
23256 * @param {Object} config The config object
23260 Roo.bootstrap.dash.TabBox = function(config){
23261 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
23266 * When a pane is added
23267 * @param {Roo.bootstrap.dash.TabPane} pane
23271 * @event activatepane
23272 * When a pane is activated
23273 * @param {Roo.bootstrap.dash.TabPane} pane
23275 "activatepane" : true
23283 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
23288 tabScrollable : false,
23290 getChildContainer : function()
23292 return this.el.select('.tab-content', true).first();
23295 getAutoCreate : function(){
23299 cls: 'pull-left header',
23307 cls: 'fa ' + this.icon
23313 cls: 'nav nav-tabs pull-right',
23319 if(this.tabScrollable){
23326 cls: 'nav nav-tabs pull-right',
23337 cls: 'nav-tabs-custom',
23342 cls: 'tab-content no-padding',
23350 initEvents : function()
23352 //Roo.log('add add pane handler');
23353 this.on('addpane', this.onAddPane, this);
23356 * Updates the box title
23357 * @param {String} html to set the title to.
23359 setTitle : function(value)
23361 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
23363 onAddPane : function(pane)
23365 this.panes.push(pane);
23366 //Roo.log('addpane');
23368 // tabs are rendere left to right..
23369 if(!this.showtabs){
23373 var ctr = this.el.select('.nav-tabs', true).first();
23376 var existing = ctr.select('.nav-tab',true);
23377 var qty = existing.getCount();;
23380 var tab = ctr.createChild({
23382 cls : 'nav-tab' + (qty ? '' : ' active'),
23390 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
23393 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
23395 pane.el.addClass('active');
23400 onTabClick : function(ev,un,ob,pane)
23402 //Roo.log('tab - prev default');
23403 ev.preventDefault();
23406 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
23407 pane.tab.addClass('active');
23408 //Roo.log(pane.title);
23409 this.getChildContainer().select('.tab-pane',true).removeClass('active');
23410 // technically we should have a deactivate event.. but maybe add later.
23411 // and it should not de-activate the selected tab...
23412 this.fireEvent('activatepane', pane);
23413 pane.el.addClass('active');
23414 pane.fireEvent('activate');
23419 getActivePane : function()
23422 Roo.each(this.panes, function(p) {
23423 if(p.el.hasClass('active')){
23444 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23446 * @class Roo.bootstrap.TabPane
23447 * @extends Roo.bootstrap.Component
23448 * Bootstrap TabPane class
23449 * @cfg {Boolean} active (false | true) Default false
23450 * @cfg {String} title title of panel
23454 * Create a new TabPane
23455 * @param {Object} config The config object
23458 Roo.bootstrap.dash.TabPane = function(config){
23459 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
23465 * When a pane is activated
23466 * @param {Roo.bootstrap.dash.TabPane} pane
23473 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
23478 // the tabBox that this is attached to.
23481 getAutoCreate : function()
23489 cfg.cls += ' active';
23494 initEvents : function()
23496 //Roo.log('trigger add pane handler');
23497 this.parent().fireEvent('addpane', this)
23501 * Updates the tab title
23502 * @param {String} html to set the title to.
23504 setTitle: function(str)
23510 this.tab.select('a', true).first().dom.innerHTML = str;
23527 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23530 * @class Roo.bootstrap.menu.Menu
23531 * @extends Roo.bootstrap.Component
23532 * Bootstrap Menu class - container for Menu
23533 * @cfg {String} html Text of the menu
23534 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
23535 * @cfg {String} icon Font awesome icon
23536 * @cfg {String} pos Menu align to (top | bottom) default bottom
23540 * Create a new Menu
23541 * @param {Object} config The config object
23545 Roo.bootstrap.menu.Menu = function(config){
23546 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
23550 * @event beforeshow
23551 * Fires before this menu is displayed
23552 * @param {Roo.bootstrap.menu.Menu} this
23556 * @event beforehide
23557 * Fires before this menu is hidden
23558 * @param {Roo.bootstrap.menu.Menu} this
23563 * Fires after this menu is displayed
23564 * @param {Roo.bootstrap.menu.Menu} this
23569 * Fires after this menu is hidden
23570 * @param {Roo.bootstrap.menu.Menu} this
23575 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
23576 * @param {Roo.bootstrap.menu.Menu} this
23577 * @param {Roo.EventObject} e
23584 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
23588 weight : 'default',
23593 getChildContainer : function() {
23594 if(this.isSubMenu){
23598 return this.el.select('ul.dropdown-menu', true).first();
23601 getAutoCreate : function()
23606 cls : 'roo-menu-text',
23614 cls : 'fa ' + this.icon
23625 cls : 'dropdown-button btn btn-' + this.weight,
23630 cls : 'dropdown-toggle btn btn-' + this.weight,
23640 cls : 'dropdown-menu'
23646 if(this.pos == 'top'){
23647 cfg.cls += ' dropup';
23650 if(this.isSubMenu){
23653 cls : 'dropdown-menu'
23660 onRender : function(ct, position)
23662 this.isSubMenu = ct.hasClass('dropdown-submenu');
23664 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
23667 initEvents : function()
23669 if(this.isSubMenu){
23673 this.hidden = true;
23675 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
23676 this.triggerEl.on('click', this.onTriggerPress, this);
23678 this.buttonEl = this.el.select('button.dropdown-button', true).first();
23679 this.buttonEl.on('click', this.onClick, this);
23685 if(this.isSubMenu){
23689 return this.el.select('ul.dropdown-menu', true).first();
23692 onClick : function(e)
23694 this.fireEvent("click", this, e);
23697 onTriggerPress : function(e)
23699 if (this.isVisible()) {
23706 isVisible : function(){
23707 return !this.hidden;
23712 this.fireEvent("beforeshow", this);
23714 this.hidden = false;
23715 this.el.addClass('open');
23717 Roo.get(document).on("mouseup", this.onMouseUp, this);
23719 this.fireEvent("show", this);
23726 this.fireEvent("beforehide", this);
23728 this.hidden = true;
23729 this.el.removeClass('open');
23731 Roo.get(document).un("mouseup", this.onMouseUp);
23733 this.fireEvent("hide", this);
23736 onMouseUp : function()
23750 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23753 * @class Roo.bootstrap.menu.Item
23754 * @extends Roo.bootstrap.Component
23755 * Bootstrap MenuItem class
23756 * @cfg {Boolean} submenu (true | false) default false
23757 * @cfg {String} html text of the item
23758 * @cfg {String} href the link
23759 * @cfg {Boolean} disable (true | false) default false
23760 * @cfg {Boolean} preventDefault (true | false) default true
23761 * @cfg {String} icon Font awesome icon
23762 * @cfg {String} pos Submenu align to (left | right) default right
23766 * Create a new Item
23767 * @param {Object} config The config object
23771 Roo.bootstrap.menu.Item = function(config){
23772 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
23776 * Fires when the mouse is hovering over this menu
23777 * @param {Roo.bootstrap.menu.Item} this
23778 * @param {Roo.EventObject} e
23783 * Fires when the mouse exits this menu
23784 * @param {Roo.bootstrap.menu.Item} this
23785 * @param {Roo.EventObject} e
23791 * The raw click event for the entire grid.
23792 * @param {Roo.EventObject} e
23798 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
23803 preventDefault: true,
23808 getAutoCreate : function()
23813 cls : 'roo-menu-item-text',
23821 cls : 'fa ' + this.icon
23830 href : this.href || '#',
23837 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
23841 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
23843 if(this.pos == 'left'){
23844 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
23851 initEvents : function()
23853 this.el.on('mouseover', this.onMouseOver, this);
23854 this.el.on('mouseout', this.onMouseOut, this);
23856 this.el.select('a', true).first().on('click', this.onClick, this);
23860 onClick : function(e)
23862 if(this.preventDefault){
23863 e.preventDefault();
23866 this.fireEvent("click", this, e);
23869 onMouseOver : function(e)
23871 if(this.submenu && this.pos == 'left'){
23872 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23875 this.fireEvent("mouseover", this, e);
23878 onMouseOut : function(e)
23880 this.fireEvent("mouseout", this, e);
23892 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23895 * @class Roo.bootstrap.menu.Separator
23896 * @extends Roo.bootstrap.Component
23897 * Bootstrap Separator class
23900 * Create a new Separator
23901 * @param {Object} config The config object
23905 Roo.bootstrap.menu.Separator = function(config){
23906 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23909 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23911 getAutoCreate : function(){
23932 * @class Roo.bootstrap.Tooltip
23933 * Bootstrap Tooltip class
23934 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23935 * to determine which dom element triggers the tooltip.
23937 * It needs to add support for additional attributes like tooltip-position
23940 * Create a new Toolti
23941 * @param {Object} config The config object
23944 Roo.bootstrap.Tooltip = function(config){
23945 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23948 Roo.apply(Roo.bootstrap.Tooltip, {
23950 * @function init initialize tooltip monitoring.
23954 currentTip : false,
23955 currentRegion : false,
23961 Roo.get(document).on('mouseover', this.enter ,this);
23962 Roo.get(document).on('mouseout', this.leave, this);
23965 this.currentTip = new Roo.bootstrap.Tooltip();
23968 enter : function(ev)
23970 var dom = ev.getTarget();
23972 //Roo.log(['enter',dom]);
23973 var el = Roo.fly(dom);
23974 if (this.currentEl) {
23976 //Roo.log(this.currentEl);
23977 //Roo.log(this.currentEl.contains(dom));
23978 if (this.currentEl == el) {
23981 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
23987 if (this.currentTip.el) {
23988 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
23993 // you can not look for children, as if el is the body.. then everythign is the child..
23994 if (!el.attr('tooltip')) { //
23995 if (!el.select("[tooltip]").elements.length) {
23998 // is the mouse over this child...?
23999 bindEl = el.select("[tooltip]").first();
24000 var xy = ev.getXY();
24001 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24002 //Roo.log("not in region.");
24005 //Roo.log("child element over..");
24008 this.currentEl = bindEl;
24009 this.currentTip.bind(bindEl);
24010 this.currentRegion = Roo.lib.Region.getRegion(dom);
24011 this.currentTip.enter();
24014 leave : function(ev)
24016 var dom = ev.getTarget();
24017 //Roo.log(['leave',dom]);
24018 if (!this.currentEl) {
24023 if (dom != this.currentEl.dom) {
24026 var xy = ev.getXY();
24027 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24030 // only activate leave if mouse cursor is outside... bounding box..
24035 if (this.currentTip) {
24036 this.currentTip.leave();
24038 //Roo.log('clear currentEl');
24039 this.currentEl = false;
24044 'left' : ['r-l', [-2,0], 'right'],
24045 'right' : ['l-r', [2,0], 'left'],
24046 'bottom' : ['t-b', [0,2], 'top'],
24047 'top' : [ 'b-t', [0,-2], 'bottom']
24053 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24058 delay : null, // can be { show : 300 , hide: 500}
24062 hoverState : null, //???
24064 placement : 'bottom',
24066 getAutoCreate : function(){
24073 cls : 'tooltip-arrow'
24076 cls : 'tooltip-inner'
24083 bind : function(el)
24089 enter : function () {
24091 if (this.timeout != null) {
24092 clearTimeout(this.timeout);
24095 this.hoverState = 'in';
24096 //Roo.log("enter - show");
24097 if (!this.delay || !this.delay.show) {
24102 this.timeout = setTimeout(function () {
24103 if (_t.hoverState == 'in') {
24106 }, this.delay.show);
24110 clearTimeout(this.timeout);
24112 this.hoverState = 'out';
24113 if (!this.delay || !this.delay.hide) {
24119 this.timeout = setTimeout(function () {
24120 //Roo.log("leave - timeout");
24122 if (_t.hoverState == 'out') {
24124 Roo.bootstrap.Tooltip.currentEl = false;
24132 this.render(document.body);
24135 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24137 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24139 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24141 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24143 var placement = typeof this.placement == 'function' ?
24144 this.placement.call(this, this.el, on_el) :
24147 var autoToken = /\s?auto?\s?/i;
24148 var autoPlace = autoToken.test(placement);
24150 placement = placement.replace(autoToken, '') || 'top';
24154 //this.el.setXY([0,0]);
24156 //this.el.dom.style.display='block';
24158 //this.el.appendTo(on_el);
24160 var p = this.getPosition();
24161 var box = this.el.getBox();
24167 var align = Roo.bootstrap.Tooltip.alignment[placement];
24169 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24171 if(placement == 'top' || placement == 'bottom'){
24173 placement = 'right';
24176 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24177 placement = 'left';
24181 align = Roo.bootstrap.Tooltip.alignment[placement];
24183 this.el.alignTo(this.bindEl, align[0],align[1]);
24184 //var arrow = this.el.select('.arrow',true).first();
24185 //arrow.set(align[2],
24187 this.el.addClass(placement);
24189 this.el.addClass('in fade');
24191 this.hoverState = null;
24193 if (this.el.hasClass('fade')) {
24204 //this.el.setXY([0,0]);
24205 this.el.removeClass('in');
24221 * @class Roo.bootstrap.LocationPicker
24222 * @extends Roo.bootstrap.Component
24223 * Bootstrap LocationPicker class
24224 * @cfg {Number} latitude Position when init default 0
24225 * @cfg {Number} longitude Position when init default 0
24226 * @cfg {Number} zoom default 15
24227 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24228 * @cfg {Boolean} mapTypeControl default false
24229 * @cfg {Boolean} disableDoubleClickZoom default false
24230 * @cfg {Boolean} scrollwheel default true
24231 * @cfg {Boolean} streetViewControl default false
24232 * @cfg {Number} radius default 0
24233 * @cfg {String} locationName
24234 * @cfg {Boolean} draggable default true
24235 * @cfg {Boolean} enableAutocomplete default false
24236 * @cfg {Boolean} enableReverseGeocode default true
24237 * @cfg {String} markerTitle
24240 * Create a new LocationPicker
24241 * @param {Object} config The config object
24245 Roo.bootstrap.LocationPicker = function(config){
24247 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
24252 * Fires when the picker initialized.
24253 * @param {Roo.bootstrap.LocationPicker} this
24254 * @param {Google Location} location
24258 * @event positionchanged
24259 * Fires when the picker position changed.
24260 * @param {Roo.bootstrap.LocationPicker} this
24261 * @param {Google Location} location
24263 positionchanged : true,
24266 * Fires when the map resize.
24267 * @param {Roo.bootstrap.LocationPicker} this
24272 * Fires when the map show.
24273 * @param {Roo.bootstrap.LocationPicker} this
24278 * Fires when the map hide.
24279 * @param {Roo.bootstrap.LocationPicker} this
24284 * Fires when click the map.
24285 * @param {Roo.bootstrap.LocationPicker} this
24286 * @param {Map event} e
24290 * @event mapRightClick
24291 * Fires when right click the map.
24292 * @param {Roo.bootstrap.LocationPicker} this
24293 * @param {Map event} e
24295 mapRightClick : true,
24297 * @event markerClick
24298 * Fires when click the marker.
24299 * @param {Roo.bootstrap.LocationPicker} this
24300 * @param {Map event} e
24302 markerClick : true,
24304 * @event markerRightClick
24305 * Fires when right click the marker.
24306 * @param {Roo.bootstrap.LocationPicker} this
24307 * @param {Map event} e
24309 markerRightClick : true,
24311 * @event OverlayViewDraw
24312 * Fires when OverlayView Draw
24313 * @param {Roo.bootstrap.LocationPicker} this
24315 OverlayViewDraw : true,
24317 * @event OverlayViewOnAdd
24318 * Fires when OverlayView Draw
24319 * @param {Roo.bootstrap.LocationPicker} this
24321 OverlayViewOnAdd : true,
24323 * @event OverlayViewOnRemove
24324 * Fires when OverlayView Draw
24325 * @param {Roo.bootstrap.LocationPicker} this
24327 OverlayViewOnRemove : true,
24329 * @event OverlayViewShow
24330 * Fires when OverlayView Draw
24331 * @param {Roo.bootstrap.LocationPicker} this
24332 * @param {Pixel} cpx
24334 OverlayViewShow : true,
24336 * @event OverlayViewHide
24337 * Fires when OverlayView Draw
24338 * @param {Roo.bootstrap.LocationPicker} this
24340 OverlayViewHide : true,
24342 * @event loadexception
24343 * Fires when load google lib failed.
24344 * @param {Roo.bootstrap.LocationPicker} this
24346 loadexception : true
24351 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
24353 gMapContext: false,
24359 mapTypeControl: false,
24360 disableDoubleClickZoom: false,
24362 streetViewControl: false,
24366 enableAutocomplete: false,
24367 enableReverseGeocode: true,
24370 getAutoCreate: function()
24375 cls: 'roo-location-picker'
24381 initEvents: function(ct, position)
24383 if(!this.el.getWidth() || this.isApplied()){
24387 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24392 initial: function()
24394 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
24395 this.fireEvent('loadexception', this);
24399 if(!this.mapTypeId){
24400 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
24403 this.gMapContext = this.GMapContext();
24405 this.initOverlayView();
24407 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
24411 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
24412 _this.setPosition(_this.gMapContext.marker.position);
24415 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
24416 _this.fireEvent('mapClick', this, event);
24420 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
24421 _this.fireEvent('mapRightClick', this, event);
24425 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
24426 _this.fireEvent('markerClick', this, event);
24430 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
24431 _this.fireEvent('markerRightClick', this, event);
24435 this.setPosition(this.gMapContext.location);
24437 this.fireEvent('initial', this, this.gMapContext.location);
24440 initOverlayView: function()
24444 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
24448 _this.fireEvent('OverlayViewDraw', _this);
24453 _this.fireEvent('OverlayViewOnAdd', _this);
24456 onRemove: function()
24458 _this.fireEvent('OverlayViewOnRemove', _this);
24461 show: function(cpx)
24463 _this.fireEvent('OverlayViewShow', _this, cpx);
24468 _this.fireEvent('OverlayViewHide', _this);
24474 fromLatLngToContainerPixel: function(event)
24476 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
24479 isApplied: function()
24481 return this.getGmapContext() == false ? false : true;
24484 getGmapContext: function()
24486 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
24489 GMapContext: function()
24491 var position = new google.maps.LatLng(this.latitude, this.longitude);
24493 var _map = new google.maps.Map(this.el.dom, {
24496 mapTypeId: this.mapTypeId,
24497 mapTypeControl: this.mapTypeControl,
24498 disableDoubleClickZoom: this.disableDoubleClickZoom,
24499 scrollwheel: this.scrollwheel,
24500 streetViewControl: this.streetViewControl,
24501 locationName: this.locationName,
24502 draggable: this.draggable,
24503 enableAutocomplete: this.enableAutocomplete,
24504 enableReverseGeocode: this.enableReverseGeocode
24507 var _marker = new google.maps.Marker({
24508 position: position,
24510 title: this.markerTitle,
24511 draggable: this.draggable
24518 location: position,
24519 radius: this.radius,
24520 locationName: this.locationName,
24521 addressComponents: {
24522 formatted_address: null,
24523 addressLine1: null,
24524 addressLine2: null,
24526 streetNumber: null,
24530 stateOrProvince: null
24533 domContainer: this.el.dom,
24534 geodecoder: new google.maps.Geocoder()
24538 drawCircle: function(center, radius, options)
24540 if (this.gMapContext.circle != null) {
24541 this.gMapContext.circle.setMap(null);
24545 options = Roo.apply({}, options, {
24546 strokeColor: "#0000FF",
24547 strokeOpacity: .35,
24549 fillColor: "#0000FF",
24553 options.map = this.gMapContext.map;
24554 options.radius = radius;
24555 options.center = center;
24556 this.gMapContext.circle = new google.maps.Circle(options);
24557 return this.gMapContext.circle;
24563 setPosition: function(location)
24565 this.gMapContext.location = location;
24566 this.gMapContext.marker.setPosition(location);
24567 this.gMapContext.map.panTo(location);
24568 this.drawCircle(location, this.gMapContext.radius, {});
24572 if (this.gMapContext.settings.enableReverseGeocode) {
24573 this.gMapContext.geodecoder.geocode({
24574 latLng: this.gMapContext.location
24575 }, function(results, status) {
24577 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
24578 _this.gMapContext.locationName = results[0].formatted_address;
24579 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
24581 _this.fireEvent('positionchanged', this, location);
24588 this.fireEvent('positionchanged', this, location);
24593 google.maps.event.trigger(this.gMapContext.map, "resize");
24595 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
24597 this.fireEvent('resize', this);
24600 setPositionByLatLng: function(latitude, longitude)
24602 this.setPosition(new google.maps.LatLng(latitude, longitude));
24605 getCurrentPosition: function()
24608 latitude: this.gMapContext.location.lat(),
24609 longitude: this.gMapContext.location.lng()
24613 getAddressName: function()
24615 return this.gMapContext.locationName;
24618 getAddressComponents: function()
24620 return this.gMapContext.addressComponents;
24623 address_component_from_google_geocode: function(address_components)
24627 for (var i = 0; i < address_components.length; i++) {
24628 var component = address_components[i];
24629 if (component.types.indexOf("postal_code") >= 0) {
24630 result.postalCode = component.short_name;
24631 } else if (component.types.indexOf("street_number") >= 0) {
24632 result.streetNumber = component.short_name;
24633 } else if (component.types.indexOf("route") >= 0) {
24634 result.streetName = component.short_name;
24635 } else if (component.types.indexOf("neighborhood") >= 0) {
24636 result.city = component.short_name;
24637 } else if (component.types.indexOf("locality") >= 0) {
24638 result.city = component.short_name;
24639 } else if (component.types.indexOf("sublocality") >= 0) {
24640 result.district = component.short_name;
24641 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
24642 result.stateOrProvince = component.short_name;
24643 } else if (component.types.indexOf("country") >= 0) {
24644 result.country = component.short_name;
24648 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
24649 result.addressLine2 = "";
24653 setZoomLevel: function(zoom)
24655 this.gMapContext.map.setZoom(zoom);
24668 this.fireEvent('show', this);
24679 this.fireEvent('hide', this);
24684 Roo.apply(Roo.bootstrap.LocationPicker, {
24686 OverlayView : function(map, options)
24688 options = options || {};
24702 * @class Roo.bootstrap.Alert
24703 * @extends Roo.bootstrap.Component
24704 * Bootstrap Alert class
24705 * @cfg {String} title The title of alert
24706 * @cfg {String} html The content of alert
24707 * @cfg {String} weight ( success | info | warning | danger )
24708 * @cfg {String} faicon font-awesomeicon
24711 * Create a new alert
24712 * @param {Object} config The config object
24716 Roo.bootstrap.Alert = function(config){
24717 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
24721 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
24728 getAutoCreate : function()
24737 cls : 'roo-alert-icon'
24742 cls : 'roo-alert-title',
24747 cls : 'roo-alert-text',
24754 cfg.cn[0].cls += ' fa ' + this.faicon;
24758 cfg.cls += ' alert-' + this.weight;
24764 initEvents: function()
24766 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24769 setTitle : function(str)
24771 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
24774 setText : function(str)
24776 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
24779 setWeight : function(weight)
24782 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
24785 this.weight = weight;
24787 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
24790 setIcon : function(icon)
24793 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
24796 this.faicon = icon;
24798 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
24819 * @class Roo.bootstrap.UploadCropbox
24820 * @extends Roo.bootstrap.Component
24821 * Bootstrap UploadCropbox class
24822 * @cfg {String} emptyText show when image has been loaded
24823 * @cfg {String} rotateNotify show when image too small to rotate
24824 * @cfg {Number} errorTimeout default 3000
24825 * @cfg {Number} minWidth default 300
24826 * @cfg {Number} minHeight default 300
24827 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
24828 * @cfg {Boolean} isDocument (true|false) default false
24829 * @cfg {String} url action url
24830 * @cfg {String} paramName default 'imageUpload'
24831 * @cfg {String} method default POST
24832 * @cfg {Boolean} loadMask (true|false) default true
24833 * @cfg {Boolean} loadingText default 'Loading...'
24836 * Create a new UploadCropbox
24837 * @param {Object} config The config object
24840 Roo.bootstrap.UploadCropbox = function(config){
24841 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
24845 * @event beforeselectfile
24846 * Fire before select file
24847 * @param {Roo.bootstrap.UploadCropbox} this
24849 "beforeselectfile" : true,
24852 * Fire after initEvent
24853 * @param {Roo.bootstrap.UploadCropbox} this
24858 * Fire after initEvent
24859 * @param {Roo.bootstrap.UploadCropbox} this
24860 * @param {String} data
24865 * Fire when preparing the file data
24866 * @param {Roo.bootstrap.UploadCropbox} this
24867 * @param {Object} file
24872 * Fire when get exception
24873 * @param {Roo.bootstrap.UploadCropbox} this
24874 * @param {XMLHttpRequest} xhr
24876 "exception" : true,
24878 * @event beforeloadcanvas
24879 * Fire before load the canvas
24880 * @param {Roo.bootstrap.UploadCropbox} this
24881 * @param {String} src
24883 "beforeloadcanvas" : true,
24886 * Fire when trash image
24887 * @param {Roo.bootstrap.UploadCropbox} this
24892 * Fire when download the image
24893 * @param {Roo.bootstrap.UploadCropbox} this
24897 * @event footerbuttonclick
24898 * Fire when footerbuttonclick
24899 * @param {Roo.bootstrap.UploadCropbox} this
24900 * @param {String} type
24902 "footerbuttonclick" : true,
24906 * @param {Roo.bootstrap.UploadCropbox} this
24911 * Fire when rotate the image
24912 * @param {Roo.bootstrap.UploadCropbox} this
24913 * @param {String} pos
24918 * Fire when inspect the file
24919 * @param {Roo.bootstrap.UploadCropbox} this
24920 * @param {Object} file
24925 * Fire when xhr upload the file
24926 * @param {Roo.bootstrap.UploadCropbox} this
24927 * @param {Object} data
24932 * Fire when arrange the file data
24933 * @param {Roo.bootstrap.UploadCropbox} this
24934 * @param {Object} formData
24939 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
24942 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
24944 emptyText : 'Click to upload image',
24945 rotateNotify : 'Image is too small to rotate',
24946 errorTimeout : 3000,
24960 cropType : 'image/jpeg',
24962 canvasLoaded : false,
24963 isDocument : false,
24965 paramName : 'imageUpload',
24967 loadingText : 'Loading...',
24970 getAutoCreate : function()
24974 cls : 'roo-upload-cropbox',
24978 cls : 'roo-upload-cropbox-selector',
24983 cls : 'roo-upload-cropbox-body',
24984 style : 'cursor:pointer',
24988 cls : 'roo-upload-cropbox-preview'
24992 cls : 'roo-upload-cropbox-thumb'
24996 cls : 'roo-upload-cropbox-empty-notify',
24997 html : this.emptyText
25001 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25002 html : this.rotateNotify
25008 cls : 'roo-upload-cropbox-footer',
25011 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25021 onRender : function(ct, position)
25023 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25025 if (this.buttons.length) {
25027 Roo.each(this.buttons, function(bb) {
25029 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25031 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25037 this.maskEl = this.el;
25041 initEvents : function()
25043 this.urlAPI = (window.createObjectURL && window) ||
25044 (window.URL && URL.revokeObjectURL && URL) ||
25045 (window.webkitURL && webkitURL);
25047 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25048 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25050 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25051 this.selectorEl.hide();
25053 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25054 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25056 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25057 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25058 this.thumbEl.hide();
25060 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25061 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25063 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25064 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25065 this.errorEl.hide();
25067 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25068 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25069 this.footerEl.hide();
25071 this.setThumbBoxSize();
25077 this.fireEvent('initial', this);
25084 window.addEventListener("resize", function() { _this.resize(); } );
25086 this.bodyEl.on('click', this.beforeSelectFile, this);
25089 this.bodyEl.on('touchstart', this.onTouchStart, this);
25090 this.bodyEl.on('touchmove', this.onTouchMove, this);
25091 this.bodyEl.on('touchend', this.onTouchEnd, this);
25095 this.bodyEl.on('mousedown', this.onMouseDown, this);
25096 this.bodyEl.on('mousemove', this.onMouseMove, this);
25097 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25098 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25099 Roo.get(document).on('mouseup', this.onMouseUp, this);
25102 this.selectorEl.on('change', this.onFileSelected, this);
25108 this.baseScale = 1;
25110 this.baseRotate = 1;
25111 this.dragable = false;
25112 this.pinching = false;
25115 this.cropData = false;
25116 this.notifyEl.dom.innerHTML = this.emptyText;
25118 this.selectorEl.dom.value = '';
25122 resize : function()
25124 if(this.fireEvent('resize', this) != false){
25125 this.setThumbBoxPosition();
25126 this.setCanvasPosition();
25130 onFooterButtonClick : function(e, el, o, type)
25133 case 'rotate-left' :
25134 this.onRotateLeft(e);
25136 case 'rotate-right' :
25137 this.onRotateRight(e);
25140 this.beforeSelectFile(e);
25155 this.fireEvent('footerbuttonclick', this, type);
25158 beforeSelectFile : function(e)
25160 e.preventDefault();
25162 if(this.fireEvent('beforeselectfile', this) != false){
25163 this.selectorEl.dom.click();
25167 onFileSelected : function(e)
25169 e.preventDefault();
25171 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25175 var file = this.selectorEl.dom.files[0];
25177 if(this.fireEvent('inspect', this, file) != false){
25178 this.prepare(file);
25183 trash : function(e)
25185 this.fireEvent('trash', this);
25188 download : function(e)
25190 this.fireEvent('download', this);
25193 loadCanvas : function(src)
25195 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25199 this.imageEl = document.createElement('img');
25203 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25205 this.imageEl.src = src;
25209 onLoadCanvas : function()
25211 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25212 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25214 this.bodyEl.un('click', this.beforeSelectFile, this);
25216 this.notifyEl.hide();
25217 this.thumbEl.show();
25218 this.footerEl.show();
25220 this.baseRotateLevel();
25222 if(this.isDocument){
25223 this.setThumbBoxSize();
25226 this.setThumbBoxPosition();
25228 this.baseScaleLevel();
25234 this.canvasLoaded = true;
25237 this.maskEl.unmask();
25242 setCanvasPosition : function()
25244 if(!this.canvasEl){
25248 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
25249 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
25251 this.previewEl.setLeft(pw);
25252 this.previewEl.setTop(ph);
25256 onMouseDown : function(e)
25260 this.dragable = true;
25261 this.pinching = false;
25263 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
25264 this.dragable = false;
25268 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25269 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25273 onMouseMove : function(e)
25277 if(!this.canvasLoaded){
25281 if (!this.dragable){
25285 var minX = Math.ceil(this.thumbEl.getLeft(true));
25286 var minY = Math.ceil(this.thumbEl.getTop(true));
25288 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
25289 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
25291 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25292 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25294 x = x - this.mouseX;
25295 y = y - this.mouseY;
25297 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
25298 var bgY = Math.ceil(y + this.previewEl.getTop(true));
25300 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
25301 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
25303 this.previewEl.setLeft(bgX);
25304 this.previewEl.setTop(bgY);
25306 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25307 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25310 onMouseUp : function(e)
25314 this.dragable = false;
25317 onMouseWheel : function(e)
25321 this.startScale = this.scale;
25323 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
25325 if(!this.zoomable()){
25326 this.scale = this.startScale;
25335 zoomable : function()
25337 var minScale = this.thumbEl.getWidth() / this.minWidth;
25339 if(this.minWidth < this.minHeight){
25340 minScale = this.thumbEl.getHeight() / this.minHeight;
25343 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
25344 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
25348 (this.rotate == 0 || this.rotate == 180) &&
25350 width > this.imageEl.OriginWidth ||
25351 height > this.imageEl.OriginHeight ||
25352 (width < this.minWidth && height < this.minHeight)
25360 (this.rotate == 90 || this.rotate == 270) &&
25362 width > this.imageEl.OriginWidth ||
25363 height > this.imageEl.OriginHeight ||
25364 (width < this.minHeight && height < this.minWidth)
25371 !this.isDocument &&
25372 (this.rotate == 0 || this.rotate == 180) &&
25374 width < this.minWidth ||
25375 width > this.imageEl.OriginWidth ||
25376 height < this.minHeight ||
25377 height > this.imageEl.OriginHeight
25384 !this.isDocument &&
25385 (this.rotate == 90 || this.rotate == 270) &&
25387 width < this.minHeight ||
25388 width > this.imageEl.OriginWidth ||
25389 height < this.minWidth ||
25390 height > this.imageEl.OriginHeight
25400 onRotateLeft : function(e)
25402 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25404 var minScale = this.thumbEl.getWidth() / this.minWidth;
25406 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25407 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25409 this.startScale = this.scale;
25411 while (this.getScaleLevel() < minScale){
25413 this.scale = this.scale + 1;
25415 if(!this.zoomable()){
25420 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25421 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25426 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25433 this.scale = this.startScale;
25435 this.onRotateFail();
25440 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25442 if(this.isDocument){
25443 this.setThumbBoxSize();
25444 this.setThumbBoxPosition();
25445 this.setCanvasPosition();
25450 this.fireEvent('rotate', this, 'left');
25454 onRotateRight : function(e)
25456 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25458 var minScale = this.thumbEl.getWidth() / this.minWidth;
25460 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25461 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25463 this.startScale = this.scale;
25465 while (this.getScaleLevel() < minScale){
25467 this.scale = this.scale + 1;
25469 if(!this.zoomable()){
25474 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25475 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25480 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25487 this.scale = this.startScale;
25489 this.onRotateFail();
25494 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25496 if(this.isDocument){
25497 this.setThumbBoxSize();
25498 this.setThumbBoxPosition();
25499 this.setCanvasPosition();
25504 this.fireEvent('rotate', this, 'right');
25507 onRotateFail : function()
25509 this.errorEl.show(true);
25513 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
25518 this.previewEl.dom.innerHTML = '';
25520 var canvasEl = document.createElement("canvas");
25522 var contextEl = canvasEl.getContext("2d");
25524 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25525 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25526 var center = this.imageEl.OriginWidth / 2;
25528 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
25529 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25530 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25531 center = this.imageEl.OriginHeight / 2;
25534 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
25536 contextEl.translate(center, center);
25537 contextEl.rotate(this.rotate * Math.PI / 180);
25539 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25541 this.canvasEl = document.createElement("canvas");
25543 this.contextEl = this.canvasEl.getContext("2d");
25545 switch (this.rotate) {
25548 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25549 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25551 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25556 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25557 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25559 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25560 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);
25564 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25569 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25570 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25572 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25573 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);
25577 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);
25582 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25583 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25585 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25586 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25590 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);
25597 this.previewEl.appendChild(this.canvasEl);
25599 this.setCanvasPosition();
25604 if(!this.canvasLoaded){
25608 var imageCanvas = document.createElement("canvas");
25610 var imageContext = imageCanvas.getContext("2d");
25612 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25613 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25615 var center = imageCanvas.width / 2;
25617 imageContext.translate(center, center);
25619 imageContext.rotate(this.rotate * Math.PI / 180);
25621 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25623 var canvas = document.createElement("canvas");
25625 var context = canvas.getContext("2d");
25627 canvas.width = this.minWidth;
25628 canvas.height = this.minHeight;
25630 switch (this.rotate) {
25633 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25634 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25636 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25637 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25639 var targetWidth = this.minWidth - 2 * x;
25640 var targetHeight = this.minHeight - 2 * y;
25644 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25645 scale = targetWidth / width;
25648 if(x > 0 && y == 0){
25649 scale = targetHeight / height;
25652 if(x > 0 && y > 0){
25653 scale = targetWidth / width;
25655 if(width < height){
25656 scale = targetHeight / height;
25660 context.scale(scale, scale);
25662 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25663 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25665 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25666 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25668 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25673 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25674 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25676 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25677 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25679 var targetWidth = this.minWidth - 2 * x;
25680 var targetHeight = this.minHeight - 2 * y;
25684 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25685 scale = targetWidth / width;
25688 if(x > 0 && y == 0){
25689 scale = targetHeight / height;
25692 if(x > 0 && y > 0){
25693 scale = targetWidth / width;
25695 if(width < height){
25696 scale = targetHeight / height;
25700 context.scale(scale, scale);
25702 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25703 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25705 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25706 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25708 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25710 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25715 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25716 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25718 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25719 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25721 var targetWidth = this.minWidth - 2 * x;
25722 var targetHeight = this.minHeight - 2 * y;
25726 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25727 scale = targetWidth / width;
25730 if(x > 0 && y == 0){
25731 scale = targetHeight / height;
25734 if(x > 0 && y > 0){
25735 scale = targetWidth / width;
25737 if(width < height){
25738 scale = targetHeight / height;
25742 context.scale(scale, scale);
25744 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25745 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25747 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25748 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25750 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25751 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25753 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25758 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25759 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25761 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25762 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25764 var targetWidth = this.minWidth - 2 * x;
25765 var targetHeight = this.minHeight - 2 * y;
25769 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25770 scale = targetWidth / width;
25773 if(x > 0 && y == 0){
25774 scale = targetHeight / height;
25777 if(x > 0 && y > 0){
25778 scale = targetWidth / width;
25780 if(width < height){
25781 scale = targetHeight / height;
25785 context.scale(scale, scale);
25787 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25788 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25790 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25791 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25793 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25795 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25802 this.cropData = canvas.toDataURL(this.cropType);
25804 if(this.fireEvent('crop', this, this.cropData) !== false){
25805 this.process(this.file, this.cropData);
25812 setThumbBoxSize : function()
25816 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
25817 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
25818 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
25820 this.minWidth = width;
25821 this.minHeight = height;
25823 if(this.rotate == 90 || this.rotate == 270){
25824 this.minWidth = height;
25825 this.minHeight = width;
25830 width = Math.ceil(this.minWidth * height / this.minHeight);
25832 if(this.minWidth > this.minHeight){
25834 height = Math.ceil(this.minHeight * width / this.minWidth);
25837 this.thumbEl.setStyle({
25838 width : width + 'px',
25839 height : height + 'px'
25846 setThumbBoxPosition : function()
25848 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
25849 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
25851 this.thumbEl.setLeft(x);
25852 this.thumbEl.setTop(y);
25856 baseRotateLevel : function()
25858 this.baseRotate = 1;
25861 typeof(this.exif) != 'undefined' &&
25862 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
25863 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
25865 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
25868 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
25872 baseScaleLevel : function()
25876 if(this.isDocument){
25878 if(this.baseRotate == 6 || this.baseRotate == 8){
25880 height = this.thumbEl.getHeight();
25881 this.baseScale = height / this.imageEl.OriginWidth;
25883 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
25884 width = this.thumbEl.getWidth();
25885 this.baseScale = width / this.imageEl.OriginHeight;
25891 height = this.thumbEl.getHeight();
25892 this.baseScale = height / this.imageEl.OriginHeight;
25894 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
25895 width = this.thumbEl.getWidth();
25896 this.baseScale = width / this.imageEl.OriginWidth;
25902 if(this.baseRotate == 6 || this.baseRotate == 8){
25904 width = this.thumbEl.getHeight();
25905 this.baseScale = width / this.imageEl.OriginHeight;
25907 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
25908 height = this.thumbEl.getWidth();
25909 this.baseScale = height / this.imageEl.OriginHeight;
25912 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25913 height = this.thumbEl.getWidth();
25914 this.baseScale = height / this.imageEl.OriginHeight;
25916 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
25917 width = this.thumbEl.getHeight();
25918 this.baseScale = width / this.imageEl.OriginWidth;
25925 width = this.thumbEl.getWidth();
25926 this.baseScale = width / this.imageEl.OriginWidth;
25928 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
25929 height = this.thumbEl.getHeight();
25930 this.baseScale = height / this.imageEl.OriginHeight;
25933 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25935 height = this.thumbEl.getHeight();
25936 this.baseScale = height / this.imageEl.OriginHeight;
25938 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
25939 width = this.thumbEl.getWidth();
25940 this.baseScale = width / this.imageEl.OriginWidth;
25948 getScaleLevel : function()
25950 return this.baseScale * Math.pow(1.1, this.scale);
25953 onTouchStart : function(e)
25955 if(!this.canvasLoaded){
25956 this.beforeSelectFile(e);
25960 var touches = e.browserEvent.touches;
25966 if(touches.length == 1){
25967 this.onMouseDown(e);
25971 if(touches.length != 2){
25977 for(var i = 0, finger; finger = touches[i]; i++){
25978 coords.push(finger.pageX, finger.pageY);
25981 var x = Math.pow(coords[0] - coords[2], 2);
25982 var y = Math.pow(coords[1] - coords[3], 2);
25984 this.startDistance = Math.sqrt(x + y);
25986 this.startScale = this.scale;
25988 this.pinching = true;
25989 this.dragable = false;
25993 onTouchMove : function(e)
25995 if(!this.pinching && !this.dragable){
25999 var touches = e.browserEvent.touches;
26006 this.onMouseMove(e);
26012 for(var i = 0, finger; finger = touches[i]; i++){
26013 coords.push(finger.pageX, finger.pageY);
26016 var x = Math.pow(coords[0] - coords[2], 2);
26017 var y = Math.pow(coords[1] - coords[3], 2);
26019 this.endDistance = Math.sqrt(x + y);
26021 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26023 if(!this.zoomable()){
26024 this.scale = this.startScale;
26032 onTouchEnd : function(e)
26034 this.pinching = false;
26035 this.dragable = false;
26039 process : function(file, crop)
26042 this.maskEl.mask(this.loadingText);
26045 this.xhr = new XMLHttpRequest();
26047 file.xhr = this.xhr;
26049 this.xhr.open(this.method, this.url, true);
26052 "Accept": "application/json",
26053 "Cache-Control": "no-cache",
26054 "X-Requested-With": "XMLHttpRequest"
26057 for (var headerName in headers) {
26058 var headerValue = headers[headerName];
26060 this.xhr.setRequestHeader(headerName, headerValue);
26066 this.xhr.onload = function()
26068 _this.xhrOnLoad(_this.xhr);
26071 this.xhr.onerror = function()
26073 _this.xhrOnError(_this.xhr);
26076 var formData = new FormData();
26078 formData.append('returnHTML', 'NO');
26081 formData.append('crop', crop);
26084 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26085 formData.append(this.paramName, file, file.name);
26088 if(typeof(file.filename) != 'undefined'){
26089 formData.append('filename', file.filename);
26092 if(typeof(file.mimetype) != 'undefined'){
26093 formData.append('mimetype', file.mimetype);
26096 if(this.fireEvent('arrange', this, formData) != false){
26097 this.xhr.send(formData);
26101 xhrOnLoad : function(xhr)
26104 this.maskEl.unmask();
26107 if (xhr.readyState !== 4) {
26108 this.fireEvent('exception', this, xhr);
26112 var response = Roo.decode(xhr.responseText);
26114 if(!response.success){
26115 this.fireEvent('exception', this, xhr);
26119 var response = Roo.decode(xhr.responseText);
26121 this.fireEvent('upload', this, response);
26125 xhrOnError : function()
26128 this.maskEl.unmask();
26131 Roo.log('xhr on error');
26133 var response = Roo.decode(xhr.responseText);
26139 prepare : function(file)
26142 this.maskEl.mask(this.loadingText);
26148 if(typeof(file) === 'string'){
26149 this.loadCanvas(file);
26153 if(!file || !this.urlAPI){
26158 this.cropType = file.type;
26162 if(this.fireEvent('prepare', this, this.file) != false){
26164 var reader = new FileReader();
26166 reader.onload = function (e) {
26167 if (e.target.error) {
26168 Roo.log(e.target.error);
26172 var buffer = e.target.result,
26173 dataView = new DataView(buffer),
26175 maxOffset = dataView.byteLength - 4,
26179 if (dataView.getUint16(0) === 0xffd8) {
26180 while (offset < maxOffset) {
26181 markerBytes = dataView.getUint16(offset);
26183 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26184 markerLength = dataView.getUint16(offset + 2) + 2;
26185 if (offset + markerLength > dataView.byteLength) {
26186 Roo.log('Invalid meta data: Invalid segment size.');
26190 if(markerBytes == 0xffe1){
26191 _this.parseExifData(
26198 offset += markerLength;
26208 var url = _this.urlAPI.createObjectURL(_this.file);
26210 _this.loadCanvas(url);
26215 reader.readAsArrayBuffer(this.file);
26221 parseExifData : function(dataView, offset, length)
26223 var tiffOffset = offset + 10,
26227 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26228 // No Exif data, might be XMP data instead
26232 // Check for the ASCII code for "Exif" (0x45786966):
26233 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26234 // No Exif data, might be XMP data instead
26237 if (tiffOffset + 8 > dataView.byteLength) {
26238 Roo.log('Invalid Exif data: Invalid segment size.');
26241 // Check for the two null bytes:
26242 if (dataView.getUint16(offset + 8) !== 0x0000) {
26243 Roo.log('Invalid Exif data: Missing byte alignment offset.');
26246 // Check the byte alignment:
26247 switch (dataView.getUint16(tiffOffset)) {
26249 littleEndian = true;
26252 littleEndian = false;
26255 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
26258 // Check for the TIFF tag marker (0x002A):
26259 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
26260 Roo.log('Invalid Exif data: Missing TIFF marker.');
26263 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
26264 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
26266 this.parseExifTags(
26269 tiffOffset + dirOffset,
26274 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
26279 if (dirOffset + 6 > dataView.byteLength) {
26280 Roo.log('Invalid Exif data: Invalid directory offset.');
26283 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
26284 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
26285 if (dirEndOffset + 4 > dataView.byteLength) {
26286 Roo.log('Invalid Exif data: Invalid directory size.');
26289 for (i = 0; i < tagsNumber; i += 1) {
26293 dirOffset + 2 + 12 * i, // tag offset
26297 // Return the offset to the next directory:
26298 return dataView.getUint32(dirEndOffset, littleEndian);
26301 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
26303 var tag = dataView.getUint16(offset, littleEndian);
26305 this.exif[tag] = this.getExifValue(
26309 dataView.getUint16(offset + 2, littleEndian), // tag type
26310 dataView.getUint32(offset + 4, littleEndian), // tag length
26315 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
26317 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
26326 Roo.log('Invalid Exif data: Invalid tag type.');
26330 tagSize = tagType.size * length;
26331 // Determine if the value is contained in the dataOffset bytes,
26332 // or if the value at the dataOffset is a pointer to the actual data:
26333 dataOffset = tagSize > 4 ?
26334 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
26335 if (dataOffset + tagSize > dataView.byteLength) {
26336 Roo.log('Invalid Exif data: Invalid data offset.');
26339 if (length === 1) {
26340 return tagType.getValue(dataView, dataOffset, littleEndian);
26343 for (i = 0; i < length; i += 1) {
26344 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
26347 if (tagType.ascii) {
26349 // Concatenate the chars:
26350 for (i = 0; i < values.length; i += 1) {
26352 // Ignore the terminating NULL byte(s):
26353 if (c === '\u0000') {
26365 Roo.apply(Roo.bootstrap.UploadCropbox, {
26367 'Orientation': 0x0112
26371 1: 0, //'top-left',
26373 3: 180, //'bottom-right',
26374 // 4: 'bottom-left',
26376 6: 90, //'right-top',
26377 // 7: 'right-bottom',
26378 8: 270 //'left-bottom'
26382 // byte, 8-bit unsigned int:
26384 getValue: function (dataView, dataOffset) {
26385 return dataView.getUint8(dataOffset);
26389 // ascii, 8-bit byte:
26391 getValue: function (dataView, dataOffset) {
26392 return String.fromCharCode(dataView.getUint8(dataOffset));
26397 // short, 16 bit int:
26399 getValue: function (dataView, dataOffset, littleEndian) {
26400 return dataView.getUint16(dataOffset, littleEndian);
26404 // long, 32 bit int:
26406 getValue: function (dataView, dataOffset, littleEndian) {
26407 return dataView.getUint32(dataOffset, littleEndian);
26411 // rational = two long values, first is numerator, second is denominator:
26413 getValue: function (dataView, dataOffset, littleEndian) {
26414 return dataView.getUint32(dataOffset, littleEndian) /
26415 dataView.getUint32(dataOffset + 4, littleEndian);
26419 // slong, 32 bit signed int:
26421 getValue: function (dataView, dataOffset, littleEndian) {
26422 return dataView.getInt32(dataOffset, littleEndian);
26426 // srational, two slongs, first is numerator, second is denominator:
26428 getValue: function (dataView, dataOffset, littleEndian) {
26429 return dataView.getInt32(dataOffset, littleEndian) /
26430 dataView.getInt32(dataOffset + 4, littleEndian);
26440 cls : 'btn-group roo-upload-cropbox-rotate-left',
26441 action : 'rotate-left',
26445 cls : 'btn btn-default',
26446 html : '<i class="fa fa-undo"></i>'
26452 cls : 'btn-group roo-upload-cropbox-picture',
26453 action : 'picture',
26457 cls : 'btn btn-default',
26458 html : '<i class="fa fa-picture-o"></i>'
26464 cls : 'btn-group roo-upload-cropbox-rotate-right',
26465 action : 'rotate-right',
26469 cls : 'btn btn-default',
26470 html : '<i class="fa fa-repeat"></i>'
26478 cls : 'btn-group roo-upload-cropbox-rotate-left',
26479 action : 'rotate-left',
26483 cls : 'btn btn-default',
26484 html : '<i class="fa fa-undo"></i>'
26490 cls : 'btn-group roo-upload-cropbox-download',
26491 action : 'download',
26495 cls : 'btn btn-default',
26496 html : '<i class="fa fa-download"></i>'
26502 cls : 'btn-group roo-upload-cropbox-crop',
26507 cls : 'btn btn-default',
26508 html : '<i class="fa fa-crop"></i>'
26514 cls : 'btn-group roo-upload-cropbox-trash',
26519 cls : 'btn btn-default',
26520 html : '<i class="fa fa-trash"></i>'
26526 cls : 'btn-group roo-upload-cropbox-rotate-right',
26527 action : 'rotate-right',
26531 cls : 'btn btn-default',
26532 html : '<i class="fa fa-repeat"></i>'
26540 cls : 'btn-group roo-upload-cropbox-rotate-left',
26541 action : 'rotate-left',
26545 cls : 'btn btn-default',
26546 html : '<i class="fa fa-undo"></i>'
26552 cls : 'btn-group roo-upload-cropbox-rotate-right',
26553 action : 'rotate-right',
26557 cls : 'btn btn-default',
26558 html : '<i class="fa fa-repeat"></i>'
26571 * @class Roo.bootstrap.DocumentManager
26572 * @extends Roo.bootstrap.Component
26573 * Bootstrap DocumentManager class
26574 * @cfg {String} paramName default 'imageUpload'
26575 * @cfg {String} method default POST
26576 * @cfg {String} url action url
26577 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
26578 * @cfg {Boolean} multiple multiple upload default true
26579 * @cfg {Number} thumbSize default 300
26580 * @cfg {String} fieldLabel
26581 * @cfg {Number} labelWidth default 4
26582 * @cfg {String} labelAlign (left|top) default left
26583 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
26586 * Create a new DocumentManager
26587 * @param {Object} config The config object
26590 Roo.bootstrap.DocumentManager = function(config){
26591 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
26596 * Fire when initial the DocumentManager
26597 * @param {Roo.bootstrap.DocumentManager} this
26602 * inspect selected file
26603 * @param {Roo.bootstrap.DocumentManager} this
26604 * @param {File} file
26609 * Fire when xhr load exception
26610 * @param {Roo.bootstrap.DocumentManager} this
26611 * @param {XMLHttpRequest} xhr
26613 "exception" : true,
26616 * prepare the form data
26617 * @param {Roo.bootstrap.DocumentManager} this
26618 * @param {Object} formData
26623 * Fire when remove the file
26624 * @param {Roo.bootstrap.DocumentManager} this
26625 * @param {Object} file
26630 * Fire after refresh the file
26631 * @param {Roo.bootstrap.DocumentManager} this
26636 * Fire after click the image
26637 * @param {Roo.bootstrap.DocumentManager} this
26638 * @param {Object} file
26643 * Fire when upload a image and editable set to true
26644 * @param {Roo.bootstrap.DocumentManager} this
26645 * @param {Object} file
26649 * @event beforeselectfile
26650 * Fire before select file
26651 * @param {Roo.bootstrap.DocumentManager} this
26653 "beforeselectfile" : true,
26656 * Fire before process file
26657 * @param {Roo.bootstrap.DocumentManager} this
26658 * @param {Object} file
26665 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
26674 paramName : 'imageUpload',
26677 labelAlign : 'left',
26684 getAutoCreate : function()
26686 var managerWidget = {
26688 cls : 'roo-document-manager',
26692 cls : 'roo-document-manager-selector',
26697 cls : 'roo-document-manager-uploader',
26701 cls : 'roo-document-manager-upload-btn',
26702 html : '<i class="fa fa-plus"></i>'
26713 cls : 'column col-md-12',
26718 if(this.fieldLabel.length){
26723 cls : 'column col-md-12',
26724 html : this.fieldLabel
26728 cls : 'column col-md-12',
26733 if(this.labelAlign == 'left'){
26737 cls : 'column col-md-' + this.labelWidth,
26738 html : this.fieldLabel
26742 cls : 'column col-md-' + (12 - this.labelWidth),
26752 cls : 'row clearfix',
26760 initEvents : function()
26762 this.managerEl = this.el.select('.roo-document-manager', true).first();
26763 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26765 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
26766 this.selectorEl.hide();
26769 this.selectorEl.attr('multiple', 'multiple');
26772 this.selectorEl.on('change', this.onFileSelected, this);
26774 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
26775 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26777 this.uploader.on('click', this.onUploaderClick, this);
26779 this.renderProgressDialog();
26783 window.addEventListener("resize", function() { _this.refresh(); } );
26785 this.fireEvent('initial', this);
26788 renderProgressDialog : function()
26792 this.progressDialog = new Roo.bootstrap.Modal({
26793 cls : 'roo-document-manager-progress-dialog',
26794 allow_close : false,
26804 btnclick : function() {
26805 _this.uploadCancel();
26811 this.progressDialog.render(Roo.get(document.body));
26813 this.progress = new Roo.bootstrap.Progress({
26814 cls : 'roo-document-manager-progress',
26819 this.progress.render(this.progressDialog.getChildContainer());
26821 this.progressBar = new Roo.bootstrap.ProgressBar({
26822 cls : 'roo-document-manager-progress-bar',
26825 aria_valuemax : 12,
26829 this.progressBar.render(this.progress.getChildContainer());
26832 onUploaderClick : function(e)
26834 e.preventDefault();
26836 if(this.fireEvent('beforeselectfile', this) != false){
26837 this.selectorEl.dom.click();
26842 onFileSelected : function(e)
26844 e.preventDefault();
26846 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26850 Roo.each(this.selectorEl.dom.files, function(file){
26851 if(this.fireEvent('inspect', this, file) != false){
26852 this.files.push(file);
26862 this.selectorEl.dom.value = '';
26864 if(!this.files.length){
26868 if(this.boxes > 0 && this.files.length > this.boxes){
26869 this.files = this.files.slice(0, this.boxes);
26872 this.uploader.show();
26874 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26875 this.uploader.hide();
26884 Roo.each(this.files, function(file){
26886 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
26887 var f = this.renderPreview(file);
26892 if(file.type.indexOf('image') != -1){
26893 this.delegates.push(
26895 _this.process(file);
26896 }).createDelegate(this)
26904 _this.process(file);
26905 }).createDelegate(this)
26910 this.files = files;
26912 this.delegates = this.delegates.concat(docs);
26914 if(!this.delegates.length){
26919 this.progressBar.aria_valuemax = this.delegates.length;
26926 arrange : function()
26928 if(!this.delegates.length){
26929 this.progressDialog.hide();
26934 var delegate = this.delegates.shift();
26936 this.progressDialog.show();
26938 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
26940 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
26945 refresh : function()
26947 this.uploader.show();
26949 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26950 this.uploader.hide();
26953 Roo.isTouch ? this.closable(false) : this.closable(true);
26955 this.fireEvent('refresh', this);
26958 onRemove : function(e, el, o)
26960 e.preventDefault();
26962 this.fireEvent('remove', this, o);
26966 remove : function(o)
26970 Roo.each(this.files, function(file){
26971 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
26980 this.files = files;
26987 Roo.each(this.files, function(file){
26992 file.target.remove();
27001 onClick : function(e, el, o)
27003 e.preventDefault();
27005 this.fireEvent('click', this, o);
27009 closable : function(closable)
27011 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27013 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27025 xhrOnLoad : function(xhr)
27027 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27031 if (xhr.readyState !== 4) {
27033 this.fireEvent('exception', this, xhr);
27037 var response = Roo.decode(xhr.responseText);
27039 if(!response.success){
27041 this.fireEvent('exception', this, xhr);
27045 var file = this.renderPreview(response.data);
27047 this.files.push(file);
27053 xhrOnError : function(xhr)
27055 Roo.log('xhr on error');
27057 var response = Roo.decode(xhr.responseText);
27064 process : function(file)
27066 if(this.fireEvent('process', this, file) !== false){
27067 if(this.editable && file.type.indexOf('image') != -1){
27068 this.fireEvent('edit', this, file);
27072 this.uploadStart(file, false);
27079 uploadStart : function(file, crop)
27081 this.xhr = new XMLHttpRequest();
27083 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27088 file.xhr = this.xhr;
27090 this.managerEl.createChild({
27092 cls : 'roo-document-manager-loading',
27096 tooltip : file.name,
27097 cls : 'roo-document-manager-thumb',
27098 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27104 this.xhr.open(this.method, this.url, true);
27107 "Accept": "application/json",
27108 "Cache-Control": "no-cache",
27109 "X-Requested-With": "XMLHttpRequest"
27112 for (var headerName in headers) {
27113 var headerValue = headers[headerName];
27115 this.xhr.setRequestHeader(headerName, headerValue);
27121 this.xhr.onload = function()
27123 _this.xhrOnLoad(_this.xhr);
27126 this.xhr.onerror = function()
27128 _this.xhrOnError(_this.xhr);
27131 var formData = new FormData();
27133 formData.append('returnHTML', 'NO');
27136 formData.append('crop', crop);
27139 formData.append(this.paramName, file, file.name);
27141 if(this.fireEvent('prepare', this, formData) != false){
27142 this.xhr.send(formData);
27146 uploadCancel : function()
27153 this.delegates = [];
27155 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27162 renderPreview : function(file)
27164 if(typeof(file.target) != 'undefined' && file.target){
27168 var previewEl = this.managerEl.createChild({
27170 cls : 'roo-document-manager-preview',
27174 tooltip : file.filename,
27175 cls : 'roo-document-manager-thumb',
27176 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27181 html : '<i class="fa fa-times-circle"></i>'
27186 var close = previewEl.select('button.close', true).first();
27188 close.on('click', this.onRemove, this, file);
27190 file.target = previewEl;
27192 var image = previewEl.select('img', true).first();
27196 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27198 image.on('click', this.onClick, this, file);
27204 onPreviewLoad : function(file, image)
27206 if(typeof(file.target) == 'undefined' || !file.target){
27210 var width = image.dom.naturalWidth || image.dom.width;
27211 var height = image.dom.naturalHeight || image.dom.height;
27213 if(width > height){
27214 file.target.addClass('wide');
27218 file.target.addClass('tall');
27223 uploadFromSource : function(file, crop)
27225 this.xhr = new XMLHttpRequest();
27227 this.managerEl.createChild({
27229 cls : 'roo-document-manager-loading',
27233 tooltip : file.name,
27234 cls : 'roo-document-manager-thumb',
27235 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27241 this.xhr.open(this.method, this.url, true);
27244 "Accept": "application/json",
27245 "Cache-Control": "no-cache",
27246 "X-Requested-With": "XMLHttpRequest"
27249 for (var headerName in headers) {
27250 var headerValue = headers[headerName];
27252 this.xhr.setRequestHeader(headerName, headerValue);
27258 this.xhr.onload = function()
27260 _this.xhrOnLoad(_this.xhr);
27263 this.xhr.onerror = function()
27265 _this.xhrOnError(_this.xhr);
27268 var formData = new FormData();
27270 formData.append('returnHTML', 'NO');
27272 formData.append('crop', crop);
27274 if(typeof(file.filename) != 'undefined'){
27275 formData.append('filename', file.filename);
27278 if(typeof(file.mimetype) != 'undefined'){
27279 formData.append('mimetype', file.mimetype);
27282 if(this.fireEvent('prepare', this, formData) != false){
27283 this.xhr.send(formData);
27293 * @class Roo.bootstrap.DocumentViewer
27294 * @extends Roo.bootstrap.Component
27295 * Bootstrap DocumentViewer class
27298 * Create a new DocumentViewer
27299 * @param {Object} config The config object
27302 Roo.bootstrap.DocumentViewer = function(config){
27303 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
27308 * Fire after initEvent
27309 * @param {Roo.bootstrap.DocumentViewer} this
27315 * @param {Roo.bootstrap.DocumentViewer} this
27320 * Fire after trash button
27321 * @param {Roo.bootstrap.DocumentViewer} this
27328 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
27330 getAutoCreate : function()
27334 cls : 'roo-document-viewer',
27338 cls : 'roo-document-viewer-body',
27342 cls : 'roo-document-viewer-thumb',
27346 cls : 'roo-document-viewer-image'
27354 cls : 'roo-document-viewer-footer',
27357 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
27365 cls : 'btn btn-default roo-document-viewer-trash',
27366 html : '<i class="fa fa-trash"></i>'
27379 initEvents : function()
27382 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
27383 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27385 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
27386 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27388 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
27389 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27391 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
27392 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27394 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
27395 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27397 this.bodyEl.on('click', this.onClick, this);
27399 this.trashBtn.on('click', this.onTrash, this);
27403 initial : function()
27405 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
27408 this.fireEvent('initial', this);
27412 onClick : function(e)
27414 e.preventDefault();
27416 this.fireEvent('click', this);
27419 onTrash : function(e)
27421 e.preventDefault();
27423 this.fireEvent('trash', this);
27435 * @class Roo.bootstrap.NavProgressBar
27436 * @extends Roo.bootstrap.Component
27437 * Bootstrap NavProgressBar class
27440 * Create a new nav progress bar
27441 * @param {Object} config The config object
27444 Roo.bootstrap.NavProgressBar = function(config){
27445 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
27447 this.bullets = this.bullets || [];
27449 // Roo.bootstrap.NavProgressBar.register(this);
27453 * Fires when the active item changes
27454 * @param {Roo.bootstrap.NavProgressBar} this
27455 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
27456 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
27463 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
27468 getAutoCreate : function()
27470 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
27474 cls : 'roo-navigation-bar-group',
27478 cls : 'roo-navigation-top-bar'
27482 cls : 'roo-navigation-bullets-bar',
27486 cls : 'roo-navigation-bar'
27493 cls : 'roo-navigation-bottom-bar'
27503 initEvents: function()
27508 onRender : function(ct, position)
27510 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
27512 if(this.bullets.length){
27513 Roo.each(this.bullets, function(b){
27522 addItem : function(cfg)
27524 var item = new Roo.bootstrap.NavProgressItem(cfg);
27526 item.parentId = this.id;
27527 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
27530 var top = new Roo.bootstrap.Element({
27532 cls : 'roo-navigation-bar-text'
27535 var bottom = new Roo.bootstrap.Element({
27537 cls : 'roo-navigation-bar-text'
27540 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
27541 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
27543 var topText = new Roo.bootstrap.Element({
27545 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
27548 var bottomText = new Roo.bootstrap.Element({
27550 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
27553 topText.onRender(top.el, null);
27554 bottomText.onRender(bottom.el, null);
27557 item.bottomEl = bottom;
27560 this.barItems.push(item);
27565 getActive : function()
27567 var active = false;
27569 Roo.each(this.barItems, function(v){
27571 if (!v.isActive()) {
27583 setActiveItem : function(item)
27587 Roo.each(this.barItems, function(v){
27588 if (v.rid == item.rid) {
27592 if (v.isActive()) {
27593 v.setActive(false);
27598 item.setActive(true);
27600 this.fireEvent('changed', this, item, prev);
27603 getBarItem: function(rid)
27607 Roo.each(this.barItems, function(e) {
27608 if (e.rid != rid) {
27619 indexOfItem : function(item)
27623 Roo.each(this.barItems, function(v, i){
27625 if (v.rid != item.rid) {
27636 setActiveNext : function()
27638 var i = this.indexOfItem(this.getActive());
27640 if (i > this.barItems.length) {
27644 this.setActiveItem(this.barItems[i+1]);
27647 setActivePrev : function()
27649 var i = this.indexOfItem(this.getActive());
27655 this.setActiveItem(this.barItems[i-1]);
27658 format : function()
27660 if(!this.barItems.length){
27664 var width = 100 / this.barItems.length;
27666 Roo.each(this.barItems, function(i){
27667 i.el.setStyle('width', width + '%');
27668 i.topEl.el.setStyle('width', width + '%');
27669 i.bottomEl.el.setStyle('width', width + '%');
27678 * Nav Progress Item
27683 * @class Roo.bootstrap.NavProgressItem
27684 * @extends Roo.bootstrap.Component
27685 * Bootstrap NavProgressItem class
27686 * @cfg {String} rid the reference id
27687 * @cfg {Boolean} active (true|false) Is item active default false
27688 * @cfg {Boolean} disabled (true|false) Is item active default false
27689 * @cfg {String} html
27690 * @cfg {String} position (top|bottom) text position default bottom
27691 * @cfg {String} icon show icon instead of number
27694 * Create a new NavProgressItem
27695 * @param {Object} config The config object
27697 Roo.bootstrap.NavProgressItem = function(config){
27698 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
27703 * The raw click event for the entire grid.
27704 * @param {Roo.bootstrap.NavProgressItem} this
27705 * @param {Roo.EventObject} e
27712 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
27718 position : 'bottom',
27721 getAutoCreate : function()
27723 var iconCls = 'roo-navigation-bar-item-icon';
27725 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
27729 cls: 'roo-navigation-bar-item',
27739 cfg.cls += ' active';
27742 cfg.cls += ' disabled';
27748 disable : function()
27750 this.setDisabled(true);
27753 enable : function()
27755 this.setDisabled(false);
27758 initEvents: function()
27760 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
27762 this.iconEl.on('click', this.onClick, this);
27765 onClick : function(e)
27767 e.preventDefault();
27773 if(this.fireEvent('click', this, e) === false){
27777 this.parent().setActiveItem(this);
27780 isActive: function ()
27782 return this.active;
27785 setActive : function(state)
27787 if(this.active == state){
27791 this.active = state;
27794 this.el.addClass('active');
27798 this.el.removeClass('active');
27803 setDisabled : function(state)
27805 if(this.disabled == state){
27809 this.disabled = state;
27812 this.el.addClass('disabled');
27816 this.el.removeClass('disabled');
27819 tooltipEl : function()
27821 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
27834 * @class Roo.bootstrap.FieldLabel
27835 * @extends Roo.bootstrap.Component
27836 * Bootstrap FieldLabel class
27837 * @cfg {String} html contents of the element
27838 * @cfg {String} tag tag of the element default label
27839 * @cfg {String} cls class of the element
27840 * @cfg {String} target label target
27841 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
27842 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
27843 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
27844 * @cfg {String} iconTooltip default "This field is required"
27847 * Create a new FieldLabel
27848 * @param {Object} config The config object
27851 Roo.bootstrap.FieldLabel = function(config){
27852 Roo.bootstrap.Element.superclass.constructor.call(this, config);
27857 * Fires after the field has been marked as invalid.
27858 * @param {Roo.form.FieldLabel} this
27859 * @param {String} msg The validation message
27864 * Fires after the field has been validated with no errors.
27865 * @param {Roo.form.FieldLabel} this
27871 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
27878 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
27879 validClass : 'text-success fa fa-lg fa-check',
27880 iconTooltip : 'This field is required',
27882 getAutoCreate : function(){
27886 cls : 'roo-bootstrap-field-label ' + this.cls,
27892 tooltip : this.iconTooltip
27904 initEvents: function()
27906 Roo.bootstrap.Element.superclass.initEvents.call(this);
27908 this.iconEl = this.el.select('i', true).first();
27910 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
27912 Roo.bootstrap.FieldLabel.register(this);
27916 * Mark this field as valid
27918 markValid : function()
27920 this.iconEl.show();
27922 this.iconEl.removeClass(this.invalidClass);
27924 this.iconEl.addClass(this.validClass);
27926 this.fireEvent('valid', this);
27930 * Mark this field as invalid
27931 * @param {String} msg The validation message
27933 markInvalid : function(msg)
27935 this.iconEl.show();
27937 this.iconEl.removeClass(this.validClass);
27939 this.iconEl.addClass(this.invalidClass);
27941 this.fireEvent('invalid', this, msg);
27947 Roo.apply(Roo.bootstrap.FieldLabel, {
27952 * register a FieldLabel Group
27953 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
27955 register : function(label)
27957 if(this.groups.hasOwnProperty(label.target)){
27961 this.groups[label.target] = label;
27965 * fetch a FieldLabel Group based on the target
27966 * @param {string} target
27967 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
27969 get: function(target) {
27970 if (typeof(this.groups[target]) == 'undefined') {
27974 return this.groups[target] ;
27983 * page DateSplitField.
27989 * @class Roo.bootstrap.DateSplitField
27990 * @extends Roo.bootstrap.Component
27991 * Bootstrap DateSplitField class
27992 * @cfg {string} fieldLabel - the label associated
27993 * @cfg {Number} labelWidth set the width of label (0-12)
27994 * @cfg {String} labelAlign (top|left)
27995 * @cfg {Boolean} dayAllowBlank (true|false) default false
27996 * @cfg {Boolean} monthAllowBlank (true|false) default false
27997 * @cfg {Boolean} yearAllowBlank (true|false) default false
27998 * @cfg {string} dayPlaceholder
27999 * @cfg {string} monthPlaceholder
28000 * @cfg {string} yearPlaceholder
28001 * @cfg {string} dayFormat default 'd'
28002 * @cfg {string} monthFormat default 'm'
28003 * @cfg {string} yearFormat default 'Y'
28007 * Create a new DateSplitField
28008 * @param {Object} config The config object
28011 Roo.bootstrap.DateSplitField = function(config){
28012 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28018 * getting the data of years
28019 * @param {Roo.bootstrap.DateSplitField} this
28020 * @param {Object} years
28025 * getting the data of days
28026 * @param {Roo.bootstrap.DateSplitField} this
28027 * @param {Object} days
28032 * Fires after the field has been marked as invalid.
28033 * @param {Roo.form.Field} this
28034 * @param {String} msg The validation message
28039 * Fires after the field has been validated with no errors.
28040 * @param {Roo.form.Field} this
28046 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28049 labelAlign : 'top',
28051 dayAllowBlank : false,
28052 monthAllowBlank : false,
28053 yearAllowBlank : false,
28054 dayPlaceholder : '',
28055 monthPlaceholder : '',
28056 yearPlaceholder : '',
28060 isFormField : true,
28062 getAutoCreate : function()
28066 cls : 'row roo-date-split-field-group',
28071 cls : 'form-hidden-field roo-date-split-field-group-value',
28077 if(this.fieldLabel){
28080 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28084 html : this.fieldLabel
28090 Roo.each(['day', 'month', 'year'], function(t){
28093 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28100 inputEl: function ()
28102 return this.el.select('.roo-date-split-field-group-value', true).first();
28105 onRender : function(ct, position)
28109 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28111 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28113 this.dayField = new Roo.bootstrap.ComboBox({
28114 allowBlank : this.dayAllowBlank,
28115 alwaysQuery : true,
28116 displayField : 'value',
28119 forceSelection : true,
28121 placeholder : this.dayPlaceholder,
28122 selectOnFocus : true,
28123 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28124 triggerAction : 'all',
28126 valueField : 'value',
28127 store : new Roo.data.SimpleStore({
28128 data : (function() {
28130 _this.fireEvent('days', _this, days);
28133 fields : [ 'value' ]
28136 select : function (_self, record, index)
28138 _this.setValue(_this.getValue());
28143 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28145 this.monthField = new Roo.bootstrap.MonthField({
28146 after : '<i class=\"fa fa-calendar\"></i>',
28147 allowBlank : this.monthAllowBlank,
28148 placeholder : this.monthPlaceholder,
28151 render : function (_self)
28153 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28154 e.preventDefault();
28158 select : function (_self, oldvalue, newvalue)
28160 _this.setValue(_this.getValue());
28165 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28167 this.yearField = new Roo.bootstrap.ComboBox({
28168 allowBlank : this.yearAllowBlank,
28169 alwaysQuery : true,
28170 displayField : 'value',
28173 forceSelection : true,
28175 placeholder : this.yearPlaceholder,
28176 selectOnFocus : true,
28177 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28178 triggerAction : 'all',
28180 valueField : 'value',
28181 store : new Roo.data.SimpleStore({
28182 data : (function() {
28184 _this.fireEvent('years', _this, years);
28187 fields : [ 'value' ]
28190 select : function (_self, record, index)
28192 _this.setValue(_this.getValue());
28197 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28200 setValue : function(v, format)
28202 this.inputEl.dom.value = v;
28204 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28206 var d = Date.parseDate(v, f);
28213 this.setDay(d.format(this.dayFormat));
28214 this.setMonth(d.format(this.monthFormat));
28215 this.setYear(d.format(this.yearFormat));
28222 setDay : function(v)
28224 this.dayField.setValue(v);
28225 this.inputEl.dom.value = this.getValue();
28230 setMonth : function(v)
28232 this.monthField.setValue(v, true);
28233 this.inputEl.dom.value = this.getValue();
28238 setYear : function(v)
28240 this.yearField.setValue(v);
28241 this.inputEl.dom.value = this.getValue();
28246 getDay : function()
28248 return this.dayField.getValue();
28251 getMonth : function()
28253 return this.monthField.getValue();
28256 getYear : function()
28258 return this.yearField.getValue();
28261 getValue : function()
28263 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
28265 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
28275 this.inputEl.dom.value = '';
28280 validate : function()
28282 var d = this.dayField.validate();
28283 var m = this.monthField.validate();
28284 var y = this.yearField.validate();
28289 (!this.dayAllowBlank && !d) ||
28290 (!this.monthAllowBlank && !m) ||
28291 (!this.yearAllowBlank && !y)
28296 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
28305 this.markInvalid();
28310 markValid : function()
28313 var label = this.el.select('label', true).first();
28314 var icon = this.el.select('i.fa-star', true).first();
28320 this.fireEvent('valid', this);
28324 * Mark this field as invalid
28325 * @param {String} msg The validation message
28327 markInvalid : function(msg)
28330 var label = this.el.select('label', true).first();
28331 var icon = this.el.select('i.fa-star', true).first();
28333 if(label && !icon){
28334 this.el.select('.roo-date-split-field-label', true).createChild({
28336 cls : 'text-danger fa fa-lg fa-star',
28337 tooltip : 'This field is required',
28338 style : 'margin-right:5px;'
28342 this.fireEvent('invalid', this, msg);
28345 clearInvalid : function()
28347 var label = this.el.select('label', true).first();
28348 var icon = this.el.select('i.fa-star', true).first();
28354 this.fireEvent('valid', this);
28357 getName: function()
28367 * http://masonry.desandro.com
28369 * The idea is to render all the bricks based on vertical width...
28371 * The original code extends 'outlayer' - we might need to use that....
28377 * @class Roo.bootstrap.LayoutMasonry
28378 * @extends Roo.bootstrap.Component
28379 * Bootstrap Layout Masonry class
28382 * Create a new Element
28383 * @param {Object} config The config object
28386 Roo.bootstrap.LayoutMasonry = function(config){
28387 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
28393 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
28396 * @cfg {Boolean} isLayoutInstant = no animation?
28398 isLayoutInstant : false, // needed?
28401 * @cfg {Number} boxWidth width of the columns
28406 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
28411 * @cfg {Number} padWidth padding below box..
28416 * @cfg {Number} gutter gutter width..
28421 * @cfg {Boolean} isAutoInitial defalut true
28423 isAutoInitial : true,
28428 * @cfg {Boolean} isHorizontal defalut false
28430 isHorizontal : false,
28432 currentSize : null,
28438 bricks: null, //CompositeElement
28442 _isLayoutInited : false,
28444 // isAlternative : false, // only use for vertical layout...
28447 * @cfg {Number} alternativePadWidth padding below box..
28449 alternativePadWidth : 50,
28451 getAutoCreate : function(){
28455 cls: 'blog-masonary-wrapper ' + this.cls,
28457 cls : 'mas-boxes masonary'
28464 getChildContainer: function( )
28466 if (this.boxesEl) {
28467 return this.boxesEl;
28470 this.boxesEl = this.el.select('.mas-boxes').first();
28472 return this.boxesEl;
28476 initEvents : function()
28480 if(this.isAutoInitial){
28481 Roo.log('hook children rendered');
28482 this.on('childrenrendered', function() {
28483 Roo.log('children rendered');
28489 initial : function()
28491 this.currentSize = this.el.getBox(true);
28493 Roo.EventManager.onWindowResize(this.resize, this);
28495 if(!this.isAutoInitial){
28503 //this.layout.defer(500,this);
28507 resize : function()
28511 var cs = this.el.getBox(true);
28513 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
28514 Roo.log("no change in with or X");
28518 this.currentSize = cs;
28524 layout : function()
28526 this._resetLayout();
28528 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
28530 this.layoutItems( isInstant );
28532 this._isLayoutInited = true;
28536 _resetLayout : function()
28538 if(this.isHorizontal){
28539 this.horizontalMeasureColumns();
28543 this.verticalMeasureColumns();
28547 verticalMeasureColumns : function()
28549 this.getContainerWidth();
28551 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28552 // this.colWidth = Math.floor(this.containerWidth * 0.8);
28556 var boxWidth = this.boxWidth + this.padWidth;
28558 if(this.containerWidth < this.boxWidth){
28559 boxWidth = this.containerWidth
28562 var containerWidth = this.containerWidth;
28564 var cols = Math.floor(containerWidth / boxWidth);
28566 this.cols = Math.max( cols, 1 );
28568 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
28570 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
28572 this.colWidth = boxWidth + avail - this.padWidth;
28574 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
28575 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
28578 horizontalMeasureColumns : function()
28580 this.getContainerWidth();
28582 var boxWidth = this.boxWidth;
28584 if(this.containerWidth < boxWidth){
28585 boxWidth = this.containerWidth;
28588 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
28590 this.el.setHeight(boxWidth);
28594 getContainerWidth : function()
28596 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
28599 layoutItems : function( isInstant )
28601 var items = Roo.apply([], this.bricks);
28603 if(this.isHorizontal){
28604 this._horizontalLayoutItems( items , isInstant );
28608 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28609 // this._verticalAlternativeLayoutItems( items , isInstant );
28613 this._verticalLayoutItems( items , isInstant );
28617 _verticalLayoutItems : function ( items , isInstant)
28619 if ( !items || !items.length ) {
28624 ['xs', 'xs', 'xs', 'tall'],
28625 ['xs', 'xs', 'tall'],
28626 ['xs', 'xs', 'sm'],
28627 ['xs', 'xs', 'xs'],
28633 ['sm', 'xs', 'xs'],
28637 ['tall', 'xs', 'xs', 'xs'],
28638 ['tall', 'xs', 'xs'],
28650 Roo.each(items, function(item, k){
28652 switch (item.size) {
28653 // these layouts take up a full box,
28664 boxes.push([item]);
28687 var filterPattern = function(box, length)
28695 var pattern = box.slice(0, length);
28699 Roo.each(pattern, function(i){
28700 format.push(i.size);
28703 Roo.each(standard, function(s){
28705 if(String(s) != String(format)){
28714 if(!match && length == 1){
28719 filterPattern(box, length - 1);
28723 queue.push(pattern);
28725 box = box.slice(length, box.length);
28727 filterPattern(box, 4);
28733 Roo.each(boxes, function(box, k){
28739 if(box.length == 1){
28744 filterPattern(box, 4);
28748 this._processVerticalLayoutQueue( queue, isInstant );
28752 // _verticalAlternativeLayoutItems : function( items , isInstant )
28754 // if ( !items || !items.length ) {
28758 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
28762 _horizontalLayoutItems : function ( items , isInstant)
28764 if ( !items || !items.length || items.length < 3) {
28770 var eItems = items.slice(0, 3);
28772 items = items.slice(3, items.length);
28775 ['xs', 'xs', 'xs', 'wide'],
28776 ['xs', 'xs', 'wide'],
28777 ['xs', 'xs', 'sm'],
28778 ['xs', 'xs', 'xs'],
28784 ['sm', 'xs', 'xs'],
28788 ['wide', 'xs', 'xs', 'xs'],
28789 ['wide', 'xs', 'xs'],
28802 Roo.each(items, function(item, k){
28804 switch (item.size) {
28815 boxes.push([item]);
28839 var filterPattern = function(box, length)
28847 var pattern = box.slice(0, length);
28851 Roo.each(pattern, function(i){
28852 format.push(i.size);
28855 Roo.each(standard, function(s){
28857 if(String(s) != String(format)){
28866 if(!match && length == 1){
28871 filterPattern(box, length - 1);
28875 queue.push(pattern);
28877 box = box.slice(length, box.length);
28879 filterPattern(box, 4);
28885 Roo.each(boxes, function(box, k){
28891 if(box.length == 1){
28896 filterPattern(box, 4);
28903 var pos = this.el.getBox(true);
28907 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
28909 var hit_end = false;
28911 Roo.each(queue, function(box){
28915 Roo.each(box, function(b){
28917 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28927 Roo.each(box, function(b){
28929 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28932 mx = Math.max(mx, b.x);
28936 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
28940 Roo.each(box, function(b){
28942 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28956 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
28959 /** Sets position of item in DOM
28960 * @param {Element} item
28961 * @param {Number} x - horizontal position
28962 * @param {Number} y - vertical position
28963 * @param {Boolean} isInstant - disables transitions
28965 _processVerticalLayoutQueue : function( queue, isInstant )
28967 var pos = this.el.getBox(true);
28972 for (var i = 0; i < this.cols; i++){
28976 Roo.each(queue, function(box, k){
28978 var col = k % this.cols;
28980 Roo.each(box, function(b,kk){
28982 b.el.position('absolute');
28984 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
28985 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
28987 if(b.size == 'md-left' || b.size == 'md-right'){
28988 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
28989 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
28992 b.el.setWidth(width);
28993 b.el.setHeight(height);
28997 for (var i = 0; i < this.cols; i++){
28999 if(maxY[i] < maxY[col]){
29004 col = Math.min(col, i);
29008 x = pos.x + col * (this.colWidth + this.padWidth);
29012 var positions = [];
29014 switch (box.length){
29016 positions = this.getVerticalOneBoxColPositions(x, y, box);
29019 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29022 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29025 positions = this.getVerticalFourBoxColPositions(x, y, box);
29031 Roo.each(box, function(b,kk){
29033 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29035 var sz = b.el.getSize();
29037 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29045 for (var i = 0; i < this.cols; i++){
29046 mY = Math.max(mY, maxY[i]);
29049 this.el.setHeight(mY - pos.y);
29053 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29055 // var pos = this.el.getBox(true);
29058 // var maxX = pos.right;
29060 // var maxHeight = 0;
29062 // Roo.each(items, function(item, k){
29066 // item.el.position('absolute');
29068 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29070 // item.el.setWidth(width);
29072 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29074 // item.el.setHeight(height);
29077 // item.el.setXY([x, y], isInstant ? false : true);
29079 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29082 // y = y + height + this.alternativePadWidth;
29084 // maxHeight = maxHeight + height + this.alternativePadWidth;
29088 // this.el.setHeight(maxHeight);
29092 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29094 var pos = this.el.getBox(true);
29099 var maxX = pos.right;
29101 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29103 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29105 Roo.each(queue, function(box, k){
29107 Roo.each(box, function(b, kk){
29109 b.el.position('absolute');
29111 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29112 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29114 if(b.size == 'md-left' || b.size == 'md-right'){
29115 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29116 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29119 b.el.setWidth(width);
29120 b.el.setHeight(height);
29128 var positions = [];
29130 switch (box.length){
29132 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29135 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29138 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29141 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29147 Roo.each(box, function(b,kk){
29149 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29151 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29159 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29161 Roo.each(eItems, function(b,k){
29163 b.size = (k == 0) ? 'sm' : 'xs';
29164 b.x = (k == 0) ? 2 : 1;
29165 b.y = (k == 0) ? 2 : 1;
29167 b.el.position('absolute');
29169 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29171 b.el.setWidth(width);
29173 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29175 b.el.setHeight(height);
29179 var positions = [];
29182 x : maxX - this.unitWidth * 2 - this.gutter,
29187 x : maxX - this.unitWidth,
29188 y : minY + (this.unitWidth + this.gutter) * 2
29192 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29196 Roo.each(eItems, function(b,k){
29198 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29204 getVerticalOneBoxColPositions : function(x, y, box)
29208 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29210 if(box[0].size == 'md-left'){
29214 if(box[0].size == 'md-right'){
29219 x : x + (this.unitWidth + this.gutter) * rand,
29226 getVerticalTwoBoxColPositions : function(x, y, box)
29230 if(box[0].size == 'xs'){
29234 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
29238 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
29252 x : x + (this.unitWidth + this.gutter) * 2,
29253 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
29260 getVerticalThreeBoxColPositions : function(x, y, box)
29264 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29272 x : x + (this.unitWidth + this.gutter) * 1,
29277 x : x + (this.unitWidth + this.gutter) * 2,
29285 if(box[0].size == 'xs' && box[1].size == 'xs'){
29294 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
29298 x : x + (this.unitWidth + this.gutter) * 1,
29312 x : x + (this.unitWidth + this.gutter) * 2,
29317 x : x + (this.unitWidth + this.gutter) * 2,
29318 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
29325 getVerticalFourBoxColPositions : function(x, y, box)
29329 if(box[0].size == 'xs'){
29338 y : y + (this.unitHeight + this.gutter) * 1
29343 y : y + (this.unitHeight + this.gutter) * 2
29347 x : x + (this.unitWidth + this.gutter) * 1,
29361 x : x + (this.unitWidth + this.gutter) * 2,
29366 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
29367 y : y + (this.unitHeight + this.gutter) * 1
29371 x : x + (this.unitWidth + this.gutter) * 2,
29372 y : y + (this.unitWidth + this.gutter) * 2
29379 getHorizontalOneBoxColPositions : function(maxX, minY, box)
29383 if(box[0].size == 'md-left'){
29385 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29392 if(box[0].size == 'md-right'){
29394 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29395 y : minY + (this.unitWidth + this.gutter) * 1
29401 var rand = Math.floor(Math.random() * (4 - box[0].y));
29404 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29405 y : minY + (this.unitWidth + this.gutter) * rand
29412 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
29416 if(box[0].size == 'xs'){
29419 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29424 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29425 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
29433 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29438 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29439 y : minY + (this.unitWidth + this.gutter) * 2
29446 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
29450 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29453 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29458 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29459 y : minY + (this.unitWidth + this.gutter) * 1
29463 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29464 y : minY + (this.unitWidth + this.gutter) * 2
29471 if(box[0].size == 'xs' && box[1].size == 'xs'){
29474 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29479 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29484 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29485 y : minY + (this.unitWidth + this.gutter) * 1
29493 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29498 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29499 y : minY + (this.unitWidth + this.gutter) * 2
29503 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29504 y : minY + (this.unitWidth + this.gutter) * 2
29511 getHorizontalFourBoxColPositions : function(maxX, minY, box)
29515 if(box[0].size == 'xs'){
29518 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29523 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29528 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),
29533 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
29534 y : minY + (this.unitWidth + this.gutter) * 1
29542 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29547 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29548 y : minY + (this.unitWidth + this.gutter) * 2
29552 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29553 y : minY + (this.unitWidth + this.gutter) * 2
29557 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),
29558 y : minY + (this.unitWidth + this.gutter) * 2
29572 * http://masonry.desandro.com
29574 * The idea is to render all the bricks based on vertical width...
29576 * The original code extends 'outlayer' - we might need to use that....
29582 * @class Roo.bootstrap.LayoutMasonryAuto
29583 * @extends Roo.bootstrap.Component
29584 * Bootstrap Layout Masonry class
29587 * Create a new Element
29588 * @param {Object} config The config object
29591 Roo.bootstrap.LayoutMasonryAuto = function(config){
29592 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
29595 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
29598 * @cfg {Boolean} isFitWidth - resize the width..
29600 isFitWidth : false, // options..
29602 * @cfg {Boolean} isOriginLeft = left align?
29604 isOriginLeft : true,
29606 * @cfg {Boolean} isOriginTop = top align?
29608 isOriginTop : false,
29610 * @cfg {Boolean} isLayoutInstant = no animation?
29612 isLayoutInstant : false, // needed?
29614 * @cfg {Boolean} isResizingContainer = not sure if this is used..
29616 isResizingContainer : true,
29618 * @cfg {Number} columnWidth width of the columns
29623 * @cfg {Number} padHeight padding below box..
29629 * @cfg {Boolean} isAutoInitial defalut true
29632 isAutoInitial : true,
29638 initialColumnWidth : 0,
29639 currentSize : null,
29641 colYs : null, // array.
29648 bricks: null, //CompositeElement
29649 cols : 0, // array?
29650 // element : null, // wrapped now this.el
29651 _isLayoutInited : null,
29654 getAutoCreate : function(){
29658 cls: 'blog-masonary-wrapper ' + this.cls,
29660 cls : 'mas-boxes masonary'
29667 getChildContainer: function( )
29669 if (this.boxesEl) {
29670 return this.boxesEl;
29673 this.boxesEl = this.el.select('.mas-boxes').first();
29675 return this.boxesEl;
29679 initEvents : function()
29683 if(this.isAutoInitial){
29684 Roo.log('hook children rendered');
29685 this.on('childrenrendered', function() {
29686 Roo.log('children rendered');
29693 initial : function()
29695 this.reloadItems();
29697 this.currentSize = this.el.getBox(true);
29699 /// was window resize... - let's see if this works..
29700 Roo.EventManager.onWindowResize(this.resize, this);
29702 if(!this.isAutoInitial){
29707 this.layout.defer(500,this);
29710 reloadItems: function()
29712 this.bricks = this.el.select('.masonry-brick', true);
29714 this.bricks.each(function(b) {
29715 //Roo.log(b.getSize());
29716 if (!b.attr('originalwidth')) {
29717 b.attr('originalwidth', b.getSize().width);
29722 Roo.log(this.bricks.elements.length);
29725 resize : function()
29728 var cs = this.el.getBox(true);
29730 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29731 Roo.log("no change in with or X");
29734 this.currentSize = cs;
29738 layout : function()
29741 this._resetLayout();
29742 //this._manageStamps();
29744 // don't animate first layout
29745 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29746 this.layoutItems( isInstant );
29748 // flag for initalized
29749 this._isLayoutInited = true;
29752 layoutItems : function( isInstant )
29754 //var items = this._getItemsForLayout( this.items );
29755 // original code supports filtering layout items.. we just ignore it..
29757 this._layoutItems( this.bricks , isInstant );
29759 this._postLayout();
29761 _layoutItems : function ( items , isInstant)
29763 //this.fireEvent( 'layout', this, items );
29766 if ( !items || !items.elements.length ) {
29767 // no items, emit event with empty array
29772 items.each(function(item) {
29773 Roo.log("layout item");
29775 // get x/y object from method
29776 var position = this._getItemLayoutPosition( item );
29778 position.item = item;
29779 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
29780 queue.push( position );
29783 this._processLayoutQueue( queue );
29785 /** Sets position of item in DOM
29786 * @param {Element} item
29787 * @param {Number} x - horizontal position
29788 * @param {Number} y - vertical position
29789 * @param {Boolean} isInstant - disables transitions
29791 _processLayoutQueue : function( queue )
29793 for ( var i=0, len = queue.length; i < len; i++ ) {
29794 var obj = queue[i];
29795 obj.item.position('absolute');
29796 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
29802 * Any logic you want to do after each layout,
29803 * i.e. size the container
29805 _postLayout : function()
29807 this.resizeContainer();
29810 resizeContainer : function()
29812 if ( !this.isResizingContainer ) {
29815 var size = this._getContainerSize();
29817 this.el.setSize(size.width,size.height);
29818 this.boxesEl.setSize(size.width,size.height);
29824 _resetLayout : function()
29826 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
29827 this.colWidth = this.el.getWidth();
29828 //this.gutter = this.el.getWidth();
29830 this.measureColumns();
29836 this.colYs.push( 0 );
29842 measureColumns : function()
29844 this.getContainerWidth();
29845 // if columnWidth is 0, default to outerWidth of first item
29846 if ( !this.columnWidth ) {
29847 var firstItem = this.bricks.first();
29848 Roo.log(firstItem);
29849 this.columnWidth = this.containerWidth;
29850 if (firstItem && firstItem.attr('originalwidth') ) {
29851 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
29853 // columnWidth fall back to item of first element
29854 Roo.log("set column width?");
29855 this.initialColumnWidth = this.columnWidth ;
29857 // if first elem has no width, default to size of container
29862 if (this.initialColumnWidth) {
29863 this.columnWidth = this.initialColumnWidth;
29868 // column width is fixed at the top - however if container width get's smaller we should
29871 // this bit calcs how man columns..
29873 var columnWidth = this.columnWidth += this.gutter;
29875 // calculate columns
29876 var containerWidth = this.containerWidth + this.gutter;
29878 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
29879 // fix rounding errors, typically with gutters
29880 var excess = columnWidth - containerWidth % columnWidth;
29883 // if overshoot is less than a pixel, round up, otherwise floor it
29884 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
29885 cols = Math[ mathMethod ]( cols );
29886 this.cols = Math.max( cols, 1 );
29889 // padding positioning..
29890 var totalColWidth = this.cols * this.columnWidth;
29891 var padavail = this.containerWidth - totalColWidth;
29892 // so for 2 columns - we need 3 'pads'
29894 var padNeeded = (1+this.cols) * this.padWidth;
29896 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
29898 this.columnWidth += padExtra
29899 //this.padWidth = Math.floor(padavail / ( this.cols));
29901 // adjust colum width so that padding is fixed??
29903 // we have 3 columns ... total = width * 3
29904 // we have X left over... that should be used by
29906 //if (this.expandC) {
29914 getContainerWidth : function()
29916 /* // container is parent if fit width
29917 var container = this.isFitWidth ? this.element.parentNode : this.element;
29918 // check that this.size and size are there
29919 // IE8 triggers resize on body size change, so they might not be
29921 var size = getSize( container ); //FIXME
29922 this.containerWidth = size && size.innerWidth; //FIXME
29925 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29929 _getItemLayoutPosition : function( item ) // what is item?
29931 // we resize the item to our columnWidth..
29933 item.setWidth(this.columnWidth);
29934 item.autoBoxAdjust = false;
29936 var sz = item.getSize();
29938 // how many columns does this brick span
29939 var remainder = this.containerWidth % this.columnWidth;
29941 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
29942 // round if off by 1 pixel, otherwise use ceil
29943 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
29944 colSpan = Math.min( colSpan, this.cols );
29946 // normally this should be '1' as we dont' currently allow multi width columns..
29948 var colGroup = this._getColGroup( colSpan );
29949 // get the minimum Y value from the columns
29950 var minimumY = Math.min.apply( Math, colGroup );
29951 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
29953 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
29955 // position the brick
29957 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
29958 y: this.currentSize.y + minimumY + this.padHeight
29962 // apply setHeight to necessary columns
29963 var setHeight = minimumY + sz.height + this.padHeight;
29964 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
29966 var setSpan = this.cols + 1 - colGroup.length;
29967 for ( var i = 0; i < setSpan; i++ ) {
29968 this.colYs[ shortColIndex + i ] = setHeight ;
29975 * @param {Number} colSpan - number of columns the element spans
29976 * @returns {Array} colGroup
29978 _getColGroup : function( colSpan )
29980 if ( colSpan < 2 ) {
29981 // if brick spans only one column, use all the column Ys
29986 // how many different places could this brick fit horizontally
29987 var groupCount = this.cols + 1 - colSpan;
29988 // for each group potential horizontal position
29989 for ( var i = 0; i < groupCount; i++ ) {
29990 // make an array of colY values for that one group
29991 var groupColYs = this.colYs.slice( i, i + colSpan );
29992 // and get the max value of the array
29993 colGroup[i] = Math.max.apply( Math, groupColYs );
29998 _manageStamp : function( stamp )
30000 var stampSize = stamp.getSize();
30001 var offset = stamp.getBox();
30002 // get the columns that this stamp affects
30003 var firstX = this.isOriginLeft ? offset.x : offset.right;
30004 var lastX = firstX + stampSize.width;
30005 var firstCol = Math.floor( firstX / this.columnWidth );
30006 firstCol = Math.max( 0, firstCol );
30008 var lastCol = Math.floor( lastX / this.columnWidth );
30009 // lastCol should not go over if multiple of columnWidth #425
30010 lastCol -= lastX % this.columnWidth ? 0 : 1;
30011 lastCol = Math.min( this.cols - 1, lastCol );
30013 // set colYs to bottom of the stamp
30014 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30017 for ( var i = firstCol; i <= lastCol; i++ ) {
30018 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30023 _getContainerSize : function()
30025 this.maxY = Math.max.apply( Math, this.colYs );
30030 if ( this.isFitWidth ) {
30031 size.width = this._getContainerFitWidth();
30037 _getContainerFitWidth : function()
30039 var unusedCols = 0;
30040 // count unused columns
30043 if ( this.colYs[i] !== 0 ) {
30048 // fit container to columns that have been used
30049 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30052 needsResizeLayout : function()
30054 var previousWidth = this.containerWidth;
30055 this.getContainerWidth();
30056 return previousWidth !== this.containerWidth;
30071 * @class Roo.bootstrap.MasonryBrick
30072 * @extends Roo.bootstrap.Component
30073 * Bootstrap MasonryBrick class
30076 * Create a new MasonryBrick
30077 * @param {Object} config The config object
30080 Roo.bootstrap.MasonryBrick = function(config){
30081 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30087 * When a MasonryBrick is clcik
30088 * @param {Roo.bootstrap.MasonryBrick} this
30089 * @param {Roo.EventObject} e
30095 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30098 * @cfg {String} title
30102 * @cfg {String} html
30106 * @cfg {String} bgimage
30110 * @cfg {String} cls
30114 * @cfg {String} href
30118 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30123 * @cfg {String} (center|bottom) placetitle
30127 getAutoCreate : function()
30129 var cls = 'masonry-brick';
30131 if(this.href.length){
30132 cls += ' masonry-brick-link';
30135 if(this.bgimage.length){
30136 cls += ' masonry-brick-image';
30140 cls += ' masonry-' + this.size + '-brick';
30143 if(this.placetitle.length){
30145 switch (this.placetitle) {
30147 cls += ' masonry-center-title';
30150 cls += ' masonry-bottom-title';
30157 if(!this.html.length && !this.bgimage.length){
30158 cls += ' masonry-center-title';
30161 if(!this.html.length && this.bgimage.length){
30162 cls += ' masonry-bottom-title';
30167 cls += ' ' + this.cls;
30171 tag: (this.href.length) ? 'a' : 'div',
30176 cls: 'masonry-brick-paragraph',
30182 if(this.href.length){
30183 cfg.href = this.href;
30186 var cn = cfg.cn[0].cn;
30188 if(this.title.length){
30191 cls: 'masonry-brick-title',
30196 if(this.html.length){
30199 cls: 'masonry-brick-text',
30204 if(this.bgimage.length){
30207 cls: 'masonry-brick-image-view',
30216 initEvents: function()
30218 switch (this.size) {
30220 // this.intSize = 1;
30225 // this.intSize = 2;
30232 // this.intSize = 3;
30237 // this.intSize = 3;
30242 // this.intSize = 3;
30247 // this.intSize = 3;
30259 this.el.on('touchstart', this.onTouchStart, this);
30260 this.el.on('touchmove', this.onTouchMove, this);
30261 this.el.on('touchend', this.onTouchEnd, this);
30263 this.el.on('mouseenter' ,this.enter, this);
30264 this.el.on('mouseleave', this.leave, this);
30267 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
30268 this.parent().bricks.push(this);
30273 onClick: function(e, el)
30281 var time = this.endTimer - this.startTimer;
30289 e.preventDefault();
30292 enter: function(e, el)
30294 e.preventDefault();
30296 if(this.bgimage.length && this.html.length){
30297 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30301 leave: function(e, el)
30303 e.preventDefault();
30305 if(this.bgimage.length && this.html.length){
30306 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30310 onTouchStart: function(e, el)
30312 // e.preventDefault();
30314 if(!this.bgimage.length || !this.html.length){
30318 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30320 this.timer = new Date().getTime();
30322 this.touchmoved = false;
30325 onTouchMove: function(e, el)
30327 this.touchmoved = true;
30330 onTouchEnd: function(e, el)
30332 // e.preventDefault();
30334 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
30338 if(!this.bgimage.length || !this.html.length){
30340 if(this.href.length){
30341 window.location.href = this.href;
30347 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30349 window.location.href = this.href;
30364 * @class Roo.bootstrap.Brick
30365 * @extends Roo.bootstrap.Component
30366 * Bootstrap Brick class
30369 * Create a new Brick
30370 * @param {Object} config The config object
30373 Roo.bootstrap.Brick = function(config){
30374 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
30380 * When a Brick is click
30381 * @param {Roo.bootstrap.Brick} this
30382 * @param {Roo.EventObject} e
30388 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
30391 * @cfg {String} title
30395 * @cfg {String} html
30399 * @cfg {String} bgimage
30403 * @cfg {String} cls
30407 * @cfg {String} href
30411 * @cfg {String} video
30415 * @cfg {Boolean} square
30419 getAutoCreate : function()
30421 var cls = 'roo-brick';
30423 if(this.href.length){
30424 cls += ' roo-brick-link';
30427 if(this.bgimage.length){
30428 cls += ' roo-brick-image';
30431 if(!this.html.length && !this.bgimage.length){
30432 cls += ' roo-brick-center-title';
30435 if(!this.html.length && this.bgimage.length){
30436 cls += ' roo-brick-bottom-title';
30440 cls += ' ' + this.cls;
30444 tag: (this.href.length) ? 'a' : 'div',
30449 cls: 'roo-brick-paragraph',
30455 if(this.href.length){
30456 cfg.href = this.href;
30459 var cn = cfg.cn[0].cn;
30461 if(this.title.length){
30464 cls: 'roo-brick-title',
30469 if(this.html.length){
30472 cls: 'roo-brick-text',
30477 if(this.bgimage.length){
30480 cls: 'roo-brick-image-view',
30488 initEvents: function()
30490 if(this.title.length || this.html.length){
30491 this.el.on('mouseenter' ,this.enter, this);
30492 this.el.on('mouseleave', this.leave, this);
30496 Roo.EventManager.onWindowResize(this.resize, this);
30501 resize : function()
30503 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
30505 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
30506 // paragraph.setHeight(paragraph.getWidth());
30508 if(this.bgimage.length){
30509 var image = this.el.select('.roo-brick-image-view', true).first();
30510 image.setWidth(paragraph.getWidth());
30511 image.setHeight(paragraph.getWidth());
30516 enter: function(e, el)
30518 e.preventDefault();
30520 if(this.bgimage.length){
30521 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
30522 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
30526 leave: function(e, el)
30528 e.preventDefault();
30530 if(this.bgimage.length){
30531 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
30532 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
30542 * Ext JS Library 1.1.1
30543 * Copyright(c) 2006-2007, Ext JS, LLC.
30545 * Originally Released Under LGPL - original licence link has changed is not relivant.
30548 * <script type="text/javascript">
30553 * @class Roo.bootstrap.SplitBar
30554 * @extends Roo.util.Observable
30555 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
30559 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
30560 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
30561 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
30562 split.minSize = 100;
30563 split.maxSize = 600;
30564 split.animate = true;
30565 split.on('moved', splitterMoved);
30568 * Create a new SplitBar
30569 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
30570 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
30571 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30572 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
30573 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
30574 position of the SplitBar).
30576 Roo.bootstrap.SplitBar = function(cfg){
30581 // dragElement : elm
30582 // resizingElement: el,
30584 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
30585 // placement : Roo.bootstrap.SplitBar.LEFT ,
30586 // existingProxy ???
30589 this.el = Roo.get(cfg.dragElement, true);
30590 this.el.dom.unselectable = "on";
30592 this.resizingEl = Roo.get(cfg.resizingElement, true);
30596 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30597 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
30600 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
30603 * The minimum size of the resizing element. (Defaults to 0)
30609 * The maximum size of the resizing element. (Defaults to 2000)
30612 this.maxSize = 2000;
30615 * Whether to animate the transition to the new size
30618 this.animate = false;
30621 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
30624 this.useShim = false;
30629 if(!cfg.existingProxy){
30631 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
30633 this.proxy = Roo.get(cfg.existingProxy).dom;
30636 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
30639 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
30642 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
30645 this.dragSpecs = {};
30648 * @private The adapter to use to positon and resize elements
30650 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30651 this.adapter.init(this);
30653 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30655 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
30656 this.el.addClass("roo-splitbar-h");
30659 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
30660 this.el.addClass("roo-splitbar-v");
30666 * Fires when the splitter is moved (alias for {@link #event-moved})
30667 * @param {Roo.bootstrap.SplitBar} this
30668 * @param {Number} newSize the new width or height
30673 * Fires when the splitter is moved
30674 * @param {Roo.bootstrap.SplitBar} this
30675 * @param {Number} newSize the new width or height
30679 * @event beforeresize
30680 * Fires before the splitter is dragged
30681 * @param {Roo.bootstrap.SplitBar} this
30683 "beforeresize" : true,
30685 "beforeapply" : true
30688 Roo.util.Observable.call(this);
30691 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
30692 onStartProxyDrag : function(x, y){
30693 this.fireEvent("beforeresize", this);
30695 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
30697 o.enableDisplayMode("block");
30698 // all splitbars share the same overlay
30699 Roo.bootstrap.SplitBar.prototype.overlay = o;
30701 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30702 this.overlay.show();
30703 Roo.get(this.proxy).setDisplayed("block");
30704 var size = this.adapter.getElementSize(this);
30705 this.activeMinSize = this.getMinimumSize();;
30706 this.activeMaxSize = this.getMaximumSize();;
30707 var c1 = size - this.activeMinSize;
30708 var c2 = Math.max(this.activeMaxSize - size, 0);
30709 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30710 this.dd.resetConstraints();
30711 this.dd.setXConstraint(
30712 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
30713 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
30715 this.dd.setYConstraint(0, 0);
30717 this.dd.resetConstraints();
30718 this.dd.setXConstraint(0, 0);
30719 this.dd.setYConstraint(
30720 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
30721 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
30724 this.dragSpecs.startSize = size;
30725 this.dragSpecs.startPoint = [x, y];
30726 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
30730 * @private Called after the drag operation by the DDProxy
30732 onEndProxyDrag : function(e){
30733 Roo.get(this.proxy).setDisplayed(false);
30734 var endPoint = Roo.lib.Event.getXY(e);
30736 this.overlay.hide();
30739 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30740 newSize = this.dragSpecs.startSize +
30741 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
30742 endPoint[0] - this.dragSpecs.startPoint[0] :
30743 this.dragSpecs.startPoint[0] - endPoint[0]
30746 newSize = this.dragSpecs.startSize +
30747 (this.placement == Roo.bootstrap.SplitBar.TOP ?
30748 endPoint[1] - this.dragSpecs.startPoint[1] :
30749 this.dragSpecs.startPoint[1] - endPoint[1]
30752 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
30753 if(newSize != this.dragSpecs.startSize){
30754 if(this.fireEvent('beforeapply', this, newSize) !== false){
30755 this.adapter.setElementSize(this, newSize);
30756 this.fireEvent("moved", this, newSize);
30757 this.fireEvent("resize", this, newSize);
30763 * Get the adapter this SplitBar uses
30764 * @return The adapter object
30766 getAdapter : function(){
30767 return this.adapter;
30771 * Set the adapter this SplitBar uses
30772 * @param {Object} adapter A SplitBar adapter object
30774 setAdapter : function(adapter){
30775 this.adapter = adapter;
30776 this.adapter.init(this);
30780 * Gets the minimum size for the resizing element
30781 * @return {Number} The minimum size
30783 getMinimumSize : function(){
30784 return this.minSize;
30788 * Sets the minimum size for the resizing element
30789 * @param {Number} minSize The minimum size
30791 setMinimumSize : function(minSize){
30792 this.minSize = minSize;
30796 * Gets the maximum size for the resizing element
30797 * @return {Number} The maximum size
30799 getMaximumSize : function(){
30800 return this.maxSize;
30804 * Sets the maximum size for the resizing element
30805 * @param {Number} maxSize The maximum size
30807 setMaximumSize : function(maxSize){
30808 this.maxSize = maxSize;
30812 * Sets the initialize size for the resizing element
30813 * @param {Number} size The initial size
30815 setCurrentSize : function(size){
30816 var oldAnimate = this.animate;
30817 this.animate = false;
30818 this.adapter.setElementSize(this, size);
30819 this.animate = oldAnimate;
30823 * Destroy this splitbar.
30824 * @param {Boolean} removeEl True to remove the element
30826 destroy : function(removeEl){
30828 this.shim.remove();
30831 this.proxy.parentNode.removeChild(this.proxy);
30839 * @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.
30841 Roo.bootstrap.SplitBar.createProxy = function(dir){
30842 var proxy = new Roo.Element(document.createElement("div"));
30843 proxy.unselectable();
30844 var cls = 'roo-splitbar-proxy';
30845 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
30846 document.body.appendChild(proxy.dom);
30851 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
30852 * Default Adapter. It assumes the splitter and resizing element are not positioned
30853 * elements and only gets/sets the width of the element. Generally used for table based layouts.
30855 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
30858 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
30859 // do nothing for now
30860 init : function(s){
30864 * Called before drag operations to get the current size of the resizing element.
30865 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30867 getElementSize : function(s){
30868 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30869 return s.resizingEl.getWidth();
30871 return s.resizingEl.getHeight();
30876 * Called after drag operations to set the size of the resizing element.
30877 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30878 * @param {Number} newSize The new size to set
30879 * @param {Function} onComplete A function to be invoked when resizing is complete
30881 setElementSize : function(s, newSize, onComplete){
30882 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30884 s.resizingEl.setWidth(newSize);
30886 onComplete(s, newSize);
30889 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
30894 s.resizingEl.setHeight(newSize);
30896 onComplete(s, newSize);
30899 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
30906 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
30907 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
30908 * Adapter that moves the splitter element to align with the resized sizing element.
30909 * Used with an absolute positioned SplitBar.
30910 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
30911 * document.body, make sure you assign an id to the body element.
30913 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
30914 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30915 this.container = Roo.get(container);
30918 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
30919 init : function(s){
30920 this.basic.init(s);
30923 getElementSize : function(s){
30924 return this.basic.getElementSize(s);
30927 setElementSize : function(s, newSize, onComplete){
30928 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
30931 moveSplitter : function(s){
30932 var yes = Roo.bootstrap.SplitBar;
30933 switch(s.placement){
30935 s.el.setX(s.resizingEl.getRight());
30938 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
30941 s.el.setY(s.resizingEl.getBottom());
30944 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
30951 * Orientation constant - Create a vertical SplitBar
30955 Roo.bootstrap.SplitBar.VERTICAL = 1;
30958 * Orientation constant - Create a horizontal SplitBar
30962 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
30965 * Placement constant - The resizing element is to the left of the splitter element
30969 Roo.bootstrap.SplitBar.LEFT = 1;
30972 * Placement constant - The resizing element is to the right of the splitter element
30976 Roo.bootstrap.SplitBar.RIGHT = 2;
30979 * Placement constant - The resizing element is positioned above the splitter element
30983 Roo.bootstrap.SplitBar.TOP = 3;
30986 * Placement constant - The resizing element is positioned under splitter element
30990 Roo.bootstrap.SplitBar.BOTTOM = 4;
30991 Roo.namespace("Roo.bootstrap.layout");/*
30993 * Ext JS Library 1.1.1
30994 * Copyright(c) 2006-2007, Ext JS, LLC.
30996 * Originally Released Under LGPL - original licence link has changed is not relivant.
30999 * <script type="text/javascript">
31003 * @class Roo.bootstrap.layout.Manager
31004 * @extends Roo.bootstrap.Component
31005 * Base class for layout managers.
31007 Roo.bootstrap.layout.Manager = function(config)
31009 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
31010 this.el = Roo.get(config.el);
31011 // ie scrollbar fix
31012 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31013 document.body.scroll = "no";
31014 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31015 this.el.position('relative');
31018 this.id = this.el.id;
31019 this.el.addClass("roo-layout-container");
31020 /** false to disable window resize monitoring @type Boolean */
31021 this.monitorWindowResize = true;
31026 * Fires when a layout is performed.
31027 * @param {Roo.LayoutManager} this
31031 * @event regionresized
31032 * Fires when the user resizes a region.
31033 * @param {Roo.LayoutRegion} region The resized region
31034 * @param {Number} newSize The new size (width for east/west, height for north/south)
31036 "regionresized" : true,
31038 * @event regioncollapsed
31039 * Fires when a region is collapsed.
31040 * @param {Roo.LayoutRegion} region The collapsed region
31042 "regioncollapsed" : true,
31044 * @event regionexpanded
31045 * Fires when a region is expanded.
31046 * @param {Roo.LayoutRegion} region The expanded region
31048 "regionexpanded" : true
31050 this.updating = false;
31051 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31054 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31059 monitorWindowResize : true,
31065 * Returns true if this layout is currently being updated
31066 * @return {Boolean}
31068 isUpdating : function(){
31069 return this.updating;
31073 * Suspend the LayoutManager from doing auto-layouts while
31074 * making multiple add or remove calls
31076 beginUpdate : function(){
31077 this.updating = true;
31081 * Restore auto-layouts and optionally disable the manager from performing a layout
31082 * @param {Boolean} noLayout true to disable a layout update
31084 endUpdate : function(noLayout){
31085 this.updating = false;
31091 layout: function(){
31095 onRegionResized : function(region, newSize){
31096 this.fireEvent("regionresized", region, newSize);
31100 onRegionCollapsed : function(region){
31101 this.fireEvent("regioncollapsed", region);
31104 onRegionExpanded : function(region){
31105 this.fireEvent("regionexpanded", region);
31109 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31110 * performs box-model adjustments.
31111 * @return {Object} The size as an object {width: (the width), height: (the height)}
31113 getViewSize : function()
31116 if(this.el.dom != document.body){
31117 size = this.el.getSize();
31119 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31121 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31122 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31127 * Returns the Element this layout is bound to.
31128 * @return {Roo.Element}
31130 getEl : function(){
31135 * Returns the specified region.
31136 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31137 * @return {Roo.LayoutRegion}
31139 getRegion : function(target){
31140 return this.regions[target.toLowerCase()];
31143 onWindowResize : function(){
31144 if(this.monitorWindowResize){
31150 * Ext JS Library 1.1.1
31151 * Copyright(c) 2006-2007, Ext JS, LLC.
31153 * Originally Released Under LGPL - original licence link has changed is not relivant.
31156 * <script type="text/javascript">
31159 * @class Roo.bootstrap.layout.Border
31160 * @extends Roo.bootstrap.layout.Manager
31161 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
31162 * please see: examples/bootstrap/nested.html<br><br>
31164 <b>The container the layout is rendered into can be either the body element or any other element.
31165 If it is not the body element, the container needs to either be an absolute positioned element,
31166 or you will need to add "position:relative" to the css of the container. You will also need to specify
31167 the container size if it is not the body element.</b>
31170 * Create a new Border
31171 * @param {Object} config Configuration options
31173 Roo.bootstrap.layout.Border = function(config){
31174 config = config || {};
31175 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
31179 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
31180 if(config[region]){
31181 config[region].region = region;
31182 this.addRegion(config[region]);
31188 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
31190 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
31192 * Creates and adds a new region if it doesn't already exist.
31193 * @param {String} target The target region key (north, south, east, west or center).
31194 * @param {Object} config The regions config object
31195 * @return {BorderLayoutRegion} The new region
31197 addRegion : function(config)
31199 if(!this.regions[config.region]){
31200 var r = this.factory(config);
31201 this.bindRegion(r);
31203 return this.regions[config.region];
31207 bindRegion : function(r){
31208 this.regions[r.config.region] = r;
31210 r.on("visibilitychange", this.layout, this);
31211 r.on("paneladded", this.layout, this);
31212 r.on("panelremoved", this.layout, this);
31213 r.on("invalidated", this.layout, this);
31214 r.on("resized", this.onRegionResized, this);
31215 r.on("collapsed", this.onRegionCollapsed, this);
31216 r.on("expanded", this.onRegionExpanded, this);
31220 * Performs a layout update.
31222 layout : function()
31224 if(this.updating) {
31227 var size = this.getViewSize();
31228 var w = size.width;
31229 var h = size.height;
31234 //var x = 0, y = 0;
31236 var rs = this.regions;
31237 var north = rs["north"];
31238 var south = rs["south"];
31239 var west = rs["west"];
31240 var east = rs["east"];
31241 var center = rs["center"];
31242 //if(this.hideOnLayout){ // not supported anymore
31243 //c.el.setStyle("display", "none");
31245 if(north && north.isVisible()){
31246 var b = north.getBox();
31247 var m = north.getMargins();
31248 b.width = w - (m.left+m.right);
31251 centerY = b.height + b.y + m.bottom;
31252 centerH -= centerY;
31253 north.updateBox(this.safeBox(b));
31255 if(south && south.isVisible()){
31256 var b = south.getBox();
31257 var m = south.getMargins();
31258 b.width = w - (m.left+m.right);
31260 var totalHeight = (b.height + m.top + m.bottom);
31261 b.y = h - totalHeight + m.top;
31262 centerH -= totalHeight;
31263 south.updateBox(this.safeBox(b));
31265 if(west && west.isVisible()){
31266 var b = west.getBox();
31267 var m = west.getMargins();
31268 b.height = centerH - (m.top+m.bottom);
31270 b.y = centerY + m.top;
31271 var totalWidth = (b.width + m.left + m.right);
31272 centerX += totalWidth;
31273 centerW -= totalWidth;
31274 west.updateBox(this.safeBox(b));
31276 if(east && east.isVisible()){
31277 var b = east.getBox();
31278 var m = east.getMargins();
31279 b.height = centerH - (m.top+m.bottom);
31280 var totalWidth = (b.width + m.left + m.right);
31281 b.x = w - totalWidth + m.left;
31282 b.y = centerY + m.top;
31283 centerW -= totalWidth;
31284 east.updateBox(this.safeBox(b));
31287 var m = center.getMargins();
31289 x: centerX + m.left,
31290 y: centerY + m.top,
31291 width: centerW - (m.left+m.right),
31292 height: centerH - (m.top+m.bottom)
31294 //if(this.hideOnLayout){
31295 //center.el.setStyle("display", "block");
31297 center.updateBox(this.safeBox(centerBox));
31300 this.fireEvent("layout", this);
31304 safeBox : function(box){
31305 box.width = Math.max(0, box.width);
31306 box.height = Math.max(0, box.height);
31311 * Adds a ContentPanel (or subclass) to this layout.
31312 * @param {String} target The target region key (north, south, east, west or center).
31313 * @param {Roo.ContentPanel} panel The panel to add
31314 * @return {Roo.ContentPanel} The added panel
31316 add : function(target, panel){
31318 target = target.toLowerCase();
31319 return this.regions[target].add(panel);
31323 * Remove a ContentPanel (or subclass) to this layout.
31324 * @param {String} target The target region key (north, south, east, west or center).
31325 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
31326 * @return {Roo.ContentPanel} The removed panel
31328 remove : function(target, panel){
31329 target = target.toLowerCase();
31330 return this.regions[target].remove(panel);
31334 * Searches all regions for a panel with the specified id
31335 * @param {String} panelId
31336 * @return {Roo.ContentPanel} The panel or null if it wasn't found
31338 findPanel : function(panelId){
31339 var rs = this.regions;
31340 for(var target in rs){
31341 if(typeof rs[target] != "function"){
31342 var p = rs[target].getPanel(panelId);
31352 * Searches all regions for a panel with the specified id and activates (shows) it.
31353 * @param {String/ContentPanel} panelId The panels id or the panel itself
31354 * @return {Roo.ContentPanel} The shown panel or null
31356 showPanel : function(panelId) {
31357 var rs = this.regions;
31358 for(var target in rs){
31359 var r = rs[target];
31360 if(typeof r != "function"){
31361 if(r.hasPanel(panelId)){
31362 return r.showPanel(panelId);
31370 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
31371 * @param {Roo.state.Provider} provider (optional) An alternate state provider
31374 restoreState : function(provider){
31376 provider = Roo.state.Manager;
31378 var sm = new Roo.LayoutStateManager();
31379 sm.init(this, provider);
31385 * Adds a xtype elements to the layout.
31389 xtype : 'ContentPanel',
31396 xtype : 'NestedLayoutPanel',
31402 items : [ ... list of content panels or nested layout panels.. ]
31406 * @param {Object} cfg Xtype definition of item to add.
31408 addxtype : function(cfg)
31410 // basically accepts a pannel...
31411 // can accept a layout region..!?!?
31412 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
31415 // theory? children can only be panels??
31417 //if (!cfg.xtype.match(/Panel$/)) {
31422 if (typeof(cfg.region) == 'undefined') {
31423 Roo.log("Failed to add Panel, region was not set");
31427 var region = cfg.region;
31433 xitems = cfg.items;
31440 case 'Content': // ContentPanel (el, cfg)
31441 case 'Scroll': // ContentPanel (el, cfg)
31443 cfg.autoCreate = true;
31444 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31446 // var el = this.el.createChild();
31447 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
31450 this.add(region, ret);
31454 case 'TreePanel': // our new panel!
31455 cfg.el = this.el.createChild();
31456 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31457 this.add(region, ret);
31462 // create a new Layout (which is a Border Layout...
31464 var clayout = cfg.layout;
31465 clayout.el = this.el.createChild();
31466 clayout.items = clayout.items || [];
31470 // replace this exitems with the clayout ones..
31471 xitems = clayout.items;
31473 // force background off if it's in center...
31474 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
31475 cfg.background = false;
31477 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
31480 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31481 //console.log('adding nested layout panel ' + cfg.toSource());
31482 this.add(region, ret);
31483 nb = {}; /// find first...
31488 // needs grid and region
31490 //var el = this.getRegion(region).el.createChild();
31491 var el = this.el.createChild();
31492 // create the grid first...
31493 cfg.grid.container = el;
31494 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
31497 if (region == 'center' && this.active ) {
31498 cfg.background = false;
31501 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31503 this.add(region, ret);
31505 if (cfg.background) {
31506 // render grid on panel activation (if panel background)
31507 ret.on('activate', function(gp) {
31508 if (!gp.grid.rendered) {
31509 gp.grid.render(gp.grid.getGridEl());
31513 cfg.grid.render(cfg.grid.getGridEl());
31518 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
31519 // it was the old xcomponent building that caused this before.
31520 // espeically if border is the top element in the tree.
31530 if (typeof(Roo[cfg.xtype]) != 'undefined') {
31532 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31533 this.add(region, ret);
31537 throw "Can not add '" + cfg.xtype + "' to Border";
31543 this.beginUpdate();
31547 Roo.each(xitems, function(i) {
31548 region = nb && i.region ? i.region : false;
31550 var add = ret.addxtype(i);
31553 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
31554 if (!i.background) {
31555 abn[region] = nb[region] ;
31562 // make the last non-background panel active..
31563 //if (nb) { Roo.log(abn); }
31566 for(var r in abn) {
31567 region = this.getRegion(r);
31569 // tried using nb[r], but it does not work..
31571 region.showPanel(abn[r]);
31582 factory : function(cfg)
31585 var validRegions = Roo.bootstrap.layout.Border.regions;
31587 var target = cfg.region;
31590 var r = Roo.bootstrap.layout;
31594 return new r.North(cfg);
31596 return new r.South(cfg);
31598 return new r.East(cfg);
31600 return new r.West(cfg);
31602 return new r.Center(cfg);
31604 throw 'Layout region "'+target+'" not supported.';
31611 * Ext JS Library 1.1.1
31612 * Copyright(c) 2006-2007, Ext JS, LLC.
31614 * Originally Released Under LGPL - original licence link has changed is not relivant.
31617 * <script type="text/javascript">
31621 * @class Roo.bootstrap.layout.Basic
31622 * @extends Roo.util.Observable
31623 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
31624 * and does not have a titlebar, tabs or any other features. All it does is size and position
31625 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
31626 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31627 * @cfg {string} region the region that it inhabits..
31628 * @cfg {bool} skipConfig skip config?
31632 Roo.bootstrap.layout.Basic = function(config){
31634 this.mgr = config.mgr;
31636 this.position = config.region;
31638 var skipConfig = config.skipConfig;
31642 * @scope Roo.BasicLayoutRegion
31646 * @event beforeremove
31647 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
31648 * @param {Roo.LayoutRegion} this
31649 * @param {Roo.ContentPanel} panel The panel
31650 * @param {Object} e The cancel event object
31652 "beforeremove" : true,
31654 * @event invalidated
31655 * Fires when the layout for this region is changed.
31656 * @param {Roo.LayoutRegion} this
31658 "invalidated" : true,
31660 * @event visibilitychange
31661 * Fires when this region is shown or hidden
31662 * @param {Roo.LayoutRegion} this
31663 * @param {Boolean} visibility true or false
31665 "visibilitychange" : true,
31667 * @event paneladded
31668 * Fires when a panel is added.
31669 * @param {Roo.LayoutRegion} this
31670 * @param {Roo.ContentPanel} panel The panel
31672 "paneladded" : true,
31674 * @event panelremoved
31675 * Fires when a panel is removed.
31676 * @param {Roo.LayoutRegion} this
31677 * @param {Roo.ContentPanel} panel The panel
31679 "panelremoved" : true,
31681 * @event beforecollapse
31682 * Fires when this region before collapse.
31683 * @param {Roo.LayoutRegion} this
31685 "beforecollapse" : true,
31688 * Fires when this region is collapsed.
31689 * @param {Roo.LayoutRegion} this
31691 "collapsed" : true,
31694 * Fires when this region is expanded.
31695 * @param {Roo.LayoutRegion} this
31700 * Fires when this region is slid into view.
31701 * @param {Roo.LayoutRegion} this
31703 "slideshow" : true,
31706 * Fires when this region slides out of view.
31707 * @param {Roo.LayoutRegion} this
31709 "slidehide" : true,
31711 * @event panelactivated
31712 * Fires when a panel is activated.
31713 * @param {Roo.LayoutRegion} this
31714 * @param {Roo.ContentPanel} panel The activated panel
31716 "panelactivated" : true,
31719 * Fires when the user resizes this region.
31720 * @param {Roo.LayoutRegion} this
31721 * @param {Number} newSize The new size (width for east/west, height for north/south)
31725 /** A collection of panels in this region. @type Roo.util.MixedCollection */
31726 this.panels = new Roo.util.MixedCollection();
31727 this.panels.getKey = this.getPanelId.createDelegate(this);
31729 this.activePanel = null;
31730 // ensure listeners are added...
31732 if (config.listeners || config.events) {
31733 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
31734 listeners : config.listeners || {},
31735 events : config.events || {}
31739 if(skipConfig !== true){
31740 this.applyConfig(config);
31744 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
31746 getPanelId : function(p){
31750 applyConfig : function(config){
31751 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
31752 this.config = config;
31757 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
31758 * the width, for horizontal (north, south) the height.
31759 * @param {Number} newSize The new width or height
31761 resizeTo : function(newSize){
31762 var el = this.el ? this.el :
31763 (this.activePanel ? this.activePanel.getEl() : null);
31765 switch(this.position){
31768 el.setWidth(newSize);
31769 this.fireEvent("resized", this, newSize);
31773 el.setHeight(newSize);
31774 this.fireEvent("resized", this, newSize);
31780 getBox : function(){
31781 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
31784 getMargins : function(){
31785 return this.margins;
31788 updateBox : function(box){
31790 var el = this.activePanel.getEl();
31791 el.dom.style.left = box.x + "px";
31792 el.dom.style.top = box.y + "px";
31793 this.activePanel.setSize(box.width, box.height);
31797 * Returns the container element for this region.
31798 * @return {Roo.Element}
31800 getEl : function(){
31801 return this.activePanel;
31805 * Returns true if this region is currently visible.
31806 * @return {Boolean}
31808 isVisible : function(){
31809 return this.activePanel ? true : false;
31812 setActivePanel : function(panel){
31813 panel = this.getPanel(panel);
31814 if(this.activePanel && this.activePanel != panel){
31815 this.activePanel.setActiveState(false);
31816 this.activePanel.getEl().setLeftTop(-10000,-10000);
31818 this.activePanel = panel;
31819 panel.setActiveState(true);
31821 panel.setSize(this.box.width, this.box.height);
31823 this.fireEvent("panelactivated", this, panel);
31824 this.fireEvent("invalidated");
31828 * Show the specified panel.
31829 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
31830 * @return {Roo.ContentPanel} The shown panel or null
31832 showPanel : function(panel){
31833 panel = this.getPanel(panel);
31835 this.setActivePanel(panel);
31841 * Get the active panel for this region.
31842 * @return {Roo.ContentPanel} The active panel or null
31844 getActivePanel : function(){
31845 return this.activePanel;
31849 * Add the passed ContentPanel(s)
31850 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
31851 * @return {Roo.ContentPanel} The panel added (if only one was added)
31853 add : function(panel){
31854 if(arguments.length > 1){
31855 for(var i = 0, len = arguments.length; i < len; i++) {
31856 this.add(arguments[i]);
31860 if(this.hasPanel(panel)){
31861 this.showPanel(panel);
31864 var el = panel.getEl();
31865 if(el.dom.parentNode != this.mgr.el.dom){
31866 this.mgr.el.dom.appendChild(el.dom);
31868 if(panel.setRegion){
31869 panel.setRegion(this);
31871 this.panels.add(panel);
31872 el.setStyle("position", "absolute");
31873 if(!panel.background){
31874 this.setActivePanel(panel);
31875 if(this.config.initialSize && this.panels.getCount()==1){
31876 this.resizeTo(this.config.initialSize);
31879 this.fireEvent("paneladded", this, panel);
31884 * Returns true if the panel is in this region.
31885 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31886 * @return {Boolean}
31888 hasPanel : function(panel){
31889 if(typeof panel == "object"){ // must be panel obj
31890 panel = panel.getId();
31892 return this.getPanel(panel) ? true : false;
31896 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
31897 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31898 * @param {Boolean} preservePanel Overrides the config preservePanel option
31899 * @return {Roo.ContentPanel} The panel that was removed
31901 remove : function(panel, preservePanel){
31902 panel = this.getPanel(panel);
31907 this.fireEvent("beforeremove", this, panel, e);
31908 if(e.cancel === true){
31911 var panelId = panel.getId();
31912 this.panels.removeKey(panelId);
31917 * Returns the panel specified or null if it's not in this region.
31918 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31919 * @return {Roo.ContentPanel}
31921 getPanel : function(id){
31922 if(typeof id == "object"){ // must be panel obj
31925 return this.panels.get(id);
31929 * Returns this regions position (north/south/east/west/center).
31932 getPosition: function(){
31933 return this.position;
31937 * Ext JS Library 1.1.1
31938 * Copyright(c) 2006-2007, Ext JS, LLC.
31940 * Originally Released Under LGPL - original licence link has changed is not relivant.
31943 * <script type="text/javascript">
31947 * @class Roo.bootstrap.layout.Region
31948 * @extends Roo.bootstrap.layout.Basic
31949 * This class represents a region in a layout manager.
31951 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
31952 * @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})
31953 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
31954 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
31955 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
31956 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
31957 * @cfg {String} title The title for the region (overrides panel titles)
31958 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
31959 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
31960 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
31961 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
31962 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
31963 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
31964 * the space available, similar to FireFox 1.5 tabs (defaults to false)
31965 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
31966 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
31967 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
31969 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
31970 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
31971 * @cfg {Boolean} disableTabTips True to disable tab tooltips
31972 * @cfg {Number} width For East/West panels
31973 * @cfg {Number} height For North/South panels
31974 * @cfg {Boolean} split To show the splitter
31975 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
31977 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31978 * @cfg {string} region the region that it inhabits..
31981 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
31982 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
31984 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
31985 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
31986 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
31988 Roo.bootstrap.layout.Region = function(config)
31991 var mgr = config.mgr;
31992 var pos = config.region;
31993 config.skipConfig = true;
31994 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
31995 var dh = Roo.DomHelper;
31996 /** This region's container element
31997 * @type Roo.Element */
31998 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "roo-layout-region roo-layout-panel roo-layout-panel-" + this.position}, true);
31999 /** This region's title element
32000 * @type Roo.Element */
32002 this.titleEl = dh.append(this.el.dom,
32005 unselectable: "on",
32006 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32008 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32009 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32012 this.titleEl.enableDisplayMode();
32013 /** This region's title text element
32014 * @type HTMLElement */
32015 this.titleTextEl = this.titleEl.dom.firstChild;
32016 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32018 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32019 this.closeBtn.enableDisplayMode();
32020 this.closeBtn.on("click", this.closeClicked, this);
32021 this.closeBtn.hide();
32023 this.createBody(config);
32024 this.visible = true;
32025 this.collapsed = false;
32027 if(config.hideWhenEmpty){
32029 this.on("paneladded", this.validateVisibility, this);
32030 this.on("panelremoved", this.validateVisibility, this);
32032 this.applyConfig(config);
32035 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32039 createBody : function(){
32040 /** This region's body element
32041 * @type Roo.Element */
32042 this.bodyEl = this.el.createChild({
32044 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32048 applyConfig : function(c)
32051 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32052 var dh = Roo.DomHelper;
32053 if(c.titlebar !== false){
32054 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32055 this.collapseBtn.on("click", this.collapse, this);
32056 this.collapseBtn.enableDisplayMode();
32058 if(c.showPin === true || this.showPin){
32059 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32060 this.stickBtn.enableDisplayMode();
32061 this.stickBtn.on("click", this.expand, this);
32062 this.stickBtn.hide();
32067 /** This region's collapsed element
32068 * @type Roo.Element */
32071 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32072 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32075 if(c.floatable !== false){
32076 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32077 this.collapsedEl.on("click", this.collapseClick, this);
32080 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32081 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32082 id: "message", unselectable: "on", style:{"float":"left"}});
32083 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32085 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32086 this.expandBtn.on("click", this.expand, this);
32090 if(this.collapseBtn){
32091 this.collapseBtn.setVisible(c.collapsible == true);
32094 this.cmargins = c.cmargins || this.cmargins ||
32095 (this.position == "west" || this.position == "east" ?
32096 {top: 0, left: 2, right:2, bottom: 0} :
32097 {top: 2, left: 0, right:0, bottom: 2});
32099 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32102 this.bottomTabs = c.tabPosition != "top";
32104 this.autoScroll = c.autoScroll || false;
32107 if(this.autoScroll){
32108 this.bodyEl.setStyle("overflow", "auto");
32110 this.bodyEl.setStyle("overflow", c.overflow || 'hidden');
32112 //if(c.titlebar !== false){
32113 if((!c.titlebar && !c.title) || c.titlebar === false){
32114 this.titleEl.hide();
32116 this.titleEl.show();
32118 this.titleTextEl.innerHTML = c.title;
32122 this.duration = c.duration || .30;
32123 this.slideDuration = c.slideDuration || .45;
32126 this.collapse(true);
32133 * Returns true if this region is currently visible.
32134 * @return {Boolean}
32136 isVisible : function(){
32137 return this.visible;
32141 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
32142 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
32144 //setCollapsedTitle : function(title){
32145 // title = title || " ";
32146 // if(this.collapsedTitleTextEl){
32147 // this.collapsedTitleTextEl.innerHTML = title;
32151 getBox : function(){
32153 // if(!this.collapsed){
32154 b = this.el.getBox(false, true);
32156 // b = this.collapsedEl.getBox(false, true);
32161 getMargins : function(){
32162 return this.margins;
32163 //return this.collapsed ? this.cmargins : this.margins;
32166 highlight : function(){
32167 this.el.addClass("x-layout-panel-dragover");
32170 unhighlight : function(){
32171 this.el.removeClass("x-layout-panel-dragover");
32174 updateBox : function(box)
32177 if(!this.collapsed){
32178 this.el.dom.style.left = box.x + "px";
32179 this.el.dom.style.top = box.y + "px";
32180 this.updateBody(box.width, box.height);
32182 this.collapsedEl.dom.style.left = box.x + "px";
32183 this.collapsedEl.dom.style.top = box.y + "px";
32184 this.collapsedEl.setSize(box.width, box.height);
32187 this.tabs.autoSizeTabs();
32191 updateBody : function(w, h)
32194 this.el.setWidth(w);
32195 w -= this.el.getBorderWidth("rl");
32196 if(this.config.adjustments){
32197 w += this.config.adjustments[0];
32201 this.el.setHeight(h);
32202 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
32203 h -= this.el.getBorderWidth("tb");
32204 if(this.config.adjustments){
32205 h += this.config.adjustments[1];
32207 this.bodyEl.setHeight(h);
32209 h = this.tabs.syncHeight(h);
32212 if(this.panelSize){
32213 w = w !== null ? w : this.panelSize.width;
32214 h = h !== null ? h : this.panelSize.height;
32216 if(this.activePanel){
32217 var el = this.activePanel.getEl();
32218 w = w !== null ? w : el.getWidth();
32219 h = h !== null ? h : el.getHeight();
32220 this.panelSize = {width: w, height: h};
32221 this.activePanel.setSize(w, h);
32223 if(Roo.isIE && this.tabs){
32224 this.tabs.el.repaint();
32229 * Returns the container element for this region.
32230 * @return {Roo.Element}
32232 getEl : function(){
32237 * Hides this region.
32240 //if(!this.collapsed){
32241 this.el.dom.style.left = "-2000px";
32244 // this.collapsedEl.dom.style.left = "-2000px";
32245 // this.collapsedEl.hide();
32247 this.visible = false;
32248 this.fireEvent("visibilitychange", this, false);
32252 * Shows this region if it was previously hidden.
32255 //if(!this.collapsed){
32258 // this.collapsedEl.show();
32260 this.visible = true;
32261 this.fireEvent("visibilitychange", this, true);
32264 closeClicked : function(){
32265 if(this.activePanel){
32266 this.remove(this.activePanel);
32270 collapseClick : function(e){
32272 e.stopPropagation();
32275 e.stopPropagation();
32281 * Collapses this region.
32282 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
32285 collapse : function(skipAnim, skipCheck = false){
32286 if(this.collapsed) {
32290 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
32292 this.collapsed = true;
32294 this.split.el.hide();
32296 if(this.config.animate && skipAnim !== true){
32297 this.fireEvent("invalidated", this);
32298 this.animateCollapse();
32300 this.el.setLocation(-20000,-20000);
32302 this.collapsedEl.show();
32303 this.fireEvent("collapsed", this);
32304 this.fireEvent("invalidated", this);
32310 animateCollapse : function(){
32315 * Expands this region if it was previously collapsed.
32316 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
32317 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
32320 expand : function(e, skipAnim){
32322 e.stopPropagation();
32324 if(!this.collapsed || this.el.hasActiveFx()) {
32328 this.afterSlideIn();
32331 this.collapsed = false;
32332 if(this.config.animate && skipAnim !== true){
32333 this.animateExpand();
32337 this.split.el.show();
32339 this.collapsedEl.setLocation(-2000,-2000);
32340 this.collapsedEl.hide();
32341 this.fireEvent("invalidated", this);
32342 this.fireEvent("expanded", this);
32346 animateExpand : function(){
32350 initTabs : function()
32352 this.bodyEl.setStyle("overflow", "hidden");
32353 var ts = new Roo.bootstrap.panel.Tabs({
32354 el: this.bodyEl.dom,
32355 tabPosition: this.bottomTabs ? 'bottom' : 'top',
32356 disableTooltips: this.config.disableTabTips,
32357 toolbar : this.config.toolbar
32360 if(this.config.hideTabs){
32361 ts.stripWrap.setDisplayed(false);
32364 ts.resizeTabs = this.config.resizeTabs === true;
32365 ts.minTabWidth = this.config.minTabWidth || 40;
32366 ts.maxTabWidth = this.config.maxTabWidth || 250;
32367 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
32368 ts.monitorResize = false;
32369 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32370 ts.bodyEl.addClass('roo-layout-tabs-body');
32371 this.panels.each(this.initPanelAsTab, this);
32374 initPanelAsTab : function(panel){
32375 var ti = this.tabs.addTab(
32377 panel.getTitle(), null,
32378 this.config.closeOnTab && panel.isClosable()
32380 if(panel.tabTip !== undefined){
32381 ti.setTooltip(panel.tabTip);
32383 ti.on("activate", function(){
32384 this.setActivePanel(panel);
32387 if(this.config.closeOnTab){
32388 ti.on("beforeclose", function(t, e){
32390 this.remove(panel);
32396 updatePanelTitle : function(panel, title)
32398 if(this.activePanel == panel){
32399 this.updateTitle(title);
32402 var ti = this.tabs.getTab(panel.getEl().id);
32404 if(panel.tabTip !== undefined){
32405 ti.setTooltip(panel.tabTip);
32410 updateTitle : function(title){
32411 if(this.titleTextEl && !this.config.title){
32412 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
32416 setActivePanel : function(panel)
32418 panel = this.getPanel(panel);
32419 if(this.activePanel && this.activePanel != panel){
32420 this.activePanel.setActiveState(false);
32422 this.activePanel = panel;
32423 panel.setActiveState(true);
32424 if(this.panelSize){
32425 panel.setSize(this.panelSize.width, this.panelSize.height);
32428 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
32430 this.updateTitle(panel.getTitle());
32432 this.fireEvent("invalidated", this);
32434 this.fireEvent("panelactivated", this, panel);
32438 * Shows the specified panel.
32439 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
32440 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
32442 showPanel : function(panel)
32444 panel = this.getPanel(panel);
32447 var tab = this.tabs.getTab(panel.getEl().id);
32448 if(tab.isHidden()){
32449 this.tabs.unhideTab(tab.id);
32453 this.setActivePanel(panel);
32460 * Get the active panel for this region.
32461 * @return {Roo.ContentPanel} The active panel or null
32463 getActivePanel : function(){
32464 return this.activePanel;
32467 validateVisibility : function(){
32468 if(this.panels.getCount() < 1){
32469 this.updateTitle(" ");
32470 this.closeBtn.hide();
32473 if(!this.isVisible()){
32480 * Adds the passed ContentPanel(s) to this region.
32481 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32482 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
32484 add : function(panel){
32485 if(arguments.length > 1){
32486 for(var i = 0, len = arguments.length; i < len; i++) {
32487 this.add(arguments[i]);
32491 if(this.hasPanel(panel)){
32492 this.showPanel(panel);
32495 panel.setRegion(this);
32496 this.panels.add(panel);
32497 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
32498 this.bodyEl.dom.appendChild(panel.getEl().dom);
32499 if(panel.background !== true){
32500 this.setActivePanel(panel);
32502 this.fireEvent("paneladded", this, panel);
32508 this.initPanelAsTab(panel);
32512 if(panel.background !== true){
32513 this.tabs.activate(panel.getEl().id);
32515 this.fireEvent("paneladded", this, panel);
32520 * Hides the tab for the specified panel.
32521 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32523 hidePanel : function(panel){
32524 if(this.tabs && (panel = this.getPanel(panel))){
32525 this.tabs.hideTab(panel.getEl().id);
32530 * Unhides the tab for a previously hidden panel.
32531 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32533 unhidePanel : function(panel){
32534 if(this.tabs && (panel = this.getPanel(panel))){
32535 this.tabs.unhideTab(panel.getEl().id);
32539 clearPanels : function(){
32540 while(this.panels.getCount() > 0){
32541 this.remove(this.panels.first());
32546 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32547 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32548 * @param {Boolean} preservePanel Overrides the config preservePanel option
32549 * @return {Roo.ContentPanel} The panel that was removed
32551 remove : function(panel, preservePanel)
32553 panel = this.getPanel(panel);
32558 this.fireEvent("beforeremove", this, panel, e);
32559 if(e.cancel === true){
32562 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
32563 var panelId = panel.getId();
32564 this.panels.removeKey(panelId);
32566 document.body.appendChild(panel.getEl().dom);
32569 this.tabs.removeTab(panel.getEl().id);
32570 }else if (!preservePanel){
32571 this.bodyEl.dom.removeChild(panel.getEl().dom);
32573 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
32574 var p = this.panels.first();
32575 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
32576 tempEl.appendChild(p.getEl().dom);
32577 this.bodyEl.update("");
32578 this.bodyEl.dom.appendChild(p.getEl().dom);
32580 this.updateTitle(p.getTitle());
32582 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32583 this.setActivePanel(p);
32585 panel.setRegion(null);
32586 if(this.activePanel == panel){
32587 this.activePanel = null;
32589 if(this.config.autoDestroy !== false && preservePanel !== true){
32590 try{panel.destroy();}catch(e){}
32592 this.fireEvent("panelremoved", this, panel);
32597 * Returns the TabPanel component used by this region
32598 * @return {Roo.TabPanel}
32600 getTabs : function(){
32604 createTool : function(parentEl, className){
32605 var btn = Roo.DomHelper.append(parentEl, {
32607 cls: "x-layout-tools-button",
32610 cls: "roo-layout-tools-button-inner " + className,
32614 btn.addClassOnOver("roo-layout-tools-button-over");
32619 * Ext JS Library 1.1.1
32620 * Copyright(c) 2006-2007, Ext JS, LLC.
32622 * Originally Released Under LGPL - original licence link has changed is not relivant.
32625 * <script type="text/javascript">
32631 * @class Roo.SplitLayoutRegion
32632 * @extends Roo.LayoutRegion
32633 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
32635 Roo.bootstrap.layout.Split = function(config){
32636 this.cursor = config.cursor;
32637 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
32640 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
32642 splitTip : "Drag to resize.",
32643 collapsibleSplitTip : "Drag to resize. Double click to hide.",
32644 useSplitTips : false,
32646 applyConfig : function(config){
32647 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
32653 var splitEl = Roo.DomHelper.append(this.mgr.el.dom, {
32655 id: this.el.id + "-split",
32656 cls: "roo-layout-split roo-layout-split-"+this.position,
32659 /** The SplitBar for this region
32660 * @type Roo.SplitBar */
32661 // does not exist yet...
32662 Roo.log([this.position, this.orientation]);
32664 this.split = new Roo.bootstrap.SplitBar({
32665 dragElement : splitEl,
32666 resizingElement: this.el,
32667 orientation : this.orientation
32670 this.split.on("moved", this.onSplitMove, this);
32671 this.split.useShim = config.useShim === true;
32672 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
32673 if(this.useSplitTips){
32674 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
32676 //if(config.collapsible){
32677 // this.split.el.on("dblclick", this.collapse, this);
32680 if(typeof config.minSize != "undefined"){
32681 this.split.minSize = config.minSize;
32683 if(typeof config.maxSize != "undefined"){
32684 this.split.maxSize = config.maxSize;
32686 if(config.hideWhenEmpty || config.hidden || config.collapsed){
32687 this.hideSplitter();
32692 getHMaxSize : function(){
32693 var cmax = this.config.maxSize || 10000;
32694 var center = this.mgr.getRegion("center");
32695 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
32698 getVMaxSize : function(){
32699 var cmax = this.config.maxSize || 10000;
32700 var center = this.mgr.getRegion("center");
32701 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
32704 onSplitMove : function(split, newSize){
32705 this.fireEvent("resized", this, newSize);
32709 * Returns the {@link Roo.SplitBar} for this region.
32710 * @return {Roo.SplitBar}
32712 getSplitBar : function(){
32717 this.hideSplitter();
32718 Roo.bootstrap.layout.Split.superclass.hide.call(this);
32721 hideSplitter : function(){
32723 this.split.el.setLocation(-2000,-2000);
32724 this.split.el.hide();
32730 this.split.el.show();
32732 Roo.bootstrap.layout.Split.superclass.show.call(this);
32735 beforeSlide: function(){
32736 if(Roo.isGecko){// firefox overflow auto bug workaround
32737 this.bodyEl.clip();
32739 this.tabs.bodyEl.clip();
32741 if(this.activePanel){
32742 this.activePanel.getEl().clip();
32744 if(this.activePanel.beforeSlide){
32745 this.activePanel.beforeSlide();
32751 afterSlide : function(){
32752 if(Roo.isGecko){// firefox overflow auto bug workaround
32753 this.bodyEl.unclip();
32755 this.tabs.bodyEl.unclip();
32757 if(this.activePanel){
32758 this.activePanel.getEl().unclip();
32759 if(this.activePanel.afterSlide){
32760 this.activePanel.afterSlide();
32766 initAutoHide : function(){
32767 if(this.autoHide !== false){
32768 if(!this.autoHideHd){
32769 var st = new Roo.util.DelayedTask(this.slideIn, this);
32770 this.autoHideHd = {
32771 "mouseout": function(e){
32772 if(!e.within(this.el, true)){
32776 "mouseover" : function(e){
32782 this.el.on(this.autoHideHd);
32786 clearAutoHide : function(){
32787 if(this.autoHide !== false){
32788 this.el.un("mouseout", this.autoHideHd.mouseout);
32789 this.el.un("mouseover", this.autoHideHd.mouseover);
32793 clearMonitor : function(){
32794 Roo.get(document).un("click", this.slideInIf, this);
32797 // these names are backwards but not changed for compat
32798 slideOut : function(){
32799 if(this.isSlid || this.el.hasActiveFx()){
32802 this.isSlid = true;
32803 if(this.collapseBtn){
32804 this.collapseBtn.hide();
32806 this.closeBtnState = this.closeBtn.getStyle('display');
32807 this.closeBtn.hide();
32809 this.stickBtn.show();
32812 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
32813 this.beforeSlide();
32814 this.el.setStyle("z-index", 10001);
32815 this.el.slideIn(this.getSlideAnchor(), {
32816 callback: function(){
32818 this.initAutoHide();
32819 Roo.get(document).on("click", this.slideInIf, this);
32820 this.fireEvent("slideshow", this);
32827 afterSlideIn : function(){
32828 this.clearAutoHide();
32829 this.isSlid = false;
32830 this.clearMonitor();
32831 this.el.setStyle("z-index", "");
32832 if(this.collapseBtn){
32833 this.collapseBtn.show();
32835 this.closeBtn.setStyle('display', this.closeBtnState);
32837 this.stickBtn.hide();
32839 this.fireEvent("slidehide", this);
32842 slideIn : function(cb){
32843 if(!this.isSlid || this.el.hasActiveFx()){
32847 this.isSlid = false;
32848 this.beforeSlide();
32849 this.el.slideOut(this.getSlideAnchor(), {
32850 callback: function(){
32851 this.el.setLeftTop(-10000, -10000);
32853 this.afterSlideIn();
32861 slideInIf : function(e){
32862 if(!e.within(this.el)){
32867 animateCollapse : function(){
32868 this.beforeSlide();
32869 this.el.setStyle("z-index", 20000);
32870 var anchor = this.getSlideAnchor();
32871 this.el.slideOut(anchor, {
32872 callback : function(){
32873 this.el.setStyle("z-index", "");
32874 this.collapsedEl.slideIn(anchor, {duration:.3});
32876 this.el.setLocation(-10000,-10000);
32878 this.fireEvent("collapsed", this);
32885 animateExpand : function(){
32886 this.beforeSlide();
32887 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
32888 this.el.setStyle("z-index", 20000);
32889 this.collapsedEl.hide({
32892 this.el.slideIn(this.getSlideAnchor(), {
32893 callback : function(){
32894 this.el.setStyle("z-index", "");
32897 this.split.el.show();
32899 this.fireEvent("invalidated", this);
32900 this.fireEvent("expanded", this);
32928 getAnchor : function(){
32929 return this.anchors[this.position];
32932 getCollapseAnchor : function(){
32933 return this.canchors[this.position];
32936 getSlideAnchor : function(){
32937 return this.sanchors[this.position];
32940 getAlignAdj : function(){
32941 var cm = this.cmargins;
32942 switch(this.position){
32958 getExpandAdj : function(){
32959 var c = this.collapsedEl, cm = this.cmargins;
32960 switch(this.position){
32962 return [-(cm.right+c.getWidth()+cm.left), 0];
32965 return [cm.right+c.getWidth()+cm.left, 0];
32968 return [0, -(cm.top+cm.bottom+c.getHeight())];
32971 return [0, cm.top+cm.bottom+c.getHeight()];
32977 * Ext JS Library 1.1.1
32978 * Copyright(c) 2006-2007, Ext JS, LLC.
32980 * Originally Released Under LGPL - original licence link has changed is not relivant.
32983 * <script type="text/javascript">
32986 * These classes are private internal classes
32988 Roo.bootstrap.layout.Center = function(config){
32989 config.region = "center";
32990 Roo.bootstrap.layout.Region.call(this, config);
32991 this.visible = true;
32992 this.minWidth = config.minWidth || 20;
32993 this.minHeight = config.minHeight || 20;
32996 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
32998 // center panel can't be hidden
33002 // center panel can't be hidden
33005 getMinWidth: function(){
33006 return this.minWidth;
33009 getMinHeight: function(){
33010 return this.minHeight;
33023 Roo.bootstrap.layout.North = function(config)
33025 config.region = 'north';
33026 config.cursor = 'n-resize';
33028 Roo.bootstrap.layout.Split.call(this, config);
33030 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33031 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33032 this.split.el.addClass("roo-layout-split-v");
33034 var size = config.initialSize || config.height;
33035 if(typeof size != "undefined"){
33036 this.el.setHeight(size);
33039 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
33041 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33042 getBox : function(){
33043 if(this.collapsed){
33044 return this.collapsedEl.getBox();
33046 var box = this.el.getBox();
33048 box.height += this.split.el.getHeight();
33053 updateBox : function(box){
33054 if(this.split && !this.collapsed){
33055 box.height -= this.split.el.getHeight();
33056 this.split.el.setLeft(box.x);
33057 this.split.el.setTop(box.y+box.height);
33058 this.split.el.setWidth(box.width);
33060 if(this.collapsed){
33061 this.updateBody(box.width, null);
33063 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33071 Roo.bootstrap.layout.South = function(config){
33072 config.region = 'south';
33073 config.cursor = 's-resize';
33074 Roo.bootstrap.layout.Split.call(this, config);
33076 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33077 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33078 this.split.el.addClass("roo-layout-split-v");
33080 var size = config.initialSize || config.height;
33081 if(typeof size != "undefined"){
33082 this.el.setHeight(size);
33086 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33087 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33088 getBox : function(){
33089 if(this.collapsed){
33090 return this.collapsedEl.getBox();
33092 var box = this.el.getBox();
33094 var sh = this.split.el.getHeight();
33101 updateBox : function(box){
33102 if(this.split && !this.collapsed){
33103 var sh = this.split.el.getHeight();
33106 this.split.el.setLeft(box.x);
33107 this.split.el.setTop(box.y-sh);
33108 this.split.el.setWidth(box.width);
33110 if(this.collapsed){
33111 this.updateBody(box.width, null);
33113 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33117 Roo.bootstrap.layout.East = function(config){
33118 config.region = "east";
33119 config.cursor = "e-resize";
33120 Roo.bootstrap.layout.Split.call(this, config);
33122 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
33123 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33124 this.split.el.addClass("roo-layout-split-h");
33126 var size = config.initialSize || config.width;
33127 if(typeof size != "undefined"){
33128 this.el.setWidth(size);
33131 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
33132 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33133 getBox : function(){
33134 if(this.collapsed){
33135 return this.collapsedEl.getBox();
33137 var box = this.el.getBox();
33139 var sw = this.split.el.getWidth();
33146 updateBox : function(box){
33147 if(this.split && !this.collapsed){
33148 var sw = this.split.el.getWidth();
33150 this.split.el.setLeft(box.x);
33151 this.split.el.setTop(box.y);
33152 this.split.el.setHeight(box.height);
33155 if(this.collapsed){
33156 this.updateBody(null, box.height);
33158 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33162 Roo.bootstrap.layout.West = function(config){
33163 config.region = "west";
33164 config.cursor = "w-resize";
33166 Roo.bootstrap.layout.Split.call(this, config);
33168 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
33169 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33170 this.split.el.addClass("roo-layout-split-h");
33172 var size = config.initialSize || config.width;
33173 if(typeof size != "undefined"){
33174 this.el.setWidth(size);
33177 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
33178 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33179 getBox : function(){
33180 if(this.collapsed){
33181 return this.collapsedEl.getBox();
33183 var box = this.el.getBox();
33185 box.width += this.split.el.getWidth();
33190 updateBox : function(box){
33191 if(this.split && !this.collapsed){
33192 var sw = this.split.el.getWidth();
33194 this.split.el.setLeft(box.x+box.width);
33195 this.split.el.setTop(box.y);
33196 this.split.el.setHeight(box.height);
33198 if(this.collapsed){
33199 this.updateBody(null, box.height);
33201 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33204 Roo.namespace("Roo.bootstrap.panel");/*
33206 * Ext JS Library 1.1.1
33207 * Copyright(c) 2006-2007, Ext JS, LLC.
33209 * Originally Released Under LGPL - original licence link has changed is not relivant.
33212 * <script type="text/javascript">
33215 * @class Roo.ContentPanel
33216 * @extends Roo.util.Observable
33217 * A basic ContentPanel element.
33218 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
33219 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
33220 * @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
33221 * @cfg {Boolean} closable True if the panel can be closed/removed
33222 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
33223 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
33224 * @cfg {Toolbar} toolbar A toolbar for this panel
33225 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
33226 * @cfg {String} title The title for this panel
33227 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
33228 * @cfg {String} url Calls {@link #setUrl} with this value
33229 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
33230 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
33231 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
33232 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
33235 * Create a new ContentPanel.
33236 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
33237 * @param {String/Object} config A string to set only the title or a config object
33238 * @param {String} content (optional) Set the HTML content for this panel
33239 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
33241 Roo.bootstrap.panel.Content = function( config){
33243 var el = config.el;
33244 var content = config.content;
33246 if(config.autoCreate){ // xtype is available if this is called from factory
33249 this.el = Roo.get(el);
33250 if(!this.el && config && config.autoCreate){
33251 if(typeof config.autoCreate == "object"){
33252 if(!config.autoCreate.id){
33253 config.autoCreate.id = config.id||el;
33255 this.el = Roo.DomHelper.append(document.body,
33256 config.autoCreate, true);
33258 var elcfg = { tag: "div",
33259 cls: "roo-layout-inactive-content",
33263 elcfg.html = config.html;
33267 this.el = Roo.DomHelper.append(document.body, elcfg , true);
33270 this.closable = false;
33271 this.loaded = false;
33272 this.active = false;
33273 if(typeof config == "string"){
33274 this.title = config;
33276 Roo.apply(this, config);
33279 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
33280 this.wrapEl = this.el.wrap();
33281 this.toolbar.container = this.el.insertSibling(false, 'before');
33282 this.toolbar = new Roo.Toolbar(this.toolbar);
33285 // xtype created footer. - not sure if will work as we normally have to render first..
33286 if (this.footer && !this.footer.el && this.footer.xtype) {
33287 if (!this.wrapEl) {
33288 this.wrapEl = this.el.wrap();
33291 this.footer.container = this.wrapEl.createChild();
33293 this.footer = Roo.factory(this.footer, Roo);
33298 this.resizeEl = Roo.get(this.resizeEl, true);
33300 this.resizeEl = this.el;
33302 // handle view.xtype
33310 * Fires when this panel is activated.
33311 * @param {Roo.ContentPanel} this
33315 * @event deactivate
33316 * Fires when this panel is activated.
33317 * @param {Roo.ContentPanel} this
33319 "deactivate" : true,
33323 * Fires when this panel is resized if fitToFrame is true.
33324 * @param {Roo.ContentPanel} this
33325 * @param {Number} width The width after any component adjustments
33326 * @param {Number} height The height after any component adjustments
33332 * Fires when this tab is created
33333 * @param {Roo.ContentPanel} this
33344 if(this.autoScroll){
33345 this.resizeEl.setStyle("overflow", "auto");
33347 // fix randome scrolling
33348 this.el.on('scroll', function() {
33349 Roo.log('fix random scolling');
33350 this.scrollTo('top',0);
33353 content = content || this.content;
33355 this.setContent(content);
33357 if(config && config.url){
33358 this.setUrl(this.url, this.params, this.loadOnce);
33363 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
33365 if (this.view && typeof(this.view.xtype) != 'undefined') {
33366 this.view.el = this.el.appendChild(document.createElement("div"));
33367 this.view = Roo.factory(this.view);
33368 this.view.render && this.view.render(false, '');
33372 this.fireEvent('render', this);
33375 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
33377 setRegion : function(region){
33378 this.region = region;
33380 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
33382 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
33387 * Returns the toolbar for this Panel if one was configured.
33388 * @return {Roo.Toolbar}
33390 getToolbar : function(){
33391 return this.toolbar;
33394 setActiveState : function(active){
33395 this.active = active;
33397 this.fireEvent("deactivate", this);
33399 this.fireEvent("activate", this);
33403 * Updates this panel's element
33404 * @param {String} content The new content
33405 * @param {Boolean} loadScripts (optional) true to look for and process scripts
33407 setContent : function(content, loadScripts){
33408 this.el.update(content, loadScripts);
33411 ignoreResize : function(w, h){
33412 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
33415 this.lastSize = {width: w, height: h};
33420 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
33421 * @return {Roo.UpdateManager} The UpdateManager
33423 getUpdateManager : function(){
33424 return this.el.getUpdateManager();
33427 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
33428 * @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:
33431 url: "your-url.php",
33432 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
33433 callback: yourFunction,
33434 scope: yourObject, //(optional scope)
33437 text: "Loading...",
33442 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
33443 * 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.
33444 * @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}
33445 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
33446 * @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.
33447 * @return {Roo.ContentPanel} this
33450 var um = this.el.getUpdateManager();
33451 um.update.apply(um, arguments);
33457 * 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.
33458 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
33459 * @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)
33460 * @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)
33461 * @return {Roo.UpdateManager} The UpdateManager
33463 setUrl : function(url, params, loadOnce){
33464 if(this.refreshDelegate){
33465 this.removeListener("activate", this.refreshDelegate);
33467 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
33468 this.on("activate", this.refreshDelegate);
33469 return this.el.getUpdateManager();
33472 _handleRefresh : function(url, params, loadOnce){
33473 if(!loadOnce || !this.loaded){
33474 var updater = this.el.getUpdateManager();
33475 updater.update(url, params, this._setLoaded.createDelegate(this));
33479 _setLoaded : function(){
33480 this.loaded = true;
33484 * Returns this panel's id
33487 getId : function(){
33492 * Returns this panel's element - used by regiosn to add.
33493 * @return {Roo.Element}
33495 getEl : function(){
33496 return this.wrapEl || this.el;
33501 adjustForComponents : function(width, height)
33503 //Roo.log('adjustForComponents ');
33504 if(this.resizeEl != this.el){
33505 width -= this.el.getFrameWidth('lr');
33506 height -= this.el.getFrameWidth('tb');
33509 var te = this.toolbar.getEl();
33510 height -= te.getHeight();
33511 te.setWidth(width);
33514 var te = this.footer.getEl();
33515 Roo.log("footer:" + te.getHeight());
33517 height -= te.getHeight();
33518 te.setWidth(width);
33522 if(this.adjustments){
33523 width += this.adjustments[0];
33524 height += this.adjustments[1];
33526 return {"width": width, "height": height};
33529 setSize : function(width, height){
33530 if(this.fitToFrame && !this.ignoreResize(width, height)){
33531 if(this.fitContainer && this.resizeEl != this.el){
33532 this.el.setSize(width, height);
33534 var size = this.adjustForComponents(width, height);
33535 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
33536 this.fireEvent('resize', this, size.width, size.height);
33541 * Returns this panel's title
33544 getTitle : function(){
33549 * Set this panel's title
33550 * @param {String} title
33552 setTitle : function(title){
33553 this.title = title;
33555 this.region.updatePanelTitle(this, title);
33560 * Returns true is this panel was configured to be closable
33561 * @return {Boolean}
33563 isClosable : function(){
33564 return this.closable;
33567 beforeSlide : function(){
33569 this.resizeEl.clip();
33572 afterSlide : function(){
33574 this.resizeEl.unclip();
33578 * Force a content refresh from the URL specified in the {@link #setUrl} method.
33579 * Will fail silently if the {@link #setUrl} method has not been called.
33580 * This does not activate the panel, just updates its content.
33582 refresh : function(){
33583 if(this.refreshDelegate){
33584 this.loaded = false;
33585 this.refreshDelegate();
33590 * Destroys this panel
33592 destroy : function(){
33593 this.el.removeAllListeners();
33594 var tempEl = document.createElement("span");
33595 tempEl.appendChild(this.el.dom);
33596 tempEl.innerHTML = "";
33602 * form - if the content panel contains a form - this is a reference to it.
33603 * @type {Roo.form.Form}
33607 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
33608 * This contains a reference to it.
33614 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
33624 * @param {Object} cfg Xtype definition of item to add.
33628 getChildContainer: function () {
33629 return this.getEl();
33634 var ret = new Roo.factory(cfg);
33639 if (cfg.xtype.match(/^Form$/)) {
33642 //if (this.footer) {
33643 // el = this.footer.container.insertSibling(false, 'before');
33645 el = this.el.createChild();
33648 this.form = new Roo.form.Form(cfg);
33651 if ( this.form.allItems.length) {
33652 this.form.render(el.dom);
33656 // should only have one of theses..
33657 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
33658 // views.. should not be just added - used named prop 'view''
33660 cfg.el = this.el.appendChild(document.createElement("div"));
33663 var ret = new Roo.factory(cfg);
33665 ret.render && ret.render(false, ''); // render blank..
33675 * @class Roo.bootstrap.panel.Grid
33676 * @extends Roo.bootstrap.panel.Content
33678 * Create a new GridPanel.
33679 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
33680 * @param {String/Object} config A string to set only the panel's title, or a config object
33682 new Roo.bootstrap.panel.Grid({
33691 Roo.bootstrap.panel.Grid = function(config){
33694 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
33695 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
33697 this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
33698 config.el = this.wrapper;
33700 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
33703 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
33705 // xtype created footer. - not sure if will work as we normally have to render first..
33706 if (this.footer && !this.footer.el && this.footer.xtype) {
33708 this.footer.container = this.grid.getView().getFooterPanel(true);
33709 this.footer.dataSource = this.grid.dataSource;
33710 this.footer = Roo.factory(this.footer, Roo);
33715 config.grid.monitorWindowResize = false; // turn off autosizing
33716 config.grid.autoHeight = false;
33717 config.grid.autoWidth = false;
33718 this.grid = config.grid;
33719 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
33724 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
33725 getId : function(){
33726 return this.grid.id;
33730 * Returns the grid for this panel
33731 * @return {Roo.bootstrap.Table}
33733 getGrid : function(){
33737 setSize : function(width, height){
33738 if(!this.ignoreResize(width, height)){
33739 var grid = this.grid;
33740 var size = this.adjustForComponents(width, height);
33741 grid.getGridEl().setSize(size.width, size.height);
33742 var thd = grid.getGridEl().select('thead');
33743 var tbd = grid.getGridEl().select('tbody');
33750 beforeSlide : function(){
33751 this.grid.getView().scroller.clip();
33754 afterSlide : function(){
33755 this.grid.getView().scroller.unclip();
33758 destroy : function(){
33759 this.grid.destroy();
33761 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
33766 * @class Roo.bootstrap.panel.Nest
33767 * @extends Roo.bootstrap.panel.Content
33769 * Create a new Panel, that can contain a layout.Border.
33772 * @param {Roo.BorderLayout} layout The layout for this panel
33773 * @param {String/Object} config A string to set only the title or a config object
33775 Roo.bootstrap.panel.Nest = function(config)
33777 // construct with only one argument..
33778 /* FIXME - implement nicer consturctors
33779 if (layout.layout) {
33781 layout = config.layout;
33782 delete config.layout;
33784 if (layout.xtype && !layout.getEl) {
33785 // then layout needs constructing..
33786 layout = Roo.factory(layout, Roo);
33790 config.el = config.layout.getEl();
33792 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
33794 config.layout.monitorWindowResize = false; // turn off autosizing
33795 this.layout = config.layout;
33796 this.layout.getEl().addClass("roo-layout-nested-layout");
33803 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
33805 setSize : function(width, height){
33806 if(!this.ignoreResize(width, height)){
33807 var size = this.adjustForComponents(width, height);
33808 var el = this.layout.getEl();
33809 el.setSize(size.width, size.height);
33810 var touch = el.dom.offsetWidth;
33811 this.layout.layout();
33812 // ie requires a double layout on the first pass
33813 if(Roo.isIE && !this.initialized){
33814 this.initialized = true;
33815 this.layout.layout();
33820 // activate all subpanels if not currently active..
33822 setActiveState : function(active){
33823 this.active = active;
33825 this.fireEvent("deactivate", this);
33829 this.fireEvent("activate", this);
33830 // not sure if this should happen before or after..
33831 if (!this.layout) {
33832 return; // should not happen..
33835 for (var r in this.layout.regions) {
33836 reg = this.layout.getRegion(r);
33837 if (reg.getActivePanel()) {
33838 //reg.showPanel(reg.getActivePanel()); // force it to activate..
33839 reg.setActivePanel(reg.getActivePanel());
33842 if (!reg.panels.length) {
33845 reg.showPanel(reg.getPanel(0));
33854 * Returns the nested BorderLayout for this panel
33855 * @return {Roo.BorderLayout}
33857 getLayout : function(){
33858 return this.layout;
33862 * Adds a xtype elements to the layout of the nested panel
33866 xtype : 'ContentPanel',
33873 xtype : 'NestedLayoutPanel',
33879 items : [ ... list of content panels or nested layout panels.. ]
33883 * @param {Object} cfg Xtype definition of item to add.
33885 addxtype : function(cfg) {
33886 return this.layout.addxtype(cfg);
33891 * Ext JS Library 1.1.1
33892 * Copyright(c) 2006-2007, Ext JS, LLC.
33894 * Originally Released Under LGPL - original licence link has changed is not relivant.
33897 * <script type="text/javascript">
33900 * @class Roo.TabPanel
33901 * @extends Roo.util.Observable
33902 * A lightweight tab container.
33906 // basic tabs 1, built from existing content
33907 var tabs = new Roo.TabPanel("tabs1");
33908 tabs.addTab("script", "View Script");
33909 tabs.addTab("markup", "View Markup");
33910 tabs.activate("script");
33912 // more advanced tabs, built from javascript
33913 var jtabs = new Roo.TabPanel("jtabs");
33914 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
33916 // set up the UpdateManager
33917 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
33918 var updater = tab2.getUpdateManager();
33919 updater.setDefaultUrl("ajax1.htm");
33920 tab2.on('activate', updater.refresh, updater, true);
33922 // Use setUrl for Ajax loading
33923 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
33924 tab3.setUrl("ajax2.htm", null, true);
33927 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
33930 jtabs.activate("jtabs-1");
33933 * Create a new TabPanel.
33934 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
33935 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
33937 Roo.bootstrap.panel.Tabs = function(config){
33939 * The container element for this TabPanel.
33940 * @type Roo.Element
33942 this.el = Roo.get(config.el);
33945 if(typeof config == "boolean"){
33946 this.tabPosition = config ? "bottom" : "top";
33948 Roo.apply(this, config);
33952 if(this.tabPosition == "bottom"){
33953 this.bodyEl = Roo.get(this.createBody(this.el.dom));
33954 this.el.addClass("roo-tabs-bottom");
33956 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
33957 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
33958 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
33960 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
33962 if(this.tabPosition != "bottom"){
33963 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
33964 * @type Roo.Element
33966 this.bodyEl = Roo.get(this.createBody(this.el.dom));
33967 this.el.addClass("roo-tabs-top");
33971 this.bodyEl.setStyle("position", "relative");
33973 this.active = null;
33974 this.activateDelegate = this.activate.createDelegate(this);
33979 * Fires when the active tab changes
33980 * @param {Roo.TabPanel} this
33981 * @param {Roo.TabPanelItem} activePanel The new active tab
33985 * @event beforetabchange
33986 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
33987 * @param {Roo.TabPanel} this
33988 * @param {Object} e Set cancel to true on this object to cancel the tab change
33989 * @param {Roo.TabPanelItem} tab The tab being changed to
33991 "beforetabchange" : true
33994 Roo.EventManager.onWindowResize(this.onResize, this);
33995 this.cpad = this.el.getPadding("lr");
33996 this.hiddenCount = 0;
33999 // toolbar on the tabbar support...
34000 if (this.toolbar) {
34001 alert("no toolbar support yet");
34002 this.toolbar = false;
34004 var tcfg = this.toolbar;
34005 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
34006 this.toolbar = new Roo.Toolbar(tcfg);
34007 if (Roo.isSafari) {
34008 var tbl = tcfg.container.child('table', true);
34009 tbl.setAttribute('width', '100%');
34017 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
34020 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
34022 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
34024 tabPosition : "top",
34026 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
34028 currentTabWidth : 0,
34030 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
34034 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
34038 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
34040 preferredTabWidth : 175,
34042 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
34044 resizeTabs : false,
34046 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
34048 monitorResize : true,
34050 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
34055 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
34056 * @param {String} id The id of the div to use <b>or create</b>
34057 * @param {String} text The text for the tab
34058 * @param {String} content (optional) Content to put in the TabPanelItem body
34059 * @param {Boolean} closable (optional) True to create a close icon on the tab
34060 * @return {Roo.TabPanelItem} The created TabPanelItem
34062 addTab : function(id, text, content, closable)
34064 var item = new Roo.bootstrap.panel.TabItem({
34068 closable : closable
34070 this.addTabItem(item);
34072 item.setContent(content);
34078 * Returns the {@link Roo.TabPanelItem} with the specified id/index
34079 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
34080 * @return {Roo.TabPanelItem}
34082 getTab : function(id){
34083 return this.items[id];
34087 * Hides the {@link Roo.TabPanelItem} with the specified id/index
34088 * @param {String/Number} id The id or index of the TabPanelItem to hide.
34090 hideTab : function(id){
34091 var t = this.items[id];
34094 this.hiddenCount++;
34095 this.autoSizeTabs();
34100 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
34101 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
34103 unhideTab : function(id){
34104 var t = this.items[id];
34106 t.setHidden(false);
34107 this.hiddenCount--;
34108 this.autoSizeTabs();
34113 * Adds an existing {@link Roo.TabPanelItem}.
34114 * @param {Roo.TabPanelItem} item The TabPanelItem to add
34116 addTabItem : function(item){
34117 this.items[item.id] = item;
34118 this.items.push(item);
34119 // if(this.resizeTabs){
34120 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
34121 // this.autoSizeTabs();
34123 // item.autoSize();
34128 * Removes a {@link Roo.TabPanelItem}.
34129 * @param {String/Number} id The id or index of the TabPanelItem to remove.
34131 removeTab : function(id){
34132 var items = this.items;
34133 var tab = items[id];
34134 if(!tab) { return; }
34135 var index = items.indexOf(tab);
34136 if(this.active == tab && items.length > 1){
34137 var newTab = this.getNextAvailable(index);
34142 this.stripEl.dom.removeChild(tab.pnode.dom);
34143 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
34144 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
34146 items.splice(index, 1);
34147 delete this.items[tab.id];
34148 tab.fireEvent("close", tab);
34149 tab.purgeListeners();
34150 this.autoSizeTabs();
34153 getNextAvailable : function(start){
34154 var items = this.items;
34156 // look for a next tab that will slide over to
34157 // replace the one being removed
34158 while(index < items.length){
34159 var item = items[++index];
34160 if(item && !item.isHidden()){
34164 // if one isn't found select the previous tab (on the left)
34167 var item = items[--index];
34168 if(item && !item.isHidden()){
34176 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
34177 * @param {String/Number} id The id or index of the TabPanelItem to disable.
34179 disableTab : function(id){
34180 var tab = this.items[id];
34181 if(tab && this.active != tab){
34187 * Enables a {@link Roo.TabPanelItem} that is disabled.
34188 * @param {String/Number} id The id or index of the TabPanelItem to enable.
34190 enableTab : function(id){
34191 var tab = this.items[id];
34196 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
34197 * @param {String/Number} id The id or index of the TabPanelItem to activate.
34198 * @return {Roo.TabPanelItem} The TabPanelItem.
34200 activate : function(id){
34201 var tab = this.items[id];
34205 if(tab == this.active || tab.disabled){
34209 this.fireEvent("beforetabchange", this, e, tab);
34210 if(e.cancel !== true && !tab.disabled){
34212 this.active.hide();
34214 this.active = this.items[id];
34215 this.active.show();
34216 this.fireEvent("tabchange", this, this.active);
34222 * Gets the active {@link Roo.TabPanelItem}.
34223 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
34225 getActiveTab : function(){
34226 return this.active;
34230 * Updates the tab body element to fit the height of the container element
34231 * for overflow scrolling
34232 * @param {Number} targetHeight (optional) Override the starting height from the elements height
34234 syncHeight : function(targetHeight){
34235 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34236 var bm = this.bodyEl.getMargins();
34237 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
34238 this.bodyEl.setHeight(newHeight);
34242 onResize : function(){
34243 if(this.monitorResize){
34244 this.autoSizeTabs();
34249 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
34251 beginUpdate : function(){
34252 this.updating = true;
34256 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
34258 endUpdate : function(){
34259 this.updating = false;
34260 this.autoSizeTabs();
34264 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
34266 autoSizeTabs : function(){
34267 var count = this.items.length;
34268 var vcount = count - this.hiddenCount;
34269 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
34272 var w = Math.max(this.el.getWidth() - this.cpad, 10);
34273 var availWidth = Math.floor(w / vcount);
34274 var b = this.stripBody;
34275 if(b.getWidth() > w){
34276 var tabs = this.items;
34277 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
34278 if(availWidth < this.minTabWidth){
34279 /*if(!this.sleft){ // incomplete scrolling code
34280 this.createScrollButtons();
34283 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
34286 if(this.currentTabWidth < this.preferredTabWidth){
34287 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
34293 * Returns the number of tabs in this TabPanel.
34296 getCount : function(){
34297 return this.items.length;
34301 * Resizes all the tabs to the passed width
34302 * @param {Number} The new width
34304 setTabWidth : function(width){
34305 this.currentTabWidth = width;
34306 for(var i = 0, len = this.items.length; i < len; i++) {
34307 if(!this.items[i].isHidden()) {
34308 this.items[i].setWidth(width);
34314 * Destroys this TabPanel
34315 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
34317 destroy : function(removeEl){
34318 Roo.EventManager.removeResizeListener(this.onResize, this);
34319 for(var i = 0, len = this.items.length; i < len; i++){
34320 this.items[i].purgeListeners();
34322 if(removeEl === true){
34323 this.el.update("");
34328 createStrip : function(container)
34330 var strip = document.createElement("nav");
34331 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
34332 container.appendChild(strip);
34336 createStripList : function(strip)
34338 // div wrapper for retard IE
34339 // returns the "tr" element.
34340 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
34341 //'<div class="x-tabs-strip-wrap">'+
34342 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
34343 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
34344 return strip.firstChild; //.firstChild.firstChild.firstChild;
34346 createBody : function(container)
34348 var body = document.createElement("div");
34349 Roo.id(body, "tab-body");
34350 //Roo.fly(body).addClass("x-tabs-body");
34351 Roo.fly(body).addClass("tab-content");
34352 container.appendChild(body);
34355 createItemBody :function(bodyEl, id){
34356 var body = Roo.getDom(id);
34358 body = document.createElement("div");
34361 //Roo.fly(body).addClass("x-tabs-item-body");
34362 Roo.fly(body).addClass("tab-pane");
34363 bodyEl.insertBefore(body, bodyEl.firstChild);
34367 createStripElements : function(stripEl, text, closable)
34369 var td = document.createElement("li"); // was td..
34370 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
34371 //stripEl.appendChild(td);
34373 td.className = "x-tabs-closable";
34374 if(!this.closeTpl){
34375 this.closeTpl = new Roo.Template(
34376 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34377 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
34378 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
34381 var el = this.closeTpl.overwrite(td, {"text": text});
34382 var close = el.getElementsByTagName("div")[0];
34383 var inner = el.getElementsByTagName("em")[0];
34384 return {"el": el, "close": close, "inner": inner};
34387 // not sure what this is..
34389 //this.tabTpl = new Roo.Template(
34390 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34391 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
34393 this.tabTpl = new Roo.Template(
34395 '<span unselectable="on"' +
34396 (this.disableTooltips ? '' : ' title="{text}"') +
34397 ' >{text}</span></span></a>'
34401 var el = this.tabTpl.overwrite(td, {"text": text});
34402 var inner = el.getElementsByTagName("span")[0];
34403 return {"el": el, "inner": inner};
34411 * @class Roo.TabPanelItem
34412 * @extends Roo.util.Observable
34413 * Represents an individual item (tab plus body) in a TabPanel.
34414 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
34415 * @param {String} id The id of this TabPanelItem
34416 * @param {String} text The text for the tab of this TabPanelItem
34417 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
34419 Roo.bootstrap.panel.TabItem = function(config){
34421 * The {@link Roo.TabPanel} this TabPanelItem belongs to
34422 * @type Roo.TabPanel
34424 this.tabPanel = config.panel;
34426 * The id for this TabPanelItem
34429 this.id = config.id;
34431 this.disabled = false;
34433 this.text = config.text;
34435 this.loaded = false;
34436 this.closable = config.closable;
34439 * The body element for this TabPanelItem.
34440 * @type Roo.Element
34442 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
34443 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
34444 this.bodyEl.setStyle("display", "block");
34445 this.bodyEl.setStyle("zoom", "1");
34446 //this.hideAction();
34448 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
34450 this.el = Roo.get(els.el);
34451 this.inner = Roo.get(els.inner, true);
34452 this.textEl = Roo.get(this.el.dom.firstChild, true);
34453 this.pnode = Roo.get(els.el.parentNode, true);
34454 this.el.on("mousedown", this.onTabMouseDown, this);
34455 this.el.on("click", this.onTabClick, this);
34457 if(config.closable){
34458 var c = Roo.get(els.close, true);
34459 c.dom.title = this.closeText;
34460 c.addClassOnOver("close-over");
34461 c.on("click", this.closeClick, this);
34467 * Fires when this tab becomes the active tab.
34468 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34469 * @param {Roo.TabPanelItem} this
34473 * @event beforeclose
34474 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
34475 * @param {Roo.TabPanelItem} this
34476 * @param {Object} e Set cancel to true on this object to cancel the close.
34478 "beforeclose": true,
34481 * Fires when this tab is closed.
34482 * @param {Roo.TabPanelItem} this
34486 * @event deactivate
34487 * Fires when this tab is no longer the active tab.
34488 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34489 * @param {Roo.TabPanelItem} this
34491 "deactivate" : true
34493 this.hidden = false;
34495 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
34498 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
34500 purgeListeners : function(){
34501 Roo.util.Observable.prototype.purgeListeners.call(this);
34502 this.el.removeAllListeners();
34505 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
34508 this.pnode.addClass("active");
34511 this.tabPanel.stripWrap.repaint();
34513 this.fireEvent("activate", this.tabPanel, this);
34517 * Returns true if this tab is the active tab.
34518 * @return {Boolean}
34520 isActive : function(){
34521 return this.tabPanel.getActiveTab() == this;
34525 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
34528 this.pnode.removeClass("active");
34530 this.fireEvent("deactivate", this.tabPanel, this);
34533 hideAction : function(){
34534 this.bodyEl.hide();
34535 this.bodyEl.setStyle("position", "absolute");
34536 this.bodyEl.setLeft("-20000px");
34537 this.bodyEl.setTop("-20000px");
34540 showAction : function(){
34541 this.bodyEl.setStyle("position", "relative");
34542 this.bodyEl.setTop("");
34543 this.bodyEl.setLeft("");
34544 this.bodyEl.show();
34548 * Set the tooltip for the tab.
34549 * @param {String} tooltip The tab's tooltip
34551 setTooltip : function(text){
34552 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
34553 this.textEl.dom.qtip = text;
34554 this.textEl.dom.removeAttribute('title');
34556 this.textEl.dom.title = text;
34560 onTabClick : function(e){
34561 e.preventDefault();
34562 this.tabPanel.activate(this.id);
34565 onTabMouseDown : function(e){
34566 e.preventDefault();
34567 this.tabPanel.activate(this.id);
34570 getWidth : function(){
34571 return this.inner.getWidth();
34574 setWidth : function(width){
34575 var iwidth = width - this.pnode.getPadding("lr");
34576 this.inner.setWidth(iwidth);
34577 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
34578 this.pnode.setWidth(width);
34582 * Show or hide the tab
34583 * @param {Boolean} hidden True to hide or false to show.
34585 setHidden : function(hidden){
34586 this.hidden = hidden;
34587 this.pnode.setStyle("display", hidden ? "none" : "");
34591 * Returns true if this tab is "hidden"
34592 * @return {Boolean}
34594 isHidden : function(){
34595 return this.hidden;
34599 * Returns the text for this tab
34602 getText : function(){
34606 autoSize : function(){
34607 //this.el.beginMeasure();
34608 this.textEl.setWidth(1);
34610 * #2804 [new] Tabs in Roojs
34611 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
34613 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
34614 //this.el.endMeasure();
34618 * Sets the text for the tab (Note: this also sets the tooltip text)
34619 * @param {String} text The tab's text and tooltip
34621 setText : function(text){
34623 this.textEl.update(text);
34624 this.setTooltip(text);
34625 //if(!this.tabPanel.resizeTabs){
34626 // this.autoSize();
34630 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
34632 activate : function(){
34633 this.tabPanel.activate(this.id);
34637 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
34639 disable : function(){
34640 if(this.tabPanel.active != this){
34641 this.disabled = true;
34642 this.pnode.addClass("disabled");
34647 * Enables this TabPanelItem if it was previously disabled.
34649 enable : function(){
34650 this.disabled = false;
34651 this.pnode.removeClass("disabled");
34655 * Sets the content for this TabPanelItem.
34656 * @param {String} content The content
34657 * @param {Boolean} loadScripts true to look for and load scripts
34659 setContent : function(content, loadScripts){
34660 this.bodyEl.update(content, loadScripts);
34664 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
34665 * @return {Roo.UpdateManager} The UpdateManager
34667 getUpdateManager : function(){
34668 return this.bodyEl.getUpdateManager();
34672 * Set a URL to be used to load the content for this TabPanelItem.
34673 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
34674 * @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)
34675 * @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)
34676 * @return {Roo.UpdateManager} The UpdateManager
34678 setUrl : function(url, params, loadOnce){
34679 if(this.refreshDelegate){
34680 this.un('activate', this.refreshDelegate);
34682 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34683 this.on("activate", this.refreshDelegate);
34684 return this.bodyEl.getUpdateManager();
34688 _handleRefresh : function(url, params, loadOnce){
34689 if(!loadOnce || !this.loaded){
34690 var updater = this.bodyEl.getUpdateManager();
34691 updater.update(url, params, this._setLoaded.createDelegate(this));
34696 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
34697 * Will fail silently if the setUrl method has not been called.
34698 * This does not activate the panel, just updates its content.
34700 refresh : function(){
34701 if(this.refreshDelegate){
34702 this.loaded = false;
34703 this.refreshDelegate();
34708 _setLoaded : function(){
34709 this.loaded = true;
34713 closeClick : function(e){
34716 this.fireEvent("beforeclose", this, o);
34717 if(o.cancel !== true){
34718 this.tabPanel.removeTab(this.id);
34722 * The text displayed in the tooltip for the close icon.
34725 closeText : "Close this tab"