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);
6008 Roo.log("failed to find th in thead?");
6009 Roo.log(e.getTarget());
6014 var cellIndex = cell.dom.cellIndex;
6016 var ename = name == 'touchstart' ? 'click' : name;
6017 this.fireEvent("header" + ename, this, cellIndex, e);
6022 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6023 cell = Roo.get(t).findParent('td', false, true);
6025 Roo.log("failed to find th in tbody?");
6026 Roo.log(e.getTarget());
6031 var row = cell.findParent('tr', false, true);
6032 var cellIndex = cell.dom.cellIndex;
6033 var rowIndex = row.dom.rowIndex - 1;
6037 this.fireEvent("row" + name, this, rowIndex, e);
6041 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6047 onMouseover : function(e, el)
6049 var cell = Roo.get(el);
6055 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6056 cell = cell.findParent('td', false, true);
6059 var row = cell.findParent('tr', false, true);
6060 var cellIndex = cell.dom.cellIndex;
6061 var rowIndex = row.dom.rowIndex - 1; // start from 0
6063 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6067 onMouseout : function(e, el)
6069 var cell = Roo.get(el);
6075 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6076 cell = cell.findParent('td', false, true);
6079 var row = cell.findParent('tr', false, true);
6080 var cellIndex = cell.dom.cellIndex;
6081 var rowIndex = row.dom.rowIndex - 1; // start from 0
6083 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6087 onClick : function(e, el)
6089 var cell = Roo.get(el);
6091 if(!cell || (!this.cellSelection && !this.rowSelection)){
6095 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6096 cell = cell.findParent('td', false, true);
6099 if(!cell || typeof(cell) == 'undefined'){
6103 var row = cell.findParent('tr', false, true);
6105 if(!row || typeof(row) == 'undefined'){
6109 var cellIndex = cell.dom.cellIndex;
6110 var rowIndex = this.getRowIndex(row);
6112 // why??? - should these not be based on SelectionModel?
6113 if(this.cellSelection){
6114 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6117 if(this.rowSelection){
6118 this.fireEvent('rowclick', this, row, rowIndex, e);
6124 onDblClick : function(e,el)
6126 var cell = Roo.get(el);
6128 if(!cell || (!this.CellSelection && !this.RowSelection)){
6132 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6133 cell = cell.findParent('td', false, true);
6136 if(!cell || typeof(cell) == 'undefined'){
6140 var row = cell.findParent('tr', false, true);
6142 if(!row || typeof(row) == 'undefined'){
6146 var cellIndex = cell.dom.cellIndex;
6147 var rowIndex = this.getRowIndex(row);
6149 if(this.CellSelection){
6150 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6153 if(this.RowSelection){
6154 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6158 sort : function(e,el)
6160 var col = Roo.get(el);
6162 if(!col.hasClass('sortable')){
6166 var sort = col.attr('sort');
6169 if(col.hasClass('glyphicon-arrow-up')){
6173 this.store.sortInfo = {field : sort, direction : dir};
6176 Roo.log("calling footer first");
6177 this.footer.onClick('first');
6180 this.store.load({ params : { start : 0 } });
6184 renderHeader : function()
6192 this.totalWidth = 0;
6194 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6196 var config = cm.config[i];
6201 html: cm.getColumnHeader(i)
6206 if(typeof(config.lgHeader) != 'undefined'){
6207 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6210 if(typeof(config.mdHeader) != 'undefined'){
6211 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6214 if(typeof(config.smHeader) != 'undefined'){
6215 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6218 if(typeof(config.xsHeader) != 'undefined'){
6219 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6226 if(typeof(config.tooltip) != 'undefined'){
6227 c.tooltip = config.tooltip;
6230 if(typeof(config.colspan) != 'undefined'){
6231 c.colspan = config.colspan;
6234 if(typeof(config.hidden) != 'undefined' && config.hidden){
6235 c.style += ' display:none;';
6238 if(typeof(config.dataIndex) != 'undefined'){
6239 c.sort = config.dataIndex;
6242 if(typeof(config.sortable) != 'undefined' && config.sortable){
6246 if(typeof(config.align) != 'undefined' && config.align.length){
6247 c.style += ' text-align:' + config.align + ';';
6250 if(typeof(config.width) != 'undefined'){
6251 c.style += ' width:' + config.width + 'px;';
6252 this.totalWidth += config.width;
6254 this.totalWidth += 100; // assume minimum of 100 per column?
6257 if(typeof(config.cls) != 'undefined'){
6258 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6261 ['xs','sm','md','lg'].map(function(size){
6263 if(typeof(config[size]) == 'undefined'){
6267 if (!config[size]) { // 0 = hidden
6268 c.cls += ' hidden-' + size;
6272 c.cls += ' col-' + size + '-' + config[size];
6282 renderBody : function()
6292 colspan : this.cm.getColumnCount()
6302 renderFooter : function()
6312 colspan : this.cm.getColumnCount()
6326 // Roo.log('ds onload');
6331 var ds = this.store;
6333 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6334 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
6335 if (_this.store.sortInfo) {
6337 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6338 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
6341 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6342 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
6347 var tbody = this.mainBody;
6349 if(ds.getCount() > 0){
6350 ds.data.each(function(d,rowIndex){
6351 var row = this.renderRow(cm, ds, rowIndex);
6353 tbody.createChild(row);
6357 if(row.cellObjects.length){
6358 Roo.each(row.cellObjects, function(r){
6359 _this.renderCellObject(r);
6366 Roo.each(this.el.select('tbody td', true).elements, function(e){
6367 e.on('mouseover', _this.onMouseover, _this);
6370 Roo.each(this.el.select('tbody td', true).elements, function(e){
6371 e.on('mouseout', _this.onMouseout, _this);
6373 this.fireEvent('rowsrendered', this);
6374 //if(this.loadMask){
6375 // this.maskEl.hide();
6382 onUpdate : function(ds,record)
6384 this.refreshRow(record);
6387 onRemove : function(ds, record, index, isUpdate){
6388 if(isUpdate !== true){
6389 this.fireEvent("beforerowremoved", this, index, record);
6391 var bt = this.mainBody.dom;
6393 var rows = this.el.select('tbody > tr', true).elements;
6395 if(typeof(rows[index]) != 'undefined'){
6396 bt.removeChild(rows[index].dom);
6399 // if(bt.rows[index]){
6400 // bt.removeChild(bt.rows[index]);
6403 if(isUpdate !== true){
6404 //this.stripeRows(index);
6405 //this.syncRowHeights(index, index);
6407 this.fireEvent("rowremoved", this, index, record);
6411 onAdd : function(ds, records, rowIndex)
6413 //Roo.log('on Add called');
6414 // - note this does not handle multiple adding very well..
6415 var bt = this.mainBody.dom;
6416 for (var i =0 ; i < records.length;i++) {
6417 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6418 //Roo.log(records[i]);
6419 //Roo.log(this.store.getAt(rowIndex+i));
6420 this.insertRow(this.store, rowIndex + i, false);
6427 refreshRow : function(record){
6428 var ds = this.store, index;
6429 if(typeof record == 'number'){
6431 record = ds.getAt(index);
6433 index = ds.indexOf(record);
6435 this.insertRow(ds, index, true);
6436 this.onRemove(ds, record, index+1, true);
6437 //this.syncRowHeights(index, index);
6439 this.fireEvent("rowupdated", this, index, record);
6442 insertRow : function(dm, rowIndex, isUpdate){
6445 this.fireEvent("beforerowsinserted", this, rowIndex);
6447 //var s = this.getScrollState();
6448 var row = this.renderRow(this.cm, this.store, rowIndex);
6449 // insert before rowIndex..
6450 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6454 if(row.cellObjects.length){
6455 Roo.each(row.cellObjects, function(r){
6456 _this.renderCellObject(r);
6461 this.fireEvent("rowsinserted", this, rowIndex);
6462 //this.syncRowHeights(firstRow, lastRow);
6463 //this.stripeRows(firstRow);
6470 getRowDom : function(rowIndex)
6472 var rows = this.el.select('tbody > tr', true).elements;
6474 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6477 // returns the object tree for a tr..
6480 renderRow : function(cm, ds, rowIndex)
6483 var d = ds.getAt(rowIndex);
6490 var cellObjects = [];
6492 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6493 var config = cm.config[i];
6495 var renderer = cm.getRenderer(i);
6499 if(typeof(renderer) !== 'undefined'){
6500 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6502 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6503 // and are rendered into the cells after the row is rendered - using the id for the element.
6505 if(typeof(value) === 'object'){
6515 rowIndex : rowIndex,
6520 this.fireEvent('rowclass', this, rowcfg);
6524 cls : rowcfg.rowClass,
6526 html: (typeof(value) === 'object') ? '' : value
6533 if(typeof(config.colspan) != 'undefined'){
6534 td.colspan = config.colspan;
6537 if(typeof(config.hidden) != 'undefined' && config.hidden){
6538 td.style += ' display:none;';
6541 if(typeof(config.align) != 'undefined' && config.align.length){
6542 td.style += ' text-align:' + config.align + ';';
6545 if(typeof(config.width) != 'undefined'){
6546 td.style += ' width:' + config.width + 'px;';
6549 if(typeof(config.cursor) != 'undefined'){
6550 td.style += ' cursor:' + config.cursor + ';';
6553 if(typeof(config.cls) != 'undefined'){
6554 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6557 ['xs','sm','md','lg'].map(function(size){
6559 if(typeof(config[size]) == 'undefined'){
6563 if (!config[size]) { // 0 = hidden
6564 td.cls += ' hidden-' + size;
6568 td.cls += ' col-' + size + '-' + config[size];
6576 row.cellObjects = cellObjects;
6584 onBeforeLoad : function()
6586 //Roo.log('ds onBeforeLoad');
6590 //if(this.loadMask){
6591 // this.maskEl.show();
6599 this.el.select('tbody', true).first().dom.innerHTML = '';
6602 * Show or hide a row.
6603 * @param {Number} rowIndex to show or hide
6604 * @param {Boolean} state hide
6606 setRowVisibility : function(rowIndex, state)
6608 var bt = this.mainBody.dom;
6610 var rows = this.el.select('tbody > tr', true).elements;
6612 if(typeof(rows[rowIndex]) == 'undefined'){
6615 rows[rowIndex].dom.style.display = state ? '' : 'none';
6619 getSelectionModel : function(){
6621 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6623 return this.selModel;
6626 * Render the Roo.bootstrap object from renderder
6628 renderCellObject : function(r)
6632 var t = r.cfg.render(r.container);
6635 Roo.each(r.cfg.cn, function(c){
6637 container: t.getChildContainer(),
6640 _this.renderCellObject(child);
6645 getRowIndex : function(row)
6649 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6660 * Returns the grid's underlying element = used by panel.Grid
6661 * @return {Element} The element
6663 getGridEl : function(){
6664 return this.container;
6667 * Forces a resize - used by panel.Grid
6668 * @return {Element} The element
6670 autoSize : function(){
6671 var ctr = Roo.get(this.container.dom.parentElement);
6673 var thd = this.getGridEl().select('thead',true).first();
6674 var tbd = this.getGridEl().select('tbody', true).first();
6677 var cw = ctr.getWidth();
6681 tbd.setSize(ctr.getWidth(), ctr.getHeight() - thd.getHeight());
6682 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6685 cw = Math.max(cw, this.totalWidth);
6686 this.getGridEl().select('tr',true).setWidth(cw);
6688 return; // we doe not have a view in this design..
6691 if(this.view.adjustForScroll){
6692 this.view.adjustForScroll();
6708 * @class Roo.bootstrap.TableCell
6709 * @extends Roo.bootstrap.Component
6710 * Bootstrap TableCell class
6711 * @cfg {String} html cell contain text
6712 * @cfg {String} cls cell class
6713 * @cfg {String} tag cell tag (td|th) default td
6714 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6715 * @cfg {String} align Aligns the content in a cell
6716 * @cfg {String} axis Categorizes cells
6717 * @cfg {String} bgcolor Specifies the background color of a cell
6718 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6719 * @cfg {Number} colspan Specifies the number of columns a cell should span
6720 * @cfg {String} headers Specifies one or more header cells a cell is related to
6721 * @cfg {Number} height Sets the height of a cell
6722 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6723 * @cfg {Number} rowspan Sets the number of rows a cell should span
6724 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6725 * @cfg {String} valign Vertical aligns the content in a cell
6726 * @cfg {Number} width Specifies the width of a cell
6729 * Create a new TableCell
6730 * @param {Object} config The config object
6733 Roo.bootstrap.TableCell = function(config){
6734 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6737 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6757 getAutoCreate : function(){
6758 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6778 cfg.align=this.align
6784 cfg.bgcolor=this.bgcolor
6787 cfg.charoff=this.charoff
6790 cfg.colspan=this.colspan
6793 cfg.headers=this.headers
6796 cfg.height=this.height
6799 cfg.nowrap=this.nowrap
6802 cfg.rowspan=this.rowspan
6805 cfg.scope=this.scope
6808 cfg.valign=this.valign
6811 cfg.width=this.width
6830 * @class Roo.bootstrap.TableRow
6831 * @extends Roo.bootstrap.Component
6832 * Bootstrap TableRow class
6833 * @cfg {String} cls row class
6834 * @cfg {String} align Aligns the content in a table row
6835 * @cfg {String} bgcolor Specifies a background color for a table row
6836 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6837 * @cfg {String} valign Vertical aligns the content in a table row
6840 * Create a new TableRow
6841 * @param {Object} config The config object
6844 Roo.bootstrap.TableRow = function(config){
6845 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6848 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6856 getAutoCreate : function(){
6857 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6867 cfg.align = this.align;
6870 cfg.bgcolor = this.bgcolor;
6873 cfg.charoff = this.charoff;
6876 cfg.valign = this.valign;
6894 * @class Roo.bootstrap.TableBody
6895 * @extends Roo.bootstrap.Component
6896 * Bootstrap TableBody class
6897 * @cfg {String} cls element class
6898 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6899 * @cfg {String} align Aligns the content inside the element
6900 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6901 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6904 * Create a new TableBody
6905 * @param {Object} config The config object
6908 Roo.bootstrap.TableBody = function(config){
6909 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6912 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6920 getAutoCreate : function(){
6921 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6935 cfg.align = this.align;
6938 cfg.charoff = this.charoff;
6941 cfg.valign = this.valign;
6948 // initEvents : function()
6955 // this.store = Roo.factory(this.store, Roo.data);
6956 // this.store.on('load', this.onLoad, this);
6958 // this.store.load();
6962 // onLoad: function ()
6964 // this.fireEvent('load', this);
6974 * Ext JS Library 1.1.1
6975 * Copyright(c) 2006-2007, Ext JS, LLC.
6977 * Originally Released Under LGPL - original licence link has changed is not relivant.
6980 * <script type="text/javascript">
6983 // as we use this in bootstrap.
6984 Roo.namespace('Roo.form');
6986 * @class Roo.form.Action
6987 * Internal Class used to handle form actions
6989 * @param {Roo.form.BasicForm} el The form element or its id
6990 * @param {Object} config Configuration options
6995 // define the action interface
6996 Roo.form.Action = function(form, options){
6998 this.options = options || {};
7001 * Client Validation Failed
7004 Roo.form.Action.CLIENT_INVALID = 'client';
7006 * Server Validation Failed
7009 Roo.form.Action.SERVER_INVALID = 'server';
7011 * Connect to Server Failed
7014 Roo.form.Action.CONNECT_FAILURE = 'connect';
7016 * Reading Data from Server Failed
7019 Roo.form.Action.LOAD_FAILURE = 'load';
7021 Roo.form.Action.prototype = {
7023 failureType : undefined,
7024 response : undefined,
7028 run : function(options){
7033 success : function(response){
7038 handleResponse : function(response){
7042 // default connection failure
7043 failure : function(response){
7045 this.response = response;
7046 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7047 this.form.afterAction(this, false);
7050 processResponse : function(response){
7051 this.response = response;
7052 if(!response.responseText){
7055 this.result = this.handleResponse(response);
7059 // utility functions used internally
7060 getUrl : function(appendParams){
7061 var url = this.options.url || this.form.url || this.form.el.dom.action;
7063 var p = this.getParams();
7065 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7071 getMethod : function(){
7072 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7075 getParams : function(){
7076 var bp = this.form.baseParams;
7077 var p = this.options.params;
7079 if(typeof p == "object"){
7080 p = Roo.urlEncode(Roo.applyIf(p, bp));
7081 }else if(typeof p == 'string' && bp){
7082 p += '&' + Roo.urlEncode(bp);
7085 p = Roo.urlEncode(bp);
7090 createCallback : function(){
7092 success: this.success,
7093 failure: this.failure,
7095 timeout: (this.form.timeout*1000),
7096 upload: this.form.fileUpload ? this.success : undefined
7101 Roo.form.Action.Submit = function(form, options){
7102 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7105 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7108 haveProgress : false,
7109 uploadComplete : false,
7111 // uploadProgress indicator.
7112 uploadProgress : function()
7114 if (!this.form.progressUrl) {
7118 if (!this.haveProgress) {
7119 Roo.MessageBox.progress("Uploading", "Uploading");
7121 if (this.uploadComplete) {
7122 Roo.MessageBox.hide();
7126 this.haveProgress = true;
7128 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7130 var c = new Roo.data.Connection();
7132 url : this.form.progressUrl,
7137 success : function(req){
7138 //console.log(data);
7142 rdata = Roo.decode(req.responseText)
7144 Roo.log("Invalid data from server..");
7148 if (!rdata || !rdata.success) {
7150 Roo.MessageBox.alert(Roo.encode(rdata));
7153 var data = rdata.data;
7155 if (this.uploadComplete) {
7156 Roo.MessageBox.hide();
7161 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7162 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7165 this.uploadProgress.defer(2000,this);
7168 failure: function(data) {
7169 Roo.log('progress url failed ');
7180 // run get Values on the form, so it syncs any secondary forms.
7181 this.form.getValues();
7183 var o = this.options;
7184 var method = this.getMethod();
7185 var isPost = method == 'POST';
7186 if(o.clientValidation === false || this.form.isValid()){
7188 if (this.form.progressUrl) {
7189 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7190 (new Date() * 1) + '' + Math.random());
7195 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7196 form:this.form.el.dom,
7197 url:this.getUrl(!isPost),
7199 params:isPost ? this.getParams() : null,
7200 isUpload: this.form.fileUpload
7203 this.uploadProgress();
7205 }else if (o.clientValidation !== false){ // client validation failed
7206 this.failureType = Roo.form.Action.CLIENT_INVALID;
7207 this.form.afterAction(this, false);
7211 success : function(response)
7213 this.uploadComplete= true;
7214 if (this.haveProgress) {
7215 Roo.MessageBox.hide();
7219 var result = this.processResponse(response);
7220 if(result === true || result.success){
7221 this.form.afterAction(this, true);
7225 this.form.markInvalid(result.errors);
7226 this.failureType = Roo.form.Action.SERVER_INVALID;
7228 this.form.afterAction(this, false);
7230 failure : function(response)
7232 this.uploadComplete= true;
7233 if (this.haveProgress) {
7234 Roo.MessageBox.hide();
7237 this.response = response;
7238 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7239 this.form.afterAction(this, false);
7242 handleResponse : function(response){
7243 if(this.form.errorReader){
7244 var rs = this.form.errorReader.read(response);
7247 for(var i = 0, len = rs.records.length; i < len; i++) {
7248 var r = rs.records[i];
7252 if(errors.length < 1){
7256 success : rs.success,
7262 ret = Roo.decode(response.responseText);
7266 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7276 Roo.form.Action.Load = function(form, options){
7277 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7278 this.reader = this.form.reader;
7281 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7286 Roo.Ajax.request(Roo.apply(
7287 this.createCallback(), {
7288 method:this.getMethod(),
7289 url:this.getUrl(false),
7290 params:this.getParams()
7294 success : function(response){
7296 var result = this.processResponse(response);
7297 if(result === true || !result.success || !result.data){
7298 this.failureType = Roo.form.Action.LOAD_FAILURE;
7299 this.form.afterAction(this, false);
7302 this.form.clearInvalid();
7303 this.form.setValues(result.data);
7304 this.form.afterAction(this, true);
7307 handleResponse : function(response){
7308 if(this.form.reader){
7309 var rs = this.form.reader.read(response);
7310 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7312 success : rs.success,
7316 return Roo.decode(response.responseText);
7320 Roo.form.Action.ACTION_TYPES = {
7321 'load' : Roo.form.Action.Load,
7322 'submit' : Roo.form.Action.Submit
7331 * @class Roo.bootstrap.Form
7332 * @extends Roo.bootstrap.Component
7333 * Bootstrap Form class
7334 * @cfg {String} method GET | POST (default POST)
7335 * @cfg {String} labelAlign top | left (default top)
7336 * @cfg {String} align left | right - for navbars
7337 * @cfg {Boolean} loadMask load mask when submit (default true)
7342 * @param {Object} config The config object
7346 Roo.bootstrap.Form = function(config){
7347 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7350 * @event clientvalidation
7351 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7352 * @param {Form} this
7353 * @param {Boolean} valid true if the form has passed client-side validation
7355 clientvalidation: true,
7357 * @event beforeaction
7358 * Fires before any action is performed. Return false to cancel the action.
7359 * @param {Form} this
7360 * @param {Action} action The action to be performed
7364 * @event actionfailed
7365 * Fires when an action fails.
7366 * @param {Form} this
7367 * @param {Action} action The action that failed
7369 actionfailed : true,
7371 * @event actioncomplete
7372 * Fires when an action is completed.
7373 * @param {Form} this
7374 * @param {Action} action The action that completed
7376 actioncomplete : true
7381 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7384 * @cfg {String} method
7385 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7390 * The URL to use for form actions if one isn't supplied in the action options.
7393 * @cfg {Boolean} fileUpload
7394 * Set to true if this form is a file upload.
7398 * @cfg {Object} baseParams
7399 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7403 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7407 * @cfg {Sting} align (left|right) for navbar forms
7412 activeAction : null,
7415 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7416 * element by passing it or its id or mask the form itself by passing in true.
7419 waitMsgTarget : false,
7423 getAutoCreate : function(){
7427 method : this.method || 'POST',
7428 id : this.id || Roo.id(),
7431 if (this.parent().xtype.match(/^Nav/)) {
7432 cfg.cls = 'navbar-form navbar-' + this.align;
7436 if (this.labelAlign == 'left' ) {
7437 cfg.cls += ' form-horizontal';
7443 initEvents : function()
7445 this.el.on('submit', this.onSubmit, this);
7446 // this was added as random key presses on the form where triggering form submit.
7447 this.el.on('keypress', function(e) {
7448 if (e.getCharCode() != 13) {
7451 // we might need to allow it for textareas.. and some other items.
7452 // check e.getTarget().
7454 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7458 Roo.log("keypress blocked");
7466 onSubmit : function(e){
7471 * Returns true if client-side validation on the form is successful.
7474 isValid : function(){
7475 var items = this.getItems();
7477 items.each(function(f){
7486 * Returns true if any fields in this form have changed since their original load.
7489 isDirty : function(){
7491 var items = this.getItems();
7492 items.each(function(f){
7502 * Performs a predefined action (submit or load) or custom actions you define on this form.
7503 * @param {String} actionName The name of the action type
7504 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7505 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7506 * accept other config options):
7508 Property Type Description
7509 ---------------- --------------- ----------------------------------------------------------------------------------
7510 url String The url for the action (defaults to the form's url)
7511 method String The form method to use (defaults to the form's method, or POST if not defined)
7512 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7513 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7514 validate the form on the client (defaults to false)
7516 * @return {BasicForm} this
7518 doAction : function(action, options){
7519 if(typeof action == 'string'){
7520 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7522 if(this.fireEvent('beforeaction', this, action) !== false){
7523 this.beforeAction(action);
7524 action.run.defer(100, action);
7530 beforeAction : function(action){
7531 var o = action.options;
7534 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7536 // not really supported yet.. ??
7538 //if(this.waitMsgTarget === true){
7539 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7540 //}else if(this.waitMsgTarget){
7541 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7542 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7544 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7550 afterAction : function(action, success){
7551 this.activeAction = null;
7552 var o = action.options;
7554 //if(this.waitMsgTarget === true){
7556 //}else if(this.waitMsgTarget){
7557 // this.waitMsgTarget.unmask();
7559 // Roo.MessageBox.updateProgress(1);
7560 // Roo.MessageBox.hide();
7567 Roo.callback(o.success, o.scope, [this, action]);
7568 this.fireEvent('actioncomplete', this, action);
7572 // failure condition..
7573 // we have a scenario where updates need confirming.
7574 // eg. if a locking scenario exists..
7575 // we look for { errors : { needs_confirm : true }} in the response.
7577 (typeof(action.result) != 'undefined') &&
7578 (typeof(action.result.errors) != 'undefined') &&
7579 (typeof(action.result.errors.needs_confirm) != 'undefined')
7582 Roo.log("not supported yet");
7585 Roo.MessageBox.confirm(
7586 "Change requires confirmation",
7587 action.result.errorMsg,
7592 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7602 Roo.callback(o.failure, o.scope, [this, action]);
7603 // show an error message if no failed handler is set..
7604 if (!this.hasListener('actionfailed')) {
7605 Roo.log("need to add dialog support");
7607 Roo.MessageBox.alert("Error",
7608 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7609 action.result.errorMsg :
7610 "Saving Failed, please check your entries or try again"
7615 this.fireEvent('actionfailed', this, action);
7620 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7621 * @param {String} id The value to search for
7624 findField : function(id){
7625 var items = this.getItems();
7626 var field = items.get(id);
7628 items.each(function(f){
7629 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7636 return field || null;
7639 * Mark fields in this form invalid in bulk.
7640 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7641 * @return {BasicForm} this
7643 markInvalid : function(errors){
7644 if(errors instanceof Array){
7645 for(var i = 0, len = errors.length; i < len; i++){
7646 var fieldError = errors[i];
7647 var f = this.findField(fieldError.id);
7649 f.markInvalid(fieldError.msg);
7655 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7656 field.markInvalid(errors[id]);
7660 //Roo.each(this.childForms || [], function (f) {
7661 // f.markInvalid(errors);
7668 * Set values for fields in this form in bulk.
7669 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7670 * @return {BasicForm} this
7672 setValues : function(values){
7673 if(values instanceof Array){ // array of objects
7674 for(var i = 0, len = values.length; i < len; i++){
7676 var f = this.findField(v.id);
7678 f.setValue(v.value);
7679 if(this.trackResetOnLoad){
7680 f.originalValue = f.getValue();
7684 }else{ // object hash
7687 if(typeof values[id] != 'function' && (field = this.findField(id))){
7689 if (field.setFromData &&
7691 field.displayField &&
7692 // combos' with local stores can
7693 // be queried via setValue()
7694 // to set their value..
7695 (field.store && !field.store.isLocal)
7699 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7700 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7701 field.setFromData(sd);
7704 field.setValue(values[id]);
7708 if(this.trackResetOnLoad){
7709 field.originalValue = field.getValue();
7715 //Roo.each(this.childForms || [], function (f) {
7716 // f.setValues(values);
7723 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7724 * they are returned as an array.
7725 * @param {Boolean} asString
7728 getValues : function(asString){
7729 //if (this.childForms) {
7730 // copy values from the child forms
7731 // Roo.each(this.childForms, function (f) {
7732 // this.setValues(f.getValues());
7738 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7739 if(asString === true){
7742 return Roo.urlDecode(fs);
7746 * Returns the fields in this form as an object with key/value pairs.
7747 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7750 getFieldValues : function(with_hidden)
7752 var items = this.getItems();
7754 items.each(function(f){
7758 var v = f.getValue();
7759 if (f.inputType =='radio') {
7760 if (typeof(ret[f.getName()]) == 'undefined') {
7761 ret[f.getName()] = ''; // empty..
7764 if (!f.el.dom.checked) {
7772 // not sure if this supported any more..
7773 if ((typeof(v) == 'object') && f.getRawValue) {
7774 v = f.getRawValue() ; // dates..
7776 // combo boxes where name != hiddenName...
7777 if (f.name != f.getName()) {
7778 ret[f.name] = f.getRawValue();
7780 ret[f.getName()] = v;
7787 * Clears all invalid messages in this form.
7788 * @return {BasicForm} this
7790 clearInvalid : function(){
7791 var items = this.getItems();
7793 items.each(function(f){
7804 * @return {BasicForm} this
7807 var items = this.getItems();
7808 items.each(function(f){
7812 Roo.each(this.childForms || [], function (f) {
7819 getItems : function()
7821 var r=new Roo.util.MixedCollection(false, function(o){
7822 return o.id || (o.id = Roo.id());
7824 var iter = function(el) {
7831 Roo.each(el.items,function(e) {
7851 * Ext JS Library 1.1.1
7852 * Copyright(c) 2006-2007, Ext JS, LLC.
7854 * Originally Released Under LGPL - original licence link has changed is not relivant.
7857 * <script type="text/javascript">
7860 * @class Roo.form.VTypes
7861 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7864 Roo.form.VTypes = function(){
7865 // closure these in so they are only created once.
7866 var alpha = /^[a-zA-Z_]+$/;
7867 var alphanum = /^[a-zA-Z0-9_]+$/;
7868 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
7869 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7871 // All these messages and functions are configurable
7874 * The function used to validate email addresses
7875 * @param {String} value The email address
7877 'email' : function(v){
7878 return email.test(v);
7881 * The error text to display when the email validation function returns false
7884 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7886 * The keystroke filter mask to be applied on email input
7889 'emailMask' : /[a-z0-9_\.\-@]/i,
7892 * The function used to validate URLs
7893 * @param {String} value The URL
7895 'url' : function(v){
7899 * The error text to display when the url validation function returns false
7902 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7905 * The function used to validate alpha values
7906 * @param {String} value The value
7908 'alpha' : function(v){
7909 return alpha.test(v);
7912 * The error text to display when the alpha validation function returns false
7915 'alphaText' : 'This field should only contain letters and _',
7917 * The keystroke filter mask to be applied on alpha input
7920 'alphaMask' : /[a-z_]/i,
7923 * The function used to validate alphanumeric values
7924 * @param {String} value The value
7926 'alphanum' : function(v){
7927 return alphanum.test(v);
7930 * The error text to display when the alphanumeric validation function returns false
7933 'alphanumText' : 'This field should only contain letters, numbers and _',
7935 * The keystroke filter mask to be applied on alphanumeric input
7938 'alphanumMask' : /[a-z0-9_]/i
7948 * @class Roo.bootstrap.Input
7949 * @extends Roo.bootstrap.Component
7950 * Bootstrap Input class
7951 * @cfg {Boolean} disabled is it disabled
7952 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7953 * @cfg {String} name name of the input
7954 * @cfg {string} fieldLabel - the label associated
7955 * @cfg {string} placeholder - placeholder to put in text.
7956 * @cfg {string} before - input group add on before
7957 * @cfg {string} after - input group add on after
7958 * @cfg {string} size - (lg|sm) or leave empty..
7959 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7960 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7961 * @cfg {Number} md colspan out of 12 for computer-sized screens
7962 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7963 * @cfg {string} value default value of the input
7964 * @cfg {Number} labelWidth set the width of label (0-12)
7965 * @cfg {String} labelAlign (top|left)
7966 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7967 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7969 * @cfg {String} align (left|center|right) Default left
7970 * @cfg {Boolean} forceFeedback (true|false) Default false
7976 * Create a new Input
7977 * @param {Object} config The config object
7980 Roo.bootstrap.Input = function(config){
7981 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7986 * Fires when this field receives input focus.
7987 * @param {Roo.form.Field} this
7992 * Fires when this field loses input focus.
7993 * @param {Roo.form.Field} this
7998 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7999 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8000 * @param {Roo.form.Field} this
8001 * @param {Roo.EventObject} e The event object
8006 * Fires just before the field blurs if the field value has changed.
8007 * @param {Roo.form.Field} this
8008 * @param {Mixed} newValue The new value
8009 * @param {Mixed} oldValue The original value
8014 * Fires after the field has been marked as invalid.
8015 * @param {Roo.form.Field} this
8016 * @param {String} msg The validation message
8021 * Fires after the field has been validated with no errors.
8022 * @param {Roo.form.Field} this
8027 * Fires after the key up
8028 * @param {Roo.form.Field} this
8029 * @param {Roo.EventObject} e The event Object
8035 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8037 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8038 automatic validation (defaults to "keyup").
8040 validationEvent : "keyup",
8042 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8044 validateOnBlur : true,
8046 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8048 validationDelay : 250,
8050 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8052 focusClass : "x-form-focus", // not needed???
8056 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8058 invalidClass : "has-warning",
8061 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8063 validClass : "has-success",
8066 * @cfg {Boolean} hasFeedback (true|false) default true
8071 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8073 invalidFeedbackClass : "glyphicon-warning-sign",
8076 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8078 validFeedbackClass : "glyphicon-ok",
8081 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8083 selectOnFocus : false,
8086 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8090 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8095 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8097 disableKeyFilter : false,
8100 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8104 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8108 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8110 blankText : "This field is required",
8113 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8117 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8119 maxLength : Number.MAX_VALUE,
8121 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8123 minLengthText : "The minimum length for this field is {0}",
8125 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8127 maxLengthText : "The maximum length for this field is {0}",
8131 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8132 * If available, this function will be called only after the basic validators all return true, and will be passed the
8133 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8137 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8138 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8139 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8143 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8147 autocomplete: false,
8166 formatedValue : false,
8167 forceFeedback : false,
8169 parentLabelAlign : function()
8172 while (parent.parent()) {
8173 parent = parent.parent();
8174 if (typeof(parent.labelAlign) !='undefined') {
8175 return parent.labelAlign;
8182 getAutoCreate : function(){
8184 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8190 if(this.inputType != 'hidden'){
8191 cfg.cls = 'form-group' //input-group
8197 type : this.inputType,
8199 cls : 'form-control',
8200 placeholder : this.placeholder || '',
8201 autocomplete : this.autocomplete || 'new-password'
8206 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8209 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8210 input.maxLength = this.maxLength;
8213 if (this.disabled) {
8214 input.disabled=true;
8217 if (this.readOnly) {
8218 input.readonly=true;
8222 input.name = this.name;
8225 input.cls += ' input-' + this.size;
8228 ['xs','sm','md','lg'].map(function(size){
8229 if (settings[size]) {
8230 cfg.cls += ' col-' + size + '-' + settings[size];
8234 var inputblock = input;
8238 cls: 'glyphicon form-control-feedback'
8241 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8244 cls : 'has-feedback',
8252 if (this.before || this.after) {
8255 cls : 'input-group',
8259 if (this.before && typeof(this.before) == 'string') {
8261 inputblock.cn.push({
8263 cls : 'roo-input-before input-group-addon',
8267 if (this.before && typeof(this.before) == 'object') {
8268 this.before = Roo.factory(this.before);
8270 inputblock.cn.push({
8272 cls : 'roo-input-before input-group-' +
8273 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8277 inputblock.cn.push(input);
8279 if (this.after && typeof(this.after) == 'string') {
8280 inputblock.cn.push({
8282 cls : 'roo-input-after input-group-addon',
8286 if (this.after && typeof(this.after) == 'object') {
8287 this.after = Roo.factory(this.after);
8289 inputblock.cn.push({
8291 cls : 'roo-input-after input-group-' +
8292 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8296 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8297 inputblock.cls += ' has-feedback';
8298 inputblock.cn.push(feedback);
8302 if (align ==='left' && this.fieldLabel.length) {
8309 cls : 'control-label col-sm-' + this.labelWidth,
8310 html : this.fieldLabel
8314 cls : "col-sm-" + (12 - this.labelWidth),
8321 } else if ( this.fieldLabel.length) {
8327 //cls : 'input-group-addon',
8328 html : this.fieldLabel
8347 if (this.parentType === 'Navbar' && this.parent().bar) {
8348 cfg.cls += ' navbar-form';
8355 * return the real input element.
8357 inputEl: function ()
8359 return this.el.select('input.form-control',true).first();
8362 tooltipEl : function()
8364 return this.inputEl();
8367 setDisabled : function(v)
8369 var i = this.inputEl().dom;
8371 i.removeAttribute('disabled');
8375 i.setAttribute('disabled','true');
8377 initEvents : function()
8380 this.inputEl().on("keydown" , this.fireKey, this);
8381 this.inputEl().on("focus", this.onFocus, this);
8382 this.inputEl().on("blur", this.onBlur, this);
8384 this.inputEl().relayEvent('keyup', this);
8386 // reference to original value for reset
8387 this.originalValue = this.getValue();
8388 //Roo.form.TextField.superclass.initEvents.call(this);
8389 if(this.validationEvent == 'keyup'){
8390 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8391 this.inputEl().on('keyup', this.filterValidation, this);
8393 else if(this.validationEvent !== false){
8394 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8397 if(this.selectOnFocus){
8398 this.on("focus", this.preFocus, this);
8401 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8402 this.inputEl().on("keypress", this.filterKeys, this);
8405 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8406 this.el.on("click", this.autoSize, this);
8409 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8410 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8413 if (typeof(this.before) == 'object') {
8414 this.before.render(this.el.select('.roo-input-before',true).first());
8416 if (typeof(this.after) == 'object') {
8417 this.after.render(this.el.select('.roo-input-after',true).first());
8422 filterValidation : function(e){
8423 if(!e.isNavKeyPress()){
8424 this.validationTask.delay(this.validationDelay);
8428 * Validates the field value
8429 * @return {Boolean} True if the value is valid, else false
8431 validate : function(){
8432 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8433 if(this.disabled || this.validateValue(this.getRawValue())){
8444 * Validates a value according to the field's validation rules and marks the field as invalid
8445 * if the validation fails
8446 * @param {Mixed} value The value to validate
8447 * @return {Boolean} True if the value is valid, else false
8449 validateValue : function(value){
8450 if(value.length < 1) { // if it's blank
8451 if(this.allowBlank){
8457 if(value.length < this.minLength){
8460 if(value.length > this.maxLength){
8464 var vt = Roo.form.VTypes;
8465 if(!vt[this.vtype](value, this)){
8469 if(typeof this.validator == "function"){
8470 var msg = this.validator(value);
8476 if(this.regex && !this.regex.test(value)){
8486 fireKey : function(e){
8487 //Roo.log('field ' + e.getKey());
8488 if(e.isNavKeyPress()){
8489 this.fireEvent("specialkey", this, e);
8492 focus : function (selectText){
8494 this.inputEl().focus();
8495 if(selectText === true){
8496 this.inputEl().dom.select();
8502 onFocus : function(){
8503 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8504 // this.el.addClass(this.focusClass);
8507 this.hasFocus = true;
8508 this.startValue = this.getValue();
8509 this.fireEvent("focus", this);
8513 beforeBlur : Roo.emptyFn,
8517 onBlur : function(){
8519 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8520 //this.el.removeClass(this.focusClass);
8522 this.hasFocus = false;
8523 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8526 var v = this.getValue();
8527 if(String(v) !== String(this.startValue)){
8528 this.fireEvent('change', this, v, this.startValue);
8530 this.fireEvent("blur", this);
8534 * Resets the current field value to the originally loaded value and clears any validation messages
8537 this.setValue(this.originalValue);
8541 * Returns the name of the field
8542 * @return {Mixed} name The name field
8544 getName: function(){
8548 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8549 * @return {Mixed} value The field value
8551 getValue : function(){
8553 var v = this.inputEl().getValue();
8558 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8559 * @return {Mixed} value The field value
8561 getRawValue : function(){
8562 var v = this.inputEl().getValue();
8568 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8569 * @param {Mixed} value The value to set
8571 setRawValue : function(v){
8572 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8575 selectText : function(start, end){
8576 var v = this.getRawValue();
8578 start = start === undefined ? 0 : start;
8579 end = end === undefined ? v.length : end;
8580 var d = this.inputEl().dom;
8581 if(d.setSelectionRange){
8582 d.setSelectionRange(start, end);
8583 }else if(d.createTextRange){
8584 var range = d.createTextRange();
8585 range.moveStart("character", start);
8586 range.moveEnd("character", v.length-end);
8593 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8594 * @param {Mixed} value The value to set
8596 setValue : function(v){
8599 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8605 processValue : function(value){
8606 if(this.stripCharsRe){
8607 var newValue = value.replace(this.stripCharsRe, '');
8608 if(newValue !== value){
8609 this.setRawValue(newValue);
8616 preFocus : function(){
8618 if(this.selectOnFocus){
8619 this.inputEl().dom.select();
8622 filterKeys : function(e){
8624 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8627 var c = e.getCharCode(), cc = String.fromCharCode(c);
8628 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8631 if(!this.maskRe.test(cc)){
8636 * Clear any invalid styles/messages for this field
8638 clearInvalid : function(){
8640 if(!this.el || this.preventMark){ // not rendered
8644 var label = this.el.select('label', true).first();
8645 var icon = this.el.select('i.fa-star', true).first();
8651 this.el.removeClass(this.invalidClass);
8653 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8655 var feedback = this.el.select('.form-control-feedback', true).first();
8658 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
8663 this.fireEvent('valid', this);
8667 * Mark this field as valid
8669 markValid : function()
8671 if(!this.el || this.preventMark){ // not rendered
8675 this.el.removeClass([this.invalidClass, this.validClass]);
8677 var feedback = this.el.select('.form-control-feedback', true).first();
8680 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8683 if(this.disabled || this.allowBlank){
8687 var formGroup = this.el.findParent('.form-group', false, true);
8691 var label = formGroup.select('label', true).first();
8692 var icon = formGroup.select('i.fa-star', true).first();
8699 this.el.addClass(this.validClass);
8701 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
8703 var feedback = this.el.select('.form-control-feedback', true).first();
8706 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8707 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8712 this.fireEvent('valid', this);
8716 * Mark this field as invalid
8717 * @param {String} msg The validation message
8719 markInvalid : function(msg)
8721 if(!this.el || this.preventMark){ // not rendered
8725 this.el.removeClass([this.invalidClass, this.validClass]);
8727 var feedback = this.el.select('.form-control-feedback', true).first();
8730 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8733 if(this.disabled || this.allowBlank){
8737 var formGroup = this.el.findParent('.form-group', false, true);
8740 var label = formGroup.select('label', true).first();
8741 var icon = formGroup.select('i.fa-star', true).first();
8743 if(!this.getValue().length && label && !icon){
8744 this.el.findParent('.form-group', false, true).createChild({
8746 cls : 'text-danger fa fa-lg fa-star',
8747 tooltip : 'This field is required',
8748 style : 'margin-right:5px;'
8754 this.el.addClass(this.invalidClass);
8756 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8758 var feedback = this.el.select('.form-control-feedback', true).first();
8761 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8763 if(this.getValue().length || this.forceFeedback){
8764 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8771 this.fireEvent('invalid', this, msg);
8774 SafariOnKeyDown : function(event)
8776 // this is a workaround for a password hang bug on chrome/ webkit.
8778 var isSelectAll = false;
8780 if(this.inputEl().dom.selectionEnd > 0){
8781 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8783 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8784 event.preventDefault();
8789 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8791 event.preventDefault();
8792 // this is very hacky as keydown always get's upper case.
8794 var cc = String.fromCharCode(event.getCharCode());
8795 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8799 adjustWidth : function(tag, w){
8800 tag = tag.toLowerCase();
8801 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8802 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8806 if(tag == 'textarea'){
8809 }else if(Roo.isOpera){
8813 if(tag == 'textarea'){
8832 * @class Roo.bootstrap.TextArea
8833 * @extends Roo.bootstrap.Input
8834 * Bootstrap TextArea class
8835 * @cfg {Number} cols Specifies the visible width of a text area
8836 * @cfg {Number} rows Specifies the visible number of lines in a text area
8837 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8838 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8839 * @cfg {string} html text
8842 * Create a new TextArea
8843 * @param {Object} config The config object
8846 Roo.bootstrap.TextArea = function(config){
8847 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8851 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8861 getAutoCreate : function(){
8863 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8874 value : this.value || '',
8875 html: this.html || '',
8876 cls : 'form-control',
8877 placeholder : this.placeholder || ''
8881 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8882 input.maxLength = this.maxLength;
8886 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8890 input.cols = this.cols;
8893 if (this.readOnly) {
8894 input.readonly = true;
8898 input.name = this.name;
8902 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8906 ['xs','sm','md','lg'].map(function(size){
8907 if (settings[size]) {
8908 cfg.cls += ' col-' + size + '-' + settings[size];
8912 var inputblock = input;
8914 if(this.hasFeedback && !this.allowBlank){
8918 cls: 'glyphicon form-control-feedback'
8922 cls : 'has-feedback',
8931 if (this.before || this.after) {
8934 cls : 'input-group',
8938 inputblock.cn.push({
8940 cls : 'input-group-addon',
8945 inputblock.cn.push(input);
8947 if(this.hasFeedback && !this.allowBlank){
8948 inputblock.cls += ' has-feedback';
8949 inputblock.cn.push(feedback);
8953 inputblock.cn.push({
8955 cls : 'input-group-addon',
8962 if (align ==='left' && this.fieldLabel.length) {
8963 // Roo.log("left and has label");
8969 cls : 'control-label col-sm-' + this.labelWidth,
8970 html : this.fieldLabel
8974 cls : "col-sm-" + (12 - this.labelWidth),
8981 } else if ( this.fieldLabel.length) {
8982 // Roo.log(" label");
8987 //cls : 'input-group-addon',
8988 html : this.fieldLabel
8998 // Roo.log(" no label && no align");
9008 if (this.disabled) {
9009 input.disabled=true;
9016 * return the real textarea element.
9018 inputEl: function ()
9020 return this.el.select('textarea.form-control',true).first();
9024 * Clear any invalid styles/messages for this field
9026 clearInvalid : function()
9029 if(!this.el || this.preventMark){ // not rendered
9033 var label = this.el.select('label', true).first();
9034 var icon = this.el.select('i.fa-star', true).first();
9040 this.el.removeClass(this.invalidClass);
9042 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9044 var feedback = this.el.select('.form-control-feedback', true).first();
9047 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9052 this.fireEvent('valid', this);
9056 * Mark this field as valid
9058 markValid : function()
9060 if(!this.el || this.preventMark){ // not rendered
9064 this.el.removeClass([this.invalidClass, this.validClass]);
9066 var feedback = this.el.select('.form-control-feedback', true).first();
9069 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9072 if(this.disabled || this.allowBlank){
9076 var label = this.el.select('label', true).first();
9077 var icon = this.el.select('i.fa-star', true).first();
9083 this.el.addClass(this.validClass);
9085 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9087 var feedback = this.el.select('.form-control-feedback', true).first();
9090 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9091 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9096 this.fireEvent('valid', this);
9100 * Mark this field as invalid
9101 * @param {String} msg The validation message
9103 markInvalid : function(msg)
9105 if(!this.el || this.preventMark){ // not rendered
9109 this.el.removeClass([this.invalidClass, this.validClass]);
9111 var feedback = this.el.select('.form-control-feedback', true).first();
9114 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9117 if(this.disabled || this.allowBlank){
9121 var label = this.el.select('label', true).first();
9122 var icon = this.el.select('i.fa-star', true).first();
9124 if(!this.getValue().length && label && !icon){
9125 this.el.createChild({
9127 cls : 'text-danger fa fa-lg fa-star',
9128 tooltip : 'This field is required',
9129 style : 'margin-right:5px;'
9133 this.el.addClass(this.invalidClass);
9135 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9137 var feedback = this.el.select('.form-control-feedback', true).first();
9140 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9142 if(this.getValue().length || this.forceFeedback){
9143 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9150 this.fireEvent('invalid', this, msg);
9158 * trigger field - base class for combo..
9163 * @class Roo.bootstrap.TriggerField
9164 * @extends Roo.bootstrap.Input
9165 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9166 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9167 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9168 * for which you can provide a custom implementation. For example:
9170 var trigger = new Roo.bootstrap.TriggerField();
9171 trigger.onTriggerClick = myTriggerFn;
9172 trigger.applyTo('my-field');
9175 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9176 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9177 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9178 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9179 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9182 * Create a new TriggerField.
9183 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9184 * to the base TextField)
9186 Roo.bootstrap.TriggerField = function(config){
9187 this.mimicing = false;
9188 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9191 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9193 * @cfg {String} triggerClass A CSS class to apply to the trigger
9196 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9201 * @cfg {Boolean} removable (true|false) special filter default false
9205 /** @cfg {Boolean} grow @hide */
9206 /** @cfg {Number} growMin @hide */
9207 /** @cfg {Number} growMax @hide */
9213 autoSize: Roo.emptyFn,
9220 actionMode : 'wrap',
9225 getAutoCreate : function(){
9227 var align = this.labelAlign || this.parentLabelAlign();
9232 cls: 'form-group' //input-group
9239 type : this.inputType,
9240 cls : 'form-control',
9241 autocomplete: 'new-password',
9242 placeholder : this.placeholder || ''
9246 input.name = this.name;
9249 input.cls += ' input-' + this.size;
9252 if (this.disabled) {
9253 input.disabled=true;
9256 var inputblock = input;
9258 if(this.hasFeedback && !this.allowBlank){
9262 cls: 'glyphicon form-control-feedback'
9265 if(this.removable && !this.editable && !this.tickable){
9267 cls : 'has-feedback',
9273 cls : 'roo-combo-removable-btn close'
9280 cls : 'has-feedback',
9289 if(this.removable && !this.editable && !this.tickable){
9291 cls : 'roo-removable',
9297 cls : 'roo-combo-removable-btn close'
9304 if (this.before || this.after) {
9307 cls : 'input-group',
9311 inputblock.cn.push({
9313 cls : 'input-group-addon',
9318 inputblock.cn.push(input);
9320 if(this.hasFeedback && !this.allowBlank){
9321 inputblock.cls += ' has-feedback';
9322 inputblock.cn.push(feedback);
9326 inputblock.cn.push({
9328 cls : 'input-group-addon',
9341 cls: 'form-hidden-field'
9355 cls: 'form-hidden-field'
9359 cls: 'roo-select2-choices',
9363 cls: 'roo-select2-search-field',
9376 cls: 'roo-select2-container input-group',
9381 // cls: 'typeahead typeahead-long dropdown-menu',
9382 // style: 'display:none'
9387 if(!this.multiple && this.showToggleBtn){
9393 if (this.caret != false) {
9396 cls: 'fa fa-' + this.caret
9403 cls : 'input-group-addon btn dropdown-toggle',
9408 cls: 'combobox-clear',
9422 combobox.cls += ' roo-select2-container-multi';
9425 if (align ==='left' && this.fieldLabel.length) {
9427 // Roo.log("left and has label");
9433 cls : 'control-label col-sm-' + this.labelWidth,
9434 html : this.fieldLabel
9438 cls : "col-sm-" + (12 - this.labelWidth),
9445 } else if ( this.fieldLabel.length) {
9446 // Roo.log(" label");
9451 //cls : 'input-group-addon',
9452 html : this.fieldLabel
9462 // Roo.log(" no label && no align");
9469 ['xs','sm','md','lg'].map(function(size){
9470 if (settings[size]) {
9471 cfg.cls += ' col-' + size + '-' + settings[size];
9482 onResize : function(w, h){
9483 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
9484 // if(typeof w == 'number'){
9485 // var x = w - this.trigger.getWidth();
9486 // this.inputEl().setWidth(this.adjustWidth('input', x));
9487 // this.trigger.setStyle('left', x+'px');
9492 adjustSize : Roo.BoxComponent.prototype.adjustSize,
9495 getResizeEl : function(){
9496 return this.inputEl();
9500 getPositionEl : function(){
9501 return this.inputEl();
9505 alignErrorIcon : function(){
9506 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
9510 initEvents : function(){
9514 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
9515 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
9516 if(!this.multiple && this.showToggleBtn){
9517 this.trigger = this.el.select('span.dropdown-toggle',true).first();
9518 if(this.hideTrigger){
9519 this.trigger.setDisplayed(false);
9521 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
9525 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
9528 if(this.removable && !this.editable && !this.tickable){
9529 var close = this.closeTriggerEl();
9532 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
9533 close.on('click', this.removeBtnClick, this, close);
9537 //this.trigger.addClassOnOver('x-form-trigger-over');
9538 //this.trigger.addClassOnClick('x-form-trigger-click');
9541 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
9545 closeTriggerEl : function()
9547 var close = this.el.select('.roo-combo-removable-btn', true).first();
9548 return close ? close : false;
9551 removeBtnClick : function(e, h, el)
9555 if(this.fireEvent("remove", this) !== false){
9557 this.fireEvent("afterremove", this)
9561 createList : function()
9563 this.list = Roo.get(document.body).createChild({
9565 cls: 'typeahead typeahead-long dropdown-menu',
9566 style: 'display:none'
9569 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
9574 initTrigger : function(){
9579 onDestroy : function(){
9581 this.trigger.removeAllListeners();
9582 // this.trigger.remove();
9585 // this.wrap.remove();
9587 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
9591 onFocus : function(){
9592 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
9595 this.wrap.addClass('x-trigger-wrap-focus');
9596 this.mimicing = true;
9597 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
9598 if(this.monitorTab){
9599 this.el.on("keydown", this.checkTab, this);
9606 checkTab : function(e){
9607 if(e.getKey() == e.TAB){
9613 onBlur : function(){
9618 mimicBlur : function(e, t){
9620 if(!this.wrap.contains(t) && this.validateBlur()){
9627 triggerBlur : function(){
9628 this.mimicing = false;
9629 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
9630 if(this.monitorTab){
9631 this.el.un("keydown", this.checkTab, this);
9633 //this.wrap.removeClass('x-trigger-wrap-focus');
9634 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
9638 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
9639 validateBlur : function(e, t){
9644 onDisable : function(){
9645 this.inputEl().dom.disabled = true;
9646 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
9648 // this.wrap.addClass('x-item-disabled');
9653 onEnable : function(){
9654 this.inputEl().dom.disabled = false;
9655 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
9657 // this.el.removeClass('x-item-disabled');
9662 onShow : function(){
9663 var ae = this.getActionEl();
9666 ae.dom.style.display = '';
9667 ae.dom.style.visibility = 'visible';
9673 onHide : function(){
9674 var ae = this.getActionEl();
9675 ae.dom.style.display = 'none';
9679 * The function that should handle the trigger's click event. This method does nothing by default until overridden
9680 * by an implementing function.
9682 * @param {EventObject} e
9684 onTriggerClick : Roo.emptyFn
9688 * Ext JS Library 1.1.1
9689 * Copyright(c) 2006-2007, Ext JS, LLC.
9691 * Originally Released Under LGPL - original licence link has changed is not relivant.
9694 * <script type="text/javascript">
9699 * @class Roo.data.SortTypes
9701 * Defines the default sorting (casting?) comparison functions used when sorting data.
9703 Roo.data.SortTypes = {
9705 * Default sort that does nothing
9706 * @param {Mixed} s The value being converted
9707 * @return {Mixed} The comparison value
9714 * The regular expression used to strip tags
9718 stripTagsRE : /<\/?[^>]+>/gi,
9721 * Strips all HTML tags to sort on text only
9722 * @param {Mixed} s The value being converted
9723 * @return {String} The comparison value
9725 asText : function(s){
9726 return String(s).replace(this.stripTagsRE, "");
9730 * Strips all HTML tags to sort on text only - Case insensitive
9731 * @param {Mixed} s The value being converted
9732 * @return {String} The comparison value
9734 asUCText : function(s){
9735 return String(s).toUpperCase().replace(this.stripTagsRE, "");
9739 * Case insensitive string
9740 * @param {Mixed} s The value being converted
9741 * @return {String} The comparison value
9743 asUCString : function(s) {
9744 return String(s).toUpperCase();
9749 * @param {Mixed} s The value being converted
9750 * @return {Number} The comparison value
9752 asDate : function(s) {
9756 if(s instanceof Date){
9759 return Date.parse(String(s));
9764 * @param {Mixed} s The value being converted
9765 * @return {Float} The comparison value
9767 asFloat : function(s) {
9768 var val = parseFloat(String(s).replace(/,/g, ""));
9777 * @param {Mixed} s The value being converted
9778 * @return {Number} The comparison value
9780 asInt : function(s) {
9781 var val = parseInt(String(s).replace(/,/g, ""));
9789 * Ext JS Library 1.1.1
9790 * Copyright(c) 2006-2007, Ext JS, LLC.
9792 * Originally Released Under LGPL - original licence link has changed is not relivant.
9795 * <script type="text/javascript">
9799 * @class Roo.data.Record
9800 * Instances of this class encapsulate both record <em>definition</em> information, and record
9801 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
9802 * to access Records cached in an {@link Roo.data.Store} object.<br>
9804 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
9805 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
9808 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
9810 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
9811 * {@link #create}. The parameters are the same.
9812 * @param {Array} data An associative Array of data values keyed by the field name.
9813 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
9814 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
9815 * not specified an integer id is generated.
9817 Roo.data.Record = function(data, id){
9818 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
9823 * Generate a constructor for a specific record layout.
9824 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
9825 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
9826 * Each field definition object may contain the following properties: <ul>
9827 * <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,
9828 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
9829 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
9830 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
9831 * is being used, then this is a string containing the javascript expression to reference the data relative to
9832 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
9833 * to the data item relative to the record element. If the mapping expression is the same as the field name,
9834 * this may be omitted.</p></li>
9835 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
9836 * <ul><li>auto (Default, implies no conversion)</li>
9841 * <li>date</li></ul></p></li>
9842 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9843 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9844 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9845 * by the Reader into an object that will be stored in the Record. It is passed the
9846 * following parameters:<ul>
9847 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9849 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9851 * <br>usage:<br><pre><code>
9852 var TopicRecord = Roo.data.Record.create(
9853 {name: 'title', mapping: 'topic_title'},
9854 {name: 'author', mapping: 'username'},
9855 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9856 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9857 {name: 'lastPoster', mapping: 'user2'},
9858 {name: 'excerpt', mapping: 'post_text'}
9861 var myNewRecord = new TopicRecord({
9862 title: 'Do my job please',
9865 lastPost: new Date(),
9866 lastPoster: 'Animal',
9867 excerpt: 'No way dude!'
9869 myStore.add(myNewRecord);
9874 Roo.data.Record.create = function(o){
9876 f.superclass.constructor.apply(this, arguments);
9878 Roo.extend(f, Roo.data.Record);
9879 var p = f.prototype;
9880 p.fields = new Roo.util.MixedCollection(false, function(field){
9883 for(var i = 0, len = o.length; i < len; i++){
9884 p.fields.add(new Roo.data.Field(o[i]));
9886 f.getField = function(name){
9887 return p.fields.get(name);
9892 Roo.data.Record.AUTO_ID = 1000;
9893 Roo.data.Record.EDIT = 'edit';
9894 Roo.data.Record.REJECT = 'reject';
9895 Roo.data.Record.COMMIT = 'commit';
9897 Roo.data.Record.prototype = {
9899 * Readonly flag - true if this record has been modified.
9908 join : function(store){
9913 * Set the named field to the specified value.
9914 * @param {String} name The name of the field to set.
9915 * @param {Object} value The value to set the field to.
9917 set : function(name, value){
9918 if(this.data[name] == value){
9925 if(typeof this.modified[name] == 'undefined'){
9926 this.modified[name] = this.data[name];
9928 this.data[name] = value;
9929 if(!this.editing && this.store){
9930 this.store.afterEdit(this);
9935 * Get the value of the named field.
9936 * @param {String} name The name of the field to get the value of.
9937 * @return {Object} The value of the field.
9939 get : function(name){
9940 return this.data[name];
9944 beginEdit : function(){
9945 this.editing = true;
9950 cancelEdit : function(){
9951 this.editing = false;
9952 delete this.modified;
9956 endEdit : function(){
9957 this.editing = false;
9958 if(this.dirty && this.store){
9959 this.store.afterEdit(this);
9964 * Usually called by the {@link Roo.data.Store} which owns the Record.
9965 * Rejects all changes made to the Record since either creation, or the last commit operation.
9966 * Modified fields are reverted to their original values.
9968 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9969 * of reject operations.
9971 reject : function(){
9972 var m = this.modified;
9974 if(typeof m[n] != "function"){
9975 this.data[n] = m[n];
9979 delete this.modified;
9980 this.editing = false;
9982 this.store.afterReject(this);
9987 * Usually called by the {@link Roo.data.Store} which owns the Record.
9988 * Commits all changes made to the Record since either creation, or the last commit operation.
9990 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9991 * of commit operations.
9993 commit : function(){
9995 delete this.modified;
9996 this.editing = false;
9998 this.store.afterCommit(this);
10003 hasError : function(){
10004 return this.error != null;
10008 clearError : function(){
10013 * Creates a copy of this record.
10014 * @param {String} id (optional) A new record id if you don't want to use this record's id
10017 copy : function(newId) {
10018 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10022 * Ext JS Library 1.1.1
10023 * Copyright(c) 2006-2007, Ext JS, LLC.
10025 * Originally Released Under LGPL - original licence link has changed is not relivant.
10028 * <script type="text/javascript">
10034 * @class Roo.data.Store
10035 * @extends Roo.util.Observable
10036 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10037 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10039 * 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
10040 * has no knowledge of the format of the data returned by the Proxy.<br>
10042 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10043 * instances from the data object. These records are cached and made available through accessor functions.
10045 * Creates a new Store.
10046 * @param {Object} config A config object containing the objects needed for the Store to access data,
10047 * and read the data into Records.
10049 Roo.data.Store = function(config){
10050 this.data = new Roo.util.MixedCollection(false);
10051 this.data.getKey = function(o){
10054 this.baseParams = {};
10056 this.paramNames = {
10061 "multisort" : "_multisort"
10064 if(config && config.data){
10065 this.inlineData = config.data;
10066 delete config.data;
10069 Roo.apply(this, config);
10071 if(this.reader){ // reader passed
10072 this.reader = Roo.factory(this.reader, Roo.data);
10073 this.reader.xmodule = this.xmodule || false;
10074 if(!this.recordType){
10075 this.recordType = this.reader.recordType;
10077 if(this.reader.onMetaChange){
10078 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10082 if(this.recordType){
10083 this.fields = this.recordType.prototype.fields;
10085 this.modified = [];
10089 * @event datachanged
10090 * Fires when the data cache has changed, and a widget which is using this Store
10091 * as a Record cache should refresh its view.
10092 * @param {Store} this
10094 datachanged : true,
10096 * @event metachange
10097 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10098 * @param {Store} this
10099 * @param {Object} meta The JSON metadata
10104 * Fires when Records have been added to the Store
10105 * @param {Store} this
10106 * @param {Roo.data.Record[]} records The array of Records added
10107 * @param {Number} index The index at which the record(s) were added
10112 * Fires when a Record has been removed from the Store
10113 * @param {Store} this
10114 * @param {Roo.data.Record} record The Record that was removed
10115 * @param {Number} index The index at which the record was removed
10120 * Fires when a Record has been updated
10121 * @param {Store} this
10122 * @param {Roo.data.Record} record The Record that was updated
10123 * @param {String} operation The update operation being performed. Value may be one of:
10125 Roo.data.Record.EDIT
10126 Roo.data.Record.REJECT
10127 Roo.data.Record.COMMIT
10133 * Fires when the data cache has been cleared.
10134 * @param {Store} this
10138 * @event beforeload
10139 * Fires before a request is made for a new data object. If the beforeload handler returns false
10140 * the load action will be canceled.
10141 * @param {Store} this
10142 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10146 * @event beforeloadadd
10147 * Fires after a new set of Records has been loaded.
10148 * @param {Store} this
10149 * @param {Roo.data.Record[]} records The Records that were loaded
10150 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10152 beforeloadadd : true,
10155 * Fires after a new set of Records has been loaded, before they are added to the store.
10156 * @param {Store} this
10157 * @param {Roo.data.Record[]} records The Records that were loaded
10158 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10159 * @params {Object} return from reader
10163 * @event loadexception
10164 * Fires if an exception occurs in the Proxy during loading.
10165 * Called with the signature of the Proxy's "loadexception" event.
10166 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10169 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10170 * @param {Object} load options
10171 * @param {Object} jsonData from your request (normally this contains the Exception)
10173 loadexception : true
10177 this.proxy = Roo.factory(this.proxy, Roo.data);
10178 this.proxy.xmodule = this.xmodule || false;
10179 this.relayEvents(this.proxy, ["loadexception"]);
10181 this.sortToggle = {};
10182 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10184 Roo.data.Store.superclass.constructor.call(this);
10186 if(this.inlineData){
10187 this.loadData(this.inlineData);
10188 delete this.inlineData;
10192 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10194 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10195 * without a remote query - used by combo/forms at present.
10199 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10202 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10205 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10206 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10209 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10210 * on any HTTP request
10213 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10216 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10220 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10221 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10223 remoteSort : false,
10226 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10227 * loaded or when a record is removed. (defaults to false).
10229 pruneModifiedRecords : false,
10232 lastOptions : null,
10235 * Add Records to the Store and fires the add event.
10236 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10238 add : function(records){
10239 records = [].concat(records);
10240 for(var i = 0, len = records.length; i < len; i++){
10241 records[i].join(this);
10243 var index = this.data.length;
10244 this.data.addAll(records);
10245 this.fireEvent("add", this, records, index);
10249 * Remove a Record from the Store and fires the remove event.
10250 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10252 remove : function(record){
10253 var index = this.data.indexOf(record);
10254 this.data.removeAt(index);
10255 if(this.pruneModifiedRecords){
10256 this.modified.remove(record);
10258 this.fireEvent("remove", this, record, index);
10262 * Remove all Records from the Store and fires the clear event.
10264 removeAll : function(){
10266 if(this.pruneModifiedRecords){
10267 this.modified = [];
10269 this.fireEvent("clear", this);
10273 * Inserts Records to the Store at the given index and fires the add event.
10274 * @param {Number} index The start index at which to insert the passed Records.
10275 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10277 insert : function(index, records){
10278 records = [].concat(records);
10279 for(var i = 0, len = records.length; i < len; i++){
10280 this.data.insert(index, records[i]);
10281 records[i].join(this);
10283 this.fireEvent("add", this, records, index);
10287 * Get the index within the cache of the passed Record.
10288 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10289 * @return {Number} The index of the passed Record. Returns -1 if not found.
10291 indexOf : function(record){
10292 return this.data.indexOf(record);
10296 * Get the index within the cache of the Record with the passed id.
10297 * @param {String} id The id of the Record to find.
10298 * @return {Number} The index of the Record. Returns -1 if not found.
10300 indexOfId : function(id){
10301 return this.data.indexOfKey(id);
10305 * Get the Record with the specified id.
10306 * @param {String} id The id of the Record to find.
10307 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10309 getById : function(id){
10310 return this.data.key(id);
10314 * Get the Record at the specified index.
10315 * @param {Number} index The index of the Record to find.
10316 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10318 getAt : function(index){
10319 return this.data.itemAt(index);
10323 * Returns a range of Records between specified indices.
10324 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10325 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10326 * @return {Roo.data.Record[]} An array of Records
10328 getRange : function(start, end){
10329 return this.data.getRange(start, end);
10333 storeOptions : function(o){
10334 o = Roo.apply({}, o);
10337 this.lastOptions = o;
10341 * Loads the Record cache from the configured Proxy using the configured Reader.
10343 * If using remote paging, then the first load call must specify the <em>start</em>
10344 * and <em>limit</em> properties in the options.params property to establish the initial
10345 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10347 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10348 * and this call will return before the new data has been loaded. Perform any post-processing
10349 * in a callback function, or in a "load" event handler.</strong>
10351 * @param {Object} options An object containing properties which control loading options:<ul>
10352 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10353 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10354 * passed the following arguments:<ul>
10355 * <li>r : Roo.data.Record[]</li>
10356 * <li>options: Options object from the load call</li>
10357 * <li>success: Boolean success indicator</li></ul></li>
10358 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10359 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10362 load : function(options){
10363 options = options || {};
10364 if(this.fireEvent("beforeload", this, options) !== false){
10365 this.storeOptions(options);
10366 var p = Roo.apply(options.params || {}, this.baseParams);
10367 // if meta was not loaded from remote source.. try requesting it.
10368 if (!this.reader.metaFromRemote) {
10369 p._requestMeta = 1;
10371 if(this.sortInfo && this.remoteSort){
10372 var pn = this.paramNames;
10373 p[pn["sort"]] = this.sortInfo.field;
10374 p[pn["dir"]] = this.sortInfo.direction;
10376 if (this.multiSort) {
10377 var pn = this.paramNames;
10378 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10381 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10386 * Reloads the Record cache from the configured Proxy using the configured Reader and
10387 * the options from the last load operation performed.
10388 * @param {Object} options (optional) An object containing properties which may override the options
10389 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10390 * the most recently used options are reused).
10392 reload : function(options){
10393 this.load(Roo.applyIf(options||{}, this.lastOptions));
10397 // Called as a callback by the Reader during a load operation.
10398 loadRecords : function(o, options, success){
10399 if(!o || success === false){
10400 if(success !== false){
10401 this.fireEvent("load", this, [], options, o);
10403 if(options.callback){
10404 options.callback.call(options.scope || this, [], options, false);
10408 // if data returned failure - throw an exception.
10409 if (o.success === false) {
10410 // show a message if no listener is registered.
10411 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10412 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10414 // loadmask wil be hooked into this..
10415 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10418 var r = o.records, t = o.totalRecords || r.length;
10420 this.fireEvent("beforeloadadd", this, r, options, o);
10422 if(!options || options.add !== true){
10423 if(this.pruneModifiedRecords){
10424 this.modified = [];
10426 for(var i = 0, len = r.length; i < len; i++){
10430 this.data = this.snapshot;
10431 delete this.snapshot;
10434 this.data.addAll(r);
10435 this.totalLength = t;
10437 this.fireEvent("datachanged", this);
10439 this.totalLength = Math.max(t, this.data.length+r.length);
10442 this.fireEvent("load", this, r, options, o);
10443 if(options.callback){
10444 options.callback.call(options.scope || this, r, options, true);
10450 * Loads data from a passed data block. A Reader which understands the format of the data
10451 * must have been configured in the constructor.
10452 * @param {Object} data The data block from which to read the Records. The format of the data expected
10453 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10454 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10456 loadData : function(o, append){
10457 var r = this.reader.readRecords(o);
10458 this.loadRecords(r, {add: append}, true);
10462 * Gets the number of cached records.
10464 * <em>If using paging, this may not be the total size of the dataset. If the data object
10465 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10466 * the data set size</em>
10468 getCount : function(){
10469 return this.data.length || 0;
10473 * Gets the total number of records in the dataset as returned by the server.
10475 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10476 * the dataset size</em>
10478 getTotalCount : function(){
10479 return this.totalLength || 0;
10483 * Returns the sort state of the Store as an object with two properties:
10485 field {String} The name of the field by which the Records are sorted
10486 direction {String} The sort order, "ASC" or "DESC"
10489 getSortState : function(){
10490 return this.sortInfo;
10494 applySort : function(){
10495 if(this.sortInfo && !this.remoteSort){
10496 var s = this.sortInfo, f = s.field;
10497 var st = this.fields.get(f).sortType;
10498 var fn = function(r1, r2){
10499 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
10500 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
10502 this.data.sort(s.direction, fn);
10503 if(this.snapshot && this.snapshot != this.data){
10504 this.snapshot.sort(s.direction, fn);
10510 * Sets the default sort column and order to be used by the next load operation.
10511 * @param {String} fieldName The name of the field to sort by.
10512 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10514 setDefaultSort : function(field, dir){
10515 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
10519 * Sort the Records.
10520 * If remote sorting is used, the sort is performed on the server, and the cache is
10521 * reloaded. If local sorting is used, the cache is sorted internally.
10522 * @param {String} fieldName The name of the field to sort by.
10523 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
10525 sort : function(fieldName, dir){
10526 var f = this.fields.get(fieldName);
10528 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
10530 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
10531 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
10536 this.sortToggle[f.name] = dir;
10537 this.sortInfo = {field: f.name, direction: dir};
10538 if(!this.remoteSort){
10540 this.fireEvent("datachanged", this);
10542 this.load(this.lastOptions);
10547 * Calls the specified function for each of the Records in the cache.
10548 * @param {Function} fn The function to call. The Record is passed as the first parameter.
10549 * Returning <em>false</em> aborts and exits the iteration.
10550 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
10552 each : function(fn, scope){
10553 this.data.each(fn, scope);
10557 * Gets all records modified since the last commit. Modified records are persisted across load operations
10558 * (e.g., during paging).
10559 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
10561 getModifiedRecords : function(){
10562 return this.modified;
10566 createFilterFn : function(property, value, anyMatch){
10567 if(!value.exec){ // not a regex
10568 value = String(value);
10569 if(value.length == 0){
10572 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
10574 return function(r){
10575 return value.test(r.data[property]);
10580 * Sums the value of <i>property</i> for each record between start and end and returns the result.
10581 * @param {String} property A field on your records
10582 * @param {Number} start The record index to start at (defaults to 0)
10583 * @param {Number} end The last record index to include (defaults to length - 1)
10584 * @return {Number} The sum
10586 sum : function(property, start, end){
10587 var rs = this.data.items, v = 0;
10588 start = start || 0;
10589 end = (end || end === 0) ? end : rs.length-1;
10591 for(var i = start; i <= end; i++){
10592 v += (rs[i].data[property] || 0);
10598 * Filter the records by a specified property.
10599 * @param {String} field A field on your records
10600 * @param {String/RegExp} value Either a string that the field
10601 * should start with or a RegExp to test against the field
10602 * @param {Boolean} anyMatch True to match any part not just the beginning
10604 filter : function(property, value, anyMatch){
10605 var fn = this.createFilterFn(property, value, anyMatch);
10606 return fn ? this.filterBy(fn) : this.clearFilter();
10610 * Filter by a function. The specified function will be called with each
10611 * record in this data source. If the function returns true the record is included,
10612 * otherwise it is filtered.
10613 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10614 * @param {Object} scope (optional) The scope of the function (defaults to this)
10616 filterBy : function(fn, scope){
10617 this.snapshot = this.snapshot || this.data;
10618 this.data = this.queryBy(fn, scope||this);
10619 this.fireEvent("datachanged", this);
10623 * Query the records by a specified property.
10624 * @param {String} field A field on your records
10625 * @param {String/RegExp} value Either a string that the field
10626 * should start with or a RegExp to test against the field
10627 * @param {Boolean} anyMatch True to match any part not just the beginning
10628 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10630 query : function(property, value, anyMatch){
10631 var fn = this.createFilterFn(property, value, anyMatch);
10632 return fn ? this.queryBy(fn) : this.data.clone();
10636 * Query by a function. The specified function will be called with each
10637 * record in this data source. If the function returns true the record is included
10639 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
10640 * @param {Object} scope (optional) The scope of the function (defaults to this)
10641 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
10643 queryBy : function(fn, scope){
10644 var data = this.snapshot || this.data;
10645 return data.filterBy(fn, scope||this);
10649 * Collects unique values for a particular dataIndex from this store.
10650 * @param {String} dataIndex The property to collect
10651 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
10652 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
10653 * @return {Array} An array of the unique values
10655 collect : function(dataIndex, allowNull, bypassFilter){
10656 var d = (bypassFilter === true && this.snapshot) ?
10657 this.snapshot.items : this.data.items;
10658 var v, sv, r = [], l = {};
10659 for(var i = 0, len = d.length; i < len; i++){
10660 v = d[i].data[dataIndex];
10662 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
10671 * Revert to a view of the Record cache with no filtering applied.
10672 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
10674 clearFilter : function(suppressEvent){
10675 if(this.snapshot && this.snapshot != this.data){
10676 this.data = this.snapshot;
10677 delete this.snapshot;
10678 if(suppressEvent !== true){
10679 this.fireEvent("datachanged", this);
10685 afterEdit : function(record){
10686 if(this.modified.indexOf(record) == -1){
10687 this.modified.push(record);
10689 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
10693 afterReject : function(record){
10694 this.modified.remove(record);
10695 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
10699 afterCommit : function(record){
10700 this.modified.remove(record);
10701 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
10705 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
10706 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
10708 commitChanges : function(){
10709 var m = this.modified.slice(0);
10710 this.modified = [];
10711 for(var i = 0, len = m.length; i < len; i++){
10717 * Cancel outstanding changes on all changed records.
10719 rejectChanges : function(){
10720 var m = this.modified.slice(0);
10721 this.modified = [];
10722 for(var i = 0, len = m.length; i < len; i++){
10727 onMetaChange : function(meta, rtype, o){
10728 this.recordType = rtype;
10729 this.fields = rtype.prototype.fields;
10730 delete this.snapshot;
10731 this.sortInfo = meta.sortInfo || this.sortInfo;
10732 this.modified = [];
10733 this.fireEvent('metachange', this, this.reader.meta);
10736 moveIndex : function(data, type)
10738 var index = this.indexOf(data);
10740 var newIndex = index + type;
10744 this.insert(newIndex, data);
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">
10759 * @class Roo.data.SimpleStore
10760 * @extends Roo.data.Store
10761 * Small helper class to make creating Stores from Array data easier.
10762 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
10763 * @cfg {Array} fields An array of field definition objects, or field name strings.
10764 * @cfg {Array} data The multi-dimensional array of data
10766 * @param {Object} config
10768 Roo.data.SimpleStore = function(config){
10769 Roo.data.SimpleStore.superclass.constructor.call(this, {
10771 reader: new Roo.data.ArrayReader({
10774 Roo.data.Record.create(config.fields)
10776 proxy : new Roo.data.MemoryProxy(config.data)
10780 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
10782 * Ext JS Library 1.1.1
10783 * Copyright(c) 2006-2007, Ext JS, LLC.
10785 * Originally Released Under LGPL - original licence link has changed is not relivant.
10788 * <script type="text/javascript">
10793 * @extends Roo.data.Store
10794 * @class Roo.data.JsonStore
10795 * Small helper class to make creating Stores for JSON data easier. <br/>
10797 var store = new Roo.data.JsonStore({
10798 url: 'get-images.php',
10800 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
10803 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
10804 * JsonReader and HttpProxy (unless inline data is provided).</b>
10805 * @cfg {Array} fields An array of field definition objects, or field name strings.
10807 * @param {Object} config
10809 Roo.data.JsonStore = function(c){
10810 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
10811 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
10812 reader: new Roo.data.JsonReader(c, c.fields)
10815 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
10817 * Ext JS Library 1.1.1
10818 * Copyright(c) 2006-2007, Ext JS, LLC.
10820 * Originally Released Under LGPL - original licence link has changed is not relivant.
10823 * <script type="text/javascript">
10827 Roo.data.Field = function(config){
10828 if(typeof config == "string"){
10829 config = {name: config};
10831 Roo.apply(this, config);
10834 this.type = "auto";
10837 var st = Roo.data.SortTypes;
10838 // named sortTypes are supported, here we look them up
10839 if(typeof this.sortType == "string"){
10840 this.sortType = st[this.sortType];
10843 // set default sortType for strings and dates
10844 if(!this.sortType){
10847 this.sortType = st.asUCString;
10850 this.sortType = st.asDate;
10853 this.sortType = st.none;
10858 var stripRe = /[\$,%]/g;
10860 // prebuilt conversion function for this field, instead of
10861 // switching every time we're reading a value
10863 var cv, dateFormat = this.dateFormat;
10868 cv = function(v){ return v; };
10871 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10875 return v !== undefined && v !== null && v !== '' ?
10876 parseInt(String(v).replace(stripRe, ""), 10) : '';
10881 return v !== undefined && v !== null && v !== '' ?
10882 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10887 cv = function(v){ return v === true || v === "true" || v == 1; };
10894 if(v instanceof Date){
10898 if(dateFormat == "timestamp"){
10899 return new Date(v*1000);
10901 return Date.parseDate(v, dateFormat);
10903 var parsed = Date.parse(v);
10904 return parsed ? new Date(parsed) : null;
10913 Roo.data.Field.prototype = {
10921 * Ext JS Library 1.1.1
10922 * Copyright(c) 2006-2007, Ext JS, LLC.
10924 * Originally Released Under LGPL - original licence link has changed is not relivant.
10927 * <script type="text/javascript">
10930 // Base class for reading structured data from a data source. This class is intended to be
10931 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10934 * @class Roo.data.DataReader
10935 * Base class for reading structured data from a data source. This class is intended to be
10936 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10939 Roo.data.DataReader = function(meta, recordType){
10943 this.recordType = recordType instanceof Array ?
10944 Roo.data.Record.create(recordType) : recordType;
10947 Roo.data.DataReader.prototype = {
10949 * Create an empty record
10950 * @param {Object} data (optional) - overlay some values
10951 * @return {Roo.data.Record} record created.
10953 newRow : function(d) {
10955 this.recordType.prototype.fields.each(function(c) {
10957 case 'int' : da[c.name] = 0; break;
10958 case 'date' : da[c.name] = new Date(); break;
10959 case 'float' : da[c.name] = 0.0; break;
10960 case 'boolean' : da[c.name] = false; break;
10961 default : da[c.name] = ""; break;
10965 return new this.recordType(Roo.apply(da, d));
10970 * Ext JS Library 1.1.1
10971 * Copyright(c) 2006-2007, Ext JS, LLC.
10973 * Originally Released Under LGPL - original licence link has changed is not relivant.
10976 * <script type="text/javascript">
10980 * @class Roo.data.DataProxy
10981 * @extends Roo.data.Observable
10982 * This class is an abstract base class for implementations which provide retrieval of
10983 * unformatted data objects.<br>
10985 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10986 * (of the appropriate type which knows how to parse the data object) to provide a block of
10987 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10989 * Custom implementations must implement the load method as described in
10990 * {@link Roo.data.HttpProxy#load}.
10992 Roo.data.DataProxy = function(){
10995 * @event beforeload
10996 * Fires before a network request is made to retrieve a data object.
10997 * @param {Object} This DataProxy object.
10998 * @param {Object} params The params parameter to the load function.
11003 * Fires before the load method's callback is called.
11004 * @param {Object} This DataProxy object.
11005 * @param {Object} o The data object.
11006 * @param {Object} arg The callback argument object passed to the load function.
11010 * @event loadexception
11011 * Fires if an Exception occurs during data retrieval.
11012 * @param {Object} This DataProxy object.
11013 * @param {Object} o The data object.
11014 * @param {Object} arg The callback argument object passed to the load function.
11015 * @param {Object} e The Exception.
11017 loadexception : true
11019 Roo.data.DataProxy.superclass.constructor.call(this);
11022 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11025 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11029 * Ext JS Library 1.1.1
11030 * Copyright(c) 2006-2007, Ext JS, LLC.
11032 * Originally Released Under LGPL - original licence link has changed is not relivant.
11035 * <script type="text/javascript">
11038 * @class Roo.data.MemoryProxy
11039 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11040 * to the Reader when its load method is called.
11042 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11044 Roo.data.MemoryProxy = function(data){
11048 Roo.data.MemoryProxy.superclass.constructor.call(this);
11052 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11055 * Load data from the requested source (in this case an in-memory
11056 * data object passed to the constructor), read the data object into
11057 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11058 * process that block using the passed callback.
11059 * @param {Object} params This parameter is not used by the MemoryProxy class.
11060 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11061 * object into a block of Roo.data.Records.
11062 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11063 * The function must be passed <ul>
11064 * <li>The Record block object</li>
11065 * <li>The "arg" argument from the load function</li>
11066 * <li>A boolean success indicator</li>
11068 * @param {Object} scope The scope in which to call the callback
11069 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11071 load : function(params, reader, callback, scope, arg){
11072 params = params || {};
11075 result = reader.readRecords(this.data);
11077 this.fireEvent("loadexception", this, arg, null, e);
11078 callback.call(scope, null, arg, false);
11081 callback.call(scope, result, arg, true);
11085 update : function(params, records){
11090 * Ext JS Library 1.1.1
11091 * Copyright(c) 2006-2007, Ext JS, LLC.
11093 * Originally Released Under LGPL - original licence link has changed is not relivant.
11096 * <script type="text/javascript">
11099 * @class Roo.data.HttpProxy
11100 * @extends Roo.data.DataProxy
11101 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11102 * configured to reference a certain URL.<br><br>
11104 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11105 * from which the running page was served.<br><br>
11107 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11109 * Be aware that to enable the browser to parse an XML document, the server must set
11110 * the Content-Type header in the HTTP response to "text/xml".
11112 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11113 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11114 * will be used to make the request.
11116 Roo.data.HttpProxy = function(conn){
11117 Roo.data.HttpProxy.superclass.constructor.call(this);
11118 // is conn a conn config or a real conn?
11120 this.useAjax = !conn || !conn.events;
11124 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11125 // thse are take from connection...
11128 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11131 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11132 * extra parameters to each request made by this object. (defaults to undefined)
11135 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11136 * to each request made by this object. (defaults to undefined)
11139 * @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)
11142 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11145 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11151 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11155 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11156 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11157 * a finer-grained basis than the DataProxy events.
11159 getConnection : function(){
11160 return this.useAjax ? Roo.Ajax : this.conn;
11164 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11165 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11166 * process that block using the passed callback.
11167 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11168 * for the request to the remote server.
11169 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11170 * object into a block of Roo.data.Records.
11171 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11172 * The function must be passed <ul>
11173 * <li>The Record block object</li>
11174 * <li>The "arg" argument from the load function</li>
11175 * <li>A boolean success indicator</li>
11177 * @param {Object} scope The scope in which to call the callback
11178 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11180 load : function(params, reader, callback, scope, arg){
11181 if(this.fireEvent("beforeload", this, params) !== false){
11183 params : params || {},
11185 callback : callback,
11190 callback : this.loadResponse,
11194 Roo.applyIf(o, this.conn);
11195 if(this.activeRequest){
11196 Roo.Ajax.abort(this.activeRequest);
11198 this.activeRequest = Roo.Ajax.request(o);
11200 this.conn.request(o);
11203 callback.call(scope||this, null, arg, false);
11208 loadResponse : function(o, success, response){
11209 delete this.activeRequest;
11211 this.fireEvent("loadexception", this, o, response);
11212 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11217 result = o.reader.read(response);
11219 this.fireEvent("loadexception", this, o, response, e);
11220 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11224 this.fireEvent("load", this, o, o.request.arg);
11225 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11229 update : function(dataSet){
11234 updateResponse : function(dataSet){
11239 * Ext JS Library 1.1.1
11240 * Copyright(c) 2006-2007, Ext JS, LLC.
11242 * Originally Released Under LGPL - original licence link has changed is not relivant.
11245 * <script type="text/javascript">
11249 * @class Roo.data.ScriptTagProxy
11250 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11251 * other than the originating domain of the running page.<br><br>
11253 * <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
11254 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11256 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11257 * source code that is used as the source inside a <script> tag.<br><br>
11259 * In order for the browser to process the returned data, the server must wrap the data object
11260 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11261 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11262 * depending on whether the callback name was passed:
11265 boolean scriptTag = false;
11266 String cb = request.getParameter("callback");
11269 response.setContentType("text/javascript");
11271 response.setContentType("application/x-json");
11273 Writer out = response.getWriter();
11275 out.write(cb + "(");
11277 out.print(dataBlock.toJsonString());
11284 * @param {Object} config A configuration object.
11286 Roo.data.ScriptTagProxy = function(config){
11287 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11288 Roo.apply(this, config);
11289 this.head = document.getElementsByTagName("head")[0];
11292 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11294 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11296 * @cfg {String} url The URL from which to request the data object.
11299 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11303 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11304 * the server the name of the callback function set up by the load call to process the returned data object.
11305 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11306 * javascript output which calls this named function passing the data object as its only parameter.
11308 callbackParam : "callback",
11310 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11311 * name to the request.
11316 * Load data from the configured URL, read the data object into
11317 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11318 * process that block using the passed callback.
11319 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11320 * for the request to the remote server.
11321 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11322 * object into a block of Roo.data.Records.
11323 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11324 * The function must be passed <ul>
11325 * <li>The Record block object</li>
11326 * <li>The "arg" argument from the load function</li>
11327 * <li>A boolean success indicator</li>
11329 * @param {Object} scope The scope in which to call the callback
11330 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11332 load : function(params, reader, callback, scope, arg){
11333 if(this.fireEvent("beforeload", this, params) !== false){
11335 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11337 var url = this.url;
11338 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11340 url += "&_dc=" + (new Date().getTime());
11342 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11345 cb : "stcCallback"+transId,
11346 scriptId : "stcScript"+transId,
11350 callback : callback,
11356 window[trans.cb] = function(o){
11357 conn.handleResponse(o, trans);
11360 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11362 if(this.autoAbort !== false){
11366 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11368 var script = document.createElement("script");
11369 script.setAttribute("src", url);
11370 script.setAttribute("type", "text/javascript");
11371 script.setAttribute("id", trans.scriptId);
11372 this.head.appendChild(script);
11374 this.trans = trans;
11376 callback.call(scope||this, null, arg, false);
11381 isLoading : function(){
11382 return this.trans ? true : false;
11386 * Abort the current server request.
11388 abort : function(){
11389 if(this.isLoading()){
11390 this.destroyTrans(this.trans);
11395 destroyTrans : function(trans, isLoaded){
11396 this.head.removeChild(document.getElementById(trans.scriptId));
11397 clearTimeout(trans.timeoutId);
11399 window[trans.cb] = undefined;
11401 delete window[trans.cb];
11404 // if hasn't been loaded, wait for load to remove it to prevent script error
11405 window[trans.cb] = function(){
11406 window[trans.cb] = undefined;
11408 delete window[trans.cb];
11415 handleResponse : function(o, trans){
11416 this.trans = false;
11417 this.destroyTrans(trans, true);
11420 result = trans.reader.readRecords(o);
11422 this.fireEvent("loadexception", this, o, trans.arg, e);
11423 trans.callback.call(trans.scope||window, null, trans.arg, false);
11426 this.fireEvent("load", this, o, trans.arg);
11427 trans.callback.call(trans.scope||window, result, trans.arg, true);
11431 handleFailure : function(trans){
11432 this.trans = false;
11433 this.destroyTrans(trans, false);
11434 this.fireEvent("loadexception", this, null, trans.arg);
11435 trans.callback.call(trans.scope||window, null, trans.arg, false);
11439 * Ext JS Library 1.1.1
11440 * Copyright(c) 2006-2007, Ext JS, LLC.
11442 * Originally Released Under LGPL - original licence link has changed is not relivant.
11445 * <script type="text/javascript">
11449 * @class Roo.data.JsonReader
11450 * @extends Roo.data.DataReader
11451 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11452 * based on mappings in a provided Roo.data.Record constructor.
11454 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11455 * in the reply previously.
11460 var RecordDef = Roo.data.Record.create([
11461 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11462 {name: 'occupation'} // This field will use "occupation" as the mapping.
11464 var myReader = new Roo.data.JsonReader({
11465 totalProperty: "results", // The property which contains the total dataset size (optional)
11466 root: "rows", // The property which contains an Array of row objects
11467 id: "id" // The property within each row object that provides an ID for the record (optional)
11471 * This would consume a JSON file like this:
11473 { 'results': 2, 'rows': [
11474 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11475 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11478 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11479 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
11480 * paged from the remote server.
11481 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
11482 * @cfg {String} root name of the property which contains the Array of row objects.
11483 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
11484 * @cfg {Array} fields Array of field definition objects
11486 * Create a new JsonReader
11487 * @param {Object} meta Metadata configuration options
11488 * @param {Object} recordType Either an Array of field definition objects,
11489 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
11491 Roo.data.JsonReader = function(meta, recordType){
11494 // set some defaults:
11495 Roo.applyIf(meta, {
11496 totalProperty: 'total',
11497 successProperty : 'success',
11502 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
11504 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
11507 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
11508 * Used by Store query builder to append _requestMeta to params.
11511 metaFromRemote : false,
11513 * This method is only used by a DataProxy which has retrieved data from a remote server.
11514 * @param {Object} response The XHR object which contains the JSON data in its responseText.
11515 * @return {Object} data A data block which is used by an Roo.data.Store object as
11516 * a cache of Roo.data.Records.
11518 read : function(response){
11519 var json = response.responseText;
11521 var o = /* eval:var:o */ eval("("+json+")");
11523 throw {message: "JsonReader.read: Json object not found"};
11529 this.metaFromRemote = true;
11530 this.meta = o.metaData;
11531 this.recordType = Roo.data.Record.create(o.metaData.fields);
11532 this.onMetaChange(this.meta, this.recordType, o);
11534 return this.readRecords(o);
11537 // private function a store will implement
11538 onMetaChange : function(meta, recordType, o){
11545 simpleAccess: function(obj, subsc) {
11552 getJsonAccessor: function(){
11554 return function(expr) {
11556 return(re.test(expr))
11557 ? new Function("obj", "return obj." + expr)
11562 return Roo.emptyFn;
11567 * Create a data block containing Roo.data.Records from an XML document.
11568 * @param {Object} o An object which contains an Array of row objects in the property specified
11569 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
11570 * which contains the total size of the dataset.
11571 * @return {Object} data A data block which is used by an Roo.data.Store object as
11572 * a cache of Roo.data.Records.
11574 readRecords : function(o){
11576 * After any data loads, the raw JSON data is available for further custom processing.
11580 var s = this.meta, Record = this.recordType,
11581 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
11583 // Generate extraction functions for the totalProperty, the root, the id, and for each field
11585 if(s.totalProperty) {
11586 this.getTotal = this.getJsonAccessor(s.totalProperty);
11588 if(s.successProperty) {
11589 this.getSuccess = this.getJsonAccessor(s.successProperty);
11591 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
11593 var g = this.getJsonAccessor(s.id);
11594 this.getId = function(rec) {
11596 return (r === undefined || r === "") ? null : r;
11599 this.getId = function(){return null;};
11602 for(var jj = 0; jj < fl; jj++){
11604 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
11605 this.ef[jj] = this.getJsonAccessor(map);
11609 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
11610 if(s.totalProperty){
11611 var vt = parseInt(this.getTotal(o), 10);
11616 if(s.successProperty){
11617 var vs = this.getSuccess(o);
11618 if(vs === false || vs === 'false'){
11623 for(var i = 0; i < c; i++){
11626 var id = this.getId(n);
11627 for(var j = 0; j < fl; j++){
11629 var v = this.ef[j](n);
11631 Roo.log('missing convert for ' + f.name);
11635 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
11637 var record = new Record(values, id);
11639 records[i] = record;
11645 totalRecords : totalRecords
11650 * Ext JS Library 1.1.1
11651 * Copyright(c) 2006-2007, Ext JS, LLC.
11653 * Originally Released Under LGPL - original licence link has changed is not relivant.
11656 * <script type="text/javascript">
11660 * @class Roo.data.ArrayReader
11661 * @extends Roo.data.DataReader
11662 * Data reader class to create an Array of Roo.data.Record objects from an Array.
11663 * Each element of that Array represents a row of data fields. The
11664 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
11665 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
11669 var RecordDef = Roo.data.Record.create([
11670 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
11671 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
11673 var myReader = new Roo.data.ArrayReader({
11674 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
11678 * This would consume an Array like this:
11680 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
11682 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
11684 * Create a new JsonReader
11685 * @param {Object} meta Metadata configuration options.
11686 * @param {Object} recordType Either an Array of field definition objects
11687 * as specified to {@link Roo.data.Record#create},
11688 * or an {@link Roo.data.Record} object
11689 * created using {@link Roo.data.Record#create}.
11691 Roo.data.ArrayReader = function(meta, recordType){
11692 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
11695 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
11697 * Create a data block containing Roo.data.Records from an XML document.
11698 * @param {Object} o An Array of row objects which represents the dataset.
11699 * @return {Object} data A data block which is used by an Roo.data.Store object as
11700 * a cache of Roo.data.Records.
11702 readRecords : function(o){
11703 var sid = this.meta ? this.meta.id : null;
11704 var recordType = this.recordType, fields = recordType.prototype.fields;
11707 for(var i = 0; i < root.length; i++){
11710 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
11711 for(var j = 0, jlen = fields.length; j < jlen; j++){
11712 var f = fields.items[j];
11713 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
11714 var v = n[k] !== undefined ? n[k] : f.defaultValue;
11716 values[f.name] = v;
11718 var record = new recordType(values, id);
11720 records[records.length] = record;
11724 totalRecords : records.length
11733 * @class Roo.bootstrap.ComboBox
11734 * @extends Roo.bootstrap.TriggerField
11735 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
11736 * @cfg {Boolean} append (true|false) default false
11737 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
11738 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
11739 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
11740 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
11741 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
11742 * @cfg {Boolean} animate default true
11743 * @cfg {Boolean} emptyResultText only for touch device
11744 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
11746 * Create a new ComboBox.
11747 * @param {Object} config Configuration options
11749 Roo.bootstrap.ComboBox = function(config){
11750 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
11754 * Fires when the dropdown list is expanded
11755 * @param {Roo.bootstrap.ComboBox} combo This combo box
11760 * Fires when the dropdown list is collapsed
11761 * @param {Roo.bootstrap.ComboBox} combo This combo box
11765 * @event beforeselect
11766 * Fires before a list item is selected. Return false to cancel the selection.
11767 * @param {Roo.bootstrap.ComboBox} combo This combo box
11768 * @param {Roo.data.Record} record The data record returned from the underlying store
11769 * @param {Number} index The index of the selected item in the dropdown list
11771 'beforeselect' : true,
11774 * Fires when a list item is selected
11775 * @param {Roo.bootstrap.ComboBox} combo This combo box
11776 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
11777 * @param {Number} index The index of the selected item in the dropdown list
11781 * @event beforequery
11782 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
11783 * The event object passed has these properties:
11784 * @param {Roo.bootstrap.ComboBox} combo This combo box
11785 * @param {String} query The query
11786 * @param {Boolean} forceAll true to force "all" query
11787 * @param {Boolean} cancel true to cancel the query
11788 * @param {Object} e The query event object
11790 'beforequery': true,
11793 * Fires when the 'add' icon is pressed (add a listener to enable add button)
11794 * @param {Roo.bootstrap.ComboBox} combo This combo box
11799 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
11800 * @param {Roo.bootstrap.ComboBox} combo This combo box
11801 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
11806 * Fires when the remove value from the combobox array
11807 * @param {Roo.bootstrap.ComboBox} combo This combo box
11811 * @event afterremove
11812 * Fires when the remove value from the combobox array
11813 * @param {Roo.bootstrap.ComboBox} combo This combo box
11815 'afterremove' : true,
11817 * @event specialfilter
11818 * Fires when specialfilter
11819 * @param {Roo.bootstrap.ComboBox} combo This combo box
11821 'specialfilter' : true,
11824 * Fires when tick the element
11825 * @param {Roo.bootstrap.ComboBox} combo This combo box
11829 * @event touchviewdisplay
11830 * Fires when touch view require special display (default is using displayField)
11831 * @param {Roo.bootstrap.ComboBox} combo This combo box
11832 * @param {Object} cfg set html .
11834 'touchviewdisplay' : true
11839 this.tickItems = [];
11841 this.selectedIndex = -1;
11842 if(this.mode == 'local'){
11843 if(config.queryDelay === undefined){
11844 this.queryDelay = 10;
11846 if(config.minChars === undefined){
11852 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
11855 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
11856 * rendering into an Roo.Editor, defaults to false)
11859 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
11860 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11863 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11866 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11867 * the dropdown list (defaults to undefined, with no header element)
11871 * @cfg {String/Roo.Template} tpl The template to use to render the output
11875 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11877 listWidth: undefined,
11879 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11880 * mode = 'remote' or 'text' if mode = 'local')
11882 displayField: undefined,
11885 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11886 * mode = 'remote' or 'value' if mode = 'local').
11887 * Note: use of a valueField requires the user make a selection
11888 * in order for a value to be mapped.
11890 valueField: undefined,
11894 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11895 * field's data value (defaults to the underlying DOM element's name)
11897 hiddenName: undefined,
11899 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11903 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11905 selectedClass: 'active',
11908 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11912 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11913 * anchor positions (defaults to 'tl-bl')
11915 listAlign: 'tl-bl?',
11917 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11921 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11922 * query specified by the allQuery config option (defaults to 'query')
11924 triggerAction: 'query',
11926 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11927 * (defaults to 4, does not apply if editable = false)
11931 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11932 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11936 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11937 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11941 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11942 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11946 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11947 * when editable = true (defaults to false)
11949 selectOnFocus:false,
11951 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11953 queryParam: 'query',
11955 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11956 * when mode = 'remote' (defaults to 'Loading...')
11958 loadingText: 'Loading...',
11960 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11964 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11968 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11969 * traditional select (defaults to true)
11973 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11977 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11981 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11982 * listWidth has a higher value)
11986 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11987 * allow the user to set arbitrary text into the field (defaults to false)
11989 forceSelection:false,
11991 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11992 * if typeAhead = true (defaults to 250)
11994 typeAheadDelay : 250,
11996 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11997 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11999 valueNotFoundText : undefined,
12001 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12003 blockFocus : false,
12006 * @cfg {Boolean} disableClear Disable showing of clear button.
12008 disableClear : false,
12010 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12012 alwaysQuery : false,
12015 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12020 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12022 invalidClass : "has-warning",
12025 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12027 validClass : "has-success",
12030 * @cfg {Boolean} specialFilter (true|false) special filter default false
12032 specialFilter : false,
12035 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12037 mobileTouchView : true,
12049 btnPosition : 'right',
12050 triggerList : true,
12051 showToggleBtn : true,
12053 emptyResultText: 'Empty',
12054 triggerText : 'Select',
12056 // element that contains real text value.. (when hidden is used..)
12058 getAutoCreate : function()
12066 if(Roo.isTouch && this.mobileTouchView){
12067 cfg = this.getAutoCreateTouchView();
12074 if(!this.tickable){
12075 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12080 * ComboBox with tickable selections
12083 var align = this.labelAlign || this.parentLabelAlign();
12086 cls : 'form-group roo-combobox-tickable' //input-group
12091 cls : 'tickable-buttons',
12096 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12097 html : this.triggerText
12103 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12110 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12117 buttons.cn.unshift({
12119 cls: 'roo-select2-search-field-input'
12125 Roo.each(buttons.cn, function(c){
12127 c.cls += ' btn-' + _this.size;
12130 if (_this.disabled) {
12141 cls: 'form-hidden-field'
12145 cls: 'roo-select2-choices',
12149 cls: 'roo-select2-search-field',
12161 cls: 'roo-select2-container input-group roo-select2-container-multi',
12166 // cls: 'typeahead typeahead-long dropdown-menu',
12167 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12172 if(this.hasFeedback && !this.allowBlank){
12176 cls: 'glyphicon form-control-feedback'
12179 combobox.cn.push(feedback);
12182 if (align ==='left' && this.fieldLabel.length) {
12184 // Roo.log("left and has label");
12190 cls : 'control-label col-sm-' + this.labelWidth,
12191 html : this.fieldLabel
12195 cls : "col-sm-" + (12 - this.labelWidth),
12202 } else if ( this.fieldLabel.length) {
12203 // Roo.log(" label");
12208 //cls : 'input-group-addon',
12209 html : this.fieldLabel
12219 // Roo.log(" no label && no align");
12226 ['xs','sm','md','lg'].map(function(size){
12227 if (settings[size]) {
12228 cfg.cls += ' col-' + size + '-' + settings[size];
12236 _initEventsCalled : false,
12239 initEvents: function()
12242 if (this._initEventsCalled) { // as we call render... prevent looping...
12245 this._initEventsCalled = true;
12248 throw "can not find store for combo";
12251 this.store = Roo.factory(this.store, Roo.data);
12253 // if we are building from html. then this element is so complex, that we can not really
12254 // use the rendered HTML.
12255 // so we have to trash and replace the previous code.
12256 if (Roo.XComponent.build_from_html) {
12258 // remove this element....
12259 var e = this.el.dom, k=0;
12260 while (e ) { e = e.previousSibling; ++k;}
12265 this.rendered = false;
12267 this.render(this.parent().getChildContainer(true), k);
12278 if(Roo.isTouch && this.mobileTouchView){
12279 this.initTouchView();
12284 this.initTickableEvents();
12288 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12290 if(this.hiddenName){
12292 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12294 this.hiddenField.dom.value =
12295 this.hiddenValue !== undefined ? this.hiddenValue :
12296 this.value !== undefined ? this.value : '';
12298 // prevent input submission
12299 this.el.dom.removeAttribute('name');
12300 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12305 // this.el.dom.setAttribute('autocomplete', 'off');
12308 var cls = 'x-combo-list';
12310 //this.list = new Roo.Layer({
12311 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12317 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12318 _this.list.setWidth(lw);
12321 this.list.on('mouseover', this.onViewOver, this);
12322 this.list.on('mousemove', this.onViewMove, this);
12324 this.list.on('scroll', this.onViewScroll, this);
12327 this.list.swallowEvent('mousewheel');
12328 this.assetHeight = 0;
12331 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12332 this.assetHeight += this.header.getHeight();
12335 this.innerList = this.list.createChild({cls:cls+'-inner'});
12336 this.innerList.on('mouseover', this.onViewOver, this);
12337 this.innerList.on('mousemove', this.onViewMove, this);
12338 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12340 if(this.allowBlank && !this.pageSize && !this.disableClear){
12341 this.footer = this.list.createChild({cls:cls+'-ft'});
12342 this.pageTb = new Roo.Toolbar(this.footer);
12346 this.footer = this.list.createChild({cls:cls+'-ft'});
12347 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
12348 {pageSize: this.pageSize});
12352 if (this.pageTb && this.allowBlank && !this.disableClear) {
12354 this.pageTb.add(new Roo.Toolbar.Fill(), {
12355 cls: 'x-btn-icon x-btn-clear',
12357 handler: function()
12360 _this.clearValue();
12361 _this.onSelect(false, -1);
12366 this.assetHeight += this.footer.getHeight();
12371 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
12374 this.view = new Roo.View(this.list, this.tpl, {
12375 singleSelect:true, store: this.store, selectedClass: this.selectedClass
12377 //this.view.wrapEl.setDisplayed(false);
12378 this.view.on('click', this.onViewClick, this);
12382 this.store.on('beforeload', this.onBeforeLoad, this);
12383 this.store.on('load', this.onLoad, this);
12384 this.store.on('loadexception', this.onLoadException, this);
12386 if(this.resizable){
12387 this.resizer = new Roo.Resizable(this.list, {
12388 pinned:true, handles:'se'
12390 this.resizer.on('resize', function(r, w, h){
12391 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
12392 this.listWidth = w;
12393 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
12394 this.restrictHeight();
12396 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
12399 if(!this.editable){
12400 this.editable = true;
12401 this.setEditable(false);
12406 if (typeof(this.events.add.listeners) != 'undefined') {
12408 this.addicon = this.wrap.createChild(
12409 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
12411 this.addicon.on('click', function(e) {
12412 this.fireEvent('add', this);
12415 if (typeof(this.events.edit.listeners) != 'undefined') {
12417 this.editicon = this.wrap.createChild(
12418 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
12419 if (this.addicon) {
12420 this.editicon.setStyle('margin-left', '40px');
12422 this.editicon.on('click', function(e) {
12424 // we fire even if inothing is selected..
12425 this.fireEvent('edit', this, this.lastData );
12431 this.keyNav = new Roo.KeyNav(this.inputEl(), {
12432 "up" : function(e){
12433 this.inKeyMode = true;
12437 "down" : function(e){
12438 if(!this.isExpanded()){
12439 this.onTriggerClick();
12441 this.inKeyMode = true;
12446 "enter" : function(e){
12447 // this.onViewClick();
12451 if(this.fireEvent("specialkey", this, e)){
12452 this.onViewClick(false);
12458 "esc" : function(e){
12462 "tab" : function(e){
12465 if(this.fireEvent("specialkey", this, e)){
12466 this.onViewClick(false);
12474 doRelay : function(foo, bar, hname){
12475 if(hname == 'down' || this.scope.isExpanded()){
12476 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12485 this.queryDelay = Math.max(this.queryDelay || 10,
12486 this.mode == 'local' ? 10 : 250);
12489 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12491 if(this.typeAhead){
12492 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12494 if(this.editable !== false){
12495 this.inputEl().on("keyup", this.onKeyUp, this);
12497 if(this.forceSelection){
12498 this.inputEl().on('blur', this.doForce, this);
12502 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12503 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12507 initTickableEvents: function()
12511 if(this.hiddenName){
12513 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12515 this.hiddenField.dom.value =
12516 this.hiddenValue !== undefined ? this.hiddenValue :
12517 this.value !== undefined ? this.value : '';
12519 // prevent input submission
12520 this.el.dom.removeAttribute('name');
12521 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12526 // this.list = this.el.select('ul.dropdown-menu',true).first();
12528 this.choices = this.el.select('ul.roo-select2-choices', true).first();
12529 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
12530 if(this.triggerList){
12531 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
12534 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
12535 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
12537 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
12538 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
12540 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
12541 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
12543 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
12544 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
12545 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
12548 this.cancelBtn.hide();
12553 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12554 _this.list.setWidth(lw);
12557 this.list.on('mouseover', this.onViewOver, this);
12558 this.list.on('mousemove', this.onViewMove, this);
12560 this.list.on('scroll', this.onViewScroll, this);
12563 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>';
12566 this.view = new Roo.View(this.list, this.tpl, {
12567 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
12570 //this.view.wrapEl.setDisplayed(false);
12571 this.view.on('click', this.onViewClick, this);
12575 this.store.on('beforeload', this.onBeforeLoad, this);
12576 this.store.on('load', this.onLoad, this);
12577 this.store.on('loadexception', this.onLoadException, this);
12580 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
12581 "up" : function(e){
12582 this.inKeyMode = true;
12586 "down" : function(e){
12587 this.inKeyMode = true;
12591 "enter" : function(e){
12592 if(this.fireEvent("specialkey", this, e)){
12593 this.onViewClick(false);
12599 "esc" : function(e){
12600 this.onTickableFooterButtonClick(e, false, false);
12603 "tab" : function(e){
12604 this.fireEvent("specialkey", this, e);
12606 this.onTickableFooterButtonClick(e, false, false);
12613 doRelay : function(e, fn, key){
12614 if(this.scope.isExpanded()){
12615 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
12624 this.queryDelay = Math.max(this.queryDelay || 10,
12625 this.mode == 'local' ? 10 : 250);
12628 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
12630 if(this.typeAhead){
12631 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
12634 if(this.editable !== false){
12635 this.tickableInputEl().on("keyup", this.onKeyUp, this);
12640 onDestroy : function(){
12642 this.view.setStore(null);
12643 this.view.el.removeAllListeners();
12644 this.view.el.remove();
12645 this.view.purgeListeners();
12648 this.list.dom.innerHTML = '';
12652 this.store.un('beforeload', this.onBeforeLoad, this);
12653 this.store.un('load', this.onLoad, this);
12654 this.store.un('loadexception', this.onLoadException, this);
12656 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
12660 fireKey : function(e){
12661 if(e.isNavKeyPress() && !this.list.isVisible()){
12662 this.fireEvent("specialkey", this, e);
12667 onResize: function(w, h){
12668 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
12670 // if(typeof w != 'number'){
12671 // // we do not handle it!?!?
12674 // var tw = this.trigger.getWidth();
12675 // // tw += this.addicon ? this.addicon.getWidth() : 0;
12676 // // tw += this.editicon ? this.editicon.getWidth() : 0;
12678 // this.inputEl().setWidth( this.adjustWidth('input', x));
12680 // //this.trigger.setStyle('left', x+'px');
12682 // if(this.list && this.listWidth === undefined){
12683 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
12684 // this.list.setWidth(lw);
12685 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12693 * Allow or prevent the user from directly editing the field text. If false is passed,
12694 * the user will only be able to select from the items defined in the dropdown list. This method
12695 * is the runtime equivalent of setting the 'editable' config option at config time.
12696 * @param {Boolean} value True to allow the user to directly edit the field text
12698 setEditable : function(value){
12699 if(value == this.editable){
12702 this.editable = value;
12704 this.inputEl().dom.setAttribute('readOnly', true);
12705 this.inputEl().on('mousedown', this.onTriggerClick, this);
12706 this.inputEl().addClass('x-combo-noedit');
12708 this.inputEl().dom.setAttribute('readOnly', false);
12709 this.inputEl().un('mousedown', this.onTriggerClick, this);
12710 this.inputEl().removeClass('x-combo-noedit');
12716 onBeforeLoad : function(combo,opts){
12717 if(!this.hasFocus){
12721 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
12723 this.restrictHeight();
12724 this.selectedIndex = -1;
12728 onLoad : function(){
12730 this.hasQuery = false;
12732 if(!this.hasFocus){
12736 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12737 this.loading.hide();
12740 if(this.store.getCount() > 0){
12742 this.restrictHeight();
12743 if(this.lastQuery == this.allQuery){
12744 if(this.editable && !this.tickable){
12745 this.inputEl().dom.select();
12749 !this.selectByValue(this.value, true) &&
12752 !this.store.lastOptions ||
12753 typeof(this.store.lastOptions.add) == 'undefined' ||
12754 this.store.lastOptions.add != true
12757 this.select(0, true);
12760 if(this.autoFocus){
12763 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
12764 this.taTask.delay(this.typeAheadDelay);
12768 this.onEmptyResults();
12774 onLoadException : function()
12776 this.hasQuery = false;
12778 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
12779 this.loading.hide();
12782 if(this.tickable && this.editable){
12787 // only causes errors at present
12788 //Roo.log(this.store.reader.jsonData);
12789 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
12791 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
12797 onTypeAhead : function(){
12798 if(this.store.getCount() > 0){
12799 var r = this.store.getAt(0);
12800 var newValue = r.data[this.displayField];
12801 var len = newValue.length;
12802 var selStart = this.getRawValue().length;
12804 if(selStart != len){
12805 this.setRawValue(newValue);
12806 this.selectText(selStart, newValue.length);
12812 onSelect : function(record, index){
12814 if(this.fireEvent('beforeselect', this, record, index) !== false){
12816 this.setFromData(index > -1 ? record.data : false);
12819 this.fireEvent('select', this, record, index);
12824 * Returns the currently selected field value or empty string if no value is set.
12825 * @return {String} value The selected value
12827 getValue : function(){
12830 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
12833 if(this.valueField){
12834 return typeof this.value != 'undefined' ? this.value : '';
12836 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
12841 * Clears any text/value currently set in the field
12843 clearValue : function(){
12844 if(this.hiddenField){
12845 this.hiddenField.dom.value = '';
12848 this.setRawValue('');
12849 this.lastSelectionText = '';
12850 this.lastData = false;
12852 var close = this.closeTriggerEl();
12861 * Sets the specified value into the field. If the value finds a match, the corresponding record text
12862 * will be displayed in the field. If the value does not match the data value of an existing item,
12863 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
12864 * Otherwise the field will be blank (although the value will still be set).
12865 * @param {String} value The value to match
12867 setValue : function(v){
12874 if(this.valueField){
12875 var r = this.findRecord(this.valueField, v);
12877 text = r.data[this.displayField];
12878 }else if(this.valueNotFoundText !== undefined){
12879 text = this.valueNotFoundText;
12882 this.lastSelectionText = text;
12883 if(this.hiddenField){
12884 this.hiddenField.dom.value = v;
12886 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
12889 var close = this.closeTriggerEl();
12892 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
12896 * @property {Object} the last set data for the element
12901 * Sets the value of the field based on a object which is related to the record format for the store.
12902 * @param {Object} value the value to set as. or false on reset?
12904 setFromData : function(o){
12911 var dv = ''; // display value
12912 var vv = ''; // value value..
12914 if (this.displayField) {
12915 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12917 // this is an error condition!!!
12918 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12921 if(this.valueField){
12922 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
12925 var close = this.closeTriggerEl();
12928 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
12931 if(this.hiddenField){
12932 this.hiddenField.dom.value = vv;
12934 this.lastSelectionText = dv;
12935 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12939 // no hidden field.. - we store the value in 'value', but still display
12940 // display field!!!!
12941 this.lastSelectionText = dv;
12942 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12949 reset : function(){
12950 // overridden so that last data is reset..
12957 this.setValue(this.originalValue);
12958 this.clearInvalid();
12959 this.lastData = false;
12961 this.view.clearSelections();
12965 findRecord : function(prop, value){
12967 if(this.store.getCount() > 0){
12968 this.store.each(function(r){
12969 if(r.data[prop] == value){
12979 getName: function()
12981 // returns hidden if it's set..
12982 if (!this.rendered) {return ''};
12983 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12987 onViewMove : function(e, t){
12988 this.inKeyMode = false;
12992 onViewOver : function(e, t){
12993 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12996 var item = this.view.findItemFromChild(t);
12999 var index = this.view.indexOf(item);
13000 this.select(index, false);
13005 onViewClick : function(view, doFocus, el, e)
13007 var index = this.view.getSelectedIndexes()[0];
13009 var r = this.store.getAt(index);
13013 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13020 Roo.each(this.tickItems, function(v,k){
13022 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13024 _this.tickItems.splice(k, 1);
13026 if(typeof(e) == 'undefined' && view == false){
13027 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13039 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13040 this.tickItems.push(r.data);
13043 if(typeof(e) == 'undefined' && view == false){
13044 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13051 this.onSelect(r, index);
13053 if(doFocus !== false && !this.blockFocus){
13054 this.inputEl().focus();
13059 restrictHeight : function(){
13060 //this.innerList.dom.style.height = '';
13061 //var inner = this.innerList.dom;
13062 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13063 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13064 //this.list.beginUpdate();
13065 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13066 this.list.alignTo(this.inputEl(), this.listAlign);
13067 this.list.alignTo(this.inputEl(), this.listAlign);
13068 //this.list.endUpdate();
13072 onEmptyResults : function(){
13074 if(this.tickable && this.editable){
13075 this.restrictHeight();
13083 * Returns true if the dropdown list is expanded, else false.
13085 isExpanded : function(){
13086 return this.list.isVisible();
13090 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13091 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13092 * @param {String} value The data value of the item to select
13093 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13094 * selected item if it is not currently in view (defaults to true)
13095 * @return {Boolean} True if the value matched an item in the list, else false
13097 selectByValue : function(v, scrollIntoView){
13098 if(v !== undefined && v !== null){
13099 var r = this.findRecord(this.valueField || this.displayField, v);
13101 this.select(this.store.indexOf(r), scrollIntoView);
13109 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13110 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13111 * @param {Number} index The zero-based index of the list item to select
13112 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13113 * selected item if it is not currently in view (defaults to true)
13115 select : function(index, scrollIntoView){
13116 this.selectedIndex = index;
13117 this.view.select(index);
13118 if(scrollIntoView !== false){
13119 var el = this.view.getNode(index);
13121 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13124 this.list.scrollChildIntoView(el, false);
13130 selectNext : function(){
13131 var ct = this.store.getCount();
13133 if(this.selectedIndex == -1){
13135 }else if(this.selectedIndex < ct-1){
13136 this.select(this.selectedIndex+1);
13142 selectPrev : function(){
13143 var ct = this.store.getCount();
13145 if(this.selectedIndex == -1){
13147 }else if(this.selectedIndex != 0){
13148 this.select(this.selectedIndex-1);
13154 onKeyUp : function(e){
13155 if(this.editable !== false && !e.isSpecialKey()){
13156 this.lastKey = e.getKey();
13157 this.dqTask.delay(this.queryDelay);
13162 validateBlur : function(){
13163 return !this.list || !this.list.isVisible();
13167 initQuery : function(){
13169 var v = this.getRawValue();
13171 if(this.tickable && this.editable){
13172 v = this.tickableInputEl().getValue();
13179 doForce : function(){
13180 if(this.inputEl().dom.value.length > 0){
13181 this.inputEl().dom.value =
13182 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13188 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13189 * query allowing the query action to be canceled if needed.
13190 * @param {String} query The SQL query to execute
13191 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13192 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13193 * saved in the current store (defaults to false)
13195 doQuery : function(q, forceAll){
13197 if(q === undefined || q === null){
13202 forceAll: forceAll,
13206 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13211 forceAll = qe.forceAll;
13212 if(forceAll === true || (q.length >= this.minChars)){
13214 this.hasQuery = true;
13216 if(this.lastQuery != q || this.alwaysQuery){
13217 this.lastQuery = q;
13218 if(this.mode == 'local'){
13219 this.selectedIndex = -1;
13221 this.store.clearFilter();
13224 if(this.specialFilter){
13225 this.fireEvent('specialfilter', this);
13230 this.store.filter(this.displayField, q);
13233 this.store.fireEvent("datachanged", this.store);
13240 this.store.baseParams[this.queryParam] = q;
13242 var options = {params : this.getParams(q)};
13245 options.add = true;
13246 options.params.start = this.page * this.pageSize;
13249 this.store.load(options);
13252 * this code will make the page width larger, at the beginning, the list not align correctly,
13253 * we should expand the list on onLoad
13254 * so command out it
13259 this.selectedIndex = -1;
13264 this.loadNext = false;
13268 getParams : function(q){
13270 //p[this.queryParam] = q;
13274 p.limit = this.pageSize;
13280 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13282 collapse : function(){
13283 if(!this.isExpanded()){
13290 this.hasFocus = false;
13292 this.cancelBtn.hide();
13293 this.trigger.show();
13296 this.tickableInputEl().dom.value = '';
13297 this.tickableInputEl().blur();
13302 Roo.get(document).un('mousedown', this.collapseIf, this);
13303 Roo.get(document).un('mousewheel', this.collapseIf, this);
13304 if (!this.editable) {
13305 Roo.get(document).un('keydown', this.listKeyPress, this);
13307 this.fireEvent('collapse', this);
13311 collapseIf : function(e){
13312 var in_combo = e.within(this.el);
13313 var in_list = e.within(this.list);
13314 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
13316 if (in_combo || in_list || is_list) {
13317 //e.stopPropagation();
13322 this.onTickableFooterButtonClick(e, false, false);
13330 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
13332 expand : function(){
13334 if(this.isExpanded() || !this.hasFocus){
13338 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
13339 this.list.setWidth(lw);
13346 this.restrictHeight();
13350 this.tickItems = Roo.apply([], this.item);
13353 this.cancelBtn.show();
13354 this.trigger.hide();
13357 this.tickableInputEl().focus();
13362 Roo.get(document).on('mousedown', this.collapseIf, this);
13363 Roo.get(document).on('mousewheel', this.collapseIf, this);
13364 if (!this.editable) {
13365 Roo.get(document).on('keydown', this.listKeyPress, this);
13368 this.fireEvent('expand', this);
13372 // Implements the default empty TriggerField.onTriggerClick function
13373 onTriggerClick : function(e)
13375 Roo.log('trigger click');
13377 if(this.disabled || !this.triggerList){
13382 this.loadNext = false;
13384 if(this.isExpanded()){
13386 if (!this.blockFocus) {
13387 this.inputEl().focus();
13391 this.hasFocus = true;
13392 if(this.triggerAction == 'all') {
13393 this.doQuery(this.allQuery, true);
13395 this.doQuery(this.getRawValue());
13397 if (!this.blockFocus) {
13398 this.inputEl().focus();
13403 onTickableTriggerClick : function(e)
13410 this.loadNext = false;
13411 this.hasFocus = true;
13413 if(this.triggerAction == 'all') {
13414 this.doQuery(this.allQuery, true);
13416 this.doQuery(this.getRawValue());
13420 onSearchFieldClick : function(e)
13422 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
13423 this.onTickableFooterButtonClick(e, false, false);
13427 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
13432 this.loadNext = false;
13433 this.hasFocus = true;
13435 if(this.triggerAction == 'all') {
13436 this.doQuery(this.allQuery, true);
13438 this.doQuery(this.getRawValue());
13442 listKeyPress : function(e)
13444 //Roo.log('listkeypress');
13445 // scroll to first matching element based on key pres..
13446 if (e.isSpecialKey()) {
13449 var k = String.fromCharCode(e.getKey()).toUpperCase();
13452 var csel = this.view.getSelectedNodes();
13453 var cselitem = false;
13455 var ix = this.view.indexOf(csel[0]);
13456 cselitem = this.store.getAt(ix);
13457 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
13463 this.store.each(function(v) {
13465 // start at existing selection.
13466 if (cselitem.id == v.id) {
13472 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
13473 match = this.store.indexOf(v);
13479 if (match === false) {
13480 return true; // no more action?
13483 this.view.select(match);
13484 var sn = Roo.get(this.view.getSelectedNodes()[0]);
13485 sn.scrollIntoView(sn.dom.parentNode, false);
13488 onViewScroll : function(e, t){
13490 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){
13494 this.hasQuery = true;
13496 this.loading = this.list.select('.loading', true).first();
13498 if(this.loading === null){
13499 this.list.createChild({
13501 cls: 'loading roo-select2-more-results roo-select2-active',
13502 html: 'Loading more results...'
13505 this.loading = this.list.select('.loading', true).first();
13507 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
13509 this.loading.hide();
13512 this.loading.show();
13517 this.loadNext = true;
13519 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
13524 addItem : function(o)
13526 var dv = ''; // display value
13528 if (this.displayField) {
13529 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13531 // this is an error condition!!!
13532 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13539 var choice = this.choices.createChild({
13541 cls: 'roo-select2-search-choice',
13550 cls: 'roo-select2-search-choice-close',
13555 }, this.searchField);
13557 var close = choice.select('a.roo-select2-search-choice-close', true).first();
13559 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
13567 this.inputEl().dom.value = '';
13572 onRemoveItem : function(e, _self, o)
13574 e.preventDefault();
13576 this.lastItem = Roo.apply([], this.item);
13578 var index = this.item.indexOf(o.data) * 1;
13581 Roo.log('not this item?!');
13585 this.item.splice(index, 1);
13590 this.fireEvent('remove', this, e);
13596 syncValue : function()
13598 if(!this.item.length){
13605 Roo.each(this.item, function(i){
13606 if(_this.valueField){
13607 value.push(i[_this.valueField]);
13614 this.value = value.join(',');
13616 if(this.hiddenField){
13617 this.hiddenField.dom.value = this.value;
13620 this.store.fireEvent("datachanged", this.store);
13623 clearItem : function()
13625 if(!this.multiple){
13631 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
13639 if(this.tickable && !Roo.isTouch){
13640 this.view.refresh();
13644 inputEl: function ()
13646 if(Roo.isTouch && this.mobileTouchView){
13647 return this.el.select('input.form-control',true).first();
13651 return this.searchField;
13654 return this.el.select('input.form-control',true).first();
13658 onTickableFooterButtonClick : function(e, btn, el)
13660 e.preventDefault();
13662 this.lastItem = Roo.apply([], this.item);
13664 if(btn && btn.name == 'cancel'){
13665 this.tickItems = Roo.apply([], this.item);
13674 Roo.each(this.tickItems, function(o){
13682 validate : function()
13684 var v = this.getRawValue();
13687 v = this.getValue();
13690 if(this.disabled || this.allowBlank || v.length){
13695 this.markInvalid();
13699 tickableInputEl : function()
13701 if(!this.tickable || !this.editable){
13702 return this.inputEl();
13705 return this.inputEl().select('.roo-select2-search-field-input', true).first();
13709 getAutoCreateTouchView : function()
13714 cls: 'form-group' //input-group
13720 type : this.inputType,
13721 cls : 'form-control x-combo-noedit',
13722 autocomplete: 'new-password',
13723 placeholder : this.placeholder || '',
13728 input.name = this.name;
13732 input.cls += ' input-' + this.size;
13735 if (this.disabled) {
13736 input.disabled = true;
13747 inputblock.cls += ' input-group';
13749 inputblock.cn.unshift({
13751 cls : 'input-group-addon',
13756 if(this.removable && !this.multiple){
13757 inputblock.cls += ' roo-removable';
13759 inputblock.cn.push({
13762 cls : 'roo-combo-removable-btn close'
13766 if(this.hasFeedback && !this.allowBlank){
13768 inputblock.cls += ' has-feedback';
13770 inputblock.cn.push({
13772 cls: 'glyphicon form-control-feedback'
13779 inputblock.cls += (this.before) ? '' : ' input-group';
13781 inputblock.cn.push({
13783 cls : 'input-group-addon',
13794 cls: 'form-hidden-field'
13808 cls: 'form-hidden-field'
13812 cls: 'roo-select2-choices',
13816 cls: 'roo-select2-search-field',
13829 cls: 'roo-select2-container input-group',
13836 combobox.cls += ' roo-select2-container-multi';
13839 var align = this.labelAlign || this.parentLabelAlign();
13843 if(this.fieldLabel.length){
13845 var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
13846 var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
13851 cls : 'control-label ' + lw,
13852 html : this.fieldLabel
13864 var settings = this;
13866 ['xs','sm','md','lg'].map(function(size){
13867 if (settings[size]) {
13868 cfg.cls += ' col-' + size + '-' + settings[size];
13875 initTouchView : function()
13877 this.renderTouchView();
13879 this.touchViewEl.on('scroll', function(){
13880 this.el.dom.scrollTop = 0;
13883 this.originalValue = this.getValue();
13885 this.inputEl().on("click", this.showTouchView, this);
13887 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
13888 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
13890 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
13892 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
13893 this.store.on('load', this.onTouchViewLoad, this);
13894 this.store.on('loadexception', this.onTouchViewLoadException, this);
13896 if(this.hiddenName){
13898 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13900 this.hiddenField.dom.value =
13901 this.hiddenValue !== undefined ? this.hiddenValue :
13902 this.value !== undefined ? this.value : '';
13904 this.el.dom.removeAttribute('name');
13905 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13909 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13910 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13913 if(this.removable && !this.multiple){
13914 var close = this.closeTriggerEl();
13916 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
13917 close.on('click', this.removeBtnClick, this, close);
13921 * fix the bug in Safari iOS8
13923 this.inputEl().on("focus", function(e){
13924 document.activeElement.blur();
13932 renderTouchView : function()
13934 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
13935 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13937 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
13938 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13940 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
13941 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13942 this.touchViewBodyEl.setStyle('overflow', 'auto');
13944 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
13945 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13947 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
13948 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13952 showTouchView : function()
13958 this.touchViewHeaderEl.hide();
13960 if(this.fieldLabel.length){
13961 this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
13962 this.touchViewHeaderEl.show();
13965 this.touchViewEl.show();
13967 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
13968 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13970 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
13972 if(this.fieldLabel.length){
13973 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
13976 this.touchViewBodyEl.setHeight(bodyHeight);
13980 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
13982 this.touchViewEl.addClass('in');
13985 this.doTouchViewQuery();
13989 hideTouchView : function()
13991 this.touchViewEl.removeClass('in');
13995 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
13997 this.touchViewEl.setStyle('display', 'none');
14002 setTouchViewValue : function()
14009 Roo.each(this.tickItems, function(o){
14014 this.hideTouchView();
14017 doTouchViewQuery : function()
14026 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14030 if(!this.alwaysQuery || this.mode == 'local'){
14031 this.onTouchViewLoad();
14038 onTouchViewBeforeLoad : function(combo,opts)
14044 onTouchViewLoad : function()
14046 if(this.store.getCount() < 1){
14047 this.onTouchViewEmptyResults();
14051 this.clearTouchView();
14053 var rawValue = this.getRawValue();
14055 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14057 this.tickItems = [];
14059 this.store.data.each(function(d, rowIndex){
14060 var row = this.touchViewListGroup.createChild(template);
14062 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14063 row.addClass(d.data.cls);
14066 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14069 html : d.data[this.displayField]
14072 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14073 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14077 if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
14078 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14081 if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
14082 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14083 this.tickItems.push(d.data);
14086 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14090 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14092 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14094 if(this.fieldLabel.length){
14095 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14098 var listHeight = this.touchViewListGroup.getHeight();
14102 if(firstChecked && listHeight > bodyHeight){
14103 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14108 onTouchViewLoadException : function()
14110 this.hideTouchView();
14113 onTouchViewEmptyResults : function()
14115 this.clearTouchView();
14117 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14119 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14123 clearTouchView : function()
14125 this.touchViewListGroup.dom.innerHTML = '';
14128 onTouchViewClick : function(e, el, o)
14130 e.preventDefault();
14133 var rowIndex = o.rowIndex;
14135 var r = this.store.getAt(rowIndex);
14137 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14139 if(!this.multiple){
14140 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14141 c.dom.removeAttribute('checked');
14144 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14146 this.setFromData(r.data);
14148 var close = this.closeTriggerEl();
14154 this.hideTouchView();
14156 this.fireEvent('select', this, r, rowIndex);
14161 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
14162 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
14163 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
14167 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14168 this.addItem(r.data);
14169 this.tickItems.push(r.data);
14175 * @cfg {Boolean} grow
14179 * @cfg {Number} growMin
14183 * @cfg {Number} growMax
14192 Roo.apply(Roo.bootstrap.ComboBox, {
14196 cls: 'modal-header',
14218 cls: 'list-group-item',
14222 cls: 'roo-combobox-list-group-item-value'
14226 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
14240 listItemCheckbox : {
14242 cls: 'list-group-item',
14246 cls: 'roo-combobox-list-group-item-value'
14250 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
14266 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
14271 cls: 'modal-footer',
14279 cls: 'col-xs-6 text-left',
14282 cls: 'btn btn-danger roo-touch-view-cancel',
14288 cls: 'col-xs-6 text-right',
14291 cls: 'btn btn-success roo-touch-view-ok',
14302 Roo.apply(Roo.bootstrap.ComboBox, {
14304 touchViewTemplate : {
14306 cls: 'modal fade roo-combobox-touch-view',
14310 cls: 'modal-dialog',
14311 style : 'position:fixed', // we have to fix position....
14315 cls: 'modal-content',
14317 Roo.bootstrap.ComboBox.header,
14318 Roo.bootstrap.ComboBox.body,
14319 Roo.bootstrap.ComboBox.footer
14328 * Ext JS Library 1.1.1
14329 * Copyright(c) 2006-2007, Ext JS, LLC.
14331 * Originally Released Under LGPL - original licence link has changed is not relivant.
14334 * <script type="text/javascript">
14339 * @extends Roo.util.Observable
14340 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
14341 * This class also supports single and multi selection modes. <br>
14342 * Create a data model bound view:
14344 var store = new Roo.data.Store(...);
14346 var view = new Roo.View({
14348 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
14350 singleSelect: true,
14351 selectedClass: "ydataview-selected",
14355 // listen for node click?
14356 view.on("click", function(vw, index, node, e){
14357 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
14361 dataModel.load("foobar.xml");
14363 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
14365 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
14366 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
14368 * Note: old style constructor is still suported (container, template, config)
14371 * Create a new View
14372 * @param {Object} config The config object
14375 Roo.View = function(config, depreciated_tpl, depreciated_config){
14377 this.parent = false;
14379 if (typeof(depreciated_tpl) == 'undefined') {
14380 // new way.. - universal constructor.
14381 Roo.apply(this, config);
14382 this.el = Roo.get(this.el);
14385 this.el = Roo.get(config);
14386 this.tpl = depreciated_tpl;
14387 Roo.apply(this, depreciated_config);
14389 this.wrapEl = this.el.wrap().wrap();
14390 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
14393 if(typeof(this.tpl) == "string"){
14394 this.tpl = new Roo.Template(this.tpl);
14396 // support xtype ctors..
14397 this.tpl = new Roo.factory(this.tpl, Roo);
14401 this.tpl.compile();
14406 * @event beforeclick
14407 * Fires before a click is processed. Returns false to cancel the default action.
14408 * @param {Roo.View} this
14409 * @param {Number} index The index of the target node
14410 * @param {HTMLElement} node The target node
14411 * @param {Roo.EventObject} e The raw event object
14413 "beforeclick" : true,
14416 * Fires when a template node is clicked.
14417 * @param {Roo.View} this
14418 * @param {Number} index The index of the target node
14419 * @param {HTMLElement} node The target node
14420 * @param {Roo.EventObject} e The raw event object
14425 * Fires when a template node is double clicked.
14426 * @param {Roo.View} this
14427 * @param {Number} index The index of the target node
14428 * @param {HTMLElement} node The target node
14429 * @param {Roo.EventObject} e The raw event object
14433 * @event contextmenu
14434 * Fires when a template node is right clicked.
14435 * @param {Roo.View} this
14436 * @param {Number} index The index of the target node
14437 * @param {HTMLElement} node The target node
14438 * @param {Roo.EventObject} e The raw event object
14440 "contextmenu" : true,
14442 * @event selectionchange
14443 * Fires when the selected nodes change.
14444 * @param {Roo.View} this
14445 * @param {Array} selections Array of the selected nodes
14447 "selectionchange" : true,
14450 * @event beforeselect
14451 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
14452 * @param {Roo.View} this
14453 * @param {HTMLElement} node The node to be selected
14454 * @param {Array} selections Array of currently selected nodes
14456 "beforeselect" : true,
14458 * @event preparedata
14459 * Fires on every row to render, to allow you to change the data.
14460 * @param {Roo.View} this
14461 * @param {Object} data to be rendered (change this)
14463 "preparedata" : true
14471 "click": this.onClick,
14472 "dblclick": this.onDblClick,
14473 "contextmenu": this.onContextMenu,
14477 this.selections = [];
14479 this.cmp = new Roo.CompositeElementLite([]);
14481 this.store = Roo.factory(this.store, Roo.data);
14482 this.setStore(this.store, true);
14485 if ( this.footer && this.footer.xtype) {
14487 var fctr = this.wrapEl.appendChild(document.createElement("div"));
14489 this.footer.dataSource = this.store;
14490 this.footer.container = fctr;
14491 this.footer = Roo.factory(this.footer, Roo);
14492 fctr.insertFirst(this.el);
14494 // this is a bit insane - as the paging toolbar seems to detach the el..
14495 // dom.parentNode.parentNode.parentNode
14496 // they get detached?
14500 Roo.View.superclass.constructor.call(this);
14505 Roo.extend(Roo.View, Roo.util.Observable, {
14508 * @cfg {Roo.data.Store} store Data store to load data from.
14513 * @cfg {String|Roo.Element} el The container element.
14518 * @cfg {String|Roo.Template} tpl The template used by this View
14522 * @cfg {String} dataName the named area of the template to use as the data area
14523 * Works with domtemplates roo-name="name"
14527 * @cfg {String} selectedClass The css class to add to selected nodes
14529 selectedClass : "x-view-selected",
14531 * @cfg {String} emptyText The empty text to show when nothing is loaded.
14536 * @cfg {String} text to display on mask (default Loading)
14540 * @cfg {Boolean} multiSelect Allow multiple selection
14542 multiSelect : false,
14544 * @cfg {Boolean} singleSelect Allow single selection
14546 singleSelect: false,
14549 * @cfg {Boolean} toggleSelect - selecting
14551 toggleSelect : false,
14554 * @cfg {Boolean} tickable - selecting
14559 * Returns the element this view is bound to.
14560 * @return {Roo.Element}
14562 getEl : function(){
14563 return this.wrapEl;
14569 * Refreshes the view. - called by datachanged on the store. - do not call directly.
14571 refresh : function(){
14572 //Roo.log('refresh');
14575 // if we are using something like 'domtemplate', then
14576 // the what gets used is:
14577 // t.applySubtemplate(NAME, data, wrapping data..)
14578 // the outer template then get' applied with
14579 // the store 'extra data'
14580 // and the body get's added to the
14581 // roo-name="data" node?
14582 // <span class='roo-tpl-{name}'></span> ?????
14586 this.clearSelections();
14587 this.el.update("");
14589 var records = this.store.getRange();
14590 if(records.length < 1) {
14592 // is this valid?? = should it render a template??
14594 this.el.update(this.emptyText);
14598 if (this.dataName) {
14599 this.el.update(t.apply(this.store.meta)); //????
14600 el = this.el.child('.roo-tpl-' + this.dataName);
14603 for(var i = 0, len = records.length; i < len; i++){
14604 var data = this.prepareData(records[i].data, i, records[i]);
14605 this.fireEvent("preparedata", this, data, i, records[i]);
14607 var d = Roo.apply({}, data);
14610 Roo.apply(d, {'roo-id' : Roo.id()});
14614 Roo.each(this.parent.item, function(item){
14615 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
14618 Roo.apply(d, {'roo-data-checked' : 'checked'});
14622 html[html.length] = Roo.util.Format.trim(
14624 t.applySubtemplate(this.dataName, d, this.store.meta) :
14631 el.update(html.join(""));
14632 this.nodes = el.dom.childNodes;
14633 this.updateIndexes(0);
14638 * Function to override to reformat the data that is sent to
14639 * the template for each node.
14640 * DEPRICATED - use the preparedata event handler.
14641 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
14642 * a JSON object for an UpdateManager bound view).
14644 prepareData : function(data, index, record)
14646 this.fireEvent("preparedata", this, data, index, record);
14650 onUpdate : function(ds, record){
14651 // Roo.log('on update');
14652 this.clearSelections();
14653 var index = this.store.indexOf(record);
14654 var n = this.nodes[index];
14655 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
14656 n.parentNode.removeChild(n);
14657 this.updateIndexes(index, index);
14663 onAdd : function(ds, records, index)
14665 //Roo.log(['on Add', ds, records, index] );
14666 this.clearSelections();
14667 if(this.nodes.length == 0){
14671 var n = this.nodes[index];
14672 for(var i = 0, len = records.length; i < len; i++){
14673 var d = this.prepareData(records[i].data, i, records[i]);
14675 this.tpl.insertBefore(n, d);
14678 this.tpl.append(this.el, d);
14681 this.updateIndexes(index);
14684 onRemove : function(ds, record, index){
14685 // Roo.log('onRemove');
14686 this.clearSelections();
14687 var el = this.dataName ?
14688 this.el.child('.roo-tpl-' + this.dataName) :
14691 el.dom.removeChild(this.nodes[index]);
14692 this.updateIndexes(index);
14696 * Refresh an individual node.
14697 * @param {Number} index
14699 refreshNode : function(index){
14700 this.onUpdate(this.store, this.store.getAt(index));
14703 updateIndexes : function(startIndex, endIndex){
14704 var ns = this.nodes;
14705 startIndex = startIndex || 0;
14706 endIndex = endIndex || ns.length - 1;
14707 for(var i = startIndex; i <= endIndex; i++){
14708 ns[i].nodeIndex = i;
14713 * Changes the data store this view uses and refresh the view.
14714 * @param {Store} store
14716 setStore : function(store, initial){
14717 if(!initial && this.store){
14718 this.store.un("datachanged", this.refresh);
14719 this.store.un("add", this.onAdd);
14720 this.store.un("remove", this.onRemove);
14721 this.store.un("update", this.onUpdate);
14722 this.store.un("clear", this.refresh);
14723 this.store.un("beforeload", this.onBeforeLoad);
14724 this.store.un("load", this.onLoad);
14725 this.store.un("loadexception", this.onLoad);
14729 store.on("datachanged", this.refresh, this);
14730 store.on("add", this.onAdd, this);
14731 store.on("remove", this.onRemove, this);
14732 store.on("update", this.onUpdate, this);
14733 store.on("clear", this.refresh, this);
14734 store.on("beforeload", this.onBeforeLoad, this);
14735 store.on("load", this.onLoad, this);
14736 store.on("loadexception", this.onLoad, this);
14744 * onbeforeLoad - masks the loading area.
14747 onBeforeLoad : function(store,opts)
14749 //Roo.log('onBeforeLoad');
14751 this.el.update("");
14753 this.el.mask(this.mask ? this.mask : "Loading" );
14755 onLoad : function ()
14762 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
14763 * @param {HTMLElement} node
14764 * @return {HTMLElement} The template node
14766 findItemFromChild : function(node){
14767 var el = this.dataName ?
14768 this.el.child('.roo-tpl-' + this.dataName,true) :
14771 if(!node || node.parentNode == el){
14774 var p = node.parentNode;
14775 while(p && p != el){
14776 if(p.parentNode == el){
14785 onClick : function(e){
14786 var item = this.findItemFromChild(e.getTarget());
14788 var index = this.indexOf(item);
14789 if(this.onItemClick(item, index, e) !== false){
14790 this.fireEvent("click", this, index, item, e);
14793 this.clearSelections();
14798 onContextMenu : function(e){
14799 var item = this.findItemFromChild(e.getTarget());
14801 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
14806 onDblClick : function(e){
14807 var item = this.findItemFromChild(e.getTarget());
14809 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
14813 onItemClick : function(item, index, e)
14815 if(this.fireEvent("beforeclick", this, index, item, e) === false){
14818 if (this.toggleSelect) {
14819 var m = this.isSelected(item) ? 'unselect' : 'select';
14822 _t[m](item, true, false);
14825 if(this.multiSelect || this.singleSelect){
14826 if(this.multiSelect && e.shiftKey && this.lastSelection){
14827 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
14829 this.select(item, this.multiSelect && e.ctrlKey);
14830 this.lastSelection = item;
14833 if(!this.tickable){
14834 e.preventDefault();
14842 * Get the number of selected nodes.
14845 getSelectionCount : function(){
14846 return this.selections.length;
14850 * Get the currently selected nodes.
14851 * @return {Array} An array of HTMLElements
14853 getSelectedNodes : function(){
14854 return this.selections;
14858 * Get the indexes of the selected nodes.
14861 getSelectedIndexes : function(){
14862 var indexes = [], s = this.selections;
14863 for(var i = 0, len = s.length; i < len; i++){
14864 indexes.push(s[i].nodeIndex);
14870 * Clear all selections
14871 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
14873 clearSelections : function(suppressEvent){
14874 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
14875 this.cmp.elements = this.selections;
14876 this.cmp.removeClass(this.selectedClass);
14877 this.selections = [];
14878 if(!suppressEvent){
14879 this.fireEvent("selectionchange", this, this.selections);
14885 * Returns true if the passed node is selected
14886 * @param {HTMLElement/Number} node The node or node index
14887 * @return {Boolean}
14889 isSelected : function(node){
14890 var s = this.selections;
14894 node = this.getNode(node);
14895 return s.indexOf(node) !== -1;
14900 * @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
14901 * @param {Boolean} keepExisting (optional) true to keep existing selections
14902 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14904 select : function(nodeInfo, keepExisting, suppressEvent){
14905 if(nodeInfo instanceof Array){
14907 this.clearSelections(true);
14909 for(var i = 0, len = nodeInfo.length; i < len; i++){
14910 this.select(nodeInfo[i], true, true);
14914 var node = this.getNode(nodeInfo);
14915 if(!node || this.isSelected(node)){
14916 return; // already selected.
14919 this.clearSelections(true);
14922 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
14923 Roo.fly(node).addClass(this.selectedClass);
14924 this.selections.push(node);
14925 if(!suppressEvent){
14926 this.fireEvent("selectionchange", this, this.selections);
14934 * @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
14935 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
14936 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
14938 unselect : function(nodeInfo, keepExisting, suppressEvent)
14940 if(nodeInfo instanceof Array){
14941 Roo.each(this.selections, function(s) {
14942 this.unselect(s, nodeInfo);
14946 var node = this.getNode(nodeInfo);
14947 if(!node || !this.isSelected(node)){
14948 //Roo.log("not selected");
14949 return; // not selected.
14953 Roo.each(this.selections, function(s) {
14955 Roo.fly(node).removeClass(this.selectedClass);
14962 this.selections= ns;
14963 this.fireEvent("selectionchange", this, this.selections);
14967 * Gets a template node.
14968 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
14969 * @return {HTMLElement} The node or null if it wasn't found
14971 getNode : function(nodeInfo){
14972 if(typeof nodeInfo == "string"){
14973 return document.getElementById(nodeInfo);
14974 }else if(typeof nodeInfo == "number"){
14975 return this.nodes[nodeInfo];
14981 * Gets a range template nodes.
14982 * @param {Number} startIndex
14983 * @param {Number} endIndex
14984 * @return {Array} An array of nodes
14986 getNodes : function(start, end){
14987 var ns = this.nodes;
14988 start = start || 0;
14989 end = typeof end == "undefined" ? ns.length - 1 : end;
14992 for(var i = start; i <= end; i++){
14996 for(var i = start; i >= end; i--){
15004 * Finds the index of the passed node
15005 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15006 * @return {Number} The index of the node or -1
15008 indexOf : function(node){
15009 node = this.getNode(node);
15010 if(typeof node.nodeIndex == "number"){
15011 return node.nodeIndex;
15013 var ns = this.nodes;
15014 for(var i = 0, len = ns.length; i < len; i++){
15025 * based on jquery fullcalendar
15029 Roo.bootstrap = Roo.bootstrap || {};
15031 * @class Roo.bootstrap.Calendar
15032 * @extends Roo.bootstrap.Component
15033 * Bootstrap Calendar class
15034 * @cfg {Boolean} loadMask (true|false) default false
15035 * @cfg {Object} header generate the user specific header of the calendar, default false
15038 * Create a new Container
15039 * @param {Object} config The config object
15044 Roo.bootstrap.Calendar = function(config){
15045 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
15049 * Fires when a date is selected
15050 * @param {DatePicker} this
15051 * @param {Date} date The selected date
15055 * @event monthchange
15056 * Fires when the displayed month changes
15057 * @param {DatePicker} this
15058 * @param {Date} date The selected month
15060 'monthchange': true,
15062 * @event evententer
15063 * Fires when mouse over an event
15064 * @param {Calendar} this
15065 * @param {event} Event
15067 'evententer': true,
15069 * @event eventleave
15070 * Fires when the mouse leaves an
15071 * @param {Calendar} this
15074 'eventleave': true,
15076 * @event eventclick
15077 * Fires when the mouse click an
15078 * @param {Calendar} this
15087 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
15090 * @cfg {Number} startDay
15091 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
15099 getAutoCreate : function(){
15102 var fc_button = function(name, corner, style, content ) {
15103 return Roo.apply({},{
15105 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
15107 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
15110 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
15121 style : 'width:100%',
15128 cls : 'fc-header-left',
15130 fc_button('prev', 'left', 'arrow', '‹' ),
15131 fc_button('next', 'right', 'arrow', '›' ),
15132 { tag: 'span', cls: 'fc-header-space' },
15133 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
15141 cls : 'fc-header-center',
15145 cls: 'fc-header-title',
15148 html : 'month / year'
15156 cls : 'fc-header-right',
15158 /* fc_button('month', 'left', '', 'month' ),
15159 fc_button('week', '', '', 'week' ),
15160 fc_button('day', 'right', '', 'day' )
15172 header = this.header;
15175 var cal_heads = function() {
15177 // fixme - handle this.
15179 for (var i =0; i < Date.dayNames.length; i++) {
15180 var d = Date.dayNames[i];
15183 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
15184 html : d.substring(0,3)
15188 ret[0].cls += ' fc-first';
15189 ret[6].cls += ' fc-last';
15192 var cal_cell = function(n) {
15195 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
15200 cls: 'fc-day-number',
15204 cls: 'fc-day-content',
15208 style: 'position: relative;' // height: 17px;
15220 var cal_rows = function() {
15223 for (var r = 0; r < 6; r++) {
15230 for (var i =0; i < Date.dayNames.length; i++) {
15231 var d = Date.dayNames[i];
15232 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
15235 row.cn[0].cls+=' fc-first';
15236 row.cn[0].cn[0].style = 'min-height:90px';
15237 row.cn[6].cls+=' fc-last';
15241 ret[0].cls += ' fc-first';
15242 ret[4].cls += ' fc-prev-last';
15243 ret[5].cls += ' fc-last';
15250 cls: 'fc-border-separate',
15251 style : 'width:100%',
15259 cls : 'fc-first fc-last',
15277 cls : 'fc-content',
15278 style : "position: relative;",
15281 cls : 'fc-view fc-view-month fc-grid',
15282 style : 'position: relative',
15283 unselectable : 'on',
15286 cls : 'fc-event-container',
15287 style : 'position:absolute;z-index:8;top:0;left:0;'
15305 initEvents : function()
15308 throw "can not find store for calendar";
15314 style: "text-align:center",
15318 style: "background-color:white;width:50%;margin:250 auto",
15322 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
15333 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
15335 var size = this.el.select('.fc-content', true).first().getSize();
15336 this.maskEl.setSize(size.width, size.height);
15337 this.maskEl.enableDisplayMode("block");
15338 if(!this.loadMask){
15339 this.maskEl.hide();
15342 this.store = Roo.factory(this.store, Roo.data);
15343 this.store.on('load', this.onLoad, this);
15344 this.store.on('beforeload', this.onBeforeLoad, this);
15348 this.cells = this.el.select('.fc-day',true);
15349 //Roo.log(this.cells);
15350 this.textNodes = this.el.query('.fc-day-number');
15351 this.cells.addClassOnOver('fc-state-hover');
15353 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
15354 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
15355 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
15356 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
15358 this.on('monthchange', this.onMonthChange, this);
15360 this.update(new Date().clearTime());
15363 resize : function() {
15364 var sz = this.el.getSize();
15366 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
15367 this.el.select('.fc-day-content div',true).setHeight(34);
15372 showPrevMonth : function(e){
15373 this.update(this.activeDate.add("mo", -1));
15375 showToday : function(e){
15376 this.update(new Date().clearTime());
15379 showNextMonth : function(e){
15380 this.update(this.activeDate.add("mo", 1));
15384 showPrevYear : function(){
15385 this.update(this.activeDate.add("y", -1));
15389 showNextYear : function(){
15390 this.update(this.activeDate.add("y", 1));
15395 update : function(date)
15397 var vd = this.activeDate;
15398 this.activeDate = date;
15399 // if(vd && this.el){
15400 // var t = date.getTime();
15401 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
15402 // Roo.log('using add remove');
15404 // this.fireEvent('monthchange', this, date);
15406 // this.cells.removeClass("fc-state-highlight");
15407 // this.cells.each(function(c){
15408 // if(c.dateValue == t){
15409 // c.addClass("fc-state-highlight");
15410 // setTimeout(function(){
15411 // try{c.dom.firstChild.focus();}catch(e){}
15421 var days = date.getDaysInMonth();
15423 var firstOfMonth = date.getFirstDateOfMonth();
15424 var startingPos = firstOfMonth.getDay()-this.startDay;
15426 if(startingPos < this.startDay){
15430 var pm = date.add(Date.MONTH, -1);
15431 var prevStart = pm.getDaysInMonth()-startingPos;
15433 this.cells = this.el.select('.fc-day',true);
15434 this.textNodes = this.el.query('.fc-day-number');
15435 this.cells.addClassOnOver('fc-state-hover');
15437 var cells = this.cells.elements;
15438 var textEls = this.textNodes;
15440 Roo.each(cells, function(cell){
15441 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
15444 days += startingPos;
15446 // convert everything to numbers so it's fast
15447 var day = 86400000;
15448 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
15451 //Roo.log(prevStart);
15453 var today = new Date().clearTime().getTime();
15454 var sel = date.clearTime().getTime();
15455 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
15456 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
15457 var ddMatch = this.disabledDatesRE;
15458 var ddText = this.disabledDatesText;
15459 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
15460 var ddaysText = this.disabledDaysText;
15461 var format = this.format;
15463 var setCellClass = function(cal, cell){
15467 //Roo.log('set Cell Class');
15469 var t = d.getTime();
15473 cell.dateValue = t;
15475 cell.className += " fc-today";
15476 cell.className += " fc-state-highlight";
15477 cell.title = cal.todayText;
15480 // disable highlight in other month..
15481 //cell.className += " fc-state-highlight";
15486 cell.className = " fc-state-disabled";
15487 cell.title = cal.minText;
15491 cell.className = " fc-state-disabled";
15492 cell.title = cal.maxText;
15496 if(ddays.indexOf(d.getDay()) != -1){
15497 cell.title = ddaysText;
15498 cell.className = " fc-state-disabled";
15501 if(ddMatch && format){
15502 var fvalue = d.dateFormat(format);
15503 if(ddMatch.test(fvalue)){
15504 cell.title = ddText.replace("%0", fvalue);
15505 cell.className = " fc-state-disabled";
15509 if (!cell.initialClassName) {
15510 cell.initialClassName = cell.dom.className;
15513 cell.dom.className = cell.initialClassName + ' ' + cell.className;
15518 for(; i < startingPos; i++) {
15519 textEls[i].innerHTML = (++prevStart);
15520 d.setDate(d.getDate()+1);
15522 cells[i].className = "fc-past fc-other-month";
15523 setCellClass(this, cells[i]);
15528 for(; i < days; i++){
15529 intDay = i - startingPos + 1;
15530 textEls[i].innerHTML = (intDay);
15531 d.setDate(d.getDate()+1);
15533 cells[i].className = ''; // "x-date-active";
15534 setCellClass(this, cells[i]);
15538 for(; i < 42; i++) {
15539 textEls[i].innerHTML = (++extraDays);
15540 d.setDate(d.getDate()+1);
15542 cells[i].className = "fc-future fc-other-month";
15543 setCellClass(this, cells[i]);
15546 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
15548 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
15550 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
15551 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
15553 if(totalRows != 6){
15554 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
15555 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
15558 this.fireEvent('monthchange', this, date);
15562 if(!this.internalRender){
15563 var main = this.el.dom.firstChild;
15564 var w = main.offsetWidth;
15565 this.el.setWidth(w + this.el.getBorderWidth("lr"));
15566 Roo.fly(main).setWidth(w);
15567 this.internalRender = true;
15568 // opera does not respect the auto grow header center column
15569 // then, after it gets a width opera refuses to recalculate
15570 // without a second pass
15571 if(Roo.isOpera && !this.secondPass){
15572 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
15573 this.secondPass = true;
15574 this.update.defer(10, this, [date]);
15581 findCell : function(dt) {
15582 dt = dt.clearTime().getTime();
15584 this.cells.each(function(c){
15585 //Roo.log("check " +c.dateValue + '?=' + dt);
15586 if(c.dateValue == dt){
15596 findCells : function(ev) {
15597 var s = ev.start.clone().clearTime().getTime();
15599 var e= ev.end.clone().clearTime().getTime();
15602 this.cells.each(function(c){
15603 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
15605 if(c.dateValue > e){
15608 if(c.dateValue < s){
15617 // findBestRow: function(cells)
15621 // for (var i =0 ; i < cells.length;i++) {
15622 // ret = Math.max(cells[i].rows || 0,ret);
15629 addItem : function(ev)
15631 // look for vertical location slot in
15632 var cells = this.findCells(ev);
15634 // ev.row = this.findBestRow(cells);
15636 // work out the location.
15640 for(var i =0; i < cells.length; i++) {
15642 cells[i].row = cells[0].row;
15645 cells[i].row = cells[i].row + 1;
15655 if (crow.start.getY() == cells[i].getY()) {
15657 crow.end = cells[i];
15674 cells[0].events.push(ev);
15676 this.calevents.push(ev);
15679 clearEvents: function() {
15681 if(!this.calevents){
15685 Roo.each(this.cells.elements, function(c){
15691 Roo.each(this.calevents, function(e) {
15692 Roo.each(e.els, function(el) {
15693 el.un('mouseenter' ,this.onEventEnter, this);
15694 el.un('mouseleave' ,this.onEventLeave, this);
15699 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
15705 renderEvents: function()
15709 this.cells.each(function(c) {
15718 if(c.row != c.events.length){
15719 r = 4 - (4 - (c.row - c.events.length));
15722 c.events = ev.slice(0, r);
15723 c.more = ev.slice(r);
15725 if(c.more.length && c.more.length == 1){
15726 c.events.push(c.more.pop());
15729 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
15733 this.cells.each(function(c) {
15735 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
15738 for (var e = 0; e < c.events.length; e++){
15739 var ev = c.events[e];
15740 var rows = ev.rows;
15742 for(var i = 0; i < rows.length; i++) {
15744 // how many rows should it span..
15747 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
15748 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
15750 unselectable : "on",
15753 cls: 'fc-event-inner',
15757 // cls: 'fc-event-time',
15758 // html : cells.length > 1 ? '' : ev.time
15762 cls: 'fc-event-title',
15763 html : String.format('{0}', ev.title)
15770 cls: 'ui-resizable-handle ui-resizable-e',
15771 html : '  '
15778 cfg.cls += ' fc-event-start';
15780 if ((i+1) == rows.length) {
15781 cfg.cls += ' fc-event-end';
15784 var ctr = _this.el.select('.fc-event-container',true).first();
15785 var cg = ctr.createChild(cfg);
15787 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
15788 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
15790 var r = (c.more.length) ? 1 : 0;
15791 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
15792 cg.setWidth(ebox.right - sbox.x -2);
15794 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
15795 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
15796 cg.on('click', _this.onEventClick, _this, ev);
15807 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
15808 style : 'position: absolute',
15809 unselectable : "on",
15812 cls: 'fc-event-inner',
15816 cls: 'fc-event-title',
15824 cls: 'ui-resizable-handle ui-resizable-e',
15825 html : '  '
15831 var ctr = _this.el.select('.fc-event-container',true).first();
15832 var cg = ctr.createChild(cfg);
15834 var sbox = c.select('.fc-day-content',true).first().getBox();
15835 var ebox = c.select('.fc-day-content',true).first().getBox();
15837 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
15838 cg.setWidth(ebox.right - sbox.x -2);
15840 cg.on('click', _this.onMoreEventClick, _this, c.more);
15850 onEventEnter: function (e, el,event,d) {
15851 this.fireEvent('evententer', this, el, event);
15854 onEventLeave: function (e, el,event,d) {
15855 this.fireEvent('eventleave', this, el, event);
15858 onEventClick: function (e, el,event,d) {
15859 this.fireEvent('eventclick', this, el, event);
15862 onMonthChange: function () {
15866 onMoreEventClick: function(e, el, more)
15870 this.calpopover.placement = 'right';
15871 this.calpopover.setTitle('More');
15873 this.calpopover.setContent('');
15875 var ctr = this.calpopover.el.select('.popover-content', true).first();
15877 Roo.each(more, function(m){
15879 cls : 'fc-event-hori fc-event-draggable',
15882 var cg = ctr.createChild(cfg);
15884 cg.on('click', _this.onEventClick, _this, m);
15887 this.calpopover.show(el);
15892 onLoad: function ()
15894 this.calevents = [];
15897 if(this.store.getCount() > 0){
15898 this.store.data.each(function(d){
15901 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
15902 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
15903 time : d.data.start_time,
15904 title : d.data.title,
15905 description : d.data.description,
15906 venue : d.data.venue
15911 this.renderEvents();
15913 if(this.calevents.length && this.loadMask){
15914 this.maskEl.hide();
15918 onBeforeLoad: function()
15920 this.clearEvents();
15922 this.maskEl.show();
15936 * @class Roo.bootstrap.Popover
15937 * @extends Roo.bootstrap.Component
15938 * Bootstrap Popover class
15939 * @cfg {String} html contents of the popover (or false to use children..)
15940 * @cfg {String} title of popover (or false to hide)
15941 * @cfg {String} placement how it is placed
15942 * @cfg {String} trigger click || hover (or false to trigger manually)
15943 * @cfg {String} over what (parent or false to trigger manually.)
15944 * @cfg {Number} delay - delay before showing
15947 * Create a new Popover
15948 * @param {Object} config The config object
15951 Roo.bootstrap.Popover = function(config){
15952 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
15958 * After the popover show
15960 * @param {Roo.bootstrap.Popover} this
15965 * After the popover hide
15967 * @param {Roo.bootstrap.Popover} this
15973 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
15975 title: 'Fill in a title',
15978 placement : 'right',
15979 trigger : 'hover', // hover
15985 can_build_overlaid : false,
15987 getChildContainer : function()
15989 return this.el.select('.popover-content',true).first();
15992 getAutoCreate : function(){
15995 cls : 'popover roo-dynamic',
15996 style: 'display:block',
16002 cls : 'popover-inner',
16006 cls: 'popover-title',
16010 cls : 'popover-content',
16021 setTitle: function(str)
16024 this.el.select('.popover-title',true).first().dom.innerHTML = str;
16026 setContent: function(str)
16029 this.el.select('.popover-content',true).first().dom.innerHTML = str;
16031 // as it get's added to the bottom of the page.
16032 onRender : function(ct, position)
16034 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16036 var cfg = Roo.apply({}, this.getAutoCreate());
16040 cfg.cls += ' ' + this.cls;
16043 cfg.style = this.style;
16045 //Roo.log("adding to ");
16046 this.el = Roo.get(document.body).createChild(cfg, position);
16047 // Roo.log(this.el);
16052 initEvents : function()
16054 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
16055 this.el.enableDisplayMode('block');
16057 if (this.over === false) {
16060 if (this.triggers === false) {
16063 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16064 var triggers = this.trigger ? this.trigger.split(' ') : [];
16065 Roo.each(triggers, function(trigger) {
16067 if (trigger == 'click') {
16068 on_el.on('click', this.toggle, this);
16069 } else if (trigger != 'manual') {
16070 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
16071 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
16073 on_el.on(eventIn ,this.enter, this);
16074 on_el.on(eventOut, this.leave, this);
16085 toggle : function () {
16086 this.hoverState == 'in' ? this.leave() : this.enter();
16089 enter : function () {
16091 clearTimeout(this.timeout);
16093 this.hoverState = 'in';
16095 if (!this.delay || !this.delay.show) {
16100 this.timeout = setTimeout(function () {
16101 if (_t.hoverState == 'in') {
16104 }, this.delay.show)
16107 leave : function() {
16108 clearTimeout(this.timeout);
16110 this.hoverState = 'out';
16112 if (!this.delay || !this.delay.hide) {
16117 this.timeout = setTimeout(function () {
16118 if (_t.hoverState == 'out') {
16121 }, this.delay.hide)
16124 show : function (on_el)
16127 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
16131 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
16132 if (this.html !== false) {
16133 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
16135 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
16136 if (!this.title.length) {
16137 this.el.select('.popover-title',true).hide();
16140 var placement = typeof this.placement == 'function' ?
16141 this.placement.call(this, this.el, on_el) :
16144 var autoToken = /\s?auto?\s?/i;
16145 var autoPlace = autoToken.test(placement);
16147 placement = placement.replace(autoToken, '') || 'top';
16151 //this.el.setXY([0,0]);
16153 this.el.dom.style.display='block';
16154 this.el.addClass(placement);
16156 //this.el.appendTo(on_el);
16158 var p = this.getPosition();
16159 var box = this.el.getBox();
16164 var align = Roo.bootstrap.Popover.alignment[placement];
16165 this.el.alignTo(on_el, align[0],align[1]);
16166 //var arrow = this.el.select('.arrow',true).first();
16167 //arrow.set(align[2],
16169 this.el.addClass('in');
16172 if (this.el.hasClass('fade')) {
16176 this.hoverState = 'in';
16178 this.fireEvent('show', this);
16183 this.el.setXY([0,0]);
16184 this.el.removeClass('in');
16186 this.hoverState = null;
16188 this.fireEvent('hide', this);
16193 Roo.bootstrap.Popover.alignment = {
16194 'left' : ['r-l', [-10,0], 'right'],
16195 'right' : ['l-r', [10,0], 'left'],
16196 'bottom' : ['t-b', [0,10], 'top'],
16197 'top' : [ 'b-t', [0,-10], 'bottom']
16208 * @class Roo.bootstrap.Progress
16209 * @extends Roo.bootstrap.Component
16210 * Bootstrap Progress class
16211 * @cfg {Boolean} striped striped of the progress bar
16212 * @cfg {Boolean} active animated of the progress bar
16216 * Create a new Progress
16217 * @param {Object} config The config object
16220 Roo.bootstrap.Progress = function(config){
16221 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
16224 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
16229 getAutoCreate : function(){
16237 cfg.cls += ' progress-striped';
16241 cfg.cls += ' active';
16260 * @class Roo.bootstrap.ProgressBar
16261 * @extends Roo.bootstrap.Component
16262 * Bootstrap ProgressBar class
16263 * @cfg {Number} aria_valuenow aria-value now
16264 * @cfg {Number} aria_valuemin aria-value min
16265 * @cfg {Number} aria_valuemax aria-value max
16266 * @cfg {String} label label for the progress bar
16267 * @cfg {String} panel (success | info | warning | danger )
16268 * @cfg {String} role role of the progress bar
16269 * @cfg {String} sr_only text
16273 * Create a new ProgressBar
16274 * @param {Object} config The config object
16277 Roo.bootstrap.ProgressBar = function(config){
16278 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
16281 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
16285 aria_valuemax : 100,
16291 getAutoCreate : function()
16296 cls: 'progress-bar',
16297 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
16309 cfg.role = this.role;
16312 if(this.aria_valuenow){
16313 cfg['aria-valuenow'] = this.aria_valuenow;
16316 if(this.aria_valuemin){
16317 cfg['aria-valuemin'] = this.aria_valuemin;
16320 if(this.aria_valuemax){
16321 cfg['aria-valuemax'] = this.aria_valuemax;
16324 if(this.label && !this.sr_only){
16325 cfg.html = this.label;
16329 cfg.cls += ' progress-bar-' + this.panel;
16335 update : function(aria_valuenow)
16337 this.aria_valuenow = aria_valuenow;
16339 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
16354 * @class Roo.bootstrap.TabGroup
16355 * @extends Roo.bootstrap.Column
16356 * Bootstrap Column class
16357 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
16358 * @cfg {Boolean} carousel true to make the group behave like a carousel
16359 * @cfg {Boolean} bullets show bullets for the panels
16360 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
16361 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
16362 * @cfg {Number} timer auto slide timer .. default 0 millisecond
16365 * Create a new TabGroup
16366 * @param {Object} config The config object
16369 Roo.bootstrap.TabGroup = function(config){
16370 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
16372 this.navId = Roo.id();
16375 Roo.bootstrap.TabGroup.register(this);
16379 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
16382 transition : false,
16387 slideOnTouch : false,
16389 getAutoCreate : function()
16391 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
16393 cfg.cls += ' tab-content';
16395 if (this.carousel) {
16396 cfg.cls += ' carousel slide';
16399 cls : 'carousel-inner'
16402 if(this.bullets && !Roo.isTouch){
16405 cls : 'carousel-bullets',
16409 if(this.bullets_cls){
16410 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
16413 for (var i = 0; i < this.bullets; i++){
16415 cls : 'bullet bullet-' + i
16423 cfg.cn[0].cn = bullets;
16430 initEvents: function()
16432 if(Roo.isTouch && this.slideOnTouch){
16433 this.el.on("touchstart", this.onTouchStart, this);
16436 if(this.autoslide){
16439 this.slideFn = window.setInterval(function() {
16440 _this.showPanelNext();
16446 onTouchStart : function(e, el, o)
16448 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
16452 this.showPanelNext();
16455 getChildContainer : function()
16457 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
16461 * register a Navigation item
16462 * @param {Roo.bootstrap.NavItem} the navitem to add
16464 register : function(item)
16466 this.tabs.push( item);
16467 item.navId = this.navId; // not really needed..
16472 getActivePanel : function()
16475 Roo.each(this.tabs, function(t) {
16485 getPanelByName : function(n)
16488 Roo.each(this.tabs, function(t) {
16489 if (t.tabId == n) {
16497 indexOfPanel : function(p)
16500 Roo.each(this.tabs, function(t,i) {
16501 if (t.tabId == p.tabId) {
16510 * show a specific panel
16511 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
16512 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
16514 showPanel : function (pan)
16516 if(this.transition || typeof(pan) == 'undefined'){
16517 Roo.log("waiting for the transitionend");
16521 if (typeof(pan) == 'number') {
16522 pan = this.tabs[pan];
16525 if (typeof(pan) == 'string') {
16526 pan = this.getPanelByName(pan);
16529 var cur = this.getActivePanel();
16532 Roo.log('pan or acitve pan is undefined');
16536 if (pan.tabId == this.getActivePanel().tabId) {
16540 if (false === cur.fireEvent('beforedeactivate')) {
16544 if(this.bullets > 0 && !Roo.isTouch){
16545 this.setActiveBullet(this.indexOfPanel(pan));
16548 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
16550 this.transition = true;
16551 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
16552 var lr = dir == 'next' ? 'left' : 'right';
16553 pan.el.addClass(dir); // or prev
16554 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
16555 cur.el.addClass(lr); // or right
16556 pan.el.addClass(lr);
16559 cur.el.on('transitionend', function() {
16560 Roo.log("trans end?");
16562 pan.el.removeClass([lr,dir]);
16563 pan.setActive(true);
16565 cur.el.removeClass([lr]);
16566 cur.setActive(false);
16568 _this.transition = false;
16570 }, this, { single: true } );
16575 cur.setActive(false);
16576 pan.setActive(true);
16581 showPanelNext : function()
16583 var i = this.indexOfPanel(this.getActivePanel());
16585 if (i >= this.tabs.length - 1 && !this.autoslide) {
16589 if (i >= this.tabs.length - 1 && this.autoslide) {
16593 this.showPanel(this.tabs[i+1]);
16596 showPanelPrev : function()
16598 var i = this.indexOfPanel(this.getActivePanel());
16600 if (i < 1 && !this.autoslide) {
16604 if (i < 1 && this.autoslide) {
16605 i = this.tabs.length;
16608 this.showPanel(this.tabs[i-1]);
16612 addBullet: function()
16614 if(!this.bullets || Roo.isTouch){
16617 var ctr = this.el.select('.carousel-bullets',true).first();
16618 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
16619 var bullet = ctr.createChild({
16620 cls : 'bullet bullet-' + i
16621 },ctr.dom.lastChild);
16626 bullet.on('click', (function(e, el, o, ii, t){
16628 e.preventDefault();
16630 this.showPanel(ii);
16632 if(this.autoslide && this.slideFn){
16633 clearInterval(this.slideFn);
16634 this.slideFn = window.setInterval(function() {
16635 _this.showPanelNext();
16639 }).createDelegate(this, [i, bullet], true));
16644 setActiveBullet : function(i)
16650 Roo.each(this.el.select('.bullet', true).elements, function(el){
16651 el.removeClass('selected');
16654 var bullet = this.el.select('.bullet-' + i, true).first();
16660 bullet.addClass('selected');
16671 Roo.apply(Roo.bootstrap.TabGroup, {
16675 * register a Navigation Group
16676 * @param {Roo.bootstrap.NavGroup} the navgroup to add
16678 register : function(navgrp)
16680 this.groups[navgrp.navId] = navgrp;
16684 * fetch a Navigation Group based on the navigation ID
16685 * if one does not exist , it will get created.
16686 * @param {string} the navgroup to add
16687 * @returns {Roo.bootstrap.NavGroup} the navgroup
16689 get: function(navId) {
16690 if (typeof(this.groups[navId]) == 'undefined') {
16691 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
16693 return this.groups[navId] ;
16708 * @class Roo.bootstrap.TabPanel
16709 * @extends Roo.bootstrap.Component
16710 * Bootstrap TabPanel class
16711 * @cfg {Boolean} active panel active
16712 * @cfg {String} html panel content
16713 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
16714 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
16718 * Create a new TabPanel
16719 * @param {Object} config The config object
16722 Roo.bootstrap.TabPanel = function(config){
16723 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
16727 * Fires when the active status changes
16728 * @param {Roo.bootstrap.TabPanel} this
16729 * @param {Boolean} state the new state
16734 * @event beforedeactivate
16735 * Fires before a tab is de-activated - can be used to do validation on a form.
16736 * @param {Roo.bootstrap.TabPanel} this
16737 * @return {Boolean} false if there is an error
16740 'beforedeactivate': true
16743 this.tabId = this.tabId || Roo.id();
16747 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
16754 getAutoCreate : function(){
16757 // item is needed for carousel - not sure if it has any effect otherwise
16758 cls: 'tab-pane item',
16759 html: this.html || ''
16763 cfg.cls += ' active';
16767 cfg.tabId = this.tabId;
16774 initEvents: function()
16776 var p = this.parent();
16777 this.navId = this.navId || p.navId;
16779 if (typeof(this.navId) != 'undefined') {
16780 // not really needed.. but just in case.. parent should be a NavGroup.
16781 var tg = Roo.bootstrap.TabGroup.get(this.navId);
16785 var i = tg.tabs.length - 1;
16787 if(this.active && tg.bullets > 0 && i < tg.bullets){
16788 tg.setActiveBullet(i);
16795 onRender : function(ct, position)
16797 // Roo.log("Call onRender: " + this.xtype);
16799 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
16807 setActive: function(state)
16809 Roo.log("panel - set active " + this.tabId + "=" + state);
16811 this.active = state;
16813 this.el.removeClass('active');
16815 } else if (!this.el.hasClass('active')) {
16816 this.el.addClass('active');
16819 this.fireEvent('changed', this, state);
16836 * @class Roo.bootstrap.DateField
16837 * @extends Roo.bootstrap.Input
16838 * Bootstrap DateField class
16839 * @cfg {Number} weekStart default 0
16840 * @cfg {String} viewMode default empty, (months|years)
16841 * @cfg {String} minViewMode default empty, (months|years)
16842 * @cfg {Number} startDate default -Infinity
16843 * @cfg {Number} endDate default Infinity
16844 * @cfg {Boolean} todayHighlight default false
16845 * @cfg {Boolean} todayBtn default false
16846 * @cfg {Boolean} calendarWeeks default false
16847 * @cfg {Object} daysOfWeekDisabled default empty
16848 * @cfg {Boolean} singleMode default false (true | false)
16850 * @cfg {Boolean} keyboardNavigation default true
16851 * @cfg {String} language default en
16854 * Create a new DateField
16855 * @param {Object} config The config object
16858 Roo.bootstrap.DateField = function(config){
16859 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
16863 * Fires when this field show.
16864 * @param {Roo.bootstrap.DateField} this
16865 * @param {Mixed} date The date value
16870 * Fires when this field hide.
16871 * @param {Roo.bootstrap.DateField} this
16872 * @param {Mixed} date The date value
16877 * Fires when select a date.
16878 * @param {Roo.bootstrap.DateField} this
16879 * @param {Mixed} date The date value
16883 * @event beforeselect
16884 * Fires when before select a date.
16885 * @param {Roo.bootstrap.DateField} this
16886 * @param {Mixed} date The date value
16888 beforeselect : true
16892 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
16895 * @cfg {String} format
16896 * The default date format string which can be overriden for localization support. The format must be
16897 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
16901 * @cfg {String} altFormats
16902 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
16903 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
16905 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
16913 todayHighlight : false,
16919 keyboardNavigation: true,
16921 calendarWeeks: false,
16923 startDate: -Infinity,
16927 daysOfWeekDisabled: [],
16931 singleMode : false,
16933 UTCDate: function()
16935 return new Date(Date.UTC.apply(Date, arguments));
16938 UTCToday: function()
16940 var today = new Date();
16941 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
16944 getDate: function() {
16945 var d = this.getUTCDate();
16946 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
16949 getUTCDate: function() {
16953 setDate: function(d) {
16954 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
16957 setUTCDate: function(d) {
16959 this.setValue(this.formatDate(this.date));
16962 onRender: function(ct, position)
16965 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
16967 this.language = this.language || 'en';
16968 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
16969 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
16971 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
16972 this.format = this.format || 'm/d/y';
16973 this.isInline = false;
16974 this.isInput = true;
16975 this.component = this.el.select('.add-on', true).first() || false;
16976 this.component = (this.component && this.component.length === 0) ? false : this.component;
16977 this.hasInput = this.component && this.inputEL().length;
16979 if (typeof(this.minViewMode === 'string')) {
16980 switch (this.minViewMode) {
16982 this.minViewMode = 1;
16985 this.minViewMode = 2;
16988 this.minViewMode = 0;
16993 if (typeof(this.viewMode === 'string')) {
16994 switch (this.viewMode) {
17007 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
17009 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
17011 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17013 this.picker().on('mousedown', this.onMousedown, this);
17014 this.picker().on('click', this.onClick, this);
17016 this.picker().addClass('datepicker-dropdown');
17018 this.startViewMode = this.viewMode;
17020 if(this.singleMode){
17021 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
17022 v.setVisibilityMode(Roo.Element.DISPLAY);
17026 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
17027 v.setStyle('width', '189px');
17031 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
17032 if(!this.calendarWeeks){
17037 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17038 v.attr('colspan', function(i, val){
17039 return parseInt(val) + 1;
17044 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
17046 this.setStartDate(this.startDate);
17047 this.setEndDate(this.endDate);
17049 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
17056 if(this.isInline) {
17061 picker : function()
17063 return this.pickerEl;
17064 // return this.el.select('.datepicker', true).first();
17067 fillDow: function()
17069 var dowCnt = this.weekStart;
17078 if(this.calendarWeeks){
17086 while (dowCnt < this.weekStart + 7) {
17090 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
17094 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
17097 fillMonths: function()
17100 var months = this.picker().select('>.datepicker-months td', true).first();
17102 months.dom.innerHTML = '';
17108 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
17111 months.createChild(month);
17118 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;
17120 if (this.date < this.startDate) {
17121 this.viewDate = new Date(this.startDate);
17122 } else if (this.date > this.endDate) {
17123 this.viewDate = new Date(this.endDate);
17125 this.viewDate = new Date(this.date);
17133 var d = new Date(this.viewDate),
17134 year = d.getUTCFullYear(),
17135 month = d.getUTCMonth(),
17136 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
17137 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
17138 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
17139 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
17140 currentDate = this.date && this.date.valueOf(),
17141 today = this.UTCToday();
17143 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
17145 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
17147 // this.picker.select('>tfoot th.today').
17148 // .text(dates[this.language].today)
17149 // .toggle(this.todayBtn !== false);
17151 this.updateNavArrows();
17154 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
17156 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
17158 prevMonth.setUTCDate(day);
17160 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
17162 var nextMonth = new Date(prevMonth);
17164 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
17166 nextMonth = nextMonth.valueOf();
17168 var fillMonths = false;
17170 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
17172 while(prevMonth.valueOf() < nextMonth) {
17175 if (prevMonth.getUTCDay() === this.weekStart) {
17177 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
17185 if(this.calendarWeeks){
17186 // ISO 8601: First week contains first thursday.
17187 // ISO also states week starts on Monday, but we can be more abstract here.
17189 // Start of current week: based on weekstart/current date
17190 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
17191 // Thursday of this week
17192 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
17193 // First Thursday of year, year from thursday
17194 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
17195 // Calendar week: ms between thursdays, div ms per day, div 7 days
17196 calWeek = (th - yth) / 864e5 / 7 + 1;
17198 fillMonths.cn.push({
17206 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
17208 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
17211 if (this.todayHighlight &&
17212 prevMonth.getUTCFullYear() == today.getFullYear() &&
17213 prevMonth.getUTCMonth() == today.getMonth() &&
17214 prevMonth.getUTCDate() == today.getDate()) {
17215 clsName += ' today';
17218 if (currentDate && prevMonth.valueOf() === currentDate) {
17219 clsName += ' active';
17222 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
17223 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
17224 clsName += ' disabled';
17227 fillMonths.cn.push({
17229 cls: 'day ' + clsName,
17230 html: prevMonth.getDate()
17233 prevMonth.setDate(prevMonth.getDate()+1);
17236 var currentYear = this.date && this.date.getUTCFullYear();
17237 var currentMonth = this.date && this.date.getUTCMonth();
17239 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
17241 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
17242 v.removeClass('active');
17244 if(currentYear === year && k === currentMonth){
17245 v.addClass('active');
17248 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
17249 v.addClass('disabled');
17255 year = parseInt(year/10, 10) * 10;
17257 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
17259 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
17262 for (var i = -1; i < 11; i++) {
17263 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
17265 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
17273 showMode: function(dir)
17276 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
17279 Roo.each(this.picker().select('>div',true).elements, function(v){
17280 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17283 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
17288 if(this.isInline) {
17292 this.picker().removeClass(['bottom', 'top']);
17294 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17296 * place to the top of element!
17300 this.picker().addClass('top');
17301 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17306 this.picker().addClass('bottom');
17308 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17311 parseDate : function(value)
17313 if(!value || value instanceof Date){
17316 var v = Date.parseDate(value, this.format);
17317 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
17318 v = Date.parseDate(value, 'Y-m-d');
17320 if(!v && this.altFormats){
17321 if(!this.altFormatsArray){
17322 this.altFormatsArray = this.altFormats.split("|");
17324 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
17325 v = Date.parseDate(value, this.altFormatsArray[i]);
17331 formatDate : function(date, fmt)
17333 return (!date || !(date instanceof Date)) ?
17334 date : date.dateFormat(fmt || this.format);
17337 onFocus : function()
17339 Roo.bootstrap.DateField.superclass.onFocus.call(this);
17343 onBlur : function()
17345 Roo.bootstrap.DateField.superclass.onBlur.call(this);
17347 var d = this.inputEl().getValue();
17356 this.picker().show();
17360 this.fireEvent('show', this, this.date);
17365 if(this.isInline) {
17368 this.picker().hide();
17369 this.viewMode = this.startViewMode;
17372 this.fireEvent('hide', this, this.date);
17376 onMousedown: function(e)
17378 e.stopPropagation();
17379 e.preventDefault();
17384 Roo.bootstrap.DateField.superclass.keyup.call(this);
17388 setValue: function(v)
17390 if(this.fireEvent('beforeselect', this, v) !== false){
17391 var d = new Date(this.parseDate(v) ).clearTime();
17393 if(isNaN(d.getTime())){
17394 this.date = this.viewDate = '';
17395 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
17399 v = this.formatDate(d);
17401 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
17403 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
17407 this.fireEvent('select', this, this.date);
17411 getValue: function()
17413 return this.formatDate(this.date);
17416 fireKey: function(e)
17418 if (!this.picker().isVisible()){
17419 if (e.keyCode == 27) { // allow escape to hide and re-show picker
17425 var dateChanged = false,
17427 newDate, newViewDate;
17432 e.preventDefault();
17436 if (!this.keyboardNavigation) {
17439 dir = e.keyCode == 37 ? -1 : 1;
17442 newDate = this.moveYear(this.date, dir);
17443 newViewDate = this.moveYear(this.viewDate, dir);
17444 } else if (e.shiftKey){
17445 newDate = this.moveMonth(this.date, dir);
17446 newViewDate = this.moveMonth(this.viewDate, dir);
17448 newDate = new Date(this.date);
17449 newDate.setUTCDate(this.date.getUTCDate() + dir);
17450 newViewDate = new Date(this.viewDate);
17451 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
17453 if (this.dateWithinRange(newDate)){
17454 this.date = newDate;
17455 this.viewDate = newViewDate;
17456 this.setValue(this.formatDate(this.date));
17458 e.preventDefault();
17459 dateChanged = true;
17464 if (!this.keyboardNavigation) {
17467 dir = e.keyCode == 38 ? -1 : 1;
17469 newDate = this.moveYear(this.date, dir);
17470 newViewDate = this.moveYear(this.viewDate, dir);
17471 } else if (e.shiftKey){
17472 newDate = this.moveMonth(this.date, dir);
17473 newViewDate = this.moveMonth(this.viewDate, dir);
17475 newDate = new Date(this.date);
17476 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
17477 newViewDate = new Date(this.viewDate);
17478 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
17480 if (this.dateWithinRange(newDate)){
17481 this.date = newDate;
17482 this.viewDate = newViewDate;
17483 this.setValue(this.formatDate(this.date));
17485 e.preventDefault();
17486 dateChanged = true;
17490 this.setValue(this.formatDate(this.date));
17492 e.preventDefault();
17495 this.setValue(this.formatDate(this.date));
17509 onClick: function(e)
17511 e.stopPropagation();
17512 e.preventDefault();
17514 var target = e.getTarget();
17516 if(target.nodeName.toLowerCase() === 'i'){
17517 target = Roo.get(target).dom.parentNode;
17520 var nodeName = target.nodeName;
17521 var className = target.className;
17522 var html = target.innerHTML;
17523 //Roo.log(nodeName);
17525 switch(nodeName.toLowerCase()) {
17527 switch(className) {
17533 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
17534 switch(this.viewMode){
17536 this.viewDate = this.moveMonth(this.viewDate, dir);
17540 this.viewDate = this.moveYear(this.viewDate, dir);
17546 var date = new Date();
17547 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
17549 this.setValue(this.formatDate(this.date));
17556 if (className.indexOf('disabled') < 0) {
17557 this.viewDate.setUTCDate(1);
17558 if (className.indexOf('month') > -1) {
17559 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
17561 var year = parseInt(html, 10) || 0;
17562 this.viewDate.setUTCFullYear(year);
17566 if(this.singleMode){
17567 this.setValue(this.formatDate(this.viewDate));
17578 //Roo.log(className);
17579 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
17580 var day = parseInt(html, 10) || 1;
17581 var year = this.viewDate.getUTCFullYear(),
17582 month = this.viewDate.getUTCMonth();
17584 if (className.indexOf('old') > -1) {
17591 } else if (className.indexOf('new') > -1) {
17599 //Roo.log([year,month,day]);
17600 this.date = this.UTCDate(year, month, day,0,0,0,0);
17601 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
17603 //Roo.log(this.formatDate(this.date));
17604 this.setValue(this.formatDate(this.date));
17611 setStartDate: function(startDate)
17613 this.startDate = startDate || -Infinity;
17614 if (this.startDate !== -Infinity) {
17615 this.startDate = this.parseDate(this.startDate);
17618 this.updateNavArrows();
17621 setEndDate: function(endDate)
17623 this.endDate = endDate || Infinity;
17624 if (this.endDate !== Infinity) {
17625 this.endDate = this.parseDate(this.endDate);
17628 this.updateNavArrows();
17631 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
17633 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
17634 if (typeof(this.daysOfWeekDisabled) !== 'object') {
17635 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
17637 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
17638 return parseInt(d, 10);
17641 this.updateNavArrows();
17644 updateNavArrows: function()
17646 if(this.singleMode){
17650 var d = new Date(this.viewDate),
17651 year = d.getUTCFullYear(),
17652 month = d.getUTCMonth();
17654 Roo.each(this.picker().select('.prev', true).elements, function(v){
17656 switch (this.viewMode) {
17659 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
17665 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
17672 Roo.each(this.picker().select('.next', true).elements, function(v){
17674 switch (this.viewMode) {
17677 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
17683 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
17691 moveMonth: function(date, dir)
17696 var new_date = new Date(date.valueOf()),
17697 day = new_date.getUTCDate(),
17698 month = new_date.getUTCMonth(),
17699 mag = Math.abs(dir),
17701 dir = dir > 0 ? 1 : -1;
17704 // If going back one month, make sure month is not current month
17705 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
17707 return new_date.getUTCMonth() == month;
17709 // If going forward one month, make sure month is as expected
17710 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
17712 return new_date.getUTCMonth() != new_month;
17714 new_month = month + dir;
17715 new_date.setUTCMonth(new_month);
17716 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
17717 if (new_month < 0 || new_month > 11) {
17718 new_month = (new_month + 12) % 12;
17721 // For magnitudes >1, move one month at a time...
17722 for (var i=0; i<mag; i++) {
17723 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
17724 new_date = this.moveMonth(new_date, dir);
17726 // ...then reset the day, keeping it in the new month
17727 new_month = new_date.getUTCMonth();
17728 new_date.setUTCDate(day);
17730 return new_month != new_date.getUTCMonth();
17733 // Common date-resetting loop -- if date is beyond end of month, make it
17736 new_date.setUTCDate(--day);
17737 new_date.setUTCMonth(new_month);
17742 moveYear: function(date, dir)
17744 return this.moveMonth(date, dir*12);
17747 dateWithinRange: function(date)
17749 return date >= this.startDate && date <= this.endDate;
17755 this.picker().remove();
17760 Roo.apply(Roo.bootstrap.DateField, {
17771 html: '<i class="fa fa-arrow-left"/>'
17781 html: '<i class="fa fa-arrow-right"/>'
17823 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
17824 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17825 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
17826 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17827 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
17840 navFnc: 'FullYear',
17845 navFnc: 'FullYear',
17850 Roo.apply(Roo.bootstrap.DateField, {
17854 cls: 'datepicker dropdown-menu roo-dynamic',
17858 cls: 'datepicker-days',
17862 cls: 'table-condensed',
17864 Roo.bootstrap.DateField.head,
17868 Roo.bootstrap.DateField.footer
17875 cls: 'datepicker-months',
17879 cls: 'table-condensed',
17881 Roo.bootstrap.DateField.head,
17882 Roo.bootstrap.DateField.content,
17883 Roo.bootstrap.DateField.footer
17890 cls: 'datepicker-years',
17894 cls: 'table-condensed',
17896 Roo.bootstrap.DateField.head,
17897 Roo.bootstrap.DateField.content,
17898 Roo.bootstrap.DateField.footer
17917 * @class Roo.bootstrap.TimeField
17918 * @extends Roo.bootstrap.Input
17919 * Bootstrap DateField class
17923 * Create a new TimeField
17924 * @param {Object} config The config object
17927 Roo.bootstrap.TimeField = function(config){
17928 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
17932 * Fires when this field show.
17933 * @param {Roo.bootstrap.DateField} thisthis
17934 * @param {Mixed} date The date value
17939 * Fires when this field hide.
17940 * @param {Roo.bootstrap.DateField} this
17941 * @param {Mixed} date The date value
17946 * Fires when select a date.
17947 * @param {Roo.bootstrap.DateField} this
17948 * @param {Mixed} date The date value
17954 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
17957 * @cfg {String} format
17958 * The default time format string which can be overriden for localization support. The format must be
17959 * valid according to {@link Date#parseDate} (defaults to 'H:i').
17963 onRender: function(ct, position)
17966 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
17968 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
17970 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17972 this.pop = this.picker().select('>.datepicker-time',true).first();
17973 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17975 this.picker().on('mousedown', this.onMousedown, this);
17976 this.picker().on('click', this.onClick, this);
17978 this.picker().addClass('datepicker-dropdown');
17983 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
17984 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
17985 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
17986 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
17987 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
17988 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
17992 fireKey: function(e){
17993 if (!this.picker().isVisible()){
17994 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18000 e.preventDefault();
18008 this.onTogglePeriod();
18011 this.onIncrementMinutes();
18014 this.onDecrementMinutes();
18023 onClick: function(e) {
18024 e.stopPropagation();
18025 e.preventDefault();
18028 picker : function()
18030 return this.el.select('.datepicker', true).first();
18033 fillTime: function()
18035 var time = this.pop.select('tbody', true).first();
18037 time.dom.innerHTML = '';
18052 cls: 'hours-up glyphicon glyphicon-chevron-up'
18072 cls: 'minutes-up glyphicon glyphicon-chevron-up'
18093 cls: 'timepicker-hour',
18108 cls: 'timepicker-minute',
18123 cls: 'btn btn-primary period',
18145 cls: 'hours-down glyphicon glyphicon-chevron-down'
18165 cls: 'minutes-down glyphicon glyphicon-chevron-down'
18183 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
18190 var hours = this.time.getHours();
18191 var minutes = this.time.getMinutes();
18204 hours = hours - 12;
18208 hours = '0' + hours;
18212 minutes = '0' + minutes;
18215 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
18216 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
18217 this.pop.select('button', true).first().dom.innerHTML = period;
18223 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
18225 var cls = ['bottom'];
18227 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
18234 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
18239 this.picker().addClass(cls.join('-'));
18243 Roo.each(cls, function(c){
18245 _this.picker().setTop(_this.inputEl().getHeight());
18249 _this.picker().setTop(0 - _this.picker().getHeight());
18254 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
18258 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
18265 onFocus : function()
18267 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
18271 onBlur : function()
18273 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
18279 this.picker().show();
18284 this.fireEvent('show', this, this.date);
18289 this.picker().hide();
18292 this.fireEvent('hide', this, this.date);
18295 setTime : function()
18298 this.setValue(this.time.format(this.format));
18300 this.fireEvent('select', this, this.date);
18305 onMousedown: function(e){
18306 e.stopPropagation();
18307 e.preventDefault();
18310 onIncrementHours: function()
18312 Roo.log('onIncrementHours');
18313 this.time = this.time.add(Date.HOUR, 1);
18318 onDecrementHours: function()
18320 Roo.log('onDecrementHours');
18321 this.time = this.time.add(Date.HOUR, -1);
18325 onIncrementMinutes: function()
18327 Roo.log('onIncrementMinutes');
18328 this.time = this.time.add(Date.MINUTE, 1);
18332 onDecrementMinutes: function()
18334 Roo.log('onDecrementMinutes');
18335 this.time = this.time.add(Date.MINUTE, -1);
18339 onTogglePeriod: function()
18341 Roo.log('onTogglePeriod');
18342 this.time = this.time.add(Date.HOUR, 12);
18349 Roo.apply(Roo.bootstrap.TimeField, {
18379 cls: 'btn btn-info ok',
18391 Roo.apply(Roo.bootstrap.TimeField, {
18395 cls: 'datepicker dropdown-menu',
18399 cls: 'datepicker-time',
18403 cls: 'table-condensed',
18405 Roo.bootstrap.TimeField.content,
18406 Roo.bootstrap.TimeField.footer
18425 * @class Roo.bootstrap.MonthField
18426 * @extends Roo.bootstrap.Input
18427 * Bootstrap MonthField class
18429 * @cfg {String} language default en
18432 * Create a new MonthField
18433 * @param {Object} config The config object
18436 Roo.bootstrap.MonthField = function(config){
18437 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
18442 * Fires when this field show.
18443 * @param {Roo.bootstrap.MonthField} this
18444 * @param {Mixed} date The date value
18449 * Fires when this field hide.
18450 * @param {Roo.bootstrap.MonthField} this
18451 * @param {Mixed} date The date value
18456 * Fires when select a date.
18457 * @param {Roo.bootstrap.MonthField} this
18458 * @param {String} oldvalue The old value
18459 * @param {String} newvalue The new value
18465 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
18467 onRender: function(ct, position)
18470 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
18472 this.language = this.language || 'en';
18473 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
18474 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
18476 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
18477 this.isInline = false;
18478 this.isInput = true;
18479 this.component = this.el.select('.add-on', true).first() || false;
18480 this.component = (this.component && this.component.length === 0) ? false : this.component;
18481 this.hasInput = this.component && this.inputEL().length;
18483 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
18485 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18487 this.picker().on('mousedown', this.onMousedown, this);
18488 this.picker().on('click', this.onClick, this);
18490 this.picker().addClass('datepicker-dropdown');
18492 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18493 v.setStyle('width', '189px');
18500 if(this.isInline) {
18506 setValue: function(v, suppressEvent)
18508 var o = this.getValue();
18510 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
18514 if(suppressEvent !== true){
18515 this.fireEvent('select', this, o, v);
18520 getValue: function()
18525 onClick: function(e)
18527 e.stopPropagation();
18528 e.preventDefault();
18530 var target = e.getTarget();
18532 if(target.nodeName.toLowerCase() === 'i'){
18533 target = Roo.get(target).dom.parentNode;
18536 var nodeName = target.nodeName;
18537 var className = target.className;
18538 var html = target.innerHTML;
18540 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
18544 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
18546 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18552 picker : function()
18554 return this.pickerEl;
18557 fillMonths: function()
18560 var months = this.picker().select('>.datepicker-months td', true).first();
18562 months.dom.innerHTML = '';
18568 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
18571 months.createChild(month);
18580 if(typeof(this.vIndex) == 'undefined' && this.value.length){
18581 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
18584 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
18585 e.removeClass('active');
18587 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
18588 e.addClass('active');
18595 if(this.isInline) {
18599 this.picker().removeClass(['bottom', 'top']);
18601 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18603 * place to the top of element!
18607 this.picker().addClass('top');
18608 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18613 this.picker().addClass('bottom');
18615 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18618 onFocus : function()
18620 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
18624 onBlur : function()
18626 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
18628 var d = this.inputEl().getValue();
18637 this.picker().show();
18638 this.picker().select('>.datepicker-months', true).first().show();
18642 this.fireEvent('show', this, this.date);
18647 if(this.isInline) {
18650 this.picker().hide();
18651 this.fireEvent('hide', this, this.date);
18655 onMousedown: function(e)
18657 e.stopPropagation();
18658 e.preventDefault();
18663 Roo.bootstrap.MonthField.superclass.keyup.call(this);
18667 fireKey: function(e)
18669 if (!this.picker().isVisible()){
18670 if (e.keyCode == 27) {// allow escape to hide and re-show picker
18681 e.preventDefault();
18685 dir = e.keyCode == 37 ? -1 : 1;
18687 this.vIndex = this.vIndex + dir;
18689 if(this.vIndex < 0){
18693 if(this.vIndex > 11){
18697 if(isNaN(this.vIndex)){
18701 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18707 dir = e.keyCode == 38 ? -1 : 1;
18709 this.vIndex = this.vIndex + dir * 4;
18711 if(this.vIndex < 0){
18715 if(this.vIndex > 11){
18719 if(isNaN(this.vIndex)){
18723 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18728 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18729 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18733 e.preventDefault();
18736 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
18737 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
18753 this.picker().remove();
18758 Roo.apply(Roo.bootstrap.MonthField, {
18777 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18778 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
18783 Roo.apply(Roo.bootstrap.MonthField, {
18787 cls: 'datepicker dropdown-menu roo-dynamic',
18791 cls: 'datepicker-months',
18795 cls: 'table-condensed',
18797 Roo.bootstrap.DateField.content
18817 * @class Roo.bootstrap.CheckBox
18818 * @extends Roo.bootstrap.Input
18819 * Bootstrap CheckBox class
18821 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
18822 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
18823 * @cfg {String} boxLabel The text that appears beside the checkbox
18824 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
18825 * @cfg {Boolean} checked initnal the element
18826 * @cfg {Boolean} inline inline the element (default false)
18827 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
18830 * Create a new CheckBox
18831 * @param {Object} config The config object
18834 Roo.bootstrap.CheckBox = function(config){
18835 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
18840 * Fires when the element is checked or unchecked.
18841 * @param {Roo.bootstrap.CheckBox} this This input
18842 * @param {Boolean} checked The new checked value
18849 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
18851 inputType: 'checkbox',
18859 getAutoCreate : function()
18861 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
18867 cfg.cls = 'form-group ' + this.inputType; //input-group
18870 cfg.cls += ' ' + this.inputType + '-inline';
18876 type : this.inputType,
18877 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
18878 cls : 'roo-' + this.inputType, //'form-box',
18879 placeholder : this.placeholder || ''
18883 if (this.weight) { // Validity check?
18884 cfg.cls += " " + this.inputType + "-" + this.weight;
18887 if (this.disabled) {
18888 input.disabled=true;
18892 input.checked = this.checked;
18896 input.name = this.name;
18900 input.cls += ' input-' + this.size;
18905 ['xs','sm','md','lg'].map(function(size){
18906 if (settings[size]) {
18907 cfg.cls += ' col-' + size + '-' + settings[size];
18911 var inputblock = input;
18913 if (this.before || this.after) {
18916 cls : 'input-group',
18921 inputblock.cn.push({
18923 cls : 'input-group-addon',
18928 inputblock.cn.push(input);
18931 inputblock.cn.push({
18933 cls : 'input-group-addon',
18940 if (align ==='left' && this.fieldLabel.length) {
18941 // Roo.log("left and has label");
18947 cls : 'control-label col-md-' + this.labelWidth,
18948 html : this.fieldLabel
18952 cls : "col-md-" + (12 - this.labelWidth),
18959 } else if ( this.fieldLabel.length) {
18960 // Roo.log(" label");
18964 tag: this.boxLabel ? 'span' : 'label',
18966 cls: 'control-label box-input-label',
18967 //cls : 'input-group-addon',
18968 html : this.fieldLabel
18978 // Roo.log(" no label && no align");
18979 cfg.cn = [ inputblock ] ;
18985 var boxLabelCfg = {
18987 //'for': id, // box label is handled by onclick - so no for...
18989 html: this.boxLabel
18993 boxLabelCfg.tooltip = this.tooltip;
18996 cfg.cn.push(boxLabelCfg);
19006 * return the real input element.
19008 inputEl: function ()
19010 return this.el.select('input.roo-' + this.inputType,true).first();
19013 labelEl: function()
19015 return this.el.select('label.control-label',true).first();
19017 /* depricated... */
19021 return this.labelEl();
19024 boxLabelEl: function()
19026 return this.el.select('label.box-label',true).first();
19029 initEvents : function()
19031 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19033 this.inputEl().on('click', this.onClick, this);
19035 if (this.boxLabel) {
19036 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
19039 this.startValue = this.getValue();
19042 Roo.bootstrap.CheckBox.register(this);
19046 onClick : function()
19048 this.setChecked(!this.checked);
19051 setChecked : function(state,suppressEvent)
19053 this.startValue = this.getValue();
19055 if(this.inputType == 'radio'){
19057 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19058 e.dom.checked = false;
19061 this.inputEl().dom.checked = true;
19063 this.inputEl().dom.value = this.inputValue;
19065 if(suppressEvent !== true){
19066 this.fireEvent('check', this, true);
19074 this.checked = state;
19076 this.inputEl().dom.checked = state;
19078 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19080 if(suppressEvent !== true){
19081 this.fireEvent('check', this, state);
19087 getValue : function()
19089 if(this.inputType == 'radio'){
19090 return this.getGroupValue();
19093 return this.inputEl().getValue();
19097 getGroupValue : function()
19099 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
19103 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
19106 setValue : function(v,suppressEvent)
19108 if(this.inputType == 'radio'){
19109 this.setGroupValue(v, suppressEvent);
19113 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
19118 setGroupValue : function(v, suppressEvent)
19120 this.startValue = this.getValue();
19122 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19123 e.dom.checked = false;
19125 if(e.dom.value == v){
19126 e.dom.checked = true;
19130 if(suppressEvent !== true){
19131 this.fireEvent('check', this, true);
19139 validate : function()
19143 (this.inputType == 'radio' && this.validateRadio()) ||
19144 (this.inputType == 'checkbox' && this.validateCheckbox())
19150 this.markInvalid();
19154 validateRadio : function()
19158 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19159 if(!e.dom.checked){
19171 validateCheckbox : function()
19174 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
19177 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19185 for(var i in group){
19190 r = (group[i].getValue() == group[i].inputValue) ? true : false;
19197 * Mark this field as valid
19199 markValid : function()
19201 if(this.allowBlank){
19207 this.fireEvent('valid', this);
19209 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19212 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19219 if(this.inputType == 'radio'){
19220 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19221 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19222 e.findParent('.form-group', false, true).addClass(_this.validClass);
19229 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19230 this.el.findParent('.form-group', false, true).addClass(this.validClass);
19234 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19240 for(var i in group){
19241 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19242 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
19247 * Mark this field as invalid
19248 * @param {String} msg The validation message
19250 markInvalid : function(msg)
19252 if(this.allowBlank){
19258 this.fireEvent('invalid', this, msg);
19260 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
19263 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
19267 label.markInvalid();
19270 if(this.inputType == 'radio'){
19271 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
19272 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
19273 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
19280 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19281 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
19285 var group = Roo.bootstrap.CheckBox.get(this.groupId);
19291 for(var i in group){
19292 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
19293 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
19300 Roo.apply(Roo.bootstrap.CheckBox, {
19305 * register a CheckBox Group
19306 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
19308 register : function(checkbox)
19310 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
19311 this.groups[checkbox.groupId] = {};
19314 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
19318 this.groups[checkbox.groupId][checkbox.name] = checkbox;
19322 * fetch a CheckBox Group based on the group ID
19323 * @param {string} the group ID
19324 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
19326 get: function(groupId) {
19327 if (typeof(this.groups[groupId]) == 'undefined') {
19331 return this.groups[groupId] ;
19343 *<div class="radio">
19345 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
19346 Option one is this and that—be sure to include why it's great
19353 *<label class="radio-inline">fieldLabel</label>
19354 *<label class="radio-inline">
19355 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
19363 * @class Roo.bootstrap.Radio
19364 * @extends Roo.bootstrap.CheckBox
19365 * Bootstrap Radio class
19368 * Create a new Radio
19369 * @param {Object} config The config object
19372 Roo.bootstrap.Radio = function(config){
19373 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
19377 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
19379 inputType: 'radio',
19383 getAutoCreate : function()
19385 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19386 align = align || 'left'; // default...
19393 tag : this.inline ? 'span' : 'div',
19398 var inline = this.inline ? ' radio-inline' : '';
19402 // does not need for, as we wrap the input with it..
19404 cls : 'control-label box-label' + inline,
19407 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
19411 //cls : 'control-label' + inline,
19412 html : this.fieldLabel,
19413 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
19422 type : this.inputType,
19423 //value : (!this.checked) ? this.valueOff : this.inputValue,
19424 value : this.inputValue,
19426 placeholder : this.placeholder || '' // ?? needed????
19429 if (this.weight) { // Validity check?
19430 input.cls += " radio-" + this.weight;
19432 if (this.disabled) {
19433 input.disabled=true;
19437 input.checked = this.checked;
19441 input.name = this.name;
19445 input.cls += ' input-' + this.size;
19448 //?? can span's inline have a width??
19451 ['xs','sm','md','lg'].map(function(size){
19452 if (settings[size]) {
19453 cfg.cls += ' col-' + size + '-' + settings[size];
19457 var inputblock = input;
19459 if (this.before || this.after) {
19462 cls : 'input-group',
19467 inputblock.cn.push({
19469 cls : 'input-group-addon',
19473 inputblock.cn.push(input);
19475 inputblock.cn.push({
19477 cls : 'input-group-addon',
19485 if (this.fieldLabel && this.fieldLabel.length) {
19486 cfg.cn.push(fieldLabel);
19489 // normal bootstrap puts the input inside the label.
19490 // however with our styled version - it has to go after the input.
19492 //lbl.cn.push(inputblock);
19496 cls: 'radio' + inline,
19503 cfg.cn.push( lblwrap);
19508 html: this.boxLabel
19517 initEvents : function()
19519 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
19521 this.inputEl().on('click', this.onClick, this);
19522 if (this.boxLabel) {
19523 //Roo.log('find label');
19524 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
19529 inputEl: function ()
19531 return this.el.select('input.roo-radio',true).first();
19533 onClick : function()
19536 this.setChecked(true);
19539 setChecked : function(state,suppressEvent)
19542 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19543 v.dom.checked = false;
19546 Roo.log(this.inputEl().dom);
19547 this.checked = state;
19548 this.inputEl().dom.checked = state;
19550 if(suppressEvent !== true){
19551 this.fireEvent('check', this, state);
19554 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
19558 getGroupValue : function()
19561 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
19562 if(v.dom.checked == true){
19563 value = v.dom.value;
19571 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19572 * @return {Mixed} value The field value
19574 getValue : function(){
19575 return this.getGroupValue();
19581 //<script type="text/javascript">
19584 * Based Ext JS Library 1.1.1
19585 * Copyright(c) 2006-2007, Ext JS, LLC.
19591 * @class Roo.HtmlEditorCore
19592 * @extends Roo.Component
19593 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
19595 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
19598 Roo.HtmlEditorCore = function(config){
19601 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
19606 * @event initialize
19607 * Fires when the editor is fully initialized (including the iframe)
19608 * @param {Roo.HtmlEditorCore} this
19613 * Fires when the editor is first receives the focus. Any insertion must wait
19614 * until after this event.
19615 * @param {Roo.HtmlEditorCore} this
19619 * @event beforesync
19620 * Fires before the textarea is updated with content from the editor iframe. Return false
19621 * to cancel the sync.
19622 * @param {Roo.HtmlEditorCore} this
19623 * @param {String} html
19627 * @event beforepush
19628 * Fires before the iframe editor is updated with content from the textarea. Return false
19629 * to cancel the push.
19630 * @param {Roo.HtmlEditorCore} this
19631 * @param {String} html
19636 * Fires when the textarea is updated with content from the editor iframe.
19637 * @param {Roo.HtmlEditorCore} this
19638 * @param {String} html
19643 * Fires when the iframe editor is updated with content from the textarea.
19644 * @param {Roo.HtmlEditorCore} this
19645 * @param {String} html
19650 * @event editorevent
19651 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19652 * @param {Roo.HtmlEditorCore} this
19658 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
19660 // defaults : white / black...
19661 this.applyBlacklists();
19668 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
19672 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
19678 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19683 * @cfg {Number} height (in pixels)
19687 * @cfg {Number} width (in pixels)
19692 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19695 stylesheets: false,
19700 // private properties
19701 validationEvent : false,
19703 initialized : false,
19705 sourceEditMode : false,
19706 onFocus : Roo.emptyFn,
19708 hideMode:'offsets',
19712 // blacklist + whitelisted elements..
19719 * Protected method that will not generally be called directly. It
19720 * is called when the editor initializes the iframe with HTML contents. Override this method if you
19721 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
19723 getDocMarkup : function(){
19727 // inherit styels from page...??
19728 if (this.stylesheets === false) {
19730 Roo.get(document.head).select('style').each(function(node) {
19731 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19734 Roo.get(document.head).select('link').each(function(node) {
19735 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
19738 } else if (!this.stylesheets.length) {
19740 st = '<style type="text/css">' +
19741 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19747 st += '<style type="text/css">' +
19748 'IMG { cursor: pointer } ' +
19752 return '<html><head>' + st +
19753 //<style type="text/css">' +
19754 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
19756 ' </head><body class="roo-htmleditor-body"></body></html>';
19760 onRender : function(ct, position)
19763 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
19764 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
19767 this.el.dom.style.border = '0 none';
19768 this.el.dom.setAttribute('tabIndex', -1);
19769 this.el.addClass('x-hidden hide');
19773 if(Roo.isIE){ // fix IE 1px bogus margin
19774 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
19778 this.frameId = Roo.id();
19782 var iframe = this.owner.wrap.createChild({
19784 cls: 'form-control', // bootstrap..
19786 name: this.frameId,
19787 frameBorder : 'no',
19788 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
19793 this.iframe = iframe.dom;
19795 this.assignDocWin();
19797 this.doc.designMode = 'on';
19800 this.doc.write(this.getDocMarkup());
19804 var task = { // must defer to wait for browser to be ready
19806 //console.log("run task?" + this.doc.readyState);
19807 this.assignDocWin();
19808 if(this.doc.body || this.doc.readyState == 'complete'){
19810 this.doc.designMode="on";
19814 Roo.TaskMgr.stop(task);
19815 this.initEditor.defer(10, this);
19822 Roo.TaskMgr.start(task);
19827 onResize : function(w, h)
19829 Roo.log('resize: ' +w + ',' + h );
19830 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
19834 if(typeof w == 'number'){
19836 this.iframe.style.width = w + 'px';
19838 if(typeof h == 'number'){
19840 this.iframe.style.height = h + 'px';
19842 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
19849 * Toggles the editor between standard and source edit mode.
19850 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19852 toggleSourceEdit : function(sourceEditMode){
19854 this.sourceEditMode = sourceEditMode === true;
19856 if(this.sourceEditMode){
19858 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
19861 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
19862 //this.iframe.className = '';
19865 //this.setSize(this.owner.wrap.getSize());
19866 //this.fireEvent('editmodechange', this, this.sourceEditMode);
19873 * Protected method that will not generally be called directly. If you need/want
19874 * custom HTML cleanup, this is the method you should override.
19875 * @param {String} html The HTML to be cleaned
19876 * return {String} The cleaned HTML
19878 cleanHtml : function(html){
19879 html = String(html);
19880 if(html.length > 5){
19881 if(Roo.isSafari){ // strip safari nonsense
19882 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
19885 if(html == ' '){
19892 * HTML Editor -> Textarea
19893 * Protected method that will not generally be called directly. Syncs the contents
19894 * of the editor iframe with the textarea.
19896 syncValue : function(){
19897 if(this.initialized){
19898 var bd = (this.doc.body || this.doc.documentElement);
19899 //this.cleanUpPaste(); -- this is done else where and causes havoc..
19900 var html = bd.innerHTML;
19902 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
19903 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
19905 html = '<div style="'+m[0]+'">' + html + '</div>';
19908 html = this.cleanHtml(html);
19909 // fix up the special chars.. normaly like back quotes in word...
19910 // however we do not want to do this with chinese..
19911 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
19912 var cc = b.charCodeAt();
19914 (cc >= 0x4E00 && cc < 0xA000 ) ||
19915 (cc >= 0x3400 && cc < 0x4E00 ) ||
19916 (cc >= 0xf900 && cc < 0xfb00 )
19922 if(this.owner.fireEvent('beforesync', this, html) !== false){
19923 this.el.dom.value = html;
19924 this.owner.fireEvent('sync', this, html);
19930 * Protected method that will not generally be called directly. Pushes the value of the textarea
19931 * into the iframe editor.
19933 pushValue : function(){
19934 if(this.initialized){
19935 var v = this.el.dom.value.trim();
19937 // if(v.length < 1){
19941 if(this.owner.fireEvent('beforepush', this, v) !== false){
19942 var d = (this.doc.body || this.doc.documentElement);
19944 this.cleanUpPaste();
19945 this.el.dom.value = d.innerHTML;
19946 this.owner.fireEvent('push', this, v);
19952 deferFocus : function(){
19953 this.focus.defer(10, this);
19957 focus : function(){
19958 if(this.win && !this.sourceEditMode){
19965 assignDocWin: function()
19967 var iframe = this.iframe;
19970 this.doc = iframe.contentWindow.document;
19971 this.win = iframe.contentWindow;
19973 // if (!Roo.get(this.frameId)) {
19976 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19977 // this.win = Roo.get(this.frameId).dom.contentWindow;
19979 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
19983 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
19984 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
19989 initEditor : function(){
19990 //console.log("INIT EDITOR");
19991 this.assignDocWin();
19995 this.doc.designMode="on";
19997 this.doc.write(this.getDocMarkup());
20000 var dbody = (this.doc.body || this.doc.documentElement);
20001 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
20002 // this copies styles from the containing element into thsi one..
20003 // not sure why we need all of this..
20004 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
20006 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
20007 //ss['background-attachment'] = 'fixed'; // w3c
20008 dbody.bgProperties = 'fixed'; // ie
20009 //Roo.DomHelper.applyStyles(dbody, ss);
20010 Roo.EventManager.on(this.doc, {
20011 //'mousedown': this.onEditorEvent,
20012 'mouseup': this.onEditorEvent,
20013 'dblclick': this.onEditorEvent,
20014 'click': this.onEditorEvent,
20015 'keyup': this.onEditorEvent,
20020 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
20022 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
20023 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
20025 this.initialized = true;
20027 this.owner.fireEvent('initialize', this);
20032 onDestroy : function(){
20038 //for (var i =0; i < this.toolbars.length;i++) {
20039 // // fixme - ask toolbars for heights?
20040 // this.toolbars[i].onDestroy();
20043 //this.wrap.dom.innerHTML = '';
20044 //this.wrap.remove();
20049 onFirstFocus : function(){
20051 this.assignDocWin();
20054 this.activated = true;
20057 if(Roo.isGecko){ // prevent silly gecko errors
20059 var s = this.win.getSelection();
20060 if(!s.focusNode || s.focusNode.nodeType != 3){
20061 var r = s.getRangeAt(0);
20062 r.selectNodeContents((this.doc.body || this.doc.documentElement));
20067 this.execCmd('useCSS', true);
20068 this.execCmd('styleWithCSS', false);
20071 this.owner.fireEvent('activate', this);
20075 adjustFont: function(btn){
20076 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
20077 //if(Roo.isSafari){ // safari
20080 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
20081 if(Roo.isSafari){ // safari
20082 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
20083 v = (v < 10) ? 10 : v;
20084 v = (v > 48) ? 48 : v;
20085 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
20090 v = Math.max(1, v+adjust);
20092 this.execCmd('FontSize', v );
20095 onEditorEvent : function(e)
20097 this.owner.fireEvent('editorevent', this, e);
20098 // this.updateToolbar();
20099 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
20102 insertTag : function(tg)
20104 // could be a bit smarter... -> wrap the current selected tRoo..
20105 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
20107 range = this.createRange(this.getSelection());
20108 var wrappingNode = this.doc.createElement(tg.toLowerCase());
20109 wrappingNode.appendChild(range.extractContents());
20110 range.insertNode(wrappingNode);
20117 this.execCmd("formatblock", tg);
20121 insertText : function(txt)
20125 var range = this.createRange();
20126 range.deleteContents();
20127 //alert(Sender.getAttribute('label'));
20129 range.insertNode(this.doc.createTextNode(txt));
20135 * Executes a Midas editor command on the editor document and performs necessary focus and
20136 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
20137 * @param {String} cmd The Midas command
20138 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20140 relayCmd : function(cmd, value){
20142 this.execCmd(cmd, value);
20143 this.owner.fireEvent('editorevent', this);
20144 //this.updateToolbar();
20145 this.owner.deferFocus();
20149 * Executes a Midas editor command directly on the editor document.
20150 * For visual commands, you should use {@link #relayCmd} instead.
20151 * <b>This should only be called after the editor is initialized.</b>
20152 * @param {String} cmd The Midas command
20153 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
20155 execCmd : function(cmd, value){
20156 this.doc.execCommand(cmd, false, value === undefined ? null : value);
20163 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
20165 * @param {String} text | dom node..
20167 insertAtCursor : function(text)
20172 if(!this.activated){
20178 var r = this.doc.selection.createRange();
20189 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
20193 // from jquery ui (MIT licenced)
20195 var win = this.win;
20197 if (win.getSelection && win.getSelection().getRangeAt) {
20198 range = win.getSelection().getRangeAt(0);
20199 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
20200 range.insertNode(node);
20201 } else if (win.document.selection && win.document.selection.createRange) {
20202 // no firefox support
20203 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20204 win.document.selection.createRange().pasteHTML(txt);
20206 // no firefox support
20207 var txt = typeof(text) == 'string' ? text : text.outerHTML;
20208 this.execCmd('InsertHTML', txt);
20217 mozKeyPress : function(e){
20219 var c = e.getCharCode(), cmd;
20222 c = String.fromCharCode(c).toLowerCase();
20236 this.cleanUpPaste.defer(100, this);
20244 e.preventDefault();
20252 fixKeys : function(){ // load time branching for fastest keydown performance
20254 return function(e){
20255 var k = e.getKey(), r;
20258 r = this.doc.selection.createRange();
20261 r.pasteHTML('    ');
20268 r = this.doc.selection.createRange();
20270 var target = r.parentElement();
20271 if(!target || target.tagName.toLowerCase() != 'li'){
20273 r.pasteHTML('<br />');
20279 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20280 this.cleanUpPaste.defer(100, this);
20286 }else if(Roo.isOpera){
20287 return function(e){
20288 var k = e.getKey();
20292 this.execCmd('InsertHTML','    ');
20295 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20296 this.cleanUpPaste.defer(100, this);
20301 }else if(Roo.isSafari){
20302 return function(e){
20303 var k = e.getKey();
20307 this.execCmd('InsertText','\t');
20311 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
20312 this.cleanUpPaste.defer(100, this);
20320 getAllAncestors: function()
20322 var p = this.getSelectedNode();
20325 a.push(p); // push blank onto stack..
20326 p = this.getParentElement();
20330 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
20334 a.push(this.doc.body);
20338 lastSelNode : false,
20341 getSelection : function()
20343 this.assignDocWin();
20344 return Roo.isIE ? this.doc.selection : this.win.getSelection();
20347 getSelectedNode: function()
20349 // this may only work on Gecko!!!
20351 // should we cache this!!!!
20356 var range = this.createRange(this.getSelection()).cloneRange();
20359 var parent = range.parentElement();
20361 var testRange = range.duplicate();
20362 testRange.moveToElementText(parent);
20363 if (testRange.inRange(range)) {
20366 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
20369 parent = parent.parentElement;
20374 // is ancestor a text element.
20375 var ac = range.commonAncestorContainer;
20376 if (ac.nodeType == 3) {
20377 ac = ac.parentNode;
20380 var ar = ac.childNodes;
20383 var other_nodes = [];
20384 var has_other_nodes = false;
20385 for (var i=0;i<ar.length;i++) {
20386 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
20389 // fullly contained node.
20391 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
20396 // probably selected..
20397 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
20398 other_nodes.push(ar[i]);
20402 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
20407 has_other_nodes = true;
20409 if (!nodes.length && other_nodes.length) {
20410 nodes= other_nodes;
20412 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
20418 createRange: function(sel)
20420 // this has strange effects when using with
20421 // top toolbar - not sure if it's a great idea.
20422 //this.editor.contentWindow.focus();
20423 if (typeof sel != "undefined") {
20425 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
20427 return this.doc.createRange();
20430 return this.doc.createRange();
20433 getParentElement: function()
20436 this.assignDocWin();
20437 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
20439 var range = this.createRange(sel);
20442 var p = range.commonAncestorContainer;
20443 while (p.nodeType == 3) { // text node
20454 * Range intersection.. the hard stuff...
20458 * [ -- selected range --- ]
20462 * if end is before start or hits it. fail.
20463 * if start is after end or hits it fail.
20465 * if either hits (but other is outside. - then it's not
20471 // @see http://www.thismuchiknow.co.uk/?p=64.
20472 rangeIntersectsNode : function(range, node)
20474 var nodeRange = node.ownerDocument.createRange();
20476 nodeRange.selectNode(node);
20478 nodeRange.selectNodeContents(node);
20481 var rangeStartRange = range.cloneRange();
20482 rangeStartRange.collapse(true);
20484 var rangeEndRange = range.cloneRange();
20485 rangeEndRange.collapse(false);
20487 var nodeStartRange = nodeRange.cloneRange();
20488 nodeStartRange.collapse(true);
20490 var nodeEndRange = nodeRange.cloneRange();
20491 nodeEndRange.collapse(false);
20493 return rangeStartRange.compareBoundaryPoints(
20494 Range.START_TO_START, nodeEndRange) == -1 &&
20495 rangeEndRange.compareBoundaryPoints(
20496 Range.START_TO_START, nodeStartRange) == 1;
20500 rangeCompareNode : function(range, node)
20502 var nodeRange = node.ownerDocument.createRange();
20504 nodeRange.selectNode(node);
20506 nodeRange.selectNodeContents(node);
20510 range.collapse(true);
20512 nodeRange.collapse(true);
20514 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
20515 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
20517 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
20519 var nodeIsBefore = ss == 1;
20520 var nodeIsAfter = ee == -1;
20522 if (nodeIsBefore && nodeIsAfter) {
20525 if (!nodeIsBefore && nodeIsAfter) {
20526 return 1; //right trailed.
20529 if (nodeIsBefore && !nodeIsAfter) {
20530 return 2; // left trailed.
20536 // private? - in a new class?
20537 cleanUpPaste : function()
20539 // cleans up the whole document..
20540 Roo.log('cleanuppaste');
20542 this.cleanUpChildren(this.doc.body);
20543 var clean = this.cleanWordChars(this.doc.body.innerHTML);
20544 if (clean != this.doc.body.innerHTML) {
20545 this.doc.body.innerHTML = clean;
20550 cleanWordChars : function(input) {// change the chars to hex code
20551 var he = Roo.HtmlEditorCore;
20553 var output = input;
20554 Roo.each(he.swapCodes, function(sw) {
20555 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
20557 output = output.replace(swapper, sw[1]);
20564 cleanUpChildren : function (n)
20566 if (!n.childNodes.length) {
20569 for (var i = n.childNodes.length-1; i > -1 ; i--) {
20570 this.cleanUpChild(n.childNodes[i]);
20577 cleanUpChild : function (node)
20580 //console.log(node);
20581 if (node.nodeName == "#text") {
20582 // clean up silly Windows -- stuff?
20585 if (node.nodeName == "#comment") {
20586 node.parentNode.removeChild(node);
20587 // clean up silly Windows -- stuff?
20590 var lcname = node.tagName.toLowerCase();
20591 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
20592 // whitelist of tags..
20594 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
20596 node.parentNode.removeChild(node);
20601 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
20603 // remove <a name=....> as rendering on yahoo mailer is borked with this.
20604 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
20606 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
20607 // remove_keep_children = true;
20610 if (remove_keep_children) {
20611 this.cleanUpChildren(node);
20612 // inserts everything just before this node...
20613 while (node.childNodes.length) {
20614 var cn = node.childNodes[0];
20615 node.removeChild(cn);
20616 node.parentNode.insertBefore(cn, node);
20618 node.parentNode.removeChild(node);
20622 if (!node.attributes || !node.attributes.length) {
20623 this.cleanUpChildren(node);
20627 function cleanAttr(n,v)
20630 if (v.match(/^\./) || v.match(/^\//)) {
20633 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
20636 if (v.match(/^#/)) {
20639 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
20640 node.removeAttribute(n);
20644 var cwhite = this.cwhite;
20645 var cblack = this.cblack;
20647 function cleanStyle(n,v)
20649 if (v.match(/expression/)) { //XSS?? should we even bother..
20650 node.removeAttribute(n);
20654 var parts = v.split(/;/);
20657 Roo.each(parts, function(p) {
20658 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
20662 var l = p.split(':').shift().replace(/\s+/g,'');
20663 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
20665 if ( cwhite.length && cblack.indexOf(l) > -1) {
20666 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20667 //node.removeAttribute(n);
20671 // only allow 'c whitelisted system attributes'
20672 if ( cwhite.length && cwhite.indexOf(l) < 0) {
20673 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
20674 //node.removeAttribute(n);
20684 if (clean.length) {
20685 node.setAttribute(n, clean.join(';'));
20687 node.removeAttribute(n);
20693 for (var i = node.attributes.length-1; i > -1 ; i--) {
20694 var a = node.attributes[i];
20697 if (a.name.toLowerCase().substr(0,2)=='on') {
20698 node.removeAttribute(a.name);
20701 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
20702 node.removeAttribute(a.name);
20705 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
20706 cleanAttr(a.name,a.value); // fixme..
20709 if (a.name == 'style') {
20710 cleanStyle(a.name,a.value);
20713 /// clean up MS crap..
20714 // tecnically this should be a list of valid class'es..
20717 if (a.name == 'class') {
20718 if (a.value.match(/^Mso/)) {
20719 node.className = '';
20722 if (a.value.match(/body/)) {
20723 node.className = '';
20734 this.cleanUpChildren(node);
20740 * Clean up MS wordisms...
20742 cleanWord : function(node)
20747 this.cleanWord(this.doc.body);
20750 if (node.nodeName == "#text") {
20751 // clean up silly Windows -- stuff?
20754 if (node.nodeName == "#comment") {
20755 node.parentNode.removeChild(node);
20756 // clean up silly Windows -- stuff?
20760 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
20761 node.parentNode.removeChild(node);
20765 // remove - but keep children..
20766 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
20767 while (node.childNodes.length) {
20768 var cn = node.childNodes[0];
20769 node.removeChild(cn);
20770 node.parentNode.insertBefore(cn, node);
20772 node.parentNode.removeChild(node);
20773 this.iterateChildren(node, this.cleanWord);
20777 if (node.className.length) {
20779 var cn = node.className.split(/\W+/);
20781 Roo.each(cn, function(cls) {
20782 if (cls.match(/Mso[a-zA-Z]+/)) {
20787 node.className = cna.length ? cna.join(' ') : '';
20789 node.removeAttribute("class");
20793 if (node.hasAttribute("lang")) {
20794 node.removeAttribute("lang");
20797 if (node.hasAttribute("style")) {
20799 var styles = node.getAttribute("style").split(";");
20801 Roo.each(styles, function(s) {
20802 if (!s.match(/:/)) {
20805 var kv = s.split(":");
20806 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
20809 // what ever is left... we allow.
20812 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20813 if (!nstyle.length) {
20814 node.removeAttribute('style');
20817 this.iterateChildren(node, this.cleanWord);
20823 * iterateChildren of a Node, calling fn each time, using this as the scole..
20824 * @param {DomNode} node node to iterate children of.
20825 * @param {Function} fn method of this class to call on each item.
20827 iterateChildren : function(node, fn)
20829 if (!node.childNodes.length) {
20832 for (var i = node.childNodes.length-1; i > -1 ; i--) {
20833 fn.call(this, node.childNodes[i])
20839 * cleanTableWidths.
20841 * Quite often pasting from word etc.. results in tables with column and widths.
20842 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
20845 cleanTableWidths : function(node)
20850 this.cleanTableWidths(this.doc.body);
20855 if (node.nodeName == "#text" || node.nodeName == "#comment") {
20858 Roo.log(node.tagName);
20859 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
20860 this.iterateChildren(node, this.cleanTableWidths);
20863 if (node.hasAttribute('width')) {
20864 node.removeAttribute('width');
20868 if (node.hasAttribute("style")) {
20871 var styles = node.getAttribute("style").split(";");
20873 Roo.each(styles, function(s) {
20874 if (!s.match(/:/)) {
20877 var kv = s.split(":");
20878 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
20881 // what ever is left... we allow.
20884 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
20885 if (!nstyle.length) {
20886 node.removeAttribute('style');
20890 this.iterateChildren(node, this.cleanTableWidths);
20898 domToHTML : function(currentElement, depth, nopadtext) {
20900 depth = depth || 0;
20901 nopadtext = nopadtext || false;
20903 if (!currentElement) {
20904 return this.domToHTML(this.doc.body);
20907 //Roo.log(currentElement);
20909 var allText = false;
20910 var nodeName = currentElement.nodeName;
20911 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
20913 if (nodeName == '#text') {
20915 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
20920 if (nodeName != 'BODY') {
20923 // Prints the node tagName, such as <A>, <IMG>, etc
20926 for(i = 0; i < currentElement.attributes.length;i++) {
20928 var aname = currentElement.attributes.item(i).name;
20929 if (!currentElement.attributes.item(i).value.length) {
20932 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
20935 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
20944 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
20947 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
20952 // Traverse the tree
20954 var currentElementChild = currentElement.childNodes.item(i);
20955 var allText = true;
20956 var innerHTML = '';
20958 while (currentElementChild) {
20959 // Formatting code (indent the tree so it looks nice on the screen)
20960 var nopad = nopadtext;
20961 if (lastnode == 'SPAN') {
20965 if (currentElementChild.nodeName == '#text') {
20966 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
20967 toadd = nopadtext ? toadd : toadd.trim();
20968 if (!nopad && toadd.length > 80) {
20969 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
20971 innerHTML += toadd;
20974 currentElementChild = currentElement.childNodes.item(i);
20980 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
20982 // Recursively traverse the tree structure of the child node
20983 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
20984 lastnode = currentElementChild.nodeName;
20986 currentElementChild=currentElement.childNodes.item(i);
20992 // The remaining code is mostly for formatting the tree
20993 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
20998 ret+= "</"+tagName+">";
21004 applyBlacklists : function()
21006 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
21007 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
21011 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
21012 if (b.indexOf(tag) > -1) {
21015 this.white.push(tag);
21019 Roo.each(w, function(tag) {
21020 if (b.indexOf(tag) > -1) {
21023 if (this.white.indexOf(tag) > -1) {
21026 this.white.push(tag);
21031 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
21032 if (w.indexOf(tag) > -1) {
21035 this.black.push(tag);
21039 Roo.each(b, function(tag) {
21040 if (w.indexOf(tag) > -1) {
21043 if (this.black.indexOf(tag) > -1) {
21046 this.black.push(tag);
21051 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
21052 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
21056 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
21057 if (b.indexOf(tag) > -1) {
21060 this.cwhite.push(tag);
21064 Roo.each(w, function(tag) {
21065 if (b.indexOf(tag) > -1) {
21068 if (this.cwhite.indexOf(tag) > -1) {
21071 this.cwhite.push(tag);
21076 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
21077 if (w.indexOf(tag) > -1) {
21080 this.cblack.push(tag);
21084 Roo.each(b, function(tag) {
21085 if (w.indexOf(tag) > -1) {
21088 if (this.cblack.indexOf(tag) > -1) {
21091 this.cblack.push(tag);
21096 setStylesheets : function(stylesheets)
21098 if(typeof(stylesheets) == 'string'){
21099 Roo.get(this.iframe.contentDocument.head).createChild({
21101 rel : 'stylesheet',
21110 Roo.each(stylesheets, function(s) {
21115 Roo.get(_this.iframe.contentDocument.head).createChild({
21117 rel : 'stylesheet',
21126 removeStylesheets : function()
21130 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
21135 // hide stuff that is not compatible
21149 * @event specialkey
21153 * @cfg {String} fieldClass @hide
21156 * @cfg {String} focusClass @hide
21159 * @cfg {String} autoCreate @hide
21162 * @cfg {String} inputType @hide
21165 * @cfg {String} invalidClass @hide
21168 * @cfg {String} invalidText @hide
21171 * @cfg {String} msgFx @hide
21174 * @cfg {String} validateOnBlur @hide
21178 Roo.HtmlEditorCore.white = [
21179 'area', 'br', 'img', 'input', 'hr', 'wbr',
21181 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
21182 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
21183 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
21184 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
21185 'table', 'ul', 'xmp',
21187 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
21190 'dir', 'menu', 'ol', 'ul', 'dl',
21196 Roo.HtmlEditorCore.black = [
21197 // 'embed', 'object', // enable - backend responsiblity to clean thiese
21199 'base', 'basefont', 'bgsound', 'blink', 'body',
21200 'frame', 'frameset', 'head', 'html', 'ilayer',
21201 'iframe', 'layer', 'link', 'meta', 'object',
21202 'script', 'style' ,'title', 'xml' // clean later..
21204 Roo.HtmlEditorCore.clean = [
21205 'script', 'style', 'title', 'xml'
21207 Roo.HtmlEditorCore.remove = [
21212 Roo.HtmlEditorCore.ablack = [
21216 Roo.HtmlEditorCore.aclean = [
21217 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
21221 Roo.HtmlEditorCore.pwhite= [
21222 'http', 'https', 'mailto'
21225 // white listed style attributes.
21226 Roo.HtmlEditorCore.cwhite= [
21227 // 'text-align', /// default is to allow most things..
21233 // black listed style attributes.
21234 Roo.HtmlEditorCore.cblack= [
21235 // 'font-size' -- this can be set by the project
21239 Roo.HtmlEditorCore.swapCodes =[
21258 * @class Roo.bootstrap.HtmlEditor
21259 * @extends Roo.bootstrap.TextArea
21260 * Bootstrap HtmlEditor class
21263 * Create a new HtmlEditor
21264 * @param {Object} config The config object
21267 Roo.bootstrap.HtmlEditor = function(config){
21268 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
21269 if (!this.toolbars) {
21270 this.toolbars = [];
21272 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
21275 * @event initialize
21276 * Fires when the editor is fully initialized (including the iframe)
21277 * @param {HtmlEditor} this
21282 * Fires when the editor is first receives the focus. Any insertion must wait
21283 * until after this event.
21284 * @param {HtmlEditor} this
21288 * @event beforesync
21289 * Fires before the textarea is updated with content from the editor iframe. Return false
21290 * to cancel the sync.
21291 * @param {HtmlEditor} this
21292 * @param {String} html
21296 * @event beforepush
21297 * Fires before the iframe editor is updated with content from the textarea. Return false
21298 * to cancel the push.
21299 * @param {HtmlEditor} this
21300 * @param {String} html
21305 * Fires when the textarea is updated with content from the editor iframe.
21306 * @param {HtmlEditor} this
21307 * @param {String} html
21312 * Fires when the iframe editor is updated with content from the textarea.
21313 * @param {HtmlEditor} this
21314 * @param {String} html
21318 * @event editmodechange
21319 * Fires when the editor switches edit modes
21320 * @param {HtmlEditor} this
21321 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
21323 editmodechange: true,
21325 * @event editorevent
21326 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21327 * @param {HtmlEditor} this
21331 * @event firstfocus
21332 * Fires when on first focus - needed by toolbars..
21333 * @param {HtmlEditor} this
21338 * Auto save the htmlEditor value as a file into Events
21339 * @param {HtmlEditor} this
21343 * @event savedpreview
21344 * preview the saved version of htmlEditor
21345 * @param {HtmlEditor} this
21352 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
21356 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
21361 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21366 * @cfg {Number} height (in pixels)
21370 * @cfg {Number} width (in pixels)
21375 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21378 stylesheets: false,
21383 // private properties
21384 validationEvent : false,
21386 initialized : false,
21389 onFocus : Roo.emptyFn,
21391 hideMode:'offsets',
21394 tbContainer : false,
21396 toolbarContainer :function() {
21397 return this.wrap.select('.x-html-editor-tb',true).first();
21401 * Protected method that will not generally be called directly. It
21402 * is called when the editor creates its toolbar. Override this method if you need to
21403 * add custom toolbar buttons.
21404 * @param {HtmlEditor} editor
21406 createToolbar : function(){
21408 Roo.log("create toolbars");
21410 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
21411 this.toolbars[0].render(this.toolbarContainer());
21415 // if (!editor.toolbars || !editor.toolbars.length) {
21416 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
21419 // for (var i =0 ; i < editor.toolbars.length;i++) {
21420 // editor.toolbars[i] = Roo.factory(
21421 // typeof(editor.toolbars[i]) == 'string' ?
21422 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
21423 // Roo.bootstrap.HtmlEditor);
21424 // editor.toolbars[i].init(editor);
21430 onRender : function(ct, position)
21432 // Roo.log("Call onRender: " + this.xtype);
21434 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
21436 this.wrap = this.inputEl().wrap({
21437 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
21440 this.editorcore.onRender(ct, position);
21442 if (this.resizable) {
21443 this.resizeEl = new Roo.Resizable(this.wrap, {
21447 minHeight : this.height,
21448 height: this.height,
21449 handles : this.resizable,
21452 resize : function(r, w, h) {
21453 _t.onResize(w,h); // -something
21459 this.createToolbar(this);
21462 if(!this.width && this.resizable){
21463 this.setSize(this.wrap.getSize());
21465 if (this.resizeEl) {
21466 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
21467 // should trigger onReize..
21473 onResize : function(w, h)
21475 Roo.log('resize: ' +w + ',' + h );
21476 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
21480 if(this.inputEl() ){
21481 if(typeof w == 'number'){
21482 var aw = w - this.wrap.getFrameWidth('lr');
21483 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
21486 if(typeof h == 'number'){
21487 var tbh = -11; // fixme it needs to tool bar size!
21488 for (var i =0; i < this.toolbars.length;i++) {
21489 // fixme - ask toolbars for heights?
21490 tbh += this.toolbars[i].el.getHeight();
21491 //if (this.toolbars[i].footer) {
21492 // tbh += this.toolbars[i].footer.el.getHeight();
21500 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
21501 ah -= 5; // knock a few pixes off for look..
21502 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
21506 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
21507 this.editorcore.onResize(ew,eh);
21512 * Toggles the editor between standard and source edit mode.
21513 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21515 toggleSourceEdit : function(sourceEditMode)
21517 this.editorcore.toggleSourceEdit(sourceEditMode);
21519 if(this.editorcore.sourceEditMode){
21520 Roo.log('editor - showing textarea');
21523 // Roo.log(this.syncValue());
21525 this.inputEl().removeClass(['hide', 'x-hidden']);
21526 this.inputEl().dom.removeAttribute('tabIndex');
21527 this.inputEl().focus();
21529 Roo.log('editor - hiding textarea');
21531 // Roo.log(this.pushValue());
21534 this.inputEl().addClass(['hide', 'x-hidden']);
21535 this.inputEl().dom.setAttribute('tabIndex', -1);
21536 //this.deferFocus();
21539 if(this.resizable){
21540 this.setSize(this.wrap.getSize());
21543 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
21546 // private (for BoxComponent)
21547 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21549 // private (for BoxComponent)
21550 getResizeEl : function(){
21554 // private (for BoxComponent)
21555 getPositionEl : function(){
21560 initEvents : function(){
21561 this.originalValue = this.getValue();
21565 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21568 // markInvalid : Roo.emptyFn,
21570 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
21573 // clearInvalid : Roo.emptyFn,
21575 setValue : function(v){
21576 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
21577 this.editorcore.pushValue();
21582 deferFocus : function(){
21583 this.focus.defer(10, this);
21587 focus : function(){
21588 this.editorcore.focus();
21594 onDestroy : function(){
21600 for (var i =0; i < this.toolbars.length;i++) {
21601 // fixme - ask toolbars for heights?
21602 this.toolbars[i].onDestroy();
21605 this.wrap.dom.innerHTML = '';
21606 this.wrap.remove();
21611 onFirstFocus : function(){
21612 //Roo.log("onFirstFocus");
21613 this.editorcore.onFirstFocus();
21614 for (var i =0; i < this.toolbars.length;i++) {
21615 this.toolbars[i].onFirstFocus();
21621 syncValue : function()
21623 this.editorcore.syncValue();
21626 pushValue : function()
21628 this.editorcore.pushValue();
21632 // hide stuff that is not compatible
21646 * @event specialkey
21650 * @cfg {String} fieldClass @hide
21653 * @cfg {String} focusClass @hide
21656 * @cfg {String} autoCreate @hide
21659 * @cfg {String} inputType @hide
21662 * @cfg {String} invalidClass @hide
21665 * @cfg {String} invalidText @hide
21668 * @cfg {String} msgFx @hide
21671 * @cfg {String} validateOnBlur @hide
21680 Roo.namespace('Roo.bootstrap.htmleditor');
21682 * @class Roo.bootstrap.HtmlEditorToolbar1
21687 new Roo.bootstrap.HtmlEditor({
21690 new Roo.bootstrap.HtmlEditorToolbar1({
21691 disable : { fonts: 1 , format: 1, ..., ... , ...],
21697 * @cfg {Object} disable List of elements to disable..
21698 * @cfg {Array} btns List of additional buttons.
21702 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
21705 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
21708 Roo.apply(this, config);
21710 // default disabled, based on 'good practice'..
21711 this.disable = this.disable || {};
21712 Roo.applyIf(this.disable, {
21715 specialElements : true
21717 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
21719 this.editor = config.editor;
21720 this.editorcore = config.editor.editorcore;
21722 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
21724 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
21725 // dont call parent... till later.
21727 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
21732 editorcore : false,
21737 "h1","h2","h3","h4","h5","h6",
21739 "abbr", "acronym", "address", "cite", "samp", "var",
21743 onRender : function(ct, position)
21745 // Roo.log("Call onRender: " + this.xtype);
21747 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
21749 this.el.dom.style.marginBottom = '0';
21751 var editorcore = this.editorcore;
21752 var editor= this.editor;
21755 var btn = function(id,cmd , toggle, handler){
21757 var event = toggle ? 'toggle' : 'click';
21762 xns: Roo.bootstrap,
21765 enableToggle:toggle !== false,
21767 pressed : toggle ? false : null,
21770 a.listeners[toggle ? 'toggle' : 'click'] = function() {
21771 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
21780 xns: Roo.bootstrap,
21781 glyphicon : 'font',
21785 xns: Roo.bootstrap,
21789 Roo.each(this.formats, function(f) {
21790 style.menu.items.push({
21792 xns: Roo.bootstrap,
21793 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
21798 editorcore.insertTag(this.tagname);
21805 children.push(style);
21808 btn('bold',false,true);
21809 btn('italic',false,true);
21810 btn('align-left', 'justifyleft',true);
21811 btn('align-center', 'justifycenter',true);
21812 btn('align-right' , 'justifyright',true);
21813 btn('link', false, false, function(btn) {
21814 //Roo.log("create link?");
21815 var url = prompt(this.createLinkText, this.defaultLinkValue);
21816 if(url && url != 'http:/'+'/'){
21817 this.editorcore.relayCmd('createlink', url);
21820 btn('list','insertunorderedlist',true);
21821 btn('pencil', false,true, function(btn){
21824 this.toggleSourceEdit(btn.pressed);
21830 xns: Roo.bootstrap,
21835 xns: Roo.bootstrap,
21840 cog.menu.items.push({
21842 xns: Roo.bootstrap,
21843 html : Clean styles,
21848 editorcore.insertTag(this.tagname);
21857 this.xtype = 'NavSimplebar';
21859 for(var i=0;i< children.length;i++) {
21861 this.buttons.add(this.addxtypeChild(children[i]));
21865 editor.on('editorevent', this.updateToolbar, this);
21867 onBtnClick : function(id)
21869 this.editorcore.relayCmd(id);
21870 this.editorcore.focus();
21874 * Protected method that will not generally be called directly. It triggers
21875 * a toolbar update by reading the markup state of the current selection in the editor.
21877 updateToolbar: function(){
21879 if(!this.editorcore.activated){
21880 this.editor.onFirstFocus(); // is this neeed?
21884 var btns = this.buttons;
21885 var doc = this.editorcore.doc;
21886 btns.get('bold').setActive(doc.queryCommandState('bold'));
21887 btns.get('italic').setActive(doc.queryCommandState('italic'));
21888 //btns.get('underline').setActive(doc.queryCommandState('underline'));
21890 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
21891 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
21892 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
21894 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
21895 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
21898 var ans = this.editorcore.getAllAncestors();
21899 if (this.formatCombo) {
21902 var store = this.formatCombo.store;
21903 this.formatCombo.setValue("");
21904 for (var i =0; i < ans.length;i++) {
21905 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
21907 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
21915 // hides menus... - so this cant be on a menu...
21916 Roo.bootstrap.MenuMgr.hideAll();
21918 Roo.bootstrap.MenuMgr.hideAll();
21919 //this.editorsyncValue();
21921 onFirstFocus: function() {
21922 this.buttons.each(function(item){
21926 toggleSourceEdit : function(sourceEditMode){
21929 if(sourceEditMode){
21930 Roo.log("disabling buttons");
21931 this.buttons.each( function(item){
21932 if(item.cmd != 'pencil'){
21938 Roo.log("enabling buttons");
21939 if(this.editorcore.initialized){
21940 this.buttons.each( function(item){
21946 Roo.log("calling toggole on editor");
21947 // tell the editor that it's been pressed..
21948 this.editor.toggleSourceEdit(sourceEditMode);
21958 * @class Roo.bootstrap.Table.AbstractSelectionModel
21959 * @extends Roo.util.Observable
21960 * Abstract base class for grid SelectionModels. It provides the interface that should be
21961 * implemented by descendant classes. This class should not be directly instantiated.
21964 Roo.bootstrap.Table.AbstractSelectionModel = function(){
21965 this.locked = false;
21966 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
21970 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
21971 /** @ignore Called by the grid automatically. Do not call directly. */
21972 init : function(grid){
21978 * Locks the selections.
21981 this.locked = true;
21985 * Unlocks the selections.
21987 unlock : function(){
21988 this.locked = false;
21992 * Returns true if the selections are locked.
21993 * @return {Boolean}
21995 isLocked : function(){
21996 return this.locked;
22000 * @extends Roo.bootstrap.Table.AbstractSelectionModel
22001 * @class Roo.bootstrap.Table.RowSelectionModel
22002 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
22003 * It supports multiple selections and keyboard selection/navigation.
22005 * @param {Object} config
22008 Roo.bootstrap.Table.RowSelectionModel = function(config){
22009 Roo.apply(this, config);
22010 this.selections = new Roo.util.MixedCollection(false, function(o){
22015 this.lastActive = false;
22019 * @event selectionchange
22020 * Fires when the selection changes
22021 * @param {SelectionModel} this
22023 "selectionchange" : true,
22025 * @event afterselectionchange
22026 * Fires after the selection changes (eg. by key press or clicking)
22027 * @param {SelectionModel} this
22029 "afterselectionchange" : true,
22031 * @event beforerowselect
22032 * Fires when a row is selected being selected, return false to cancel.
22033 * @param {SelectionModel} this
22034 * @param {Number} rowIndex The selected index
22035 * @param {Boolean} keepExisting False if other selections will be cleared
22037 "beforerowselect" : true,
22040 * Fires when a row is selected.
22041 * @param {SelectionModel} this
22042 * @param {Number} rowIndex The selected index
22043 * @param {Roo.data.Record} r The record
22045 "rowselect" : true,
22047 * @event rowdeselect
22048 * Fires when a row is deselected.
22049 * @param {SelectionModel} this
22050 * @param {Number} rowIndex The selected index
22052 "rowdeselect" : true
22054 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
22055 this.locked = false;
22058 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
22060 * @cfg {Boolean} singleSelect
22061 * True to allow selection of only one row at a time (defaults to false)
22063 singleSelect : false,
22066 initEvents : function(){
22068 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
22069 this.grid.on("mousedown", this.handleMouseDown, this);
22070 }else{ // allow click to work like normal
22071 this.grid.on("rowclick", this.handleDragableRowClick, this);
22074 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
22075 "up" : function(e){
22077 this.selectPrevious(e.shiftKey);
22078 }else if(this.last !== false && this.lastActive !== false){
22079 var last = this.last;
22080 this.selectRange(this.last, this.lastActive-1);
22081 this.grid.getView().focusRow(this.lastActive);
22082 if(last !== false){
22086 this.selectFirstRow();
22088 this.fireEvent("afterselectionchange", this);
22090 "down" : function(e){
22092 this.selectNext(e.shiftKey);
22093 }else if(this.last !== false && this.lastActive !== false){
22094 var last = this.last;
22095 this.selectRange(this.last, this.lastActive+1);
22096 this.grid.getView().focusRow(this.lastActive);
22097 if(last !== false){
22101 this.selectFirstRow();
22103 this.fireEvent("afterselectionchange", this);
22108 var view = this.grid.view;
22109 view.on("refresh", this.onRefresh, this);
22110 view.on("rowupdated", this.onRowUpdated, this);
22111 view.on("rowremoved", this.onRemove, this);
22115 onRefresh : function(){
22116 var ds = this.grid.dataSource, i, v = this.grid.view;
22117 var s = this.selections;
22118 s.each(function(r){
22119 if((i = ds.indexOfId(r.id)) != -1){
22128 onRemove : function(v, index, r){
22129 this.selections.remove(r);
22133 onRowUpdated : function(v, index, r){
22134 if(this.isSelected(r)){
22135 v.onRowSelect(index);
22141 * @param {Array} records The records to select
22142 * @param {Boolean} keepExisting (optional) True to keep existing selections
22144 selectRecords : function(records, keepExisting){
22146 this.clearSelections();
22148 var ds = this.grid.dataSource;
22149 for(var i = 0, len = records.length; i < len; i++){
22150 this.selectRow(ds.indexOf(records[i]), true);
22155 * Gets the number of selected rows.
22158 getCount : function(){
22159 return this.selections.length;
22163 * Selects the first row in the grid.
22165 selectFirstRow : function(){
22170 * Select the last row.
22171 * @param {Boolean} keepExisting (optional) True to keep existing selections
22173 selectLastRow : function(keepExisting){
22174 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
22178 * Selects the row immediately following the last selected row.
22179 * @param {Boolean} keepExisting (optional) True to keep existing selections
22181 selectNext : function(keepExisting){
22182 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
22183 this.selectRow(this.last+1, keepExisting);
22184 this.grid.getView().focusRow(this.last);
22189 * Selects the row that precedes the last selected row.
22190 * @param {Boolean} keepExisting (optional) True to keep existing selections
22192 selectPrevious : function(keepExisting){
22194 this.selectRow(this.last-1, keepExisting);
22195 this.grid.getView().focusRow(this.last);
22200 * Returns the selected records
22201 * @return {Array} Array of selected records
22203 getSelections : function(){
22204 return [].concat(this.selections.items);
22208 * Returns the first selected record.
22211 getSelected : function(){
22212 return this.selections.itemAt(0);
22217 * Clears all selections.
22219 clearSelections : function(fast){
22224 var ds = this.grid.dataSource;
22225 var s = this.selections;
22226 s.each(function(r){
22227 this.deselectRow(ds.indexOfId(r.id));
22231 this.selections.clear();
22238 * Selects all rows.
22240 selectAll : function(){
22244 this.selections.clear();
22245 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
22246 this.selectRow(i, true);
22251 * Returns True if there is a selection.
22252 * @return {Boolean}
22254 hasSelection : function(){
22255 return this.selections.length > 0;
22259 * Returns True if the specified row is selected.
22260 * @param {Number/Record} record The record or index of the record to check
22261 * @return {Boolean}
22263 isSelected : function(index){
22264 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
22265 return (r && this.selections.key(r.id) ? true : false);
22269 * Returns True if the specified record id is selected.
22270 * @param {String} id The id of record to check
22271 * @return {Boolean}
22273 isIdSelected : function(id){
22274 return (this.selections.key(id) ? true : false);
22278 handleMouseDown : function(e, t){
22279 var view = this.grid.getView(), rowIndex;
22280 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
22283 if(e.shiftKey && this.last !== false){
22284 var last = this.last;
22285 this.selectRange(last, rowIndex, e.ctrlKey);
22286 this.last = last; // reset the last
22287 view.focusRow(rowIndex);
22289 var isSelected = this.isSelected(rowIndex);
22290 if(e.button !== 0 && isSelected){
22291 view.focusRow(rowIndex);
22292 }else if(e.ctrlKey && isSelected){
22293 this.deselectRow(rowIndex);
22294 }else if(!isSelected){
22295 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
22296 view.focusRow(rowIndex);
22299 this.fireEvent("afterselectionchange", this);
22302 handleDragableRowClick : function(grid, rowIndex, e)
22304 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
22305 this.selectRow(rowIndex, false);
22306 grid.view.focusRow(rowIndex);
22307 this.fireEvent("afterselectionchange", this);
22312 * Selects multiple rows.
22313 * @param {Array} rows Array of the indexes of the row to select
22314 * @param {Boolean} keepExisting (optional) True to keep existing selections
22316 selectRows : function(rows, keepExisting){
22318 this.clearSelections();
22320 for(var i = 0, len = rows.length; i < len; i++){
22321 this.selectRow(rows[i], true);
22326 * Selects a range of rows. All rows in between startRow and endRow are also selected.
22327 * @param {Number} startRow The index of the first row in the range
22328 * @param {Number} endRow The index of the last row in the range
22329 * @param {Boolean} keepExisting (optional) True to retain existing selections
22331 selectRange : function(startRow, endRow, keepExisting){
22336 this.clearSelections();
22338 if(startRow <= endRow){
22339 for(var i = startRow; i <= endRow; i++){
22340 this.selectRow(i, true);
22343 for(var i = startRow; i >= endRow; i--){
22344 this.selectRow(i, true);
22350 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
22351 * @param {Number} startRow The index of the first row in the range
22352 * @param {Number} endRow The index of the last row in the range
22354 deselectRange : function(startRow, endRow, preventViewNotify){
22358 for(var i = startRow; i <= endRow; i++){
22359 this.deselectRow(i, preventViewNotify);
22365 * @param {Number} row The index of the row to select
22366 * @param {Boolean} keepExisting (optional) True to keep existing selections
22368 selectRow : function(index, keepExisting, preventViewNotify){
22369 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
22372 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
22373 if(!keepExisting || this.singleSelect){
22374 this.clearSelections();
22376 var r = this.grid.dataSource.getAt(index);
22377 this.selections.add(r);
22378 this.last = this.lastActive = index;
22379 if(!preventViewNotify){
22380 this.grid.getView().onRowSelect(index);
22382 this.fireEvent("rowselect", this, index, r);
22383 this.fireEvent("selectionchange", this);
22389 * @param {Number} row The index of the row to deselect
22391 deselectRow : function(index, preventViewNotify){
22395 if(this.last == index){
22398 if(this.lastActive == index){
22399 this.lastActive = false;
22401 var r = this.grid.dataSource.getAt(index);
22402 this.selections.remove(r);
22403 if(!preventViewNotify){
22404 this.grid.getView().onRowDeselect(index);
22406 this.fireEvent("rowdeselect", this, index);
22407 this.fireEvent("selectionchange", this);
22411 restoreLast : function(){
22413 this.last = this._last;
22418 acceptsNav : function(row, col, cm){
22419 return !cm.isHidden(col) && cm.isCellEditable(col, row);
22423 onEditorKey : function(field, e){
22424 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
22429 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
22431 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
22433 }else if(k == e.ENTER && !e.ctrlKey){
22437 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
22439 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
22441 }else if(k == e.ESC){
22445 g.startEditing(newCell[0], newCell[1]);
22450 * Ext JS Library 1.1.1
22451 * Copyright(c) 2006-2007, Ext JS, LLC.
22453 * Originally Released Under LGPL - original licence link has changed is not relivant.
22456 * <script type="text/javascript">
22460 * @class Roo.bootstrap.PagingToolbar
22461 * @extends Roo.bootstrap.NavSimplebar
22462 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
22464 * Create a new PagingToolbar
22465 * @param {Object} config The config object
22466 * @param {Roo.data.Store} store
22468 Roo.bootstrap.PagingToolbar = function(config)
22470 // old args format still supported... - xtype is prefered..
22471 // created from xtype...
22473 this.ds = config.dataSource;
22475 if (config.store && !this.ds) {
22476 this.store= Roo.factory(config.store, Roo.data);
22477 this.ds = this.store;
22478 this.ds.xmodule = this.xmodule || false;
22481 this.toolbarItems = [];
22482 if (config.items) {
22483 this.toolbarItems = config.items;
22486 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
22491 this.bind(this.ds);
22494 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
22498 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
22500 * @cfg {Roo.data.Store} dataSource
22501 * The underlying data store providing the paged data
22504 * @cfg {String/HTMLElement/Element} container
22505 * container The id or element that will contain the toolbar
22508 * @cfg {Boolean} displayInfo
22509 * True to display the displayMsg (defaults to false)
22512 * @cfg {Number} pageSize
22513 * The number of records to display per page (defaults to 20)
22517 * @cfg {String} displayMsg
22518 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
22520 displayMsg : 'Displaying {0} - {1} of {2}',
22522 * @cfg {String} emptyMsg
22523 * The message to display when no records are found (defaults to "No data to display")
22525 emptyMsg : 'No data to display',
22527 * Customizable piece of the default paging text (defaults to "Page")
22530 beforePageText : "Page",
22532 * Customizable piece of the default paging text (defaults to "of %0")
22535 afterPageText : "of {0}",
22537 * Customizable piece of the default paging text (defaults to "First Page")
22540 firstText : "First Page",
22542 * Customizable piece of the default paging text (defaults to "Previous Page")
22545 prevText : "Previous Page",
22547 * Customizable piece of the default paging text (defaults to "Next Page")
22550 nextText : "Next Page",
22552 * Customizable piece of the default paging text (defaults to "Last Page")
22555 lastText : "Last Page",
22557 * Customizable piece of the default paging text (defaults to "Refresh")
22560 refreshText : "Refresh",
22564 onRender : function(ct, position)
22566 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
22567 this.navgroup.parentId = this.id;
22568 this.navgroup.onRender(this.el, null);
22569 // add the buttons to the navgroup
22571 if(this.displayInfo){
22572 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
22573 this.displayEl = this.el.select('.x-paging-info', true).first();
22574 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
22575 // this.displayEl = navel.el.select('span',true).first();
22581 Roo.each(_this.buttons, function(e){ // this might need to use render????
22582 Roo.factory(e).onRender(_this.el, null);
22586 Roo.each(_this.toolbarItems, function(e) {
22587 _this.navgroup.addItem(e);
22591 this.first = this.navgroup.addItem({
22592 tooltip: this.firstText,
22594 icon : 'fa fa-backward',
22596 preventDefault: true,
22597 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
22600 this.prev = this.navgroup.addItem({
22601 tooltip: this.prevText,
22603 icon : 'fa fa-step-backward',
22605 preventDefault: true,
22606 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
22608 //this.addSeparator();
22611 var field = this.navgroup.addItem( {
22613 cls : 'x-paging-position',
22615 html : this.beforePageText +
22616 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
22617 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
22620 this.field = field.el.select('input', true).first();
22621 this.field.on("keydown", this.onPagingKeydown, this);
22622 this.field.on("focus", function(){this.dom.select();});
22625 this.afterTextEl = field.el.select('.x-paging-after',true).first();
22626 //this.field.setHeight(18);
22627 //this.addSeparator();
22628 this.next = this.navgroup.addItem({
22629 tooltip: this.nextText,
22631 html : ' <i class="fa fa-step-forward">',
22633 preventDefault: true,
22634 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
22636 this.last = this.navgroup.addItem({
22637 tooltip: this.lastText,
22638 icon : 'fa fa-forward',
22641 preventDefault: true,
22642 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
22644 //this.addSeparator();
22645 this.loading = this.navgroup.addItem({
22646 tooltip: this.refreshText,
22647 icon: 'fa fa-refresh',
22648 preventDefault: true,
22649 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
22655 updateInfo : function(){
22656 if(this.displayEl){
22657 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
22658 var msg = count == 0 ?
22662 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
22664 this.displayEl.update(msg);
22669 onLoad : function(ds, r, o){
22670 this.cursor = o.params ? o.params.start : 0;
22671 var d = this.getPageData(),
22675 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
22676 this.field.dom.value = ap;
22677 this.first.setDisabled(ap == 1);
22678 this.prev.setDisabled(ap == 1);
22679 this.next.setDisabled(ap == ps);
22680 this.last.setDisabled(ap == ps);
22681 this.loading.enable();
22686 getPageData : function(){
22687 var total = this.ds.getTotalCount();
22690 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
22691 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
22696 onLoadError : function(){
22697 this.loading.enable();
22701 onPagingKeydown : function(e){
22702 var k = e.getKey();
22703 var d = this.getPageData();
22705 var v = this.field.dom.value, pageNum;
22706 if(!v || isNaN(pageNum = parseInt(v, 10))){
22707 this.field.dom.value = d.activePage;
22710 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
22711 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22714 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))
22716 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
22717 this.field.dom.value = pageNum;
22718 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
22721 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
22723 var v = this.field.dom.value, pageNum;
22724 var increment = (e.shiftKey) ? 10 : 1;
22725 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
22728 if(!v || isNaN(pageNum = parseInt(v, 10))) {
22729 this.field.dom.value = d.activePage;
22732 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
22734 this.field.dom.value = parseInt(v, 10) + increment;
22735 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
22736 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
22743 beforeLoad : function(){
22745 this.loading.disable();
22750 onClick : function(which){
22759 ds.load({params:{start: 0, limit: this.pageSize}});
22762 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
22765 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
22768 var total = ds.getTotalCount();
22769 var extra = total % this.pageSize;
22770 var lastStart = extra ? (total - extra) : total-this.pageSize;
22771 ds.load({params:{start: lastStart, limit: this.pageSize}});
22774 ds.load({params:{start: this.cursor, limit: this.pageSize}});
22780 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
22781 * @param {Roo.data.Store} store The data store to unbind
22783 unbind : function(ds){
22784 ds.un("beforeload", this.beforeLoad, this);
22785 ds.un("load", this.onLoad, this);
22786 ds.un("loadexception", this.onLoadError, this);
22787 ds.un("remove", this.updateInfo, this);
22788 ds.un("add", this.updateInfo, this);
22789 this.ds = undefined;
22793 * Binds the paging toolbar to the specified {@link Roo.data.Store}
22794 * @param {Roo.data.Store} store The data store to bind
22796 bind : function(ds){
22797 ds.on("beforeload", this.beforeLoad, this);
22798 ds.on("load", this.onLoad, this);
22799 ds.on("loadexception", this.onLoadError, this);
22800 ds.on("remove", this.updateInfo, this);
22801 ds.on("add", this.updateInfo, this);
22812 * @class Roo.bootstrap.MessageBar
22813 * @extends Roo.bootstrap.Component
22814 * Bootstrap MessageBar class
22815 * @cfg {String} html contents of the MessageBar
22816 * @cfg {String} weight (info | success | warning | danger) default info
22817 * @cfg {String} beforeClass insert the bar before the given class
22818 * @cfg {Boolean} closable (true | false) default false
22819 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
22822 * Create a new Element
22823 * @param {Object} config The config object
22826 Roo.bootstrap.MessageBar = function(config){
22827 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
22830 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
22836 beforeClass: 'bootstrap-sticky-wrap',
22838 getAutoCreate : function(){
22842 cls: 'alert alert-dismissable alert-' + this.weight,
22847 html: this.html || ''
22853 cfg.cls += ' alert-messages-fixed';
22867 onRender : function(ct, position)
22869 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
22872 var cfg = Roo.apply({}, this.getAutoCreate());
22876 cfg.cls += ' ' + this.cls;
22879 cfg.style = this.style;
22881 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
22883 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22886 this.el.select('>button.close').on('click', this.hide, this);
22892 if (!this.rendered) {
22898 this.fireEvent('show', this);
22904 if (!this.rendered) {
22910 this.fireEvent('hide', this);
22913 update : function()
22915 // var e = this.el.dom.firstChild;
22917 // if(this.closable){
22918 // e = e.nextSibling;
22921 // e.data = this.html || '';
22923 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
22939 * @class Roo.bootstrap.Graph
22940 * @extends Roo.bootstrap.Component
22941 * Bootstrap Graph class
22945 @cfg {String} graphtype bar | vbar | pie
22946 @cfg {number} g_x coodinator | centre x (pie)
22947 @cfg {number} g_y coodinator | centre y (pie)
22948 @cfg {number} g_r radius (pie)
22949 @cfg {number} g_height height of the chart (respected by all elements in the set)
22950 @cfg {number} g_width width of the chart (respected by all elements in the set)
22951 @cfg {Object} title The title of the chart
22954 -opts (object) options for the chart
22956 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
22957 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
22959 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.
22960 o stacked (boolean) whether or not to tread values as in a stacked bar chart
22962 o stretch (boolean)
22964 -opts (object) options for the pie
22967 o startAngle (number)
22968 o endAngle (number)
22972 * Create a new Input
22973 * @param {Object} config The config object
22976 Roo.bootstrap.Graph = function(config){
22977 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
22983 * The img click event for the img.
22984 * @param {Roo.EventObject} e
22990 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
23001 //g_colors: this.colors,
23008 getAutoCreate : function(){
23019 onRender : function(ct,position){
23022 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
23024 if (typeof(Raphael) == 'undefined') {
23025 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
23029 this.raphael = Raphael(this.el.dom);
23031 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23032 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23033 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
23034 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
23036 r.text(160, 10, "Single Series Chart").attr(txtattr);
23037 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
23038 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
23039 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
23041 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
23042 r.barchart(330, 10, 300, 220, data1);
23043 r.barchart(10, 250, 300, 220, data2, {stacked: true});
23044 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
23047 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23048 // r.barchart(30, 30, 560, 250, xdata, {
23049 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
23050 // axis : "0 0 1 1",
23051 // axisxlabels : xdata
23052 // //yvalues : cols,
23055 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
23057 // this.load(null,xdata,{
23058 // axis : "0 0 1 1",
23059 // axisxlabels : xdata
23064 load : function(graphtype,xdata,opts)
23066 this.raphael.clear();
23068 graphtype = this.graphtype;
23073 var r = this.raphael,
23074 fin = function () {
23075 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
23077 fout = function () {
23078 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
23080 pfin = function() {
23081 this.sector.stop();
23082 this.sector.scale(1.1, 1.1, this.cx, this.cy);
23085 this.label[0].stop();
23086 this.label[0].attr({ r: 7.5 });
23087 this.label[1].attr({ "font-weight": 800 });
23090 pfout = function() {
23091 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
23094 this.label[0].animate({ r: 5 }, 500, "bounce");
23095 this.label[1].attr({ "font-weight": 400 });
23101 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23104 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
23107 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
23108 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
23110 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
23117 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
23122 setTitle: function(o)
23127 initEvents: function() {
23130 this.el.on('click', this.onClick, this);
23134 onClick : function(e)
23136 Roo.log('img onclick');
23137 this.fireEvent('click', this, e);
23149 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23152 * @class Roo.bootstrap.dash.NumberBox
23153 * @extends Roo.bootstrap.Component
23154 * Bootstrap NumberBox class
23155 * @cfg {String} headline Box headline
23156 * @cfg {String} content Box content
23157 * @cfg {String} icon Box icon
23158 * @cfg {String} footer Footer text
23159 * @cfg {String} fhref Footer href
23162 * Create a new NumberBox
23163 * @param {Object} config The config object
23167 Roo.bootstrap.dash.NumberBox = function(config){
23168 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
23172 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
23181 getAutoCreate : function(){
23185 cls : 'small-box ',
23193 cls : 'roo-headline',
23194 html : this.headline
23198 cls : 'roo-content',
23199 html : this.content
23213 cls : 'ion ' + this.icon
23222 cls : 'small-box-footer',
23223 href : this.fhref || '#',
23227 cfg.cn.push(footer);
23234 onRender : function(ct,position){
23235 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
23242 setHeadline: function (value)
23244 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
23247 setFooter: function (value, href)
23249 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
23252 this.el.select('a.small-box-footer',true).first().attr('href', href);
23257 setContent: function (value)
23259 this.el.select('.roo-content',true).first().dom.innerHTML = value;
23262 initEvents: function()
23276 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23279 * @class Roo.bootstrap.dash.TabBox
23280 * @extends Roo.bootstrap.Component
23281 * Bootstrap TabBox class
23282 * @cfg {String} title Title of the TabBox
23283 * @cfg {String} icon Icon of the TabBox
23284 * @cfg {Boolean} showtabs (true|false) show the tabs default true
23285 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
23288 * Create a new TabBox
23289 * @param {Object} config The config object
23293 Roo.bootstrap.dash.TabBox = function(config){
23294 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
23299 * When a pane is added
23300 * @param {Roo.bootstrap.dash.TabPane} pane
23304 * @event activatepane
23305 * When a pane is activated
23306 * @param {Roo.bootstrap.dash.TabPane} pane
23308 "activatepane" : true
23316 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
23321 tabScrollable : false,
23323 getChildContainer : function()
23325 return this.el.select('.tab-content', true).first();
23328 getAutoCreate : function(){
23332 cls: 'pull-left header',
23340 cls: 'fa ' + this.icon
23346 cls: 'nav nav-tabs pull-right',
23352 if(this.tabScrollable){
23359 cls: 'nav nav-tabs pull-right',
23370 cls: 'nav-tabs-custom',
23375 cls: 'tab-content no-padding',
23383 initEvents : function()
23385 //Roo.log('add add pane handler');
23386 this.on('addpane', this.onAddPane, this);
23389 * Updates the box title
23390 * @param {String} html to set the title to.
23392 setTitle : function(value)
23394 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
23396 onAddPane : function(pane)
23398 this.panes.push(pane);
23399 //Roo.log('addpane');
23401 // tabs are rendere left to right..
23402 if(!this.showtabs){
23406 var ctr = this.el.select('.nav-tabs', true).first();
23409 var existing = ctr.select('.nav-tab',true);
23410 var qty = existing.getCount();;
23413 var tab = ctr.createChild({
23415 cls : 'nav-tab' + (qty ? '' : ' active'),
23423 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
23426 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
23428 pane.el.addClass('active');
23433 onTabClick : function(ev,un,ob,pane)
23435 //Roo.log('tab - prev default');
23436 ev.preventDefault();
23439 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
23440 pane.tab.addClass('active');
23441 //Roo.log(pane.title);
23442 this.getChildContainer().select('.tab-pane',true).removeClass('active');
23443 // technically we should have a deactivate event.. but maybe add later.
23444 // and it should not de-activate the selected tab...
23445 this.fireEvent('activatepane', pane);
23446 pane.el.addClass('active');
23447 pane.fireEvent('activate');
23452 getActivePane : function()
23455 Roo.each(this.panes, function(p) {
23456 if(p.el.hasClass('active')){
23477 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
23479 * @class Roo.bootstrap.TabPane
23480 * @extends Roo.bootstrap.Component
23481 * Bootstrap TabPane class
23482 * @cfg {Boolean} active (false | true) Default false
23483 * @cfg {String} title title of panel
23487 * Create a new TabPane
23488 * @param {Object} config The config object
23491 Roo.bootstrap.dash.TabPane = function(config){
23492 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
23498 * When a pane is activated
23499 * @param {Roo.bootstrap.dash.TabPane} pane
23506 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
23511 // the tabBox that this is attached to.
23514 getAutoCreate : function()
23522 cfg.cls += ' active';
23527 initEvents : function()
23529 //Roo.log('trigger add pane handler');
23530 this.parent().fireEvent('addpane', this)
23534 * Updates the tab title
23535 * @param {String} html to set the title to.
23537 setTitle: function(str)
23543 this.tab.select('a', true).first().dom.innerHTML = str;
23560 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23563 * @class Roo.bootstrap.menu.Menu
23564 * @extends Roo.bootstrap.Component
23565 * Bootstrap Menu class - container for Menu
23566 * @cfg {String} html Text of the menu
23567 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
23568 * @cfg {String} icon Font awesome icon
23569 * @cfg {String} pos Menu align to (top | bottom) default bottom
23573 * Create a new Menu
23574 * @param {Object} config The config object
23578 Roo.bootstrap.menu.Menu = function(config){
23579 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
23583 * @event beforeshow
23584 * Fires before this menu is displayed
23585 * @param {Roo.bootstrap.menu.Menu} this
23589 * @event beforehide
23590 * Fires before this menu is hidden
23591 * @param {Roo.bootstrap.menu.Menu} this
23596 * Fires after this menu is displayed
23597 * @param {Roo.bootstrap.menu.Menu} this
23602 * Fires after this menu is hidden
23603 * @param {Roo.bootstrap.menu.Menu} this
23608 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
23609 * @param {Roo.bootstrap.menu.Menu} this
23610 * @param {Roo.EventObject} e
23617 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
23621 weight : 'default',
23626 getChildContainer : function() {
23627 if(this.isSubMenu){
23631 return this.el.select('ul.dropdown-menu', true).first();
23634 getAutoCreate : function()
23639 cls : 'roo-menu-text',
23647 cls : 'fa ' + this.icon
23658 cls : 'dropdown-button btn btn-' + this.weight,
23663 cls : 'dropdown-toggle btn btn-' + this.weight,
23673 cls : 'dropdown-menu'
23679 if(this.pos == 'top'){
23680 cfg.cls += ' dropup';
23683 if(this.isSubMenu){
23686 cls : 'dropdown-menu'
23693 onRender : function(ct, position)
23695 this.isSubMenu = ct.hasClass('dropdown-submenu');
23697 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
23700 initEvents : function()
23702 if(this.isSubMenu){
23706 this.hidden = true;
23708 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
23709 this.triggerEl.on('click', this.onTriggerPress, this);
23711 this.buttonEl = this.el.select('button.dropdown-button', true).first();
23712 this.buttonEl.on('click', this.onClick, this);
23718 if(this.isSubMenu){
23722 return this.el.select('ul.dropdown-menu', true).first();
23725 onClick : function(e)
23727 this.fireEvent("click", this, e);
23730 onTriggerPress : function(e)
23732 if (this.isVisible()) {
23739 isVisible : function(){
23740 return !this.hidden;
23745 this.fireEvent("beforeshow", this);
23747 this.hidden = false;
23748 this.el.addClass('open');
23750 Roo.get(document).on("mouseup", this.onMouseUp, this);
23752 this.fireEvent("show", this);
23759 this.fireEvent("beforehide", this);
23761 this.hidden = true;
23762 this.el.removeClass('open');
23764 Roo.get(document).un("mouseup", this.onMouseUp);
23766 this.fireEvent("hide", this);
23769 onMouseUp : function()
23783 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23786 * @class Roo.bootstrap.menu.Item
23787 * @extends Roo.bootstrap.Component
23788 * Bootstrap MenuItem class
23789 * @cfg {Boolean} submenu (true | false) default false
23790 * @cfg {String} html text of the item
23791 * @cfg {String} href the link
23792 * @cfg {Boolean} disable (true | false) default false
23793 * @cfg {Boolean} preventDefault (true | false) default true
23794 * @cfg {String} icon Font awesome icon
23795 * @cfg {String} pos Submenu align to (left | right) default right
23799 * Create a new Item
23800 * @param {Object} config The config object
23804 Roo.bootstrap.menu.Item = function(config){
23805 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
23809 * Fires when the mouse is hovering over this menu
23810 * @param {Roo.bootstrap.menu.Item} this
23811 * @param {Roo.EventObject} e
23816 * Fires when the mouse exits this menu
23817 * @param {Roo.bootstrap.menu.Item} this
23818 * @param {Roo.EventObject} e
23824 * The raw click event for the entire grid.
23825 * @param {Roo.EventObject} e
23831 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
23836 preventDefault: true,
23841 getAutoCreate : function()
23846 cls : 'roo-menu-item-text',
23854 cls : 'fa ' + this.icon
23863 href : this.href || '#',
23870 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
23874 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
23876 if(this.pos == 'left'){
23877 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
23884 initEvents : function()
23886 this.el.on('mouseover', this.onMouseOver, this);
23887 this.el.on('mouseout', this.onMouseOut, this);
23889 this.el.select('a', true).first().on('click', this.onClick, this);
23893 onClick : function(e)
23895 if(this.preventDefault){
23896 e.preventDefault();
23899 this.fireEvent("click", this, e);
23902 onMouseOver : function(e)
23904 if(this.submenu && this.pos == 'left'){
23905 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
23908 this.fireEvent("mouseover", this, e);
23911 onMouseOut : function(e)
23913 this.fireEvent("mouseout", this, e);
23925 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
23928 * @class Roo.bootstrap.menu.Separator
23929 * @extends Roo.bootstrap.Component
23930 * Bootstrap Separator class
23933 * Create a new Separator
23934 * @param {Object} config The config object
23938 Roo.bootstrap.menu.Separator = function(config){
23939 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
23942 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
23944 getAutoCreate : function(){
23965 * @class Roo.bootstrap.Tooltip
23966 * Bootstrap Tooltip class
23967 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
23968 * to determine which dom element triggers the tooltip.
23970 * It needs to add support for additional attributes like tooltip-position
23973 * Create a new Toolti
23974 * @param {Object} config The config object
23977 Roo.bootstrap.Tooltip = function(config){
23978 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23981 Roo.apply(Roo.bootstrap.Tooltip, {
23983 * @function init initialize tooltip monitoring.
23987 currentTip : false,
23988 currentRegion : false,
23994 Roo.get(document).on('mouseover', this.enter ,this);
23995 Roo.get(document).on('mouseout', this.leave, this);
23998 this.currentTip = new Roo.bootstrap.Tooltip();
24001 enter : function(ev)
24003 var dom = ev.getTarget();
24005 //Roo.log(['enter',dom]);
24006 var el = Roo.fly(dom);
24007 if (this.currentEl) {
24009 //Roo.log(this.currentEl);
24010 //Roo.log(this.currentEl.contains(dom));
24011 if (this.currentEl == el) {
24014 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
24020 if (this.currentTip.el) {
24021 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
24026 // you can not look for children, as if el is the body.. then everythign is the child..
24027 if (!el.attr('tooltip')) { //
24028 if (!el.select("[tooltip]").elements.length) {
24031 // is the mouse over this child...?
24032 bindEl = el.select("[tooltip]").first();
24033 var xy = ev.getXY();
24034 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
24035 //Roo.log("not in region.");
24038 //Roo.log("child element over..");
24041 this.currentEl = bindEl;
24042 this.currentTip.bind(bindEl);
24043 this.currentRegion = Roo.lib.Region.getRegion(dom);
24044 this.currentTip.enter();
24047 leave : function(ev)
24049 var dom = ev.getTarget();
24050 //Roo.log(['leave',dom]);
24051 if (!this.currentEl) {
24056 if (dom != this.currentEl.dom) {
24059 var xy = ev.getXY();
24060 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
24063 // only activate leave if mouse cursor is outside... bounding box..
24068 if (this.currentTip) {
24069 this.currentTip.leave();
24071 //Roo.log('clear currentEl');
24072 this.currentEl = false;
24077 'left' : ['r-l', [-2,0], 'right'],
24078 'right' : ['l-r', [2,0], 'left'],
24079 'bottom' : ['t-b', [0,2], 'top'],
24080 'top' : [ 'b-t', [0,-2], 'bottom']
24086 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
24091 delay : null, // can be { show : 300 , hide: 500}
24095 hoverState : null, //???
24097 placement : 'bottom',
24099 getAutoCreate : function(){
24106 cls : 'tooltip-arrow'
24109 cls : 'tooltip-inner'
24116 bind : function(el)
24122 enter : function () {
24124 if (this.timeout != null) {
24125 clearTimeout(this.timeout);
24128 this.hoverState = 'in';
24129 //Roo.log("enter - show");
24130 if (!this.delay || !this.delay.show) {
24135 this.timeout = setTimeout(function () {
24136 if (_t.hoverState == 'in') {
24139 }, this.delay.show);
24143 clearTimeout(this.timeout);
24145 this.hoverState = 'out';
24146 if (!this.delay || !this.delay.hide) {
24152 this.timeout = setTimeout(function () {
24153 //Roo.log("leave - timeout");
24155 if (_t.hoverState == 'out') {
24157 Roo.bootstrap.Tooltip.currentEl = false;
24165 this.render(document.body);
24168 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
24170 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
24172 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
24174 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
24176 var placement = typeof this.placement == 'function' ?
24177 this.placement.call(this, this.el, on_el) :
24180 var autoToken = /\s?auto?\s?/i;
24181 var autoPlace = autoToken.test(placement);
24183 placement = placement.replace(autoToken, '') || 'top';
24187 //this.el.setXY([0,0]);
24189 //this.el.dom.style.display='block';
24191 //this.el.appendTo(on_el);
24193 var p = this.getPosition();
24194 var box = this.el.getBox();
24200 var align = Roo.bootstrap.Tooltip.alignment[placement];
24202 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
24204 if(placement == 'top' || placement == 'bottom'){
24206 placement = 'right';
24209 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
24210 placement = 'left';
24214 align = Roo.bootstrap.Tooltip.alignment[placement];
24216 this.el.alignTo(this.bindEl, align[0],align[1]);
24217 //var arrow = this.el.select('.arrow',true).first();
24218 //arrow.set(align[2],
24220 this.el.addClass(placement);
24222 this.el.addClass('in fade');
24224 this.hoverState = null;
24226 if (this.el.hasClass('fade')) {
24237 //this.el.setXY([0,0]);
24238 this.el.removeClass('in');
24254 * @class Roo.bootstrap.LocationPicker
24255 * @extends Roo.bootstrap.Component
24256 * Bootstrap LocationPicker class
24257 * @cfg {Number} latitude Position when init default 0
24258 * @cfg {Number} longitude Position when init default 0
24259 * @cfg {Number} zoom default 15
24260 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
24261 * @cfg {Boolean} mapTypeControl default false
24262 * @cfg {Boolean} disableDoubleClickZoom default false
24263 * @cfg {Boolean} scrollwheel default true
24264 * @cfg {Boolean} streetViewControl default false
24265 * @cfg {Number} radius default 0
24266 * @cfg {String} locationName
24267 * @cfg {Boolean} draggable default true
24268 * @cfg {Boolean} enableAutocomplete default false
24269 * @cfg {Boolean} enableReverseGeocode default true
24270 * @cfg {String} markerTitle
24273 * Create a new LocationPicker
24274 * @param {Object} config The config object
24278 Roo.bootstrap.LocationPicker = function(config){
24280 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
24285 * Fires when the picker initialized.
24286 * @param {Roo.bootstrap.LocationPicker} this
24287 * @param {Google Location} location
24291 * @event positionchanged
24292 * Fires when the picker position changed.
24293 * @param {Roo.bootstrap.LocationPicker} this
24294 * @param {Google Location} location
24296 positionchanged : true,
24299 * Fires when the map resize.
24300 * @param {Roo.bootstrap.LocationPicker} this
24305 * Fires when the map show.
24306 * @param {Roo.bootstrap.LocationPicker} this
24311 * Fires when the map hide.
24312 * @param {Roo.bootstrap.LocationPicker} this
24317 * Fires when click the map.
24318 * @param {Roo.bootstrap.LocationPicker} this
24319 * @param {Map event} e
24323 * @event mapRightClick
24324 * Fires when right click the map.
24325 * @param {Roo.bootstrap.LocationPicker} this
24326 * @param {Map event} e
24328 mapRightClick : true,
24330 * @event markerClick
24331 * Fires when click the marker.
24332 * @param {Roo.bootstrap.LocationPicker} this
24333 * @param {Map event} e
24335 markerClick : true,
24337 * @event markerRightClick
24338 * Fires when right click the marker.
24339 * @param {Roo.bootstrap.LocationPicker} this
24340 * @param {Map event} e
24342 markerRightClick : true,
24344 * @event OverlayViewDraw
24345 * Fires when OverlayView Draw
24346 * @param {Roo.bootstrap.LocationPicker} this
24348 OverlayViewDraw : true,
24350 * @event OverlayViewOnAdd
24351 * Fires when OverlayView Draw
24352 * @param {Roo.bootstrap.LocationPicker} this
24354 OverlayViewOnAdd : true,
24356 * @event OverlayViewOnRemove
24357 * Fires when OverlayView Draw
24358 * @param {Roo.bootstrap.LocationPicker} this
24360 OverlayViewOnRemove : true,
24362 * @event OverlayViewShow
24363 * Fires when OverlayView Draw
24364 * @param {Roo.bootstrap.LocationPicker} this
24365 * @param {Pixel} cpx
24367 OverlayViewShow : true,
24369 * @event OverlayViewHide
24370 * Fires when OverlayView Draw
24371 * @param {Roo.bootstrap.LocationPicker} this
24373 OverlayViewHide : true,
24375 * @event loadexception
24376 * Fires when load google lib failed.
24377 * @param {Roo.bootstrap.LocationPicker} this
24379 loadexception : true
24384 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
24386 gMapContext: false,
24392 mapTypeControl: false,
24393 disableDoubleClickZoom: false,
24395 streetViewControl: false,
24399 enableAutocomplete: false,
24400 enableReverseGeocode: true,
24403 getAutoCreate: function()
24408 cls: 'roo-location-picker'
24414 initEvents: function(ct, position)
24416 if(!this.el.getWidth() || this.isApplied()){
24420 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24425 initial: function()
24427 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
24428 this.fireEvent('loadexception', this);
24432 if(!this.mapTypeId){
24433 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
24436 this.gMapContext = this.GMapContext();
24438 this.initOverlayView();
24440 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
24444 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
24445 _this.setPosition(_this.gMapContext.marker.position);
24448 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
24449 _this.fireEvent('mapClick', this, event);
24453 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
24454 _this.fireEvent('mapRightClick', this, event);
24458 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
24459 _this.fireEvent('markerClick', this, event);
24463 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
24464 _this.fireEvent('markerRightClick', this, event);
24468 this.setPosition(this.gMapContext.location);
24470 this.fireEvent('initial', this, this.gMapContext.location);
24473 initOverlayView: function()
24477 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
24481 _this.fireEvent('OverlayViewDraw', _this);
24486 _this.fireEvent('OverlayViewOnAdd', _this);
24489 onRemove: function()
24491 _this.fireEvent('OverlayViewOnRemove', _this);
24494 show: function(cpx)
24496 _this.fireEvent('OverlayViewShow', _this, cpx);
24501 _this.fireEvent('OverlayViewHide', _this);
24507 fromLatLngToContainerPixel: function(event)
24509 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
24512 isApplied: function()
24514 return this.getGmapContext() == false ? false : true;
24517 getGmapContext: function()
24519 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
24522 GMapContext: function()
24524 var position = new google.maps.LatLng(this.latitude, this.longitude);
24526 var _map = new google.maps.Map(this.el.dom, {
24529 mapTypeId: this.mapTypeId,
24530 mapTypeControl: this.mapTypeControl,
24531 disableDoubleClickZoom: this.disableDoubleClickZoom,
24532 scrollwheel: this.scrollwheel,
24533 streetViewControl: this.streetViewControl,
24534 locationName: this.locationName,
24535 draggable: this.draggable,
24536 enableAutocomplete: this.enableAutocomplete,
24537 enableReverseGeocode: this.enableReverseGeocode
24540 var _marker = new google.maps.Marker({
24541 position: position,
24543 title: this.markerTitle,
24544 draggable: this.draggable
24551 location: position,
24552 radius: this.radius,
24553 locationName: this.locationName,
24554 addressComponents: {
24555 formatted_address: null,
24556 addressLine1: null,
24557 addressLine2: null,
24559 streetNumber: null,
24563 stateOrProvince: null
24566 domContainer: this.el.dom,
24567 geodecoder: new google.maps.Geocoder()
24571 drawCircle: function(center, radius, options)
24573 if (this.gMapContext.circle != null) {
24574 this.gMapContext.circle.setMap(null);
24578 options = Roo.apply({}, options, {
24579 strokeColor: "#0000FF",
24580 strokeOpacity: .35,
24582 fillColor: "#0000FF",
24586 options.map = this.gMapContext.map;
24587 options.radius = radius;
24588 options.center = center;
24589 this.gMapContext.circle = new google.maps.Circle(options);
24590 return this.gMapContext.circle;
24596 setPosition: function(location)
24598 this.gMapContext.location = location;
24599 this.gMapContext.marker.setPosition(location);
24600 this.gMapContext.map.panTo(location);
24601 this.drawCircle(location, this.gMapContext.radius, {});
24605 if (this.gMapContext.settings.enableReverseGeocode) {
24606 this.gMapContext.geodecoder.geocode({
24607 latLng: this.gMapContext.location
24608 }, function(results, status) {
24610 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
24611 _this.gMapContext.locationName = results[0].formatted_address;
24612 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
24614 _this.fireEvent('positionchanged', this, location);
24621 this.fireEvent('positionchanged', this, location);
24626 google.maps.event.trigger(this.gMapContext.map, "resize");
24628 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
24630 this.fireEvent('resize', this);
24633 setPositionByLatLng: function(latitude, longitude)
24635 this.setPosition(new google.maps.LatLng(latitude, longitude));
24638 getCurrentPosition: function()
24641 latitude: this.gMapContext.location.lat(),
24642 longitude: this.gMapContext.location.lng()
24646 getAddressName: function()
24648 return this.gMapContext.locationName;
24651 getAddressComponents: function()
24653 return this.gMapContext.addressComponents;
24656 address_component_from_google_geocode: function(address_components)
24660 for (var i = 0; i < address_components.length; i++) {
24661 var component = address_components[i];
24662 if (component.types.indexOf("postal_code") >= 0) {
24663 result.postalCode = component.short_name;
24664 } else if (component.types.indexOf("street_number") >= 0) {
24665 result.streetNumber = component.short_name;
24666 } else if (component.types.indexOf("route") >= 0) {
24667 result.streetName = component.short_name;
24668 } else if (component.types.indexOf("neighborhood") >= 0) {
24669 result.city = component.short_name;
24670 } else if (component.types.indexOf("locality") >= 0) {
24671 result.city = component.short_name;
24672 } else if (component.types.indexOf("sublocality") >= 0) {
24673 result.district = component.short_name;
24674 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
24675 result.stateOrProvince = component.short_name;
24676 } else if (component.types.indexOf("country") >= 0) {
24677 result.country = component.short_name;
24681 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
24682 result.addressLine2 = "";
24686 setZoomLevel: function(zoom)
24688 this.gMapContext.map.setZoom(zoom);
24701 this.fireEvent('show', this);
24712 this.fireEvent('hide', this);
24717 Roo.apply(Roo.bootstrap.LocationPicker, {
24719 OverlayView : function(map, options)
24721 options = options || {};
24735 * @class Roo.bootstrap.Alert
24736 * @extends Roo.bootstrap.Component
24737 * Bootstrap Alert class
24738 * @cfg {String} title The title of alert
24739 * @cfg {String} html The content of alert
24740 * @cfg {String} weight ( success | info | warning | danger )
24741 * @cfg {String} faicon font-awesomeicon
24744 * Create a new alert
24745 * @param {Object} config The config object
24749 Roo.bootstrap.Alert = function(config){
24750 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
24754 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
24761 getAutoCreate : function()
24770 cls : 'roo-alert-icon'
24775 cls : 'roo-alert-title',
24780 cls : 'roo-alert-text',
24787 cfg.cn[0].cls += ' fa ' + this.faicon;
24791 cfg.cls += ' alert-' + this.weight;
24797 initEvents: function()
24799 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24802 setTitle : function(str)
24804 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
24807 setText : function(str)
24809 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
24812 setWeight : function(weight)
24815 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
24818 this.weight = weight;
24820 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
24823 setIcon : function(icon)
24826 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
24829 this.faicon = icon;
24831 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
24852 * @class Roo.bootstrap.UploadCropbox
24853 * @extends Roo.bootstrap.Component
24854 * Bootstrap UploadCropbox class
24855 * @cfg {String} emptyText show when image has been loaded
24856 * @cfg {String} rotateNotify show when image too small to rotate
24857 * @cfg {Number} errorTimeout default 3000
24858 * @cfg {Number} minWidth default 300
24859 * @cfg {Number} minHeight default 300
24860 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
24861 * @cfg {Boolean} isDocument (true|false) default false
24862 * @cfg {String} url action url
24863 * @cfg {String} paramName default 'imageUpload'
24864 * @cfg {String} method default POST
24865 * @cfg {Boolean} loadMask (true|false) default true
24866 * @cfg {Boolean} loadingText default 'Loading...'
24869 * Create a new UploadCropbox
24870 * @param {Object} config The config object
24873 Roo.bootstrap.UploadCropbox = function(config){
24874 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
24878 * @event beforeselectfile
24879 * Fire before select file
24880 * @param {Roo.bootstrap.UploadCropbox} this
24882 "beforeselectfile" : true,
24885 * Fire after initEvent
24886 * @param {Roo.bootstrap.UploadCropbox} this
24891 * Fire after initEvent
24892 * @param {Roo.bootstrap.UploadCropbox} this
24893 * @param {String} data
24898 * Fire when preparing the file data
24899 * @param {Roo.bootstrap.UploadCropbox} this
24900 * @param {Object} file
24905 * Fire when get exception
24906 * @param {Roo.bootstrap.UploadCropbox} this
24907 * @param {XMLHttpRequest} xhr
24909 "exception" : true,
24911 * @event beforeloadcanvas
24912 * Fire before load the canvas
24913 * @param {Roo.bootstrap.UploadCropbox} this
24914 * @param {String} src
24916 "beforeloadcanvas" : true,
24919 * Fire when trash image
24920 * @param {Roo.bootstrap.UploadCropbox} this
24925 * Fire when download the image
24926 * @param {Roo.bootstrap.UploadCropbox} this
24930 * @event footerbuttonclick
24931 * Fire when footerbuttonclick
24932 * @param {Roo.bootstrap.UploadCropbox} this
24933 * @param {String} type
24935 "footerbuttonclick" : true,
24939 * @param {Roo.bootstrap.UploadCropbox} this
24944 * Fire when rotate the image
24945 * @param {Roo.bootstrap.UploadCropbox} this
24946 * @param {String} pos
24951 * Fire when inspect the file
24952 * @param {Roo.bootstrap.UploadCropbox} this
24953 * @param {Object} file
24958 * Fire when xhr upload the file
24959 * @param {Roo.bootstrap.UploadCropbox} this
24960 * @param {Object} data
24965 * Fire when arrange the file data
24966 * @param {Roo.bootstrap.UploadCropbox} this
24967 * @param {Object} formData
24972 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
24975 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
24977 emptyText : 'Click to upload image',
24978 rotateNotify : 'Image is too small to rotate',
24979 errorTimeout : 3000,
24993 cropType : 'image/jpeg',
24995 canvasLoaded : false,
24996 isDocument : false,
24998 paramName : 'imageUpload',
25000 loadingText : 'Loading...',
25003 getAutoCreate : function()
25007 cls : 'roo-upload-cropbox',
25011 cls : 'roo-upload-cropbox-selector',
25016 cls : 'roo-upload-cropbox-body',
25017 style : 'cursor:pointer',
25021 cls : 'roo-upload-cropbox-preview'
25025 cls : 'roo-upload-cropbox-thumb'
25029 cls : 'roo-upload-cropbox-empty-notify',
25030 html : this.emptyText
25034 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
25035 html : this.rotateNotify
25041 cls : 'roo-upload-cropbox-footer',
25044 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
25054 onRender : function(ct, position)
25056 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
25058 if (this.buttons.length) {
25060 Roo.each(this.buttons, function(bb) {
25062 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
25064 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
25070 this.maskEl = this.el;
25074 initEvents : function()
25076 this.urlAPI = (window.createObjectURL && window) ||
25077 (window.URL && URL.revokeObjectURL && URL) ||
25078 (window.webkitURL && webkitURL);
25080 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
25081 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25083 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
25084 this.selectorEl.hide();
25086 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
25087 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25089 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
25090 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25091 this.thumbEl.hide();
25093 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
25094 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25096 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
25097 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25098 this.errorEl.hide();
25100 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
25101 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
25102 this.footerEl.hide();
25104 this.setThumbBoxSize();
25110 this.fireEvent('initial', this);
25117 window.addEventListener("resize", function() { _this.resize(); } );
25119 this.bodyEl.on('click', this.beforeSelectFile, this);
25122 this.bodyEl.on('touchstart', this.onTouchStart, this);
25123 this.bodyEl.on('touchmove', this.onTouchMove, this);
25124 this.bodyEl.on('touchend', this.onTouchEnd, this);
25128 this.bodyEl.on('mousedown', this.onMouseDown, this);
25129 this.bodyEl.on('mousemove', this.onMouseMove, this);
25130 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
25131 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
25132 Roo.get(document).on('mouseup', this.onMouseUp, this);
25135 this.selectorEl.on('change', this.onFileSelected, this);
25141 this.baseScale = 1;
25143 this.baseRotate = 1;
25144 this.dragable = false;
25145 this.pinching = false;
25148 this.cropData = false;
25149 this.notifyEl.dom.innerHTML = this.emptyText;
25151 this.selectorEl.dom.value = '';
25155 resize : function()
25157 if(this.fireEvent('resize', this) != false){
25158 this.setThumbBoxPosition();
25159 this.setCanvasPosition();
25163 onFooterButtonClick : function(e, el, o, type)
25166 case 'rotate-left' :
25167 this.onRotateLeft(e);
25169 case 'rotate-right' :
25170 this.onRotateRight(e);
25173 this.beforeSelectFile(e);
25188 this.fireEvent('footerbuttonclick', this, type);
25191 beforeSelectFile : function(e)
25193 e.preventDefault();
25195 if(this.fireEvent('beforeselectfile', this) != false){
25196 this.selectorEl.dom.click();
25200 onFileSelected : function(e)
25202 e.preventDefault();
25204 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
25208 var file = this.selectorEl.dom.files[0];
25210 if(this.fireEvent('inspect', this, file) != false){
25211 this.prepare(file);
25216 trash : function(e)
25218 this.fireEvent('trash', this);
25221 download : function(e)
25223 this.fireEvent('download', this);
25226 loadCanvas : function(src)
25228 if(this.fireEvent('beforeloadcanvas', this, src) != false){
25232 this.imageEl = document.createElement('img');
25236 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
25238 this.imageEl.src = src;
25242 onLoadCanvas : function()
25244 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
25245 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
25247 this.bodyEl.un('click', this.beforeSelectFile, this);
25249 this.notifyEl.hide();
25250 this.thumbEl.show();
25251 this.footerEl.show();
25253 this.baseRotateLevel();
25255 if(this.isDocument){
25256 this.setThumbBoxSize();
25259 this.setThumbBoxPosition();
25261 this.baseScaleLevel();
25267 this.canvasLoaded = true;
25270 this.maskEl.unmask();
25275 setCanvasPosition : function()
25277 if(!this.canvasEl){
25281 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
25282 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
25284 this.previewEl.setLeft(pw);
25285 this.previewEl.setTop(ph);
25289 onMouseDown : function(e)
25293 this.dragable = true;
25294 this.pinching = false;
25296 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
25297 this.dragable = false;
25301 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25302 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25306 onMouseMove : function(e)
25310 if(!this.canvasLoaded){
25314 if (!this.dragable){
25318 var minX = Math.ceil(this.thumbEl.getLeft(true));
25319 var minY = Math.ceil(this.thumbEl.getTop(true));
25321 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
25322 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
25324 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25325 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25327 x = x - this.mouseX;
25328 y = y - this.mouseY;
25330 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
25331 var bgY = Math.ceil(y + this.previewEl.getTop(true));
25333 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
25334 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
25336 this.previewEl.setLeft(bgX);
25337 this.previewEl.setTop(bgY);
25339 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
25340 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
25343 onMouseUp : function(e)
25347 this.dragable = false;
25350 onMouseWheel : function(e)
25354 this.startScale = this.scale;
25356 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
25358 if(!this.zoomable()){
25359 this.scale = this.startScale;
25368 zoomable : function()
25370 var minScale = this.thumbEl.getWidth() / this.minWidth;
25372 if(this.minWidth < this.minHeight){
25373 minScale = this.thumbEl.getHeight() / this.minHeight;
25376 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
25377 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
25381 (this.rotate == 0 || this.rotate == 180) &&
25383 width > this.imageEl.OriginWidth ||
25384 height > this.imageEl.OriginHeight ||
25385 (width < this.minWidth && height < this.minHeight)
25393 (this.rotate == 90 || this.rotate == 270) &&
25395 width > this.imageEl.OriginWidth ||
25396 height > this.imageEl.OriginHeight ||
25397 (width < this.minHeight && height < this.minWidth)
25404 !this.isDocument &&
25405 (this.rotate == 0 || this.rotate == 180) &&
25407 width < this.minWidth ||
25408 width > this.imageEl.OriginWidth ||
25409 height < this.minHeight ||
25410 height > this.imageEl.OriginHeight
25417 !this.isDocument &&
25418 (this.rotate == 90 || this.rotate == 270) &&
25420 width < this.minHeight ||
25421 width > this.imageEl.OriginWidth ||
25422 height < this.minWidth ||
25423 height > this.imageEl.OriginHeight
25433 onRotateLeft : function(e)
25435 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25437 var minScale = this.thumbEl.getWidth() / this.minWidth;
25439 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25440 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25442 this.startScale = this.scale;
25444 while (this.getScaleLevel() < minScale){
25446 this.scale = this.scale + 1;
25448 if(!this.zoomable()){
25453 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25454 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25459 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25466 this.scale = this.startScale;
25468 this.onRotateFail();
25473 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
25475 if(this.isDocument){
25476 this.setThumbBoxSize();
25477 this.setThumbBoxPosition();
25478 this.setCanvasPosition();
25483 this.fireEvent('rotate', this, 'left');
25487 onRotateRight : function(e)
25489 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
25491 var minScale = this.thumbEl.getWidth() / this.minWidth;
25493 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
25494 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
25496 this.startScale = this.scale;
25498 while (this.getScaleLevel() < minScale){
25500 this.scale = this.scale + 1;
25502 if(!this.zoomable()){
25507 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
25508 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
25513 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25520 this.scale = this.startScale;
25522 this.onRotateFail();
25527 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
25529 if(this.isDocument){
25530 this.setThumbBoxSize();
25531 this.setThumbBoxPosition();
25532 this.setCanvasPosition();
25537 this.fireEvent('rotate', this, 'right');
25540 onRotateFail : function()
25542 this.errorEl.show(true);
25546 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
25551 this.previewEl.dom.innerHTML = '';
25553 var canvasEl = document.createElement("canvas");
25555 var contextEl = canvasEl.getContext("2d");
25557 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25558 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25559 var center = this.imageEl.OriginWidth / 2;
25561 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
25562 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25563 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25564 center = this.imageEl.OriginHeight / 2;
25567 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
25569 contextEl.translate(center, center);
25570 contextEl.rotate(this.rotate * Math.PI / 180);
25572 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25574 this.canvasEl = document.createElement("canvas");
25576 this.contextEl = this.canvasEl.getContext("2d");
25578 switch (this.rotate) {
25581 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25582 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25584 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25589 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25590 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25592 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25593 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);
25597 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25602 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
25603 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
25605 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25606 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);
25610 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);
25615 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
25616 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
25618 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25619 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
25623 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);
25630 this.previewEl.appendChild(this.canvasEl);
25632 this.setCanvasPosition();
25637 if(!this.canvasLoaded){
25641 var imageCanvas = document.createElement("canvas");
25643 var imageContext = imageCanvas.getContext("2d");
25645 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25646 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
25648 var center = imageCanvas.width / 2;
25650 imageContext.translate(center, center);
25652 imageContext.rotate(this.rotate * Math.PI / 180);
25654 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
25656 var canvas = document.createElement("canvas");
25658 var context = canvas.getContext("2d");
25660 canvas.width = this.minWidth;
25661 canvas.height = this.minHeight;
25663 switch (this.rotate) {
25666 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25667 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25669 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25670 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25672 var targetWidth = this.minWidth - 2 * x;
25673 var targetHeight = this.minHeight - 2 * y;
25677 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25678 scale = targetWidth / width;
25681 if(x > 0 && y == 0){
25682 scale = targetHeight / height;
25685 if(x > 0 && y > 0){
25686 scale = targetWidth / width;
25688 if(width < height){
25689 scale = targetHeight / height;
25693 context.scale(scale, scale);
25695 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25696 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25698 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25699 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25701 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25706 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25707 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25709 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25710 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25712 var targetWidth = this.minWidth - 2 * x;
25713 var targetHeight = this.minHeight - 2 * y;
25717 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25718 scale = targetWidth / width;
25721 if(x > 0 && y == 0){
25722 scale = targetHeight / height;
25725 if(x > 0 && y > 0){
25726 scale = targetWidth / width;
25728 if(width < height){
25729 scale = targetHeight / height;
25733 context.scale(scale, scale);
25735 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25736 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25738 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25739 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25741 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25743 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25748 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
25749 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
25751 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25752 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25754 var targetWidth = this.minWidth - 2 * x;
25755 var targetHeight = this.minHeight - 2 * y;
25759 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25760 scale = targetWidth / width;
25763 if(x > 0 && y == 0){
25764 scale = targetHeight / height;
25767 if(x > 0 && y > 0){
25768 scale = targetWidth / width;
25770 if(width < height){
25771 scale = targetHeight / height;
25775 context.scale(scale, scale);
25777 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25778 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25780 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25781 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25783 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25784 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
25786 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25791 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
25792 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
25794 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
25795 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
25797 var targetWidth = this.minWidth - 2 * x;
25798 var targetHeight = this.minHeight - 2 * y;
25802 if((x == 0 && y == 0) || (x == 0 && y > 0)){
25803 scale = targetWidth / width;
25806 if(x > 0 && y == 0){
25807 scale = targetHeight / height;
25810 if(x > 0 && y > 0){
25811 scale = targetWidth / width;
25813 if(width < height){
25814 scale = targetHeight / height;
25818 context.scale(scale, scale);
25820 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
25821 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
25823 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
25824 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
25826 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
25828 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
25835 this.cropData = canvas.toDataURL(this.cropType);
25837 if(this.fireEvent('crop', this, this.cropData) !== false){
25838 this.process(this.file, this.cropData);
25845 setThumbBoxSize : function()
25849 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
25850 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
25851 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
25853 this.minWidth = width;
25854 this.minHeight = height;
25856 if(this.rotate == 90 || this.rotate == 270){
25857 this.minWidth = height;
25858 this.minHeight = width;
25863 width = Math.ceil(this.minWidth * height / this.minHeight);
25865 if(this.minWidth > this.minHeight){
25867 height = Math.ceil(this.minHeight * width / this.minWidth);
25870 this.thumbEl.setStyle({
25871 width : width + 'px',
25872 height : height + 'px'
25879 setThumbBoxPosition : function()
25881 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
25882 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
25884 this.thumbEl.setLeft(x);
25885 this.thumbEl.setTop(y);
25889 baseRotateLevel : function()
25891 this.baseRotate = 1;
25894 typeof(this.exif) != 'undefined' &&
25895 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
25896 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
25898 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
25901 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
25905 baseScaleLevel : function()
25909 if(this.isDocument){
25911 if(this.baseRotate == 6 || this.baseRotate == 8){
25913 height = this.thumbEl.getHeight();
25914 this.baseScale = height / this.imageEl.OriginWidth;
25916 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
25917 width = this.thumbEl.getWidth();
25918 this.baseScale = width / this.imageEl.OriginHeight;
25924 height = this.thumbEl.getHeight();
25925 this.baseScale = height / this.imageEl.OriginHeight;
25927 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
25928 width = this.thumbEl.getWidth();
25929 this.baseScale = width / this.imageEl.OriginWidth;
25935 if(this.baseRotate == 6 || this.baseRotate == 8){
25937 width = this.thumbEl.getHeight();
25938 this.baseScale = width / this.imageEl.OriginHeight;
25940 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
25941 height = this.thumbEl.getWidth();
25942 this.baseScale = height / this.imageEl.OriginHeight;
25945 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25946 height = this.thumbEl.getWidth();
25947 this.baseScale = height / this.imageEl.OriginHeight;
25949 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
25950 width = this.thumbEl.getHeight();
25951 this.baseScale = width / this.imageEl.OriginWidth;
25958 width = this.thumbEl.getWidth();
25959 this.baseScale = width / this.imageEl.OriginWidth;
25961 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
25962 height = this.thumbEl.getHeight();
25963 this.baseScale = height / this.imageEl.OriginHeight;
25966 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
25968 height = this.thumbEl.getHeight();
25969 this.baseScale = height / this.imageEl.OriginHeight;
25971 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
25972 width = this.thumbEl.getWidth();
25973 this.baseScale = width / this.imageEl.OriginWidth;
25981 getScaleLevel : function()
25983 return this.baseScale * Math.pow(1.1, this.scale);
25986 onTouchStart : function(e)
25988 if(!this.canvasLoaded){
25989 this.beforeSelectFile(e);
25993 var touches = e.browserEvent.touches;
25999 if(touches.length == 1){
26000 this.onMouseDown(e);
26004 if(touches.length != 2){
26010 for(var i = 0, finger; finger = touches[i]; i++){
26011 coords.push(finger.pageX, finger.pageY);
26014 var x = Math.pow(coords[0] - coords[2], 2);
26015 var y = Math.pow(coords[1] - coords[3], 2);
26017 this.startDistance = Math.sqrt(x + y);
26019 this.startScale = this.scale;
26021 this.pinching = true;
26022 this.dragable = false;
26026 onTouchMove : function(e)
26028 if(!this.pinching && !this.dragable){
26032 var touches = e.browserEvent.touches;
26039 this.onMouseMove(e);
26045 for(var i = 0, finger; finger = touches[i]; i++){
26046 coords.push(finger.pageX, finger.pageY);
26049 var x = Math.pow(coords[0] - coords[2], 2);
26050 var y = Math.pow(coords[1] - coords[3], 2);
26052 this.endDistance = Math.sqrt(x + y);
26054 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
26056 if(!this.zoomable()){
26057 this.scale = this.startScale;
26065 onTouchEnd : function(e)
26067 this.pinching = false;
26068 this.dragable = false;
26072 process : function(file, crop)
26075 this.maskEl.mask(this.loadingText);
26078 this.xhr = new XMLHttpRequest();
26080 file.xhr = this.xhr;
26082 this.xhr.open(this.method, this.url, true);
26085 "Accept": "application/json",
26086 "Cache-Control": "no-cache",
26087 "X-Requested-With": "XMLHttpRequest"
26090 for (var headerName in headers) {
26091 var headerValue = headers[headerName];
26093 this.xhr.setRequestHeader(headerName, headerValue);
26099 this.xhr.onload = function()
26101 _this.xhrOnLoad(_this.xhr);
26104 this.xhr.onerror = function()
26106 _this.xhrOnError(_this.xhr);
26109 var formData = new FormData();
26111 formData.append('returnHTML', 'NO');
26114 formData.append('crop', crop);
26117 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
26118 formData.append(this.paramName, file, file.name);
26121 if(typeof(file.filename) != 'undefined'){
26122 formData.append('filename', file.filename);
26125 if(typeof(file.mimetype) != 'undefined'){
26126 formData.append('mimetype', file.mimetype);
26129 if(this.fireEvent('arrange', this, formData) != false){
26130 this.xhr.send(formData);
26134 xhrOnLoad : function(xhr)
26137 this.maskEl.unmask();
26140 if (xhr.readyState !== 4) {
26141 this.fireEvent('exception', this, xhr);
26145 var response = Roo.decode(xhr.responseText);
26147 if(!response.success){
26148 this.fireEvent('exception', this, xhr);
26152 var response = Roo.decode(xhr.responseText);
26154 this.fireEvent('upload', this, response);
26158 xhrOnError : function()
26161 this.maskEl.unmask();
26164 Roo.log('xhr on error');
26166 var response = Roo.decode(xhr.responseText);
26172 prepare : function(file)
26175 this.maskEl.mask(this.loadingText);
26181 if(typeof(file) === 'string'){
26182 this.loadCanvas(file);
26186 if(!file || !this.urlAPI){
26191 this.cropType = file.type;
26195 if(this.fireEvent('prepare', this, this.file) != false){
26197 var reader = new FileReader();
26199 reader.onload = function (e) {
26200 if (e.target.error) {
26201 Roo.log(e.target.error);
26205 var buffer = e.target.result,
26206 dataView = new DataView(buffer),
26208 maxOffset = dataView.byteLength - 4,
26212 if (dataView.getUint16(0) === 0xffd8) {
26213 while (offset < maxOffset) {
26214 markerBytes = dataView.getUint16(offset);
26216 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
26217 markerLength = dataView.getUint16(offset + 2) + 2;
26218 if (offset + markerLength > dataView.byteLength) {
26219 Roo.log('Invalid meta data: Invalid segment size.');
26223 if(markerBytes == 0xffe1){
26224 _this.parseExifData(
26231 offset += markerLength;
26241 var url = _this.urlAPI.createObjectURL(_this.file);
26243 _this.loadCanvas(url);
26248 reader.readAsArrayBuffer(this.file);
26254 parseExifData : function(dataView, offset, length)
26256 var tiffOffset = offset + 10,
26260 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26261 // No Exif data, might be XMP data instead
26265 // Check for the ASCII code for "Exif" (0x45786966):
26266 if (dataView.getUint32(offset + 4) !== 0x45786966) {
26267 // No Exif data, might be XMP data instead
26270 if (tiffOffset + 8 > dataView.byteLength) {
26271 Roo.log('Invalid Exif data: Invalid segment size.');
26274 // Check for the two null bytes:
26275 if (dataView.getUint16(offset + 8) !== 0x0000) {
26276 Roo.log('Invalid Exif data: Missing byte alignment offset.');
26279 // Check the byte alignment:
26280 switch (dataView.getUint16(tiffOffset)) {
26282 littleEndian = true;
26285 littleEndian = false;
26288 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
26291 // Check for the TIFF tag marker (0x002A):
26292 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
26293 Roo.log('Invalid Exif data: Missing TIFF marker.');
26296 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
26297 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
26299 this.parseExifTags(
26302 tiffOffset + dirOffset,
26307 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
26312 if (dirOffset + 6 > dataView.byteLength) {
26313 Roo.log('Invalid Exif data: Invalid directory offset.');
26316 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
26317 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
26318 if (dirEndOffset + 4 > dataView.byteLength) {
26319 Roo.log('Invalid Exif data: Invalid directory size.');
26322 for (i = 0; i < tagsNumber; i += 1) {
26326 dirOffset + 2 + 12 * i, // tag offset
26330 // Return the offset to the next directory:
26331 return dataView.getUint32(dirEndOffset, littleEndian);
26334 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
26336 var tag = dataView.getUint16(offset, littleEndian);
26338 this.exif[tag] = this.getExifValue(
26342 dataView.getUint16(offset + 2, littleEndian), // tag type
26343 dataView.getUint32(offset + 4, littleEndian), // tag length
26348 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
26350 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
26359 Roo.log('Invalid Exif data: Invalid tag type.');
26363 tagSize = tagType.size * length;
26364 // Determine if the value is contained in the dataOffset bytes,
26365 // or if the value at the dataOffset is a pointer to the actual data:
26366 dataOffset = tagSize > 4 ?
26367 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
26368 if (dataOffset + tagSize > dataView.byteLength) {
26369 Roo.log('Invalid Exif data: Invalid data offset.');
26372 if (length === 1) {
26373 return tagType.getValue(dataView, dataOffset, littleEndian);
26376 for (i = 0; i < length; i += 1) {
26377 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
26380 if (tagType.ascii) {
26382 // Concatenate the chars:
26383 for (i = 0; i < values.length; i += 1) {
26385 // Ignore the terminating NULL byte(s):
26386 if (c === '\u0000') {
26398 Roo.apply(Roo.bootstrap.UploadCropbox, {
26400 'Orientation': 0x0112
26404 1: 0, //'top-left',
26406 3: 180, //'bottom-right',
26407 // 4: 'bottom-left',
26409 6: 90, //'right-top',
26410 // 7: 'right-bottom',
26411 8: 270 //'left-bottom'
26415 // byte, 8-bit unsigned int:
26417 getValue: function (dataView, dataOffset) {
26418 return dataView.getUint8(dataOffset);
26422 // ascii, 8-bit byte:
26424 getValue: function (dataView, dataOffset) {
26425 return String.fromCharCode(dataView.getUint8(dataOffset));
26430 // short, 16 bit int:
26432 getValue: function (dataView, dataOffset, littleEndian) {
26433 return dataView.getUint16(dataOffset, littleEndian);
26437 // long, 32 bit int:
26439 getValue: function (dataView, dataOffset, littleEndian) {
26440 return dataView.getUint32(dataOffset, littleEndian);
26444 // rational = two long values, first is numerator, second is denominator:
26446 getValue: function (dataView, dataOffset, littleEndian) {
26447 return dataView.getUint32(dataOffset, littleEndian) /
26448 dataView.getUint32(dataOffset + 4, littleEndian);
26452 // slong, 32 bit signed int:
26454 getValue: function (dataView, dataOffset, littleEndian) {
26455 return dataView.getInt32(dataOffset, littleEndian);
26459 // srational, two slongs, first is numerator, second is denominator:
26461 getValue: function (dataView, dataOffset, littleEndian) {
26462 return dataView.getInt32(dataOffset, littleEndian) /
26463 dataView.getInt32(dataOffset + 4, littleEndian);
26473 cls : 'btn-group roo-upload-cropbox-rotate-left',
26474 action : 'rotate-left',
26478 cls : 'btn btn-default',
26479 html : '<i class="fa fa-undo"></i>'
26485 cls : 'btn-group roo-upload-cropbox-picture',
26486 action : 'picture',
26490 cls : 'btn btn-default',
26491 html : '<i class="fa fa-picture-o"></i>'
26497 cls : 'btn-group roo-upload-cropbox-rotate-right',
26498 action : 'rotate-right',
26502 cls : 'btn btn-default',
26503 html : '<i class="fa fa-repeat"></i>'
26511 cls : 'btn-group roo-upload-cropbox-rotate-left',
26512 action : 'rotate-left',
26516 cls : 'btn btn-default',
26517 html : '<i class="fa fa-undo"></i>'
26523 cls : 'btn-group roo-upload-cropbox-download',
26524 action : 'download',
26528 cls : 'btn btn-default',
26529 html : '<i class="fa fa-download"></i>'
26535 cls : 'btn-group roo-upload-cropbox-crop',
26540 cls : 'btn btn-default',
26541 html : '<i class="fa fa-crop"></i>'
26547 cls : 'btn-group roo-upload-cropbox-trash',
26552 cls : 'btn btn-default',
26553 html : '<i class="fa fa-trash"></i>'
26559 cls : 'btn-group roo-upload-cropbox-rotate-right',
26560 action : 'rotate-right',
26564 cls : 'btn btn-default',
26565 html : '<i class="fa fa-repeat"></i>'
26573 cls : 'btn-group roo-upload-cropbox-rotate-left',
26574 action : 'rotate-left',
26578 cls : 'btn btn-default',
26579 html : '<i class="fa fa-undo"></i>'
26585 cls : 'btn-group roo-upload-cropbox-rotate-right',
26586 action : 'rotate-right',
26590 cls : 'btn btn-default',
26591 html : '<i class="fa fa-repeat"></i>'
26604 * @class Roo.bootstrap.DocumentManager
26605 * @extends Roo.bootstrap.Component
26606 * Bootstrap DocumentManager class
26607 * @cfg {String} paramName default 'imageUpload'
26608 * @cfg {String} method default POST
26609 * @cfg {String} url action url
26610 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
26611 * @cfg {Boolean} multiple multiple upload default true
26612 * @cfg {Number} thumbSize default 300
26613 * @cfg {String} fieldLabel
26614 * @cfg {Number} labelWidth default 4
26615 * @cfg {String} labelAlign (left|top) default left
26616 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
26619 * Create a new DocumentManager
26620 * @param {Object} config The config object
26623 Roo.bootstrap.DocumentManager = function(config){
26624 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
26629 * Fire when initial the DocumentManager
26630 * @param {Roo.bootstrap.DocumentManager} this
26635 * inspect selected file
26636 * @param {Roo.bootstrap.DocumentManager} this
26637 * @param {File} file
26642 * Fire when xhr load exception
26643 * @param {Roo.bootstrap.DocumentManager} this
26644 * @param {XMLHttpRequest} xhr
26646 "exception" : true,
26649 * prepare the form data
26650 * @param {Roo.bootstrap.DocumentManager} this
26651 * @param {Object} formData
26656 * Fire when remove the file
26657 * @param {Roo.bootstrap.DocumentManager} this
26658 * @param {Object} file
26663 * Fire after refresh the file
26664 * @param {Roo.bootstrap.DocumentManager} this
26669 * Fire after click the image
26670 * @param {Roo.bootstrap.DocumentManager} this
26671 * @param {Object} file
26676 * Fire when upload a image and editable set to true
26677 * @param {Roo.bootstrap.DocumentManager} this
26678 * @param {Object} file
26682 * @event beforeselectfile
26683 * Fire before select file
26684 * @param {Roo.bootstrap.DocumentManager} this
26686 "beforeselectfile" : true,
26689 * Fire before process file
26690 * @param {Roo.bootstrap.DocumentManager} this
26691 * @param {Object} file
26698 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
26707 paramName : 'imageUpload',
26710 labelAlign : 'left',
26717 getAutoCreate : function()
26719 var managerWidget = {
26721 cls : 'roo-document-manager',
26725 cls : 'roo-document-manager-selector',
26730 cls : 'roo-document-manager-uploader',
26734 cls : 'roo-document-manager-upload-btn',
26735 html : '<i class="fa fa-plus"></i>'
26746 cls : 'column col-md-12',
26751 if(this.fieldLabel.length){
26756 cls : 'column col-md-12',
26757 html : this.fieldLabel
26761 cls : 'column col-md-12',
26766 if(this.labelAlign == 'left'){
26770 cls : 'column col-md-' + this.labelWidth,
26771 html : this.fieldLabel
26775 cls : 'column col-md-' + (12 - this.labelWidth),
26785 cls : 'row clearfix',
26793 initEvents : function()
26795 this.managerEl = this.el.select('.roo-document-manager', true).first();
26796 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26798 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
26799 this.selectorEl.hide();
26802 this.selectorEl.attr('multiple', 'multiple');
26805 this.selectorEl.on('change', this.onFileSelected, this);
26807 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
26808 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26810 this.uploader.on('click', this.onUploaderClick, this);
26812 this.renderProgressDialog();
26816 window.addEventListener("resize", function() { _this.refresh(); } );
26818 this.fireEvent('initial', this);
26821 renderProgressDialog : function()
26825 this.progressDialog = new Roo.bootstrap.Modal({
26826 cls : 'roo-document-manager-progress-dialog',
26827 allow_close : false,
26837 btnclick : function() {
26838 _this.uploadCancel();
26844 this.progressDialog.render(Roo.get(document.body));
26846 this.progress = new Roo.bootstrap.Progress({
26847 cls : 'roo-document-manager-progress',
26852 this.progress.render(this.progressDialog.getChildContainer());
26854 this.progressBar = new Roo.bootstrap.ProgressBar({
26855 cls : 'roo-document-manager-progress-bar',
26858 aria_valuemax : 12,
26862 this.progressBar.render(this.progress.getChildContainer());
26865 onUploaderClick : function(e)
26867 e.preventDefault();
26869 if(this.fireEvent('beforeselectfile', this) != false){
26870 this.selectorEl.dom.click();
26875 onFileSelected : function(e)
26877 e.preventDefault();
26879 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26883 Roo.each(this.selectorEl.dom.files, function(file){
26884 if(this.fireEvent('inspect', this, file) != false){
26885 this.files.push(file);
26895 this.selectorEl.dom.value = '';
26897 if(!this.files.length){
26901 if(this.boxes > 0 && this.files.length > this.boxes){
26902 this.files = this.files.slice(0, this.boxes);
26905 this.uploader.show();
26907 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26908 this.uploader.hide();
26917 Roo.each(this.files, function(file){
26919 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
26920 var f = this.renderPreview(file);
26925 if(file.type.indexOf('image') != -1){
26926 this.delegates.push(
26928 _this.process(file);
26929 }).createDelegate(this)
26937 _this.process(file);
26938 }).createDelegate(this)
26943 this.files = files;
26945 this.delegates = this.delegates.concat(docs);
26947 if(!this.delegates.length){
26952 this.progressBar.aria_valuemax = this.delegates.length;
26959 arrange : function()
26961 if(!this.delegates.length){
26962 this.progressDialog.hide();
26967 var delegate = this.delegates.shift();
26969 this.progressDialog.show();
26971 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
26973 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
26978 refresh : function()
26980 this.uploader.show();
26982 if(this.boxes > 0 && this.files.length > this.boxes - 1){
26983 this.uploader.hide();
26986 Roo.isTouch ? this.closable(false) : this.closable(true);
26988 this.fireEvent('refresh', this);
26991 onRemove : function(e, el, o)
26993 e.preventDefault();
26995 this.fireEvent('remove', this, o);
26999 remove : function(o)
27003 Roo.each(this.files, function(file){
27004 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
27013 this.files = files;
27020 Roo.each(this.files, function(file){
27025 file.target.remove();
27034 onClick : function(e, el, o)
27036 e.preventDefault();
27038 this.fireEvent('click', this, o);
27042 closable : function(closable)
27044 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
27046 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27058 xhrOnLoad : function(xhr)
27060 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27064 if (xhr.readyState !== 4) {
27066 this.fireEvent('exception', this, xhr);
27070 var response = Roo.decode(xhr.responseText);
27072 if(!response.success){
27074 this.fireEvent('exception', this, xhr);
27078 var file = this.renderPreview(response.data);
27080 this.files.push(file);
27086 xhrOnError : function(xhr)
27088 Roo.log('xhr on error');
27090 var response = Roo.decode(xhr.responseText);
27097 process : function(file)
27099 if(this.fireEvent('process', this, file) !== false){
27100 if(this.editable && file.type.indexOf('image') != -1){
27101 this.fireEvent('edit', this, file);
27105 this.uploadStart(file, false);
27112 uploadStart : function(file, crop)
27114 this.xhr = new XMLHttpRequest();
27116 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
27121 file.xhr = this.xhr;
27123 this.managerEl.createChild({
27125 cls : 'roo-document-manager-loading',
27129 tooltip : file.name,
27130 cls : 'roo-document-manager-thumb',
27131 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27137 this.xhr.open(this.method, this.url, true);
27140 "Accept": "application/json",
27141 "Cache-Control": "no-cache",
27142 "X-Requested-With": "XMLHttpRequest"
27145 for (var headerName in headers) {
27146 var headerValue = headers[headerName];
27148 this.xhr.setRequestHeader(headerName, headerValue);
27154 this.xhr.onload = function()
27156 _this.xhrOnLoad(_this.xhr);
27159 this.xhr.onerror = function()
27161 _this.xhrOnError(_this.xhr);
27164 var formData = new FormData();
27166 formData.append('returnHTML', 'NO');
27169 formData.append('crop', crop);
27172 formData.append(this.paramName, file, file.name);
27174 if(this.fireEvent('prepare', this, formData) != false){
27175 this.xhr.send(formData);
27179 uploadCancel : function()
27186 this.delegates = [];
27188 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
27195 renderPreview : function(file)
27197 if(typeof(file.target) != 'undefined' && file.target){
27201 var previewEl = this.managerEl.createChild({
27203 cls : 'roo-document-manager-preview',
27207 tooltip : file.filename,
27208 cls : 'roo-document-manager-thumb',
27209 html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
27214 html : '<i class="fa fa-times-circle"></i>'
27219 var close = previewEl.select('button.close', true).first();
27221 close.on('click', this.onRemove, this, file);
27223 file.target = previewEl;
27225 var image = previewEl.select('img', true).first();
27229 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
27231 image.on('click', this.onClick, this, file);
27237 onPreviewLoad : function(file, image)
27239 if(typeof(file.target) == 'undefined' || !file.target){
27243 var width = image.dom.naturalWidth || image.dom.width;
27244 var height = image.dom.naturalHeight || image.dom.height;
27246 if(width > height){
27247 file.target.addClass('wide');
27251 file.target.addClass('tall');
27256 uploadFromSource : function(file, crop)
27258 this.xhr = new XMLHttpRequest();
27260 this.managerEl.createChild({
27262 cls : 'roo-document-manager-loading',
27266 tooltip : file.name,
27267 cls : 'roo-document-manager-thumb',
27268 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
27274 this.xhr.open(this.method, this.url, true);
27277 "Accept": "application/json",
27278 "Cache-Control": "no-cache",
27279 "X-Requested-With": "XMLHttpRequest"
27282 for (var headerName in headers) {
27283 var headerValue = headers[headerName];
27285 this.xhr.setRequestHeader(headerName, headerValue);
27291 this.xhr.onload = function()
27293 _this.xhrOnLoad(_this.xhr);
27296 this.xhr.onerror = function()
27298 _this.xhrOnError(_this.xhr);
27301 var formData = new FormData();
27303 formData.append('returnHTML', 'NO');
27305 formData.append('crop', crop);
27307 if(typeof(file.filename) != 'undefined'){
27308 formData.append('filename', file.filename);
27311 if(typeof(file.mimetype) != 'undefined'){
27312 formData.append('mimetype', file.mimetype);
27315 if(this.fireEvent('prepare', this, formData) != false){
27316 this.xhr.send(formData);
27326 * @class Roo.bootstrap.DocumentViewer
27327 * @extends Roo.bootstrap.Component
27328 * Bootstrap DocumentViewer class
27331 * Create a new DocumentViewer
27332 * @param {Object} config The config object
27335 Roo.bootstrap.DocumentViewer = function(config){
27336 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
27341 * Fire after initEvent
27342 * @param {Roo.bootstrap.DocumentViewer} this
27348 * @param {Roo.bootstrap.DocumentViewer} this
27353 * Fire after trash button
27354 * @param {Roo.bootstrap.DocumentViewer} this
27361 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
27363 getAutoCreate : function()
27367 cls : 'roo-document-viewer',
27371 cls : 'roo-document-viewer-body',
27375 cls : 'roo-document-viewer-thumb',
27379 cls : 'roo-document-viewer-image'
27387 cls : 'roo-document-viewer-footer',
27390 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
27398 cls : 'btn btn-default roo-document-viewer-trash',
27399 html : '<i class="fa fa-trash"></i>'
27412 initEvents : function()
27415 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
27416 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27418 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
27419 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27421 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
27422 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27424 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
27425 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27427 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
27428 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27430 this.bodyEl.on('click', this.onClick, this);
27432 this.trashBtn.on('click', this.onTrash, this);
27436 initial : function()
27438 // this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
27441 this.fireEvent('initial', this);
27445 onClick : function(e)
27447 e.preventDefault();
27449 this.fireEvent('click', this);
27452 onTrash : function(e)
27454 e.preventDefault();
27456 this.fireEvent('trash', this);
27468 * @class Roo.bootstrap.NavProgressBar
27469 * @extends Roo.bootstrap.Component
27470 * Bootstrap NavProgressBar class
27473 * Create a new nav progress bar
27474 * @param {Object} config The config object
27477 Roo.bootstrap.NavProgressBar = function(config){
27478 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
27480 this.bullets = this.bullets || [];
27482 // Roo.bootstrap.NavProgressBar.register(this);
27486 * Fires when the active item changes
27487 * @param {Roo.bootstrap.NavProgressBar} this
27488 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
27489 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
27496 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
27501 getAutoCreate : function()
27503 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
27507 cls : 'roo-navigation-bar-group',
27511 cls : 'roo-navigation-top-bar'
27515 cls : 'roo-navigation-bullets-bar',
27519 cls : 'roo-navigation-bar'
27526 cls : 'roo-navigation-bottom-bar'
27536 initEvents: function()
27541 onRender : function(ct, position)
27543 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
27545 if(this.bullets.length){
27546 Roo.each(this.bullets, function(b){
27555 addItem : function(cfg)
27557 var item = new Roo.bootstrap.NavProgressItem(cfg);
27559 item.parentId = this.id;
27560 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
27563 var top = new Roo.bootstrap.Element({
27565 cls : 'roo-navigation-bar-text'
27568 var bottom = new Roo.bootstrap.Element({
27570 cls : 'roo-navigation-bar-text'
27573 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
27574 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
27576 var topText = new Roo.bootstrap.Element({
27578 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
27581 var bottomText = new Roo.bootstrap.Element({
27583 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
27586 topText.onRender(top.el, null);
27587 bottomText.onRender(bottom.el, null);
27590 item.bottomEl = bottom;
27593 this.barItems.push(item);
27598 getActive : function()
27600 var active = false;
27602 Roo.each(this.barItems, function(v){
27604 if (!v.isActive()) {
27616 setActiveItem : function(item)
27620 Roo.each(this.barItems, function(v){
27621 if (v.rid == item.rid) {
27625 if (v.isActive()) {
27626 v.setActive(false);
27631 item.setActive(true);
27633 this.fireEvent('changed', this, item, prev);
27636 getBarItem: function(rid)
27640 Roo.each(this.barItems, function(e) {
27641 if (e.rid != rid) {
27652 indexOfItem : function(item)
27656 Roo.each(this.barItems, function(v, i){
27658 if (v.rid != item.rid) {
27669 setActiveNext : function()
27671 var i = this.indexOfItem(this.getActive());
27673 if (i > this.barItems.length) {
27677 this.setActiveItem(this.barItems[i+1]);
27680 setActivePrev : function()
27682 var i = this.indexOfItem(this.getActive());
27688 this.setActiveItem(this.barItems[i-1]);
27691 format : function()
27693 if(!this.barItems.length){
27697 var width = 100 / this.barItems.length;
27699 Roo.each(this.barItems, function(i){
27700 i.el.setStyle('width', width + '%');
27701 i.topEl.el.setStyle('width', width + '%');
27702 i.bottomEl.el.setStyle('width', width + '%');
27711 * Nav Progress Item
27716 * @class Roo.bootstrap.NavProgressItem
27717 * @extends Roo.bootstrap.Component
27718 * Bootstrap NavProgressItem class
27719 * @cfg {String} rid the reference id
27720 * @cfg {Boolean} active (true|false) Is item active default false
27721 * @cfg {Boolean} disabled (true|false) Is item active default false
27722 * @cfg {String} html
27723 * @cfg {String} position (top|bottom) text position default bottom
27724 * @cfg {String} icon show icon instead of number
27727 * Create a new NavProgressItem
27728 * @param {Object} config The config object
27730 Roo.bootstrap.NavProgressItem = function(config){
27731 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
27736 * The raw click event for the entire grid.
27737 * @param {Roo.bootstrap.NavProgressItem} this
27738 * @param {Roo.EventObject} e
27745 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
27751 position : 'bottom',
27754 getAutoCreate : function()
27756 var iconCls = 'roo-navigation-bar-item-icon';
27758 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
27762 cls: 'roo-navigation-bar-item',
27772 cfg.cls += ' active';
27775 cfg.cls += ' disabled';
27781 disable : function()
27783 this.setDisabled(true);
27786 enable : function()
27788 this.setDisabled(false);
27791 initEvents: function()
27793 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
27795 this.iconEl.on('click', this.onClick, this);
27798 onClick : function(e)
27800 e.preventDefault();
27806 if(this.fireEvent('click', this, e) === false){
27810 this.parent().setActiveItem(this);
27813 isActive: function ()
27815 return this.active;
27818 setActive : function(state)
27820 if(this.active == state){
27824 this.active = state;
27827 this.el.addClass('active');
27831 this.el.removeClass('active');
27836 setDisabled : function(state)
27838 if(this.disabled == state){
27842 this.disabled = state;
27845 this.el.addClass('disabled');
27849 this.el.removeClass('disabled');
27852 tooltipEl : function()
27854 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
27867 * @class Roo.bootstrap.FieldLabel
27868 * @extends Roo.bootstrap.Component
27869 * Bootstrap FieldLabel class
27870 * @cfg {String} html contents of the element
27871 * @cfg {String} tag tag of the element default label
27872 * @cfg {String} cls class of the element
27873 * @cfg {String} target label target
27874 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
27875 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
27876 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
27877 * @cfg {String} iconTooltip default "This field is required"
27880 * Create a new FieldLabel
27881 * @param {Object} config The config object
27884 Roo.bootstrap.FieldLabel = function(config){
27885 Roo.bootstrap.Element.superclass.constructor.call(this, config);
27890 * Fires after the field has been marked as invalid.
27891 * @param {Roo.form.FieldLabel} this
27892 * @param {String} msg The validation message
27897 * Fires after the field has been validated with no errors.
27898 * @param {Roo.form.FieldLabel} this
27904 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
27911 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
27912 validClass : 'text-success fa fa-lg fa-check',
27913 iconTooltip : 'This field is required',
27915 getAutoCreate : function(){
27919 cls : 'roo-bootstrap-field-label ' + this.cls,
27925 tooltip : this.iconTooltip
27937 initEvents: function()
27939 Roo.bootstrap.Element.superclass.initEvents.call(this);
27941 this.iconEl = this.el.select('i', true).first();
27943 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
27945 Roo.bootstrap.FieldLabel.register(this);
27949 * Mark this field as valid
27951 markValid : function()
27953 this.iconEl.show();
27955 this.iconEl.removeClass(this.invalidClass);
27957 this.iconEl.addClass(this.validClass);
27959 this.fireEvent('valid', this);
27963 * Mark this field as invalid
27964 * @param {String} msg The validation message
27966 markInvalid : function(msg)
27968 this.iconEl.show();
27970 this.iconEl.removeClass(this.validClass);
27972 this.iconEl.addClass(this.invalidClass);
27974 this.fireEvent('invalid', this, msg);
27980 Roo.apply(Roo.bootstrap.FieldLabel, {
27985 * register a FieldLabel Group
27986 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
27988 register : function(label)
27990 if(this.groups.hasOwnProperty(label.target)){
27994 this.groups[label.target] = label;
27998 * fetch a FieldLabel Group based on the target
27999 * @param {string} target
28000 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
28002 get: function(target) {
28003 if (typeof(this.groups[target]) == 'undefined') {
28007 return this.groups[target] ;
28016 * page DateSplitField.
28022 * @class Roo.bootstrap.DateSplitField
28023 * @extends Roo.bootstrap.Component
28024 * Bootstrap DateSplitField class
28025 * @cfg {string} fieldLabel - the label associated
28026 * @cfg {Number} labelWidth set the width of label (0-12)
28027 * @cfg {String} labelAlign (top|left)
28028 * @cfg {Boolean} dayAllowBlank (true|false) default false
28029 * @cfg {Boolean} monthAllowBlank (true|false) default false
28030 * @cfg {Boolean} yearAllowBlank (true|false) default false
28031 * @cfg {string} dayPlaceholder
28032 * @cfg {string} monthPlaceholder
28033 * @cfg {string} yearPlaceholder
28034 * @cfg {string} dayFormat default 'd'
28035 * @cfg {string} monthFormat default 'm'
28036 * @cfg {string} yearFormat default 'Y'
28040 * Create a new DateSplitField
28041 * @param {Object} config The config object
28044 Roo.bootstrap.DateSplitField = function(config){
28045 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
28051 * getting the data of years
28052 * @param {Roo.bootstrap.DateSplitField} this
28053 * @param {Object} years
28058 * getting the data of days
28059 * @param {Roo.bootstrap.DateSplitField} this
28060 * @param {Object} days
28065 * Fires after the field has been marked as invalid.
28066 * @param {Roo.form.Field} this
28067 * @param {String} msg The validation message
28072 * Fires after the field has been validated with no errors.
28073 * @param {Roo.form.Field} this
28079 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
28082 labelAlign : 'top',
28084 dayAllowBlank : false,
28085 monthAllowBlank : false,
28086 yearAllowBlank : false,
28087 dayPlaceholder : '',
28088 monthPlaceholder : '',
28089 yearPlaceholder : '',
28093 isFormField : true,
28095 getAutoCreate : function()
28099 cls : 'row roo-date-split-field-group',
28104 cls : 'form-hidden-field roo-date-split-field-group-value',
28110 if(this.fieldLabel){
28113 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
28117 html : this.fieldLabel
28123 Roo.each(['day', 'month', 'year'], function(t){
28126 cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
28133 inputEl: function ()
28135 return this.el.select('.roo-date-split-field-group-value', true).first();
28138 onRender : function(ct, position)
28142 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28144 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
28146 this.dayField = new Roo.bootstrap.ComboBox({
28147 allowBlank : this.dayAllowBlank,
28148 alwaysQuery : true,
28149 displayField : 'value',
28152 forceSelection : true,
28154 placeholder : this.dayPlaceholder,
28155 selectOnFocus : true,
28156 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28157 triggerAction : 'all',
28159 valueField : 'value',
28160 store : new Roo.data.SimpleStore({
28161 data : (function() {
28163 _this.fireEvent('days', _this, days);
28166 fields : [ 'value' ]
28169 select : function (_self, record, index)
28171 _this.setValue(_this.getValue());
28176 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
28178 this.monthField = new Roo.bootstrap.MonthField({
28179 after : '<i class=\"fa fa-calendar\"></i>',
28180 allowBlank : this.monthAllowBlank,
28181 placeholder : this.monthPlaceholder,
28184 render : function (_self)
28186 this.el.select('span.input-group-addon', true).first().on('click', function(e){
28187 e.preventDefault();
28191 select : function (_self, oldvalue, newvalue)
28193 _this.setValue(_this.getValue());
28198 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
28200 this.yearField = new Roo.bootstrap.ComboBox({
28201 allowBlank : this.yearAllowBlank,
28202 alwaysQuery : true,
28203 displayField : 'value',
28206 forceSelection : true,
28208 placeholder : this.yearPlaceholder,
28209 selectOnFocus : true,
28210 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
28211 triggerAction : 'all',
28213 valueField : 'value',
28214 store : new Roo.data.SimpleStore({
28215 data : (function() {
28217 _this.fireEvent('years', _this, years);
28220 fields : [ 'value' ]
28223 select : function (_self, record, index)
28225 _this.setValue(_this.getValue());
28230 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
28233 setValue : function(v, format)
28235 this.inputEl.dom.value = v;
28237 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
28239 var d = Date.parseDate(v, f);
28246 this.setDay(d.format(this.dayFormat));
28247 this.setMonth(d.format(this.monthFormat));
28248 this.setYear(d.format(this.yearFormat));
28255 setDay : function(v)
28257 this.dayField.setValue(v);
28258 this.inputEl.dom.value = this.getValue();
28263 setMonth : function(v)
28265 this.monthField.setValue(v, true);
28266 this.inputEl.dom.value = this.getValue();
28271 setYear : function(v)
28273 this.yearField.setValue(v);
28274 this.inputEl.dom.value = this.getValue();
28279 getDay : function()
28281 return this.dayField.getValue();
28284 getMonth : function()
28286 return this.monthField.getValue();
28289 getYear : function()
28291 return this.yearField.getValue();
28294 getValue : function()
28296 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
28298 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
28308 this.inputEl.dom.value = '';
28313 validate : function()
28315 var d = this.dayField.validate();
28316 var m = this.monthField.validate();
28317 var y = this.yearField.validate();
28322 (!this.dayAllowBlank && !d) ||
28323 (!this.monthAllowBlank && !m) ||
28324 (!this.yearAllowBlank && !y)
28329 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
28338 this.markInvalid();
28343 markValid : function()
28346 var label = this.el.select('label', true).first();
28347 var icon = this.el.select('i.fa-star', true).first();
28353 this.fireEvent('valid', this);
28357 * Mark this field as invalid
28358 * @param {String} msg The validation message
28360 markInvalid : function(msg)
28363 var label = this.el.select('label', true).first();
28364 var icon = this.el.select('i.fa-star', true).first();
28366 if(label && !icon){
28367 this.el.select('.roo-date-split-field-label', true).createChild({
28369 cls : 'text-danger fa fa-lg fa-star',
28370 tooltip : 'This field is required',
28371 style : 'margin-right:5px;'
28375 this.fireEvent('invalid', this, msg);
28378 clearInvalid : function()
28380 var label = this.el.select('label', true).first();
28381 var icon = this.el.select('i.fa-star', true).first();
28387 this.fireEvent('valid', this);
28390 getName: function()
28400 * http://masonry.desandro.com
28402 * The idea is to render all the bricks based on vertical width...
28404 * The original code extends 'outlayer' - we might need to use that....
28410 * @class Roo.bootstrap.LayoutMasonry
28411 * @extends Roo.bootstrap.Component
28412 * Bootstrap Layout Masonry class
28415 * Create a new Element
28416 * @param {Object} config The config object
28419 Roo.bootstrap.LayoutMasonry = function(config){
28420 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
28426 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
28429 * @cfg {Boolean} isLayoutInstant = no animation?
28431 isLayoutInstant : false, // needed?
28434 * @cfg {Number} boxWidth width of the columns
28439 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
28444 * @cfg {Number} padWidth padding below box..
28449 * @cfg {Number} gutter gutter width..
28454 * @cfg {Boolean} isAutoInitial defalut true
28456 isAutoInitial : true,
28461 * @cfg {Boolean} isHorizontal defalut false
28463 isHorizontal : false,
28465 currentSize : null,
28471 bricks: null, //CompositeElement
28475 _isLayoutInited : false,
28477 // isAlternative : false, // only use for vertical layout...
28480 * @cfg {Number} alternativePadWidth padding below box..
28482 alternativePadWidth : 50,
28484 getAutoCreate : function(){
28488 cls: 'blog-masonary-wrapper ' + this.cls,
28490 cls : 'mas-boxes masonary'
28497 getChildContainer: function( )
28499 if (this.boxesEl) {
28500 return this.boxesEl;
28503 this.boxesEl = this.el.select('.mas-boxes').first();
28505 return this.boxesEl;
28509 initEvents : function()
28513 if(this.isAutoInitial){
28514 Roo.log('hook children rendered');
28515 this.on('childrenrendered', function() {
28516 Roo.log('children rendered');
28522 initial : function()
28524 this.currentSize = this.el.getBox(true);
28526 Roo.EventManager.onWindowResize(this.resize, this);
28528 if(!this.isAutoInitial){
28536 //this.layout.defer(500,this);
28540 resize : function()
28544 var cs = this.el.getBox(true);
28546 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
28547 Roo.log("no change in with or X");
28551 this.currentSize = cs;
28557 layout : function()
28559 this._resetLayout();
28561 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
28563 this.layoutItems( isInstant );
28565 this._isLayoutInited = true;
28569 _resetLayout : function()
28571 if(this.isHorizontal){
28572 this.horizontalMeasureColumns();
28576 this.verticalMeasureColumns();
28580 verticalMeasureColumns : function()
28582 this.getContainerWidth();
28584 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28585 // this.colWidth = Math.floor(this.containerWidth * 0.8);
28589 var boxWidth = this.boxWidth + this.padWidth;
28591 if(this.containerWidth < this.boxWidth){
28592 boxWidth = this.containerWidth
28595 var containerWidth = this.containerWidth;
28597 var cols = Math.floor(containerWidth / boxWidth);
28599 this.cols = Math.max( cols, 1 );
28601 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
28603 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
28605 this.colWidth = boxWidth + avail - this.padWidth;
28607 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
28608 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
28611 horizontalMeasureColumns : function()
28613 this.getContainerWidth();
28615 var boxWidth = this.boxWidth;
28617 if(this.containerWidth < boxWidth){
28618 boxWidth = this.containerWidth;
28621 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
28623 this.el.setHeight(boxWidth);
28627 getContainerWidth : function()
28629 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
28632 layoutItems : function( isInstant )
28634 var items = Roo.apply([], this.bricks);
28636 if(this.isHorizontal){
28637 this._horizontalLayoutItems( items , isInstant );
28641 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
28642 // this._verticalAlternativeLayoutItems( items , isInstant );
28646 this._verticalLayoutItems( items , isInstant );
28650 _verticalLayoutItems : function ( items , isInstant)
28652 if ( !items || !items.length ) {
28657 ['xs', 'xs', 'xs', 'tall'],
28658 ['xs', 'xs', 'tall'],
28659 ['xs', 'xs', 'sm'],
28660 ['xs', 'xs', 'xs'],
28666 ['sm', 'xs', 'xs'],
28670 ['tall', 'xs', 'xs', 'xs'],
28671 ['tall', 'xs', 'xs'],
28683 Roo.each(items, function(item, k){
28685 switch (item.size) {
28686 // these layouts take up a full box,
28697 boxes.push([item]);
28720 var filterPattern = function(box, length)
28728 var pattern = box.slice(0, length);
28732 Roo.each(pattern, function(i){
28733 format.push(i.size);
28736 Roo.each(standard, function(s){
28738 if(String(s) != String(format)){
28747 if(!match && length == 1){
28752 filterPattern(box, length - 1);
28756 queue.push(pattern);
28758 box = box.slice(length, box.length);
28760 filterPattern(box, 4);
28766 Roo.each(boxes, function(box, k){
28772 if(box.length == 1){
28777 filterPattern(box, 4);
28781 this._processVerticalLayoutQueue( queue, isInstant );
28785 // _verticalAlternativeLayoutItems : function( items , isInstant )
28787 // if ( !items || !items.length ) {
28791 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
28795 _horizontalLayoutItems : function ( items , isInstant)
28797 if ( !items || !items.length || items.length < 3) {
28803 var eItems = items.slice(0, 3);
28805 items = items.slice(3, items.length);
28808 ['xs', 'xs', 'xs', 'wide'],
28809 ['xs', 'xs', 'wide'],
28810 ['xs', 'xs', 'sm'],
28811 ['xs', 'xs', 'xs'],
28817 ['sm', 'xs', 'xs'],
28821 ['wide', 'xs', 'xs', 'xs'],
28822 ['wide', 'xs', 'xs'],
28835 Roo.each(items, function(item, k){
28837 switch (item.size) {
28848 boxes.push([item]);
28872 var filterPattern = function(box, length)
28880 var pattern = box.slice(0, length);
28884 Roo.each(pattern, function(i){
28885 format.push(i.size);
28888 Roo.each(standard, function(s){
28890 if(String(s) != String(format)){
28899 if(!match && length == 1){
28904 filterPattern(box, length - 1);
28908 queue.push(pattern);
28910 box = box.slice(length, box.length);
28912 filterPattern(box, 4);
28918 Roo.each(boxes, function(box, k){
28924 if(box.length == 1){
28929 filterPattern(box, 4);
28936 var pos = this.el.getBox(true);
28940 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
28942 var hit_end = false;
28944 Roo.each(queue, function(box){
28948 Roo.each(box, function(b){
28950 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28960 Roo.each(box, function(b){
28962 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28965 mx = Math.max(mx, b.x);
28969 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
28973 Roo.each(box, function(b){
28975 b.el.setVisibilityMode(Roo.Element.DISPLAY);
28989 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
28992 /** Sets position of item in DOM
28993 * @param {Element} item
28994 * @param {Number} x - horizontal position
28995 * @param {Number} y - vertical position
28996 * @param {Boolean} isInstant - disables transitions
28998 _processVerticalLayoutQueue : function( queue, isInstant )
29000 var pos = this.el.getBox(true);
29005 for (var i = 0; i < this.cols; i++){
29009 Roo.each(queue, function(box, k){
29011 var col = k % this.cols;
29013 Roo.each(box, function(b,kk){
29015 b.el.position('absolute');
29017 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29018 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29020 if(b.size == 'md-left' || b.size == 'md-right'){
29021 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29022 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29025 b.el.setWidth(width);
29026 b.el.setHeight(height);
29030 for (var i = 0; i < this.cols; i++){
29032 if(maxY[i] < maxY[col]){
29037 col = Math.min(col, i);
29041 x = pos.x + col * (this.colWidth + this.padWidth);
29045 var positions = [];
29047 switch (box.length){
29049 positions = this.getVerticalOneBoxColPositions(x, y, box);
29052 positions = this.getVerticalTwoBoxColPositions(x, y, box);
29055 positions = this.getVerticalThreeBoxColPositions(x, y, box);
29058 positions = this.getVerticalFourBoxColPositions(x, y, box);
29064 Roo.each(box, function(b,kk){
29066 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29068 var sz = b.el.getSize();
29070 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
29078 for (var i = 0; i < this.cols; i++){
29079 mY = Math.max(mY, maxY[i]);
29082 this.el.setHeight(mY - pos.y);
29086 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
29088 // var pos = this.el.getBox(true);
29091 // var maxX = pos.right;
29093 // var maxHeight = 0;
29095 // Roo.each(items, function(item, k){
29099 // item.el.position('absolute');
29101 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
29103 // item.el.setWidth(width);
29105 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
29107 // item.el.setHeight(height);
29110 // item.el.setXY([x, y], isInstant ? false : true);
29112 // item.el.setXY([maxX - width, y], isInstant ? false : true);
29115 // y = y + height + this.alternativePadWidth;
29117 // maxHeight = maxHeight + height + this.alternativePadWidth;
29121 // this.el.setHeight(maxHeight);
29125 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
29127 var pos = this.el.getBox(true);
29132 var maxX = pos.right;
29134 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
29136 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
29138 Roo.each(queue, function(box, k){
29140 Roo.each(box, function(b, kk){
29142 b.el.position('absolute');
29144 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29145 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29147 if(b.size == 'md-left' || b.size == 'md-right'){
29148 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
29149 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
29152 b.el.setWidth(width);
29153 b.el.setHeight(height);
29161 var positions = [];
29163 switch (box.length){
29165 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
29168 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
29171 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
29174 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
29180 Roo.each(box, function(b,kk){
29182 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
29184 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
29192 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
29194 Roo.each(eItems, function(b,k){
29196 b.size = (k == 0) ? 'sm' : 'xs';
29197 b.x = (k == 0) ? 2 : 1;
29198 b.y = (k == 0) ? 2 : 1;
29200 b.el.position('absolute');
29202 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
29204 b.el.setWidth(width);
29206 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
29208 b.el.setHeight(height);
29212 var positions = [];
29215 x : maxX - this.unitWidth * 2 - this.gutter,
29220 x : maxX - this.unitWidth,
29221 y : minY + (this.unitWidth + this.gutter) * 2
29225 x : maxX - this.unitWidth * 3 - this.gutter * 2,
29229 Roo.each(eItems, function(b,k){
29231 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
29237 getVerticalOneBoxColPositions : function(x, y, box)
29241 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
29243 if(box[0].size == 'md-left'){
29247 if(box[0].size == 'md-right'){
29252 x : x + (this.unitWidth + this.gutter) * rand,
29259 getVerticalTwoBoxColPositions : function(x, y, box)
29263 if(box[0].size == 'xs'){
29267 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
29271 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
29285 x : x + (this.unitWidth + this.gutter) * 2,
29286 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
29293 getVerticalThreeBoxColPositions : function(x, y, box)
29297 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29305 x : x + (this.unitWidth + this.gutter) * 1,
29310 x : x + (this.unitWidth + this.gutter) * 2,
29318 if(box[0].size == 'xs' && box[1].size == 'xs'){
29327 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
29331 x : x + (this.unitWidth + this.gutter) * 1,
29345 x : x + (this.unitWidth + this.gutter) * 2,
29350 x : x + (this.unitWidth + this.gutter) * 2,
29351 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
29358 getVerticalFourBoxColPositions : function(x, y, box)
29362 if(box[0].size == 'xs'){
29371 y : y + (this.unitHeight + this.gutter) * 1
29376 y : y + (this.unitHeight + this.gutter) * 2
29380 x : x + (this.unitWidth + this.gutter) * 1,
29394 x : x + (this.unitWidth + this.gutter) * 2,
29399 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
29400 y : y + (this.unitHeight + this.gutter) * 1
29404 x : x + (this.unitWidth + this.gutter) * 2,
29405 y : y + (this.unitWidth + this.gutter) * 2
29412 getHorizontalOneBoxColPositions : function(maxX, minY, box)
29416 if(box[0].size == 'md-left'){
29418 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29425 if(box[0].size == 'md-right'){
29427 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
29428 y : minY + (this.unitWidth + this.gutter) * 1
29434 var rand = Math.floor(Math.random() * (4 - box[0].y));
29437 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29438 y : minY + (this.unitWidth + this.gutter) * rand
29445 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
29449 if(box[0].size == 'xs'){
29452 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29457 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29458 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
29466 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29471 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29472 y : minY + (this.unitWidth + this.gutter) * 2
29479 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
29483 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
29486 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29491 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29492 y : minY + (this.unitWidth + this.gutter) * 1
29496 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29497 y : minY + (this.unitWidth + this.gutter) * 2
29504 if(box[0].size == 'xs' && box[1].size == 'xs'){
29507 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29512 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29517 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29518 y : minY + (this.unitWidth + this.gutter) * 1
29526 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29531 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29532 y : minY + (this.unitWidth + this.gutter) * 2
29536 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29537 y : minY + (this.unitWidth + this.gutter) * 2
29544 getHorizontalFourBoxColPositions : function(maxX, minY, box)
29548 if(box[0].size == 'xs'){
29551 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29556 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29561 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),
29566 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
29567 y : minY + (this.unitWidth + this.gutter) * 1
29575 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
29580 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
29581 y : minY + (this.unitWidth + this.gutter) * 2
29585 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
29586 y : minY + (this.unitWidth + this.gutter) * 2
29590 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),
29591 y : minY + (this.unitWidth + this.gutter) * 2
29605 * http://masonry.desandro.com
29607 * The idea is to render all the bricks based on vertical width...
29609 * The original code extends 'outlayer' - we might need to use that....
29615 * @class Roo.bootstrap.LayoutMasonryAuto
29616 * @extends Roo.bootstrap.Component
29617 * Bootstrap Layout Masonry class
29620 * Create a new Element
29621 * @param {Object} config The config object
29624 Roo.bootstrap.LayoutMasonryAuto = function(config){
29625 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
29628 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
29631 * @cfg {Boolean} isFitWidth - resize the width..
29633 isFitWidth : false, // options..
29635 * @cfg {Boolean} isOriginLeft = left align?
29637 isOriginLeft : true,
29639 * @cfg {Boolean} isOriginTop = top align?
29641 isOriginTop : false,
29643 * @cfg {Boolean} isLayoutInstant = no animation?
29645 isLayoutInstant : false, // needed?
29647 * @cfg {Boolean} isResizingContainer = not sure if this is used..
29649 isResizingContainer : true,
29651 * @cfg {Number} columnWidth width of the columns
29656 * @cfg {Number} padHeight padding below box..
29662 * @cfg {Boolean} isAutoInitial defalut true
29665 isAutoInitial : true,
29671 initialColumnWidth : 0,
29672 currentSize : null,
29674 colYs : null, // array.
29681 bricks: null, //CompositeElement
29682 cols : 0, // array?
29683 // element : null, // wrapped now this.el
29684 _isLayoutInited : null,
29687 getAutoCreate : function(){
29691 cls: 'blog-masonary-wrapper ' + this.cls,
29693 cls : 'mas-boxes masonary'
29700 getChildContainer: function( )
29702 if (this.boxesEl) {
29703 return this.boxesEl;
29706 this.boxesEl = this.el.select('.mas-boxes').first();
29708 return this.boxesEl;
29712 initEvents : function()
29716 if(this.isAutoInitial){
29717 Roo.log('hook children rendered');
29718 this.on('childrenrendered', function() {
29719 Roo.log('children rendered');
29726 initial : function()
29728 this.reloadItems();
29730 this.currentSize = this.el.getBox(true);
29732 /// was window resize... - let's see if this works..
29733 Roo.EventManager.onWindowResize(this.resize, this);
29735 if(!this.isAutoInitial){
29740 this.layout.defer(500,this);
29743 reloadItems: function()
29745 this.bricks = this.el.select('.masonry-brick', true);
29747 this.bricks.each(function(b) {
29748 //Roo.log(b.getSize());
29749 if (!b.attr('originalwidth')) {
29750 b.attr('originalwidth', b.getSize().width);
29755 Roo.log(this.bricks.elements.length);
29758 resize : function()
29761 var cs = this.el.getBox(true);
29763 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29764 Roo.log("no change in with or X");
29767 this.currentSize = cs;
29771 layout : function()
29774 this._resetLayout();
29775 //this._manageStamps();
29777 // don't animate first layout
29778 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29779 this.layoutItems( isInstant );
29781 // flag for initalized
29782 this._isLayoutInited = true;
29785 layoutItems : function( isInstant )
29787 //var items = this._getItemsForLayout( this.items );
29788 // original code supports filtering layout items.. we just ignore it..
29790 this._layoutItems( this.bricks , isInstant );
29792 this._postLayout();
29794 _layoutItems : function ( items , isInstant)
29796 //this.fireEvent( 'layout', this, items );
29799 if ( !items || !items.elements.length ) {
29800 // no items, emit event with empty array
29805 items.each(function(item) {
29806 Roo.log("layout item");
29808 // get x/y object from method
29809 var position = this._getItemLayoutPosition( item );
29811 position.item = item;
29812 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
29813 queue.push( position );
29816 this._processLayoutQueue( queue );
29818 /** Sets position of item in DOM
29819 * @param {Element} item
29820 * @param {Number} x - horizontal position
29821 * @param {Number} y - vertical position
29822 * @param {Boolean} isInstant - disables transitions
29824 _processLayoutQueue : function( queue )
29826 for ( var i=0, len = queue.length; i < len; i++ ) {
29827 var obj = queue[i];
29828 obj.item.position('absolute');
29829 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
29835 * Any logic you want to do after each layout,
29836 * i.e. size the container
29838 _postLayout : function()
29840 this.resizeContainer();
29843 resizeContainer : function()
29845 if ( !this.isResizingContainer ) {
29848 var size = this._getContainerSize();
29850 this.el.setSize(size.width,size.height);
29851 this.boxesEl.setSize(size.width,size.height);
29857 _resetLayout : function()
29859 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
29860 this.colWidth = this.el.getWidth();
29861 //this.gutter = this.el.getWidth();
29863 this.measureColumns();
29869 this.colYs.push( 0 );
29875 measureColumns : function()
29877 this.getContainerWidth();
29878 // if columnWidth is 0, default to outerWidth of first item
29879 if ( !this.columnWidth ) {
29880 var firstItem = this.bricks.first();
29881 Roo.log(firstItem);
29882 this.columnWidth = this.containerWidth;
29883 if (firstItem && firstItem.attr('originalwidth') ) {
29884 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
29886 // columnWidth fall back to item of first element
29887 Roo.log("set column width?");
29888 this.initialColumnWidth = this.columnWidth ;
29890 // if first elem has no width, default to size of container
29895 if (this.initialColumnWidth) {
29896 this.columnWidth = this.initialColumnWidth;
29901 // column width is fixed at the top - however if container width get's smaller we should
29904 // this bit calcs how man columns..
29906 var columnWidth = this.columnWidth += this.gutter;
29908 // calculate columns
29909 var containerWidth = this.containerWidth + this.gutter;
29911 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
29912 // fix rounding errors, typically with gutters
29913 var excess = columnWidth - containerWidth % columnWidth;
29916 // if overshoot is less than a pixel, round up, otherwise floor it
29917 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
29918 cols = Math[ mathMethod ]( cols );
29919 this.cols = Math.max( cols, 1 );
29922 // padding positioning..
29923 var totalColWidth = this.cols * this.columnWidth;
29924 var padavail = this.containerWidth - totalColWidth;
29925 // so for 2 columns - we need 3 'pads'
29927 var padNeeded = (1+this.cols) * this.padWidth;
29929 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
29931 this.columnWidth += padExtra
29932 //this.padWidth = Math.floor(padavail / ( this.cols));
29934 // adjust colum width so that padding is fixed??
29936 // we have 3 columns ... total = width * 3
29937 // we have X left over... that should be used by
29939 //if (this.expandC) {
29947 getContainerWidth : function()
29949 /* // container is parent if fit width
29950 var container = this.isFitWidth ? this.element.parentNode : this.element;
29951 // check that this.size and size are there
29952 // IE8 triggers resize on body size change, so they might not be
29954 var size = getSize( container ); //FIXME
29955 this.containerWidth = size && size.innerWidth; //FIXME
29958 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29962 _getItemLayoutPosition : function( item ) // what is item?
29964 // we resize the item to our columnWidth..
29966 item.setWidth(this.columnWidth);
29967 item.autoBoxAdjust = false;
29969 var sz = item.getSize();
29971 // how many columns does this brick span
29972 var remainder = this.containerWidth % this.columnWidth;
29974 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
29975 // round if off by 1 pixel, otherwise use ceil
29976 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
29977 colSpan = Math.min( colSpan, this.cols );
29979 // normally this should be '1' as we dont' currently allow multi width columns..
29981 var colGroup = this._getColGroup( colSpan );
29982 // get the minimum Y value from the columns
29983 var minimumY = Math.min.apply( Math, colGroup );
29984 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
29986 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
29988 // position the brick
29990 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
29991 y: this.currentSize.y + minimumY + this.padHeight
29995 // apply setHeight to necessary columns
29996 var setHeight = minimumY + sz.height + this.padHeight;
29997 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
29999 var setSpan = this.cols + 1 - colGroup.length;
30000 for ( var i = 0; i < setSpan; i++ ) {
30001 this.colYs[ shortColIndex + i ] = setHeight ;
30008 * @param {Number} colSpan - number of columns the element spans
30009 * @returns {Array} colGroup
30011 _getColGroup : function( colSpan )
30013 if ( colSpan < 2 ) {
30014 // if brick spans only one column, use all the column Ys
30019 // how many different places could this brick fit horizontally
30020 var groupCount = this.cols + 1 - colSpan;
30021 // for each group potential horizontal position
30022 for ( var i = 0; i < groupCount; i++ ) {
30023 // make an array of colY values for that one group
30024 var groupColYs = this.colYs.slice( i, i + colSpan );
30025 // and get the max value of the array
30026 colGroup[i] = Math.max.apply( Math, groupColYs );
30031 _manageStamp : function( stamp )
30033 var stampSize = stamp.getSize();
30034 var offset = stamp.getBox();
30035 // get the columns that this stamp affects
30036 var firstX = this.isOriginLeft ? offset.x : offset.right;
30037 var lastX = firstX + stampSize.width;
30038 var firstCol = Math.floor( firstX / this.columnWidth );
30039 firstCol = Math.max( 0, firstCol );
30041 var lastCol = Math.floor( lastX / this.columnWidth );
30042 // lastCol should not go over if multiple of columnWidth #425
30043 lastCol -= lastX % this.columnWidth ? 0 : 1;
30044 lastCol = Math.min( this.cols - 1, lastCol );
30046 // set colYs to bottom of the stamp
30047 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
30050 for ( var i = firstCol; i <= lastCol; i++ ) {
30051 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
30056 _getContainerSize : function()
30058 this.maxY = Math.max.apply( Math, this.colYs );
30063 if ( this.isFitWidth ) {
30064 size.width = this._getContainerFitWidth();
30070 _getContainerFitWidth : function()
30072 var unusedCols = 0;
30073 // count unused columns
30076 if ( this.colYs[i] !== 0 ) {
30081 // fit container to columns that have been used
30082 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
30085 needsResizeLayout : function()
30087 var previousWidth = this.containerWidth;
30088 this.getContainerWidth();
30089 return previousWidth !== this.containerWidth;
30104 * @class Roo.bootstrap.MasonryBrick
30105 * @extends Roo.bootstrap.Component
30106 * Bootstrap MasonryBrick class
30109 * Create a new MasonryBrick
30110 * @param {Object} config The config object
30113 Roo.bootstrap.MasonryBrick = function(config){
30114 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
30120 * When a MasonryBrick is clcik
30121 * @param {Roo.bootstrap.MasonryBrick} this
30122 * @param {Roo.EventObject} e
30128 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
30131 * @cfg {String} title
30135 * @cfg {String} html
30139 * @cfg {String} bgimage
30143 * @cfg {String} cls
30147 * @cfg {String} href
30151 * @cfg {String} (xs|sm|md|md-left|md-right|tall|wide) size
30156 * @cfg {String} (center|bottom) placetitle
30160 getAutoCreate : function()
30162 var cls = 'masonry-brick';
30164 if(this.href.length){
30165 cls += ' masonry-brick-link';
30168 if(this.bgimage.length){
30169 cls += ' masonry-brick-image';
30173 cls += ' masonry-' + this.size + '-brick';
30176 if(this.placetitle.length){
30178 switch (this.placetitle) {
30180 cls += ' masonry-center-title';
30183 cls += ' masonry-bottom-title';
30190 if(!this.html.length && !this.bgimage.length){
30191 cls += ' masonry-center-title';
30194 if(!this.html.length && this.bgimage.length){
30195 cls += ' masonry-bottom-title';
30200 cls += ' ' + this.cls;
30204 tag: (this.href.length) ? 'a' : 'div',
30209 cls: 'masonry-brick-paragraph',
30215 if(this.href.length){
30216 cfg.href = this.href;
30219 var cn = cfg.cn[0].cn;
30221 if(this.title.length){
30224 cls: 'masonry-brick-title',
30229 if(this.html.length){
30232 cls: 'masonry-brick-text',
30237 if(this.bgimage.length){
30240 cls: 'masonry-brick-image-view',
30249 initEvents: function()
30251 switch (this.size) {
30253 // this.intSize = 1;
30258 // this.intSize = 2;
30265 // this.intSize = 3;
30270 // this.intSize = 3;
30275 // this.intSize = 3;
30280 // this.intSize = 3;
30292 this.el.on('touchstart', this.onTouchStart, this);
30293 this.el.on('touchmove', this.onTouchMove, this);
30294 this.el.on('touchend', this.onTouchEnd, this);
30296 this.el.on('mouseenter' ,this.enter, this);
30297 this.el.on('mouseleave', this.leave, this);
30300 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
30301 this.parent().bricks.push(this);
30306 onClick: function(e, el)
30314 var time = this.endTimer - this.startTimer;
30322 e.preventDefault();
30325 enter: function(e, el)
30327 e.preventDefault();
30329 if(this.bgimage.length && this.html.length){
30330 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30334 leave: function(e, el)
30336 e.preventDefault();
30338 if(this.bgimage.length && this.html.length){
30339 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30343 onTouchStart: function(e, el)
30345 // e.preventDefault();
30347 if(!this.bgimage.length || !this.html.length){
30351 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
30353 this.timer = new Date().getTime();
30355 this.touchmoved = false;
30358 onTouchMove: function(e, el)
30360 this.touchmoved = true;
30363 onTouchEnd: function(e, el)
30365 // e.preventDefault();
30367 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
30371 if(!this.bgimage.length || !this.html.length){
30373 if(this.href.length){
30374 window.location.href = this.href;
30380 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
30382 window.location.href = this.href;
30397 * @class Roo.bootstrap.Brick
30398 * @extends Roo.bootstrap.Component
30399 * Bootstrap Brick class
30402 * Create a new Brick
30403 * @param {Object} config The config object
30406 Roo.bootstrap.Brick = function(config){
30407 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
30413 * When a Brick is click
30414 * @param {Roo.bootstrap.Brick} this
30415 * @param {Roo.EventObject} e
30421 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
30424 * @cfg {String} title
30428 * @cfg {String} html
30432 * @cfg {String} bgimage
30436 * @cfg {String} cls
30440 * @cfg {String} href
30444 * @cfg {String} video
30448 * @cfg {Boolean} square
30452 getAutoCreate : function()
30454 var cls = 'roo-brick';
30456 if(this.href.length){
30457 cls += ' roo-brick-link';
30460 if(this.bgimage.length){
30461 cls += ' roo-brick-image';
30464 if(!this.html.length && !this.bgimage.length){
30465 cls += ' roo-brick-center-title';
30468 if(!this.html.length && this.bgimage.length){
30469 cls += ' roo-brick-bottom-title';
30473 cls += ' ' + this.cls;
30477 tag: (this.href.length) ? 'a' : 'div',
30482 cls: 'roo-brick-paragraph',
30488 if(this.href.length){
30489 cfg.href = this.href;
30492 var cn = cfg.cn[0].cn;
30494 if(this.title.length){
30497 cls: 'roo-brick-title',
30502 if(this.html.length){
30505 cls: 'roo-brick-text',
30510 if(this.bgimage.length){
30513 cls: 'roo-brick-image-view',
30521 initEvents: function()
30523 if(this.title.length || this.html.length){
30524 this.el.on('mouseenter' ,this.enter, this);
30525 this.el.on('mouseleave', this.leave, this);
30529 Roo.EventManager.onWindowResize(this.resize, this);
30534 resize : function()
30536 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
30538 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
30539 // paragraph.setHeight(paragraph.getWidth());
30541 if(this.bgimage.length){
30542 var image = this.el.select('.roo-brick-image-view', true).first();
30543 image.setWidth(paragraph.getWidth());
30544 image.setHeight(paragraph.getWidth());
30549 enter: function(e, el)
30551 e.preventDefault();
30553 if(this.bgimage.length){
30554 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
30555 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
30559 leave: function(e, el)
30561 e.preventDefault();
30563 if(this.bgimage.length){
30564 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
30565 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
30575 * Ext JS Library 1.1.1
30576 * Copyright(c) 2006-2007, Ext JS, LLC.
30578 * Originally Released Under LGPL - original licence link has changed is not relivant.
30581 * <script type="text/javascript">
30586 * @class Roo.bootstrap.SplitBar
30587 * @extends Roo.util.Observable
30588 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
30592 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
30593 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
30594 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
30595 split.minSize = 100;
30596 split.maxSize = 600;
30597 split.animate = true;
30598 split.on('moved', splitterMoved);
30601 * Create a new SplitBar
30602 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
30603 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
30604 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30605 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
30606 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
30607 position of the SplitBar).
30609 Roo.bootstrap.SplitBar = function(cfg){
30614 // dragElement : elm
30615 // resizingElement: el,
30617 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
30618 // placement : Roo.bootstrap.SplitBar.LEFT ,
30619 // existingProxy ???
30622 this.el = Roo.get(cfg.dragElement, true);
30623 this.el.dom.unselectable = "on";
30625 this.resizingEl = Roo.get(cfg.resizingElement, true);
30629 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
30630 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
30633 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
30636 * The minimum size of the resizing element. (Defaults to 0)
30642 * The maximum size of the resizing element. (Defaults to 2000)
30645 this.maxSize = 2000;
30648 * Whether to animate the transition to the new size
30651 this.animate = false;
30654 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
30657 this.useShim = false;
30662 if(!cfg.existingProxy){
30664 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
30666 this.proxy = Roo.get(cfg.existingProxy).dom;
30669 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
30672 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
30675 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
30678 this.dragSpecs = {};
30681 * @private The adapter to use to positon and resize elements
30683 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30684 this.adapter.init(this);
30686 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30688 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
30689 this.el.addClass("roo-splitbar-h");
30692 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
30693 this.el.addClass("roo-splitbar-v");
30699 * Fires when the splitter is moved (alias for {@link #event-moved})
30700 * @param {Roo.bootstrap.SplitBar} this
30701 * @param {Number} newSize the new width or height
30706 * Fires when the splitter is moved
30707 * @param {Roo.bootstrap.SplitBar} this
30708 * @param {Number} newSize the new width or height
30712 * @event beforeresize
30713 * Fires before the splitter is dragged
30714 * @param {Roo.bootstrap.SplitBar} this
30716 "beforeresize" : true,
30718 "beforeapply" : true
30721 Roo.util.Observable.call(this);
30724 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
30725 onStartProxyDrag : function(x, y){
30726 this.fireEvent("beforeresize", this);
30728 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
30730 o.enableDisplayMode("block");
30731 // all splitbars share the same overlay
30732 Roo.bootstrap.SplitBar.prototype.overlay = o;
30734 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30735 this.overlay.show();
30736 Roo.get(this.proxy).setDisplayed("block");
30737 var size = this.adapter.getElementSize(this);
30738 this.activeMinSize = this.getMinimumSize();;
30739 this.activeMaxSize = this.getMaximumSize();;
30740 var c1 = size - this.activeMinSize;
30741 var c2 = Math.max(this.activeMaxSize - size, 0);
30742 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30743 this.dd.resetConstraints();
30744 this.dd.setXConstraint(
30745 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
30746 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
30748 this.dd.setYConstraint(0, 0);
30750 this.dd.resetConstraints();
30751 this.dd.setXConstraint(0, 0);
30752 this.dd.setYConstraint(
30753 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
30754 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
30757 this.dragSpecs.startSize = size;
30758 this.dragSpecs.startPoint = [x, y];
30759 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
30763 * @private Called after the drag operation by the DDProxy
30765 onEndProxyDrag : function(e){
30766 Roo.get(this.proxy).setDisplayed(false);
30767 var endPoint = Roo.lib.Event.getXY(e);
30769 this.overlay.hide();
30772 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30773 newSize = this.dragSpecs.startSize +
30774 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
30775 endPoint[0] - this.dragSpecs.startPoint[0] :
30776 this.dragSpecs.startPoint[0] - endPoint[0]
30779 newSize = this.dragSpecs.startSize +
30780 (this.placement == Roo.bootstrap.SplitBar.TOP ?
30781 endPoint[1] - this.dragSpecs.startPoint[1] :
30782 this.dragSpecs.startPoint[1] - endPoint[1]
30785 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
30786 if(newSize != this.dragSpecs.startSize){
30787 if(this.fireEvent('beforeapply', this, newSize) !== false){
30788 this.adapter.setElementSize(this, newSize);
30789 this.fireEvent("moved", this, newSize);
30790 this.fireEvent("resize", this, newSize);
30796 * Get the adapter this SplitBar uses
30797 * @return The adapter object
30799 getAdapter : function(){
30800 return this.adapter;
30804 * Set the adapter this SplitBar uses
30805 * @param {Object} adapter A SplitBar adapter object
30807 setAdapter : function(adapter){
30808 this.adapter = adapter;
30809 this.adapter.init(this);
30813 * Gets the minimum size for the resizing element
30814 * @return {Number} The minimum size
30816 getMinimumSize : function(){
30817 return this.minSize;
30821 * Sets the minimum size for the resizing element
30822 * @param {Number} minSize The minimum size
30824 setMinimumSize : function(minSize){
30825 this.minSize = minSize;
30829 * Gets the maximum size for the resizing element
30830 * @return {Number} The maximum size
30832 getMaximumSize : function(){
30833 return this.maxSize;
30837 * Sets the maximum size for the resizing element
30838 * @param {Number} maxSize The maximum size
30840 setMaximumSize : function(maxSize){
30841 this.maxSize = maxSize;
30845 * Sets the initialize size for the resizing element
30846 * @param {Number} size The initial size
30848 setCurrentSize : function(size){
30849 var oldAnimate = this.animate;
30850 this.animate = false;
30851 this.adapter.setElementSize(this, size);
30852 this.animate = oldAnimate;
30856 * Destroy this splitbar.
30857 * @param {Boolean} removeEl True to remove the element
30859 destroy : function(removeEl){
30861 this.shim.remove();
30864 this.proxy.parentNode.removeChild(this.proxy);
30872 * @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.
30874 Roo.bootstrap.SplitBar.createProxy = function(dir){
30875 var proxy = new Roo.Element(document.createElement("div"));
30876 proxy.unselectable();
30877 var cls = 'roo-splitbar-proxy';
30878 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
30879 document.body.appendChild(proxy.dom);
30884 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
30885 * Default Adapter. It assumes the splitter and resizing element are not positioned
30886 * elements and only gets/sets the width of the element. Generally used for table based layouts.
30888 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
30891 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
30892 // do nothing for now
30893 init : function(s){
30897 * Called before drag operations to get the current size of the resizing element.
30898 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30900 getElementSize : function(s){
30901 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30902 return s.resizingEl.getWidth();
30904 return s.resizingEl.getHeight();
30909 * Called after drag operations to set the size of the resizing element.
30910 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
30911 * @param {Number} newSize The new size to set
30912 * @param {Function} onComplete A function to be invoked when resizing is complete
30914 setElementSize : function(s, newSize, onComplete){
30915 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
30917 s.resizingEl.setWidth(newSize);
30919 onComplete(s, newSize);
30922 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
30927 s.resizingEl.setHeight(newSize);
30929 onComplete(s, newSize);
30932 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
30939 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
30940 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
30941 * Adapter that moves the splitter element to align with the resized sizing element.
30942 * Used with an absolute positioned SplitBar.
30943 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
30944 * document.body, make sure you assign an id to the body element.
30946 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
30947 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
30948 this.container = Roo.get(container);
30951 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
30952 init : function(s){
30953 this.basic.init(s);
30956 getElementSize : function(s){
30957 return this.basic.getElementSize(s);
30960 setElementSize : function(s, newSize, onComplete){
30961 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
30964 moveSplitter : function(s){
30965 var yes = Roo.bootstrap.SplitBar;
30966 switch(s.placement){
30968 s.el.setX(s.resizingEl.getRight());
30971 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
30974 s.el.setY(s.resizingEl.getBottom());
30977 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
30984 * Orientation constant - Create a vertical SplitBar
30988 Roo.bootstrap.SplitBar.VERTICAL = 1;
30991 * Orientation constant - Create a horizontal SplitBar
30995 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
30998 * Placement constant - The resizing element is to the left of the splitter element
31002 Roo.bootstrap.SplitBar.LEFT = 1;
31005 * Placement constant - The resizing element is to the right of the splitter element
31009 Roo.bootstrap.SplitBar.RIGHT = 2;
31012 * Placement constant - The resizing element is positioned above the splitter element
31016 Roo.bootstrap.SplitBar.TOP = 3;
31019 * Placement constant - The resizing element is positioned under splitter element
31023 Roo.bootstrap.SplitBar.BOTTOM = 4;
31024 Roo.namespace("Roo.bootstrap.layout");/*
31026 * Ext JS Library 1.1.1
31027 * Copyright(c) 2006-2007, Ext JS, LLC.
31029 * Originally Released Under LGPL - original licence link has changed is not relivant.
31032 * <script type="text/javascript">
31036 * @class Roo.bootstrap.layout.Manager
31037 * @extends Roo.bootstrap.Component
31038 * Base class for layout managers.
31040 Roo.bootstrap.layout.Manager = function(config)
31042 Roo.bootstrap.layout.Manager.superclass.constructor.call(this);
31043 this.el = Roo.get(config.el);
31044 // ie scrollbar fix
31045 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
31046 document.body.scroll = "no";
31047 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
31048 this.el.position('relative');
31051 this.id = this.el.id;
31052 this.el.addClass("roo-layout-container");
31053 /** false to disable window resize monitoring @type Boolean */
31054 this.monitorWindowResize = true;
31059 * Fires when a layout is performed.
31060 * @param {Roo.LayoutManager} this
31064 * @event regionresized
31065 * Fires when the user resizes a region.
31066 * @param {Roo.LayoutRegion} region The resized region
31067 * @param {Number} newSize The new size (width for east/west, height for north/south)
31069 "regionresized" : true,
31071 * @event regioncollapsed
31072 * Fires when a region is collapsed.
31073 * @param {Roo.LayoutRegion} region The collapsed region
31075 "regioncollapsed" : true,
31077 * @event regionexpanded
31078 * Fires when a region is expanded.
31079 * @param {Roo.LayoutRegion} region The expanded region
31081 "regionexpanded" : true
31083 this.updating = false;
31084 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
31087 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
31092 monitorWindowResize : true,
31098 * Returns true if this layout is currently being updated
31099 * @return {Boolean}
31101 isUpdating : function(){
31102 return this.updating;
31106 * Suspend the LayoutManager from doing auto-layouts while
31107 * making multiple add or remove calls
31109 beginUpdate : function(){
31110 this.updating = true;
31114 * Restore auto-layouts and optionally disable the manager from performing a layout
31115 * @param {Boolean} noLayout true to disable a layout update
31117 endUpdate : function(noLayout){
31118 this.updating = false;
31124 layout: function(){
31128 onRegionResized : function(region, newSize){
31129 this.fireEvent("regionresized", region, newSize);
31133 onRegionCollapsed : function(region){
31134 this.fireEvent("regioncollapsed", region);
31137 onRegionExpanded : function(region){
31138 this.fireEvent("regionexpanded", region);
31142 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
31143 * performs box-model adjustments.
31144 * @return {Object} The size as an object {width: (the width), height: (the height)}
31146 getViewSize : function()
31149 if(this.el.dom != document.body){
31150 size = this.el.getSize();
31152 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
31154 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
31155 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
31160 * Returns the Element this layout is bound to.
31161 * @return {Roo.Element}
31163 getEl : function(){
31168 * Returns the specified region.
31169 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
31170 * @return {Roo.LayoutRegion}
31172 getRegion : function(target){
31173 return this.regions[target.toLowerCase()];
31176 onWindowResize : function(){
31177 if(this.monitorWindowResize){
31183 * Ext JS Library 1.1.1
31184 * Copyright(c) 2006-2007, Ext JS, LLC.
31186 * Originally Released Under LGPL - original licence link has changed is not relivant.
31189 * <script type="text/javascript">
31192 * @class Roo.bootstrap.layout.Border
31193 * @extends Roo.bootstrap.layout.Manager
31194 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
31195 * please see: examples/bootstrap/nested.html<br><br>
31197 <b>The container the layout is rendered into can be either the body element or any other element.
31198 If it is not the body element, the container needs to either be an absolute positioned element,
31199 or you will need to add "position:relative" to the css of the container. You will also need to specify
31200 the container size if it is not the body element.</b>
31203 * Create a new Border
31204 * @param {Object} config Configuration options
31206 Roo.bootstrap.layout.Border = function(config){
31207 config = config || {};
31208 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
31212 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
31213 if(config[region]){
31214 config[region].region = region;
31215 this.addRegion(config[region]);
31221 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
31223 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
31225 * Creates and adds a new region if it doesn't already exist.
31226 * @param {String} target The target region key (north, south, east, west or center).
31227 * @param {Object} config The regions config object
31228 * @return {BorderLayoutRegion} The new region
31230 addRegion : function(config)
31232 if(!this.regions[config.region]){
31233 var r = this.factory(config);
31234 this.bindRegion(r);
31236 return this.regions[config.region];
31240 bindRegion : function(r){
31241 this.regions[r.config.region] = r;
31243 r.on("visibilitychange", this.layout, this);
31244 r.on("paneladded", this.layout, this);
31245 r.on("panelremoved", this.layout, this);
31246 r.on("invalidated", this.layout, this);
31247 r.on("resized", this.onRegionResized, this);
31248 r.on("collapsed", this.onRegionCollapsed, this);
31249 r.on("expanded", this.onRegionExpanded, this);
31253 * Performs a layout update.
31255 layout : function()
31257 if(this.updating) {
31260 var size = this.getViewSize();
31261 var w = size.width;
31262 var h = size.height;
31267 //var x = 0, y = 0;
31269 var rs = this.regions;
31270 var north = rs["north"];
31271 var south = rs["south"];
31272 var west = rs["west"];
31273 var east = rs["east"];
31274 var center = rs["center"];
31275 //if(this.hideOnLayout){ // not supported anymore
31276 //c.el.setStyle("display", "none");
31278 if(north && north.isVisible()){
31279 var b = north.getBox();
31280 var m = north.getMargins();
31281 b.width = w - (m.left+m.right);
31284 centerY = b.height + b.y + m.bottom;
31285 centerH -= centerY;
31286 north.updateBox(this.safeBox(b));
31288 if(south && south.isVisible()){
31289 var b = south.getBox();
31290 var m = south.getMargins();
31291 b.width = w - (m.left+m.right);
31293 var totalHeight = (b.height + m.top + m.bottom);
31294 b.y = h - totalHeight + m.top;
31295 centerH -= totalHeight;
31296 south.updateBox(this.safeBox(b));
31298 if(west && west.isVisible()){
31299 var b = west.getBox();
31300 var m = west.getMargins();
31301 b.height = centerH - (m.top+m.bottom);
31303 b.y = centerY + m.top;
31304 var totalWidth = (b.width + m.left + m.right);
31305 centerX += totalWidth;
31306 centerW -= totalWidth;
31307 west.updateBox(this.safeBox(b));
31309 if(east && east.isVisible()){
31310 var b = east.getBox();
31311 var m = east.getMargins();
31312 b.height = centerH - (m.top+m.bottom);
31313 var totalWidth = (b.width + m.left + m.right);
31314 b.x = w - totalWidth + m.left;
31315 b.y = centerY + m.top;
31316 centerW -= totalWidth;
31317 east.updateBox(this.safeBox(b));
31320 var m = center.getMargins();
31322 x: centerX + m.left,
31323 y: centerY + m.top,
31324 width: centerW - (m.left+m.right),
31325 height: centerH - (m.top+m.bottom)
31327 //if(this.hideOnLayout){
31328 //center.el.setStyle("display", "block");
31330 center.updateBox(this.safeBox(centerBox));
31333 this.fireEvent("layout", this);
31337 safeBox : function(box){
31338 box.width = Math.max(0, box.width);
31339 box.height = Math.max(0, box.height);
31344 * Adds a ContentPanel (or subclass) to this layout.
31345 * @param {String} target The target region key (north, south, east, west or center).
31346 * @param {Roo.ContentPanel} panel The panel to add
31347 * @return {Roo.ContentPanel} The added panel
31349 add : function(target, panel){
31351 target = target.toLowerCase();
31352 return this.regions[target].add(panel);
31356 * Remove a ContentPanel (or subclass) to this layout.
31357 * @param {String} target The target region key (north, south, east, west or center).
31358 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
31359 * @return {Roo.ContentPanel} The removed panel
31361 remove : function(target, panel){
31362 target = target.toLowerCase();
31363 return this.regions[target].remove(panel);
31367 * Searches all regions for a panel with the specified id
31368 * @param {String} panelId
31369 * @return {Roo.ContentPanel} The panel or null if it wasn't found
31371 findPanel : function(panelId){
31372 var rs = this.regions;
31373 for(var target in rs){
31374 if(typeof rs[target] != "function"){
31375 var p = rs[target].getPanel(panelId);
31385 * Searches all regions for a panel with the specified id and activates (shows) it.
31386 * @param {String/ContentPanel} panelId The panels id or the panel itself
31387 * @return {Roo.ContentPanel} The shown panel or null
31389 showPanel : function(panelId) {
31390 var rs = this.regions;
31391 for(var target in rs){
31392 var r = rs[target];
31393 if(typeof r != "function"){
31394 if(r.hasPanel(panelId)){
31395 return r.showPanel(panelId);
31403 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
31404 * @param {Roo.state.Provider} provider (optional) An alternate state provider
31407 restoreState : function(provider){
31409 provider = Roo.state.Manager;
31411 var sm = new Roo.LayoutStateManager();
31412 sm.init(this, provider);
31418 * Adds a xtype elements to the layout.
31422 xtype : 'ContentPanel',
31429 xtype : 'NestedLayoutPanel',
31435 items : [ ... list of content panels or nested layout panels.. ]
31439 * @param {Object} cfg Xtype definition of item to add.
31441 addxtype : function(cfg)
31443 // basically accepts a pannel...
31444 // can accept a layout region..!?!?
31445 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
31448 // theory? children can only be panels??
31450 //if (!cfg.xtype.match(/Panel$/)) {
31455 if (typeof(cfg.region) == 'undefined') {
31456 Roo.log("Failed to add Panel, region was not set");
31460 var region = cfg.region;
31466 xitems = cfg.items;
31473 case 'Content': // ContentPanel (el, cfg)
31474 case 'Scroll': // ContentPanel (el, cfg)
31476 cfg.autoCreate = true;
31477 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31479 // var el = this.el.createChild();
31480 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
31483 this.add(region, ret);
31487 case 'TreePanel': // our new panel!
31488 cfg.el = this.el.createChild();
31489 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31490 this.add(region, ret);
31495 // create a new Layout (which is a Border Layout...
31497 var clayout = cfg.layout;
31498 clayout.el = this.el.createChild();
31499 clayout.items = clayout.items || [];
31503 // replace this exitems with the clayout ones..
31504 xitems = clayout.items;
31506 // force background off if it's in center...
31507 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
31508 cfg.background = false;
31510 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
31513 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31514 //console.log('adding nested layout panel ' + cfg.toSource());
31515 this.add(region, ret);
31516 nb = {}; /// find first...
31521 // needs grid and region
31523 //var el = this.getRegion(region).el.createChild();
31524 var el = this.el.createChild();
31525 // create the grid first...
31526 cfg.grid.container = el;
31527 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
31530 if (region == 'center' && this.active ) {
31531 cfg.background = false;
31534 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
31536 this.add(region, ret);
31538 if (cfg.background) {
31539 // render grid on panel activation (if panel background)
31540 ret.on('activate', function(gp) {
31541 if (!gp.grid.rendered) {
31542 gp.grid.render(gp.grid.getGridEl());
31546 cfg.grid.render(cfg.grid.getGridEl());
31551 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
31552 // it was the old xcomponent building that caused this before.
31553 // espeically if border is the top element in the tree.
31563 if (typeof(Roo[cfg.xtype]) != 'undefined') {
31565 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
31566 this.add(region, ret);
31570 throw "Can not add '" + cfg.xtype + "' to Border";
31576 this.beginUpdate();
31580 Roo.each(xitems, function(i) {
31581 region = nb && i.region ? i.region : false;
31583 var add = ret.addxtype(i);
31586 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
31587 if (!i.background) {
31588 abn[region] = nb[region] ;
31595 // make the last non-background panel active..
31596 //if (nb) { Roo.log(abn); }
31599 for(var r in abn) {
31600 region = this.getRegion(r);
31602 // tried using nb[r], but it does not work..
31604 region.showPanel(abn[r]);
31615 factory : function(cfg)
31618 var validRegions = Roo.bootstrap.layout.Border.regions;
31620 var target = cfg.region;
31623 var r = Roo.bootstrap.layout;
31627 return new r.North(cfg);
31629 return new r.South(cfg);
31631 return new r.East(cfg);
31633 return new r.West(cfg);
31635 return new r.Center(cfg);
31637 throw 'Layout region "'+target+'" not supported.';
31644 * Ext JS Library 1.1.1
31645 * Copyright(c) 2006-2007, Ext JS, LLC.
31647 * Originally Released Under LGPL - original licence link has changed is not relivant.
31650 * <script type="text/javascript">
31654 * @class Roo.bootstrap.layout.Basic
31655 * @extends Roo.util.Observable
31656 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
31657 * and does not have a titlebar, tabs or any other features. All it does is size and position
31658 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
31659 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
31660 * @cfg {string} region the region that it inhabits..
31661 * @cfg {bool} skipConfig skip config?
31665 Roo.bootstrap.layout.Basic = function(config){
31667 this.mgr = config.mgr;
31669 this.position = config.region;
31671 var skipConfig = config.skipConfig;
31675 * @scope Roo.BasicLayoutRegion
31679 * @event beforeremove
31680 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
31681 * @param {Roo.LayoutRegion} this
31682 * @param {Roo.ContentPanel} panel The panel
31683 * @param {Object} e The cancel event object
31685 "beforeremove" : true,
31687 * @event invalidated
31688 * Fires when the layout for this region is changed.
31689 * @param {Roo.LayoutRegion} this
31691 "invalidated" : true,
31693 * @event visibilitychange
31694 * Fires when this region is shown or hidden
31695 * @param {Roo.LayoutRegion} this
31696 * @param {Boolean} visibility true or false
31698 "visibilitychange" : true,
31700 * @event paneladded
31701 * Fires when a panel is added.
31702 * @param {Roo.LayoutRegion} this
31703 * @param {Roo.ContentPanel} panel The panel
31705 "paneladded" : true,
31707 * @event panelremoved
31708 * Fires when a panel is removed.
31709 * @param {Roo.LayoutRegion} this
31710 * @param {Roo.ContentPanel} panel The panel
31712 "panelremoved" : true,
31714 * @event beforecollapse
31715 * Fires when this region before collapse.
31716 * @param {Roo.LayoutRegion} this
31718 "beforecollapse" : true,
31721 * Fires when this region is collapsed.
31722 * @param {Roo.LayoutRegion} this
31724 "collapsed" : true,
31727 * Fires when this region is expanded.
31728 * @param {Roo.LayoutRegion} this
31733 * Fires when this region is slid into view.
31734 * @param {Roo.LayoutRegion} this
31736 "slideshow" : true,
31739 * Fires when this region slides out of view.
31740 * @param {Roo.LayoutRegion} this
31742 "slidehide" : true,
31744 * @event panelactivated
31745 * Fires when a panel is activated.
31746 * @param {Roo.LayoutRegion} this
31747 * @param {Roo.ContentPanel} panel The activated panel
31749 "panelactivated" : true,
31752 * Fires when the user resizes this region.
31753 * @param {Roo.LayoutRegion} this
31754 * @param {Number} newSize The new size (width for east/west, height for north/south)
31758 /** A collection of panels in this region. @type Roo.util.MixedCollection */
31759 this.panels = new Roo.util.MixedCollection();
31760 this.panels.getKey = this.getPanelId.createDelegate(this);
31762 this.activePanel = null;
31763 // ensure listeners are added...
31765 if (config.listeners || config.events) {
31766 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
31767 listeners : config.listeners || {},
31768 events : config.events || {}
31772 if(skipConfig !== true){
31773 this.applyConfig(config);
31777 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
31779 getPanelId : function(p){
31783 applyConfig : function(config){
31784 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
31785 this.config = config;
31790 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
31791 * the width, for horizontal (north, south) the height.
31792 * @param {Number} newSize The new width or height
31794 resizeTo : function(newSize){
31795 var el = this.el ? this.el :
31796 (this.activePanel ? this.activePanel.getEl() : null);
31798 switch(this.position){
31801 el.setWidth(newSize);
31802 this.fireEvent("resized", this, newSize);
31806 el.setHeight(newSize);
31807 this.fireEvent("resized", this, newSize);
31813 getBox : function(){
31814 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
31817 getMargins : function(){
31818 return this.margins;
31821 updateBox : function(box){
31823 var el = this.activePanel.getEl();
31824 el.dom.style.left = box.x + "px";
31825 el.dom.style.top = box.y + "px";
31826 this.activePanel.setSize(box.width, box.height);
31830 * Returns the container element for this region.
31831 * @return {Roo.Element}
31833 getEl : function(){
31834 return this.activePanel;
31838 * Returns true if this region is currently visible.
31839 * @return {Boolean}
31841 isVisible : function(){
31842 return this.activePanel ? true : false;
31845 setActivePanel : function(panel){
31846 panel = this.getPanel(panel);
31847 if(this.activePanel && this.activePanel != panel){
31848 this.activePanel.setActiveState(false);
31849 this.activePanel.getEl().setLeftTop(-10000,-10000);
31851 this.activePanel = panel;
31852 panel.setActiveState(true);
31854 panel.setSize(this.box.width, this.box.height);
31856 this.fireEvent("panelactivated", this, panel);
31857 this.fireEvent("invalidated");
31861 * Show the specified panel.
31862 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
31863 * @return {Roo.ContentPanel} The shown panel or null
31865 showPanel : function(panel){
31866 panel = this.getPanel(panel);
31868 this.setActivePanel(panel);
31874 * Get the active panel for this region.
31875 * @return {Roo.ContentPanel} The active panel or null
31877 getActivePanel : function(){
31878 return this.activePanel;
31882 * Add the passed ContentPanel(s)
31883 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
31884 * @return {Roo.ContentPanel} The panel added (if only one was added)
31886 add : function(panel){
31887 if(arguments.length > 1){
31888 for(var i = 0, len = arguments.length; i < len; i++) {
31889 this.add(arguments[i]);
31893 if(this.hasPanel(panel)){
31894 this.showPanel(panel);
31897 var el = panel.getEl();
31898 if(el.dom.parentNode != this.mgr.el.dom){
31899 this.mgr.el.dom.appendChild(el.dom);
31901 if(panel.setRegion){
31902 panel.setRegion(this);
31904 this.panels.add(panel);
31905 el.setStyle("position", "absolute");
31906 if(!panel.background){
31907 this.setActivePanel(panel);
31908 if(this.config.initialSize && this.panels.getCount()==1){
31909 this.resizeTo(this.config.initialSize);
31912 this.fireEvent("paneladded", this, panel);
31917 * Returns true if the panel is in this region.
31918 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31919 * @return {Boolean}
31921 hasPanel : function(panel){
31922 if(typeof panel == "object"){ // must be panel obj
31923 panel = panel.getId();
31925 return this.getPanel(panel) ? true : false;
31929 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
31930 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31931 * @param {Boolean} preservePanel Overrides the config preservePanel option
31932 * @return {Roo.ContentPanel} The panel that was removed
31934 remove : function(panel, preservePanel){
31935 panel = this.getPanel(panel);
31940 this.fireEvent("beforeremove", this, panel, e);
31941 if(e.cancel === true){
31944 var panelId = panel.getId();
31945 this.panels.removeKey(panelId);
31950 * Returns the panel specified or null if it's not in this region.
31951 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
31952 * @return {Roo.ContentPanel}
31954 getPanel : function(id){
31955 if(typeof id == "object"){ // must be panel obj
31958 return this.panels.get(id);
31962 * Returns this regions position (north/south/east/west/center).
31965 getPosition: function(){
31966 return this.position;
31970 * Ext JS Library 1.1.1
31971 * Copyright(c) 2006-2007, Ext JS, LLC.
31973 * Originally Released Under LGPL - original licence link has changed is not relivant.
31976 * <script type="text/javascript">
31980 * @class Roo.bootstrap.layout.Region
31981 * @extends Roo.bootstrap.layout.Basic
31982 * This class represents a region in a layout manager.
31984 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
31985 * @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})
31986 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
31987 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
31988 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
31989 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
31990 * @cfg {String} title The title for the region (overrides panel titles)
31991 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
31992 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
31993 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
31994 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
31995 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
31996 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
31997 * the space available, similar to FireFox 1.5 tabs (defaults to false)
31998 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
31999 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
32000 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
32002 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
32003 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
32004 * @cfg {Boolean} disableTabTips True to disable tab tooltips
32005 * @cfg {Number} width For East/West panels
32006 * @cfg {Number} height For North/South panels
32007 * @cfg {Boolean} split To show the splitter
32008 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
32010 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
32011 * @cfg {string} region the region that it inhabits..
32014 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
32015 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
32017 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
32018 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
32019 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
32021 Roo.bootstrap.layout.Region = function(config)
32024 var mgr = config.mgr;
32025 var pos = config.region;
32026 config.skipConfig = true;
32027 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
32028 var dh = Roo.DomHelper;
32029 /** This region's container element
32030 * @type Roo.Element */
32031 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "roo-layout-region roo-layout-panel roo-layout-panel-" + this.position}, true);
32032 /** This region's title element
32033 * @type Roo.Element */
32035 this.titleEl = dh.append(this.el.dom,
32038 unselectable: "on",
32039 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
32041 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
32042 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
32045 this.titleEl.enableDisplayMode();
32046 /** This region's title text element
32047 * @type HTMLElement */
32048 this.titleTextEl = this.titleEl.dom.firstChild;
32049 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
32051 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
32052 this.closeBtn.enableDisplayMode();
32053 this.closeBtn.on("click", this.closeClicked, this);
32054 this.closeBtn.hide();
32056 this.createBody(config);
32057 this.visible = true;
32058 this.collapsed = false;
32060 if(config.hideWhenEmpty){
32062 this.on("paneladded", this.validateVisibility, this);
32063 this.on("panelremoved", this.validateVisibility, this);
32065 this.applyConfig(config);
32068 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
32072 createBody : function(){
32073 /** This region's body element
32074 * @type Roo.Element */
32075 this.bodyEl = this.el.createChild({
32077 cls: "roo-layout-panel-body tab-content" // bootstrap added...
32081 applyConfig : function(c)
32084 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
32085 var dh = Roo.DomHelper;
32086 if(c.titlebar !== false){
32087 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
32088 this.collapseBtn.on("click", this.collapse, this);
32089 this.collapseBtn.enableDisplayMode();
32091 if(c.showPin === true || this.showPin){
32092 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
32093 this.stickBtn.enableDisplayMode();
32094 this.stickBtn.on("click", this.expand, this);
32095 this.stickBtn.hide();
32100 /** This region's collapsed element
32101 * @type Roo.Element */
32104 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
32105 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
32108 if(c.floatable !== false){
32109 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
32110 this.collapsedEl.on("click", this.collapseClick, this);
32113 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
32114 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
32115 id: "message", unselectable: "on", style:{"float":"left"}});
32116 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
32118 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
32119 this.expandBtn.on("click", this.expand, this);
32123 if(this.collapseBtn){
32124 this.collapseBtn.setVisible(c.collapsible == true);
32127 this.cmargins = c.cmargins || this.cmargins ||
32128 (this.position == "west" || this.position == "east" ?
32129 {top: 0, left: 2, right:2, bottom: 0} :
32130 {top: 2, left: 0, right:0, bottom: 2});
32132 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
32135 this.bottomTabs = c.tabPosition != "top";
32137 this.autoScroll = c.autoScroll || false;
32140 if(this.autoScroll){
32141 this.bodyEl.setStyle("overflow", "auto");
32143 this.bodyEl.setStyle("overflow", c.overflow || 'hidden');
32145 //if(c.titlebar !== false){
32146 if((!c.titlebar && !c.title) || c.titlebar === false){
32147 this.titleEl.hide();
32149 this.titleEl.show();
32151 this.titleTextEl.innerHTML = c.title;
32155 this.duration = c.duration || .30;
32156 this.slideDuration = c.slideDuration || .45;
32159 this.collapse(true);
32166 * Returns true if this region is currently visible.
32167 * @return {Boolean}
32169 isVisible : function(){
32170 return this.visible;
32174 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
32175 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
32177 //setCollapsedTitle : function(title){
32178 // title = title || " ";
32179 // if(this.collapsedTitleTextEl){
32180 // this.collapsedTitleTextEl.innerHTML = title;
32184 getBox : function(){
32186 // if(!this.collapsed){
32187 b = this.el.getBox(false, true);
32189 // b = this.collapsedEl.getBox(false, true);
32194 getMargins : function(){
32195 return this.margins;
32196 //return this.collapsed ? this.cmargins : this.margins;
32199 highlight : function(){
32200 this.el.addClass("x-layout-panel-dragover");
32203 unhighlight : function(){
32204 this.el.removeClass("x-layout-panel-dragover");
32207 updateBox : function(box)
32210 if(!this.collapsed){
32211 this.el.dom.style.left = box.x + "px";
32212 this.el.dom.style.top = box.y + "px";
32213 this.updateBody(box.width, box.height);
32215 this.collapsedEl.dom.style.left = box.x + "px";
32216 this.collapsedEl.dom.style.top = box.y + "px";
32217 this.collapsedEl.setSize(box.width, box.height);
32220 this.tabs.autoSizeTabs();
32224 updateBody : function(w, h)
32227 this.el.setWidth(w);
32228 w -= this.el.getBorderWidth("rl");
32229 if(this.config.adjustments){
32230 w += this.config.adjustments[0];
32234 this.el.setHeight(h);
32235 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
32236 h -= this.el.getBorderWidth("tb");
32237 if(this.config.adjustments){
32238 h += this.config.adjustments[1];
32240 this.bodyEl.setHeight(h);
32242 h = this.tabs.syncHeight(h);
32245 if(this.panelSize){
32246 w = w !== null ? w : this.panelSize.width;
32247 h = h !== null ? h : this.panelSize.height;
32249 if(this.activePanel){
32250 var el = this.activePanel.getEl();
32251 w = w !== null ? w : el.getWidth();
32252 h = h !== null ? h : el.getHeight();
32253 this.panelSize = {width: w, height: h};
32254 this.activePanel.setSize(w, h);
32256 if(Roo.isIE && this.tabs){
32257 this.tabs.el.repaint();
32262 * Returns the container element for this region.
32263 * @return {Roo.Element}
32265 getEl : function(){
32270 * Hides this region.
32273 //if(!this.collapsed){
32274 this.el.dom.style.left = "-2000px";
32277 // this.collapsedEl.dom.style.left = "-2000px";
32278 // this.collapsedEl.hide();
32280 this.visible = false;
32281 this.fireEvent("visibilitychange", this, false);
32285 * Shows this region if it was previously hidden.
32288 //if(!this.collapsed){
32291 // this.collapsedEl.show();
32293 this.visible = true;
32294 this.fireEvent("visibilitychange", this, true);
32297 closeClicked : function(){
32298 if(this.activePanel){
32299 this.remove(this.activePanel);
32303 collapseClick : function(e){
32305 e.stopPropagation();
32308 e.stopPropagation();
32314 * Collapses this region.
32315 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
32318 collapse : function(skipAnim, skipCheck = false){
32319 if(this.collapsed) {
32323 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
32325 this.collapsed = true;
32327 this.split.el.hide();
32329 if(this.config.animate && skipAnim !== true){
32330 this.fireEvent("invalidated", this);
32331 this.animateCollapse();
32333 this.el.setLocation(-20000,-20000);
32335 this.collapsedEl.show();
32336 this.fireEvent("collapsed", this);
32337 this.fireEvent("invalidated", this);
32343 animateCollapse : function(){
32348 * Expands this region if it was previously collapsed.
32349 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
32350 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
32353 expand : function(e, skipAnim){
32355 e.stopPropagation();
32357 if(!this.collapsed || this.el.hasActiveFx()) {
32361 this.afterSlideIn();
32364 this.collapsed = false;
32365 if(this.config.animate && skipAnim !== true){
32366 this.animateExpand();
32370 this.split.el.show();
32372 this.collapsedEl.setLocation(-2000,-2000);
32373 this.collapsedEl.hide();
32374 this.fireEvent("invalidated", this);
32375 this.fireEvent("expanded", this);
32379 animateExpand : function(){
32383 initTabs : function()
32385 this.bodyEl.setStyle("overflow", "hidden");
32386 var ts = new Roo.bootstrap.panel.Tabs({
32387 el: this.bodyEl.dom,
32388 tabPosition: this.bottomTabs ? 'bottom' : 'top',
32389 disableTooltips: this.config.disableTabTips,
32390 toolbar : this.config.toolbar
32393 if(this.config.hideTabs){
32394 ts.stripWrap.setDisplayed(false);
32397 ts.resizeTabs = this.config.resizeTabs === true;
32398 ts.minTabWidth = this.config.minTabWidth || 40;
32399 ts.maxTabWidth = this.config.maxTabWidth || 250;
32400 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
32401 ts.monitorResize = false;
32402 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32403 ts.bodyEl.addClass('roo-layout-tabs-body');
32404 this.panels.each(this.initPanelAsTab, this);
32407 initPanelAsTab : function(panel){
32408 var ti = this.tabs.addTab(
32410 panel.getTitle(), null,
32411 this.config.closeOnTab && panel.isClosable()
32413 if(panel.tabTip !== undefined){
32414 ti.setTooltip(panel.tabTip);
32416 ti.on("activate", function(){
32417 this.setActivePanel(panel);
32420 if(this.config.closeOnTab){
32421 ti.on("beforeclose", function(t, e){
32423 this.remove(panel);
32429 updatePanelTitle : function(panel, title)
32431 if(this.activePanel == panel){
32432 this.updateTitle(title);
32435 var ti = this.tabs.getTab(panel.getEl().id);
32437 if(panel.tabTip !== undefined){
32438 ti.setTooltip(panel.tabTip);
32443 updateTitle : function(title){
32444 if(this.titleTextEl && !this.config.title){
32445 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
32449 setActivePanel : function(panel)
32451 panel = this.getPanel(panel);
32452 if(this.activePanel && this.activePanel != panel){
32453 this.activePanel.setActiveState(false);
32455 this.activePanel = panel;
32456 panel.setActiveState(true);
32457 if(this.panelSize){
32458 panel.setSize(this.panelSize.width, this.panelSize.height);
32461 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
32463 this.updateTitle(panel.getTitle());
32465 this.fireEvent("invalidated", this);
32467 this.fireEvent("panelactivated", this, panel);
32471 * Shows the specified panel.
32472 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
32473 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
32475 showPanel : function(panel)
32477 panel = this.getPanel(panel);
32480 var tab = this.tabs.getTab(panel.getEl().id);
32481 if(tab.isHidden()){
32482 this.tabs.unhideTab(tab.id);
32486 this.setActivePanel(panel);
32493 * Get the active panel for this region.
32494 * @return {Roo.ContentPanel} The active panel or null
32496 getActivePanel : function(){
32497 return this.activePanel;
32500 validateVisibility : function(){
32501 if(this.panels.getCount() < 1){
32502 this.updateTitle(" ");
32503 this.closeBtn.hide();
32506 if(!this.isVisible()){
32513 * Adds the passed ContentPanel(s) to this region.
32514 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
32515 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
32517 add : function(panel){
32518 if(arguments.length > 1){
32519 for(var i = 0, len = arguments.length; i < len; i++) {
32520 this.add(arguments[i]);
32524 if(this.hasPanel(panel)){
32525 this.showPanel(panel);
32528 panel.setRegion(this);
32529 this.panels.add(panel);
32530 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
32531 this.bodyEl.dom.appendChild(panel.getEl().dom);
32532 if(panel.background !== true){
32533 this.setActivePanel(panel);
32535 this.fireEvent("paneladded", this, panel);
32541 this.initPanelAsTab(panel);
32545 if(panel.background !== true){
32546 this.tabs.activate(panel.getEl().id);
32548 this.fireEvent("paneladded", this, panel);
32553 * Hides the tab for the specified panel.
32554 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32556 hidePanel : function(panel){
32557 if(this.tabs && (panel = this.getPanel(panel))){
32558 this.tabs.hideTab(panel.getEl().id);
32563 * Unhides the tab for a previously hidden panel.
32564 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32566 unhidePanel : function(panel){
32567 if(this.tabs && (panel = this.getPanel(panel))){
32568 this.tabs.unhideTab(panel.getEl().id);
32572 clearPanels : function(){
32573 while(this.panels.getCount() > 0){
32574 this.remove(this.panels.first());
32579 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
32580 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
32581 * @param {Boolean} preservePanel Overrides the config preservePanel option
32582 * @return {Roo.ContentPanel} The panel that was removed
32584 remove : function(panel, preservePanel)
32586 panel = this.getPanel(panel);
32591 this.fireEvent("beforeremove", this, panel, e);
32592 if(e.cancel === true){
32595 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
32596 var panelId = panel.getId();
32597 this.panels.removeKey(panelId);
32599 document.body.appendChild(panel.getEl().dom);
32602 this.tabs.removeTab(panel.getEl().id);
32603 }else if (!preservePanel){
32604 this.bodyEl.dom.removeChild(panel.getEl().dom);
32606 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
32607 var p = this.panels.first();
32608 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
32609 tempEl.appendChild(p.getEl().dom);
32610 this.bodyEl.update("");
32611 this.bodyEl.dom.appendChild(p.getEl().dom);
32613 this.updateTitle(p.getTitle());
32615 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
32616 this.setActivePanel(p);
32618 panel.setRegion(null);
32619 if(this.activePanel == panel){
32620 this.activePanel = null;
32622 if(this.config.autoDestroy !== false && preservePanel !== true){
32623 try{panel.destroy();}catch(e){}
32625 this.fireEvent("panelremoved", this, panel);
32630 * Returns the TabPanel component used by this region
32631 * @return {Roo.TabPanel}
32633 getTabs : function(){
32637 createTool : function(parentEl, className){
32638 var btn = Roo.DomHelper.append(parentEl, {
32640 cls: "x-layout-tools-button",
32643 cls: "roo-layout-tools-button-inner " + className,
32647 btn.addClassOnOver("roo-layout-tools-button-over");
32652 * Ext JS Library 1.1.1
32653 * Copyright(c) 2006-2007, Ext JS, LLC.
32655 * Originally Released Under LGPL - original licence link has changed is not relivant.
32658 * <script type="text/javascript">
32664 * @class Roo.SplitLayoutRegion
32665 * @extends Roo.LayoutRegion
32666 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
32668 Roo.bootstrap.layout.Split = function(config){
32669 this.cursor = config.cursor;
32670 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
32673 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
32675 splitTip : "Drag to resize.",
32676 collapsibleSplitTip : "Drag to resize. Double click to hide.",
32677 useSplitTips : false,
32679 applyConfig : function(config){
32680 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
32686 var splitEl = Roo.DomHelper.append(this.mgr.el.dom, {
32688 id: this.el.id + "-split",
32689 cls: "roo-layout-split roo-layout-split-"+this.position,
32692 /** The SplitBar for this region
32693 * @type Roo.SplitBar */
32694 // does not exist yet...
32695 Roo.log([this.position, this.orientation]);
32697 this.split = new Roo.bootstrap.SplitBar({
32698 dragElement : splitEl,
32699 resizingElement: this.el,
32700 orientation : this.orientation
32703 this.split.on("moved", this.onSplitMove, this);
32704 this.split.useShim = config.useShim === true;
32705 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
32706 if(this.useSplitTips){
32707 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
32709 //if(config.collapsible){
32710 // this.split.el.on("dblclick", this.collapse, this);
32713 if(typeof config.minSize != "undefined"){
32714 this.split.minSize = config.minSize;
32716 if(typeof config.maxSize != "undefined"){
32717 this.split.maxSize = config.maxSize;
32719 if(config.hideWhenEmpty || config.hidden || config.collapsed){
32720 this.hideSplitter();
32725 getHMaxSize : function(){
32726 var cmax = this.config.maxSize || 10000;
32727 var center = this.mgr.getRegion("center");
32728 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
32731 getVMaxSize : function(){
32732 var cmax = this.config.maxSize || 10000;
32733 var center = this.mgr.getRegion("center");
32734 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
32737 onSplitMove : function(split, newSize){
32738 this.fireEvent("resized", this, newSize);
32742 * Returns the {@link Roo.SplitBar} for this region.
32743 * @return {Roo.SplitBar}
32745 getSplitBar : function(){
32750 this.hideSplitter();
32751 Roo.bootstrap.layout.Split.superclass.hide.call(this);
32754 hideSplitter : function(){
32756 this.split.el.setLocation(-2000,-2000);
32757 this.split.el.hide();
32763 this.split.el.show();
32765 Roo.bootstrap.layout.Split.superclass.show.call(this);
32768 beforeSlide: function(){
32769 if(Roo.isGecko){// firefox overflow auto bug workaround
32770 this.bodyEl.clip();
32772 this.tabs.bodyEl.clip();
32774 if(this.activePanel){
32775 this.activePanel.getEl().clip();
32777 if(this.activePanel.beforeSlide){
32778 this.activePanel.beforeSlide();
32784 afterSlide : function(){
32785 if(Roo.isGecko){// firefox overflow auto bug workaround
32786 this.bodyEl.unclip();
32788 this.tabs.bodyEl.unclip();
32790 if(this.activePanel){
32791 this.activePanel.getEl().unclip();
32792 if(this.activePanel.afterSlide){
32793 this.activePanel.afterSlide();
32799 initAutoHide : function(){
32800 if(this.autoHide !== false){
32801 if(!this.autoHideHd){
32802 var st = new Roo.util.DelayedTask(this.slideIn, this);
32803 this.autoHideHd = {
32804 "mouseout": function(e){
32805 if(!e.within(this.el, true)){
32809 "mouseover" : function(e){
32815 this.el.on(this.autoHideHd);
32819 clearAutoHide : function(){
32820 if(this.autoHide !== false){
32821 this.el.un("mouseout", this.autoHideHd.mouseout);
32822 this.el.un("mouseover", this.autoHideHd.mouseover);
32826 clearMonitor : function(){
32827 Roo.get(document).un("click", this.slideInIf, this);
32830 // these names are backwards but not changed for compat
32831 slideOut : function(){
32832 if(this.isSlid || this.el.hasActiveFx()){
32835 this.isSlid = true;
32836 if(this.collapseBtn){
32837 this.collapseBtn.hide();
32839 this.closeBtnState = this.closeBtn.getStyle('display');
32840 this.closeBtn.hide();
32842 this.stickBtn.show();
32845 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
32846 this.beforeSlide();
32847 this.el.setStyle("z-index", 10001);
32848 this.el.slideIn(this.getSlideAnchor(), {
32849 callback: function(){
32851 this.initAutoHide();
32852 Roo.get(document).on("click", this.slideInIf, this);
32853 this.fireEvent("slideshow", this);
32860 afterSlideIn : function(){
32861 this.clearAutoHide();
32862 this.isSlid = false;
32863 this.clearMonitor();
32864 this.el.setStyle("z-index", "");
32865 if(this.collapseBtn){
32866 this.collapseBtn.show();
32868 this.closeBtn.setStyle('display', this.closeBtnState);
32870 this.stickBtn.hide();
32872 this.fireEvent("slidehide", this);
32875 slideIn : function(cb){
32876 if(!this.isSlid || this.el.hasActiveFx()){
32880 this.isSlid = false;
32881 this.beforeSlide();
32882 this.el.slideOut(this.getSlideAnchor(), {
32883 callback: function(){
32884 this.el.setLeftTop(-10000, -10000);
32886 this.afterSlideIn();
32894 slideInIf : function(e){
32895 if(!e.within(this.el)){
32900 animateCollapse : function(){
32901 this.beforeSlide();
32902 this.el.setStyle("z-index", 20000);
32903 var anchor = this.getSlideAnchor();
32904 this.el.slideOut(anchor, {
32905 callback : function(){
32906 this.el.setStyle("z-index", "");
32907 this.collapsedEl.slideIn(anchor, {duration:.3});
32909 this.el.setLocation(-10000,-10000);
32911 this.fireEvent("collapsed", this);
32918 animateExpand : function(){
32919 this.beforeSlide();
32920 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
32921 this.el.setStyle("z-index", 20000);
32922 this.collapsedEl.hide({
32925 this.el.slideIn(this.getSlideAnchor(), {
32926 callback : function(){
32927 this.el.setStyle("z-index", "");
32930 this.split.el.show();
32932 this.fireEvent("invalidated", this);
32933 this.fireEvent("expanded", this);
32961 getAnchor : function(){
32962 return this.anchors[this.position];
32965 getCollapseAnchor : function(){
32966 return this.canchors[this.position];
32969 getSlideAnchor : function(){
32970 return this.sanchors[this.position];
32973 getAlignAdj : function(){
32974 var cm = this.cmargins;
32975 switch(this.position){
32991 getExpandAdj : function(){
32992 var c = this.collapsedEl, cm = this.cmargins;
32993 switch(this.position){
32995 return [-(cm.right+c.getWidth()+cm.left), 0];
32998 return [cm.right+c.getWidth()+cm.left, 0];
33001 return [0, -(cm.top+cm.bottom+c.getHeight())];
33004 return [0, cm.top+cm.bottom+c.getHeight()];
33010 * Ext JS Library 1.1.1
33011 * Copyright(c) 2006-2007, Ext JS, LLC.
33013 * Originally Released Under LGPL - original licence link has changed is not relivant.
33016 * <script type="text/javascript">
33019 * These classes are private internal classes
33021 Roo.bootstrap.layout.Center = function(config){
33022 config.region = "center";
33023 Roo.bootstrap.layout.Region.call(this, config);
33024 this.visible = true;
33025 this.minWidth = config.minWidth || 20;
33026 this.minHeight = config.minHeight || 20;
33029 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
33031 // center panel can't be hidden
33035 // center panel can't be hidden
33038 getMinWidth: function(){
33039 return this.minWidth;
33042 getMinHeight: function(){
33043 return this.minHeight;
33056 Roo.bootstrap.layout.North = function(config)
33058 config.region = 'north';
33059 config.cursor = 'n-resize';
33061 Roo.bootstrap.layout.Split.call(this, config);
33063 this.split.placement = Roo.bootstrap.SplitBar.TOP;
33064 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33065 this.split.el.addClass("roo-layout-split-v");
33067 var size = config.initialSize || config.height;
33068 if(typeof size != "undefined"){
33069 this.el.setHeight(size);
33072 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
33074 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33075 getBox : function(){
33076 if(this.collapsed){
33077 return this.collapsedEl.getBox();
33079 var box = this.el.getBox();
33081 box.height += this.split.el.getHeight();
33086 updateBox : function(box){
33087 if(this.split && !this.collapsed){
33088 box.height -= this.split.el.getHeight();
33089 this.split.el.setLeft(box.x);
33090 this.split.el.setTop(box.y+box.height);
33091 this.split.el.setWidth(box.width);
33093 if(this.collapsed){
33094 this.updateBody(box.width, null);
33096 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33104 Roo.bootstrap.layout.South = function(config){
33105 config.region = 'south';
33106 config.cursor = 's-resize';
33107 Roo.bootstrap.layout.Split.call(this, config);
33109 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
33110 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
33111 this.split.el.addClass("roo-layout-split-v");
33113 var size = config.initialSize || config.height;
33114 if(typeof size != "undefined"){
33115 this.el.setHeight(size);
33119 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
33120 orientation: Roo.bootstrap.SplitBar.VERTICAL,
33121 getBox : function(){
33122 if(this.collapsed){
33123 return this.collapsedEl.getBox();
33125 var box = this.el.getBox();
33127 var sh = this.split.el.getHeight();
33134 updateBox : function(box){
33135 if(this.split && !this.collapsed){
33136 var sh = this.split.el.getHeight();
33139 this.split.el.setLeft(box.x);
33140 this.split.el.setTop(box.y-sh);
33141 this.split.el.setWidth(box.width);
33143 if(this.collapsed){
33144 this.updateBody(box.width, null);
33146 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33150 Roo.bootstrap.layout.East = function(config){
33151 config.region = "east";
33152 config.cursor = "e-resize";
33153 Roo.bootstrap.layout.Split.call(this, config);
33155 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
33156 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33157 this.split.el.addClass("roo-layout-split-h");
33159 var size = config.initialSize || config.width;
33160 if(typeof size != "undefined"){
33161 this.el.setWidth(size);
33164 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
33165 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33166 getBox : function(){
33167 if(this.collapsed){
33168 return this.collapsedEl.getBox();
33170 var box = this.el.getBox();
33172 var sw = this.split.el.getWidth();
33179 updateBox : function(box){
33180 if(this.split && !this.collapsed){
33181 var sw = this.split.el.getWidth();
33183 this.split.el.setLeft(box.x);
33184 this.split.el.setTop(box.y);
33185 this.split.el.setHeight(box.height);
33188 if(this.collapsed){
33189 this.updateBody(null, box.height);
33191 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33195 Roo.bootstrap.layout.West = function(config){
33196 config.region = "west";
33197 config.cursor = "w-resize";
33199 Roo.bootstrap.layout.Split.call(this, config);
33201 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
33202 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
33203 this.split.el.addClass("roo-layout-split-h");
33205 var size = config.initialSize || config.width;
33206 if(typeof size != "undefined"){
33207 this.el.setWidth(size);
33210 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
33211 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
33212 getBox : function(){
33213 if(this.collapsed){
33214 return this.collapsedEl.getBox();
33216 var box = this.el.getBox();
33218 box.width += this.split.el.getWidth();
33223 updateBox : function(box){
33224 if(this.split && !this.collapsed){
33225 var sw = this.split.el.getWidth();
33227 this.split.el.setLeft(box.x+box.width);
33228 this.split.el.setTop(box.y);
33229 this.split.el.setHeight(box.height);
33231 if(this.collapsed){
33232 this.updateBody(null, box.height);
33234 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
33237 Roo.namespace("Roo.bootstrap.panel");/*
33239 * Ext JS Library 1.1.1
33240 * Copyright(c) 2006-2007, Ext JS, LLC.
33242 * Originally Released Under LGPL - original licence link has changed is not relivant.
33245 * <script type="text/javascript">
33248 * @class Roo.ContentPanel
33249 * @extends Roo.util.Observable
33250 * A basic ContentPanel element.
33251 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
33252 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
33253 * @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
33254 * @cfg {Boolean} closable True if the panel can be closed/removed
33255 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
33256 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
33257 * @cfg {Toolbar} toolbar A toolbar for this panel
33258 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
33259 * @cfg {String} title The title for this panel
33260 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
33261 * @cfg {String} url Calls {@link #setUrl} with this value
33262 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
33263 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
33264 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
33265 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
33268 * Create a new ContentPanel.
33269 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
33270 * @param {String/Object} config A string to set only the title or a config object
33271 * @param {String} content (optional) Set the HTML content for this panel
33272 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
33274 Roo.bootstrap.panel.Content = function( config){
33276 var el = config.el;
33277 var content = config.content;
33279 if(config.autoCreate){ // xtype is available if this is called from factory
33282 this.el = Roo.get(el);
33283 if(!this.el && config && config.autoCreate){
33284 if(typeof config.autoCreate == "object"){
33285 if(!config.autoCreate.id){
33286 config.autoCreate.id = config.id||el;
33288 this.el = Roo.DomHelper.append(document.body,
33289 config.autoCreate, true);
33291 var elcfg = { tag: "div",
33292 cls: "roo-layout-inactive-content",
33296 elcfg.html = config.html;
33300 this.el = Roo.DomHelper.append(document.body, elcfg , true);
33303 this.closable = false;
33304 this.loaded = false;
33305 this.active = false;
33306 if(typeof config == "string"){
33307 this.title = config;
33309 Roo.apply(this, config);
33312 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
33313 this.wrapEl = this.el.wrap();
33314 this.toolbar.container = this.el.insertSibling(false, 'before');
33315 this.toolbar = new Roo.Toolbar(this.toolbar);
33318 // xtype created footer. - not sure if will work as we normally have to render first..
33319 if (this.footer && !this.footer.el && this.footer.xtype) {
33320 if (!this.wrapEl) {
33321 this.wrapEl = this.el.wrap();
33324 this.footer.container = this.wrapEl.createChild();
33326 this.footer = Roo.factory(this.footer, Roo);
33331 this.resizeEl = Roo.get(this.resizeEl, true);
33333 this.resizeEl = this.el;
33335 // handle view.xtype
33343 * Fires when this panel is activated.
33344 * @param {Roo.ContentPanel} this
33348 * @event deactivate
33349 * Fires when this panel is activated.
33350 * @param {Roo.ContentPanel} this
33352 "deactivate" : true,
33356 * Fires when this panel is resized if fitToFrame is true.
33357 * @param {Roo.ContentPanel} this
33358 * @param {Number} width The width after any component adjustments
33359 * @param {Number} height The height after any component adjustments
33365 * Fires when this tab is created
33366 * @param {Roo.ContentPanel} this
33377 if(this.autoScroll){
33378 this.resizeEl.setStyle("overflow", "auto");
33380 // fix randome scrolling
33381 this.el.on('scroll', function() {
33382 Roo.log('fix random scolling');
33383 this.scrollTo('top',0);
33386 content = content || this.content;
33388 this.setContent(content);
33390 if(config && config.url){
33391 this.setUrl(this.url, this.params, this.loadOnce);
33396 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
33398 if (this.view && typeof(this.view.xtype) != 'undefined') {
33399 this.view.el = this.el.appendChild(document.createElement("div"));
33400 this.view = Roo.factory(this.view);
33401 this.view.render && this.view.render(false, '');
33405 this.fireEvent('render', this);
33408 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
33410 setRegion : function(region){
33411 this.region = region;
33413 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
33415 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
33420 * Returns the toolbar for this Panel if one was configured.
33421 * @return {Roo.Toolbar}
33423 getToolbar : function(){
33424 return this.toolbar;
33427 setActiveState : function(active){
33428 this.active = active;
33430 this.fireEvent("deactivate", this);
33432 this.fireEvent("activate", this);
33436 * Updates this panel's element
33437 * @param {String} content The new content
33438 * @param {Boolean} loadScripts (optional) true to look for and process scripts
33440 setContent : function(content, loadScripts){
33441 this.el.update(content, loadScripts);
33444 ignoreResize : function(w, h){
33445 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
33448 this.lastSize = {width: w, height: h};
33453 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
33454 * @return {Roo.UpdateManager} The UpdateManager
33456 getUpdateManager : function(){
33457 return this.el.getUpdateManager();
33460 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
33461 * @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:
33464 url: "your-url.php",
33465 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
33466 callback: yourFunction,
33467 scope: yourObject, //(optional scope)
33470 text: "Loading...",
33475 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
33476 * 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.
33477 * @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}
33478 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
33479 * @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.
33480 * @return {Roo.ContentPanel} this
33483 var um = this.el.getUpdateManager();
33484 um.update.apply(um, arguments);
33490 * 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.
33491 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
33492 * @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)
33493 * @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)
33494 * @return {Roo.UpdateManager} The UpdateManager
33496 setUrl : function(url, params, loadOnce){
33497 if(this.refreshDelegate){
33498 this.removeListener("activate", this.refreshDelegate);
33500 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
33501 this.on("activate", this.refreshDelegate);
33502 return this.el.getUpdateManager();
33505 _handleRefresh : function(url, params, loadOnce){
33506 if(!loadOnce || !this.loaded){
33507 var updater = this.el.getUpdateManager();
33508 updater.update(url, params, this._setLoaded.createDelegate(this));
33512 _setLoaded : function(){
33513 this.loaded = true;
33517 * Returns this panel's id
33520 getId : function(){
33525 * Returns this panel's element - used by regiosn to add.
33526 * @return {Roo.Element}
33528 getEl : function(){
33529 return this.wrapEl || this.el;
33534 adjustForComponents : function(width, height)
33536 //Roo.log('adjustForComponents ');
33537 if(this.resizeEl != this.el){
33538 width -= this.el.getFrameWidth('lr');
33539 height -= this.el.getFrameWidth('tb');
33542 var te = this.toolbar.getEl();
33543 height -= te.getHeight();
33544 te.setWidth(width);
33547 var te = this.footer.getEl();
33548 Roo.log("footer:" + te.getHeight());
33550 height -= te.getHeight();
33551 te.setWidth(width);
33555 if(this.adjustments){
33556 width += this.adjustments[0];
33557 height += this.adjustments[1];
33559 return {"width": width, "height": height};
33562 setSize : function(width, height){
33563 if(this.fitToFrame && !this.ignoreResize(width, height)){
33564 if(this.fitContainer && this.resizeEl != this.el){
33565 this.el.setSize(width, height);
33567 var size = this.adjustForComponents(width, height);
33568 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
33569 this.fireEvent('resize', this, size.width, size.height);
33574 * Returns this panel's title
33577 getTitle : function(){
33582 * Set this panel's title
33583 * @param {String} title
33585 setTitle : function(title){
33586 this.title = title;
33588 this.region.updatePanelTitle(this, title);
33593 * Returns true is this panel was configured to be closable
33594 * @return {Boolean}
33596 isClosable : function(){
33597 return this.closable;
33600 beforeSlide : function(){
33602 this.resizeEl.clip();
33605 afterSlide : function(){
33607 this.resizeEl.unclip();
33611 * Force a content refresh from the URL specified in the {@link #setUrl} method.
33612 * Will fail silently if the {@link #setUrl} method has not been called.
33613 * This does not activate the panel, just updates its content.
33615 refresh : function(){
33616 if(this.refreshDelegate){
33617 this.loaded = false;
33618 this.refreshDelegate();
33623 * Destroys this panel
33625 destroy : function(){
33626 this.el.removeAllListeners();
33627 var tempEl = document.createElement("span");
33628 tempEl.appendChild(this.el.dom);
33629 tempEl.innerHTML = "";
33635 * form - if the content panel contains a form - this is a reference to it.
33636 * @type {Roo.form.Form}
33640 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
33641 * This contains a reference to it.
33647 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
33657 * @param {Object} cfg Xtype definition of item to add.
33661 getChildContainer: function () {
33662 return this.getEl();
33667 var ret = new Roo.factory(cfg);
33672 if (cfg.xtype.match(/^Form$/)) {
33675 //if (this.footer) {
33676 // el = this.footer.container.insertSibling(false, 'before');
33678 el = this.el.createChild();
33681 this.form = new Roo.form.Form(cfg);
33684 if ( this.form.allItems.length) {
33685 this.form.render(el.dom);
33689 // should only have one of theses..
33690 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
33691 // views.. should not be just added - used named prop 'view''
33693 cfg.el = this.el.appendChild(document.createElement("div"));
33696 var ret = new Roo.factory(cfg);
33698 ret.render && ret.render(false, ''); // render blank..
33708 * @class Roo.bootstrap.panel.Grid
33709 * @extends Roo.bootstrap.panel.Content
33711 * Create a new GridPanel.
33712 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
33713 * @param {String/Object} config A string to set only the panel's title, or a config object
33715 new Roo.bootstrap.panel.Grid({
33724 Roo.bootstrap.panel.Grid = function(config){
33727 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
33728 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
33730 this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
33731 config.el = this.wrapper;
33733 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
33736 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
33738 // xtype created footer. - not sure if will work as we normally have to render first..
33739 if (this.footer && !this.footer.el && this.footer.xtype) {
33741 this.footer.container = this.grid.getView().getFooterPanel(true);
33742 this.footer.dataSource = this.grid.dataSource;
33743 this.footer = Roo.factory(this.footer, Roo);
33748 config.grid.monitorWindowResize = false; // turn off autosizing
33749 config.grid.autoHeight = false;
33750 config.grid.autoWidth = false;
33751 this.grid = config.grid;
33752 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
33757 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
33758 getId : function(){
33759 return this.grid.id;
33763 * Returns the grid for this panel
33764 * @return {Roo.bootstrap.Table}
33766 getGrid : function(){
33770 setSize : function(width, height){
33771 if(!this.ignoreResize(width, height)){
33772 var grid = this.grid;
33773 var size = this.adjustForComponents(width, height);
33774 grid.getGridEl().setSize(size.width, size.height);
33776 var thd = grid.getGridEl().select('thead',true).first();
33777 var tbd = grid.getGridEl().select('tbody', true).first();
33779 tbd.setSize(width, height - thd.getHeight());
33788 beforeSlide : function(){
33789 this.grid.getView().scroller.clip();
33792 afterSlide : function(){
33793 this.grid.getView().scroller.unclip();
33796 destroy : function(){
33797 this.grid.destroy();
33799 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
33804 * @class Roo.bootstrap.panel.Nest
33805 * @extends Roo.bootstrap.panel.Content
33807 * Create a new Panel, that can contain a layout.Border.
33810 * @param {Roo.BorderLayout} layout The layout for this panel
33811 * @param {String/Object} config A string to set only the title or a config object
33813 Roo.bootstrap.panel.Nest = function(config)
33815 // construct with only one argument..
33816 /* FIXME - implement nicer consturctors
33817 if (layout.layout) {
33819 layout = config.layout;
33820 delete config.layout;
33822 if (layout.xtype && !layout.getEl) {
33823 // then layout needs constructing..
33824 layout = Roo.factory(layout, Roo);
33828 config.el = config.layout.getEl();
33830 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
33832 config.layout.monitorWindowResize = false; // turn off autosizing
33833 this.layout = config.layout;
33834 this.layout.getEl().addClass("roo-layout-nested-layout");
33841 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
33843 setSize : function(width, height){
33844 if(!this.ignoreResize(width, height)){
33845 var size = this.adjustForComponents(width, height);
33846 var el = this.layout.getEl();
33847 el.setSize(size.width, size.height);
33848 var touch = el.dom.offsetWidth;
33849 this.layout.layout();
33850 // ie requires a double layout on the first pass
33851 if(Roo.isIE && !this.initialized){
33852 this.initialized = true;
33853 this.layout.layout();
33858 // activate all subpanels if not currently active..
33860 setActiveState : function(active){
33861 this.active = active;
33863 this.fireEvent("deactivate", this);
33867 this.fireEvent("activate", this);
33868 // not sure if this should happen before or after..
33869 if (!this.layout) {
33870 return; // should not happen..
33873 for (var r in this.layout.regions) {
33874 reg = this.layout.getRegion(r);
33875 if (reg.getActivePanel()) {
33876 //reg.showPanel(reg.getActivePanel()); // force it to activate..
33877 reg.setActivePanel(reg.getActivePanel());
33880 if (!reg.panels.length) {
33883 reg.showPanel(reg.getPanel(0));
33892 * Returns the nested BorderLayout for this panel
33893 * @return {Roo.BorderLayout}
33895 getLayout : function(){
33896 return this.layout;
33900 * Adds a xtype elements to the layout of the nested panel
33904 xtype : 'ContentPanel',
33911 xtype : 'NestedLayoutPanel',
33917 items : [ ... list of content panels or nested layout panels.. ]
33921 * @param {Object} cfg Xtype definition of item to add.
33923 addxtype : function(cfg) {
33924 return this.layout.addxtype(cfg);
33929 * Ext JS Library 1.1.1
33930 * Copyright(c) 2006-2007, Ext JS, LLC.
33932 * Originally Released Under LGPL - original licence link has changed is not relivant.
33935 * <script type="text/javascript">
33938 * @class Roo.TabPanel
33939 * @extends Roo.util.Observable
33940 * A lightweight tab container.
33944 // basic tabs 1, built from existing content
33945 var tabs = new Roo.TabPanel("tabs1");
33946 tabs.addTab("script", "View Script");
33947 tabs.addTab("markup", "View Markup");
33948 tabs.activate("script");
33950 // more advanced tabs, built from javascript
33951 var jtabs = new Roo.TabPanel("jtabs");
33952 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
33954 // set up the UpdateManager
33955 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
33956 var updater = tab2.getUpdateManager();
33957 updater.setDefaultUrl("ajax1.htm");
33958 tab2.on('activate', updater.refresh, updater, true);
33960 // Use setUrl for Ajax loading
33961 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
33962 tab3.setUrl("ajax2.htm", null, true);
33965 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
33968 jtabs.activate("jtabs-1");
33971 * Create a new TabPanel.
33972 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
33973 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
33975 Roo.bootstrap.panel.Tabs = function(config){
33977 * The container element for this TabPanel.
33978 * @type Roo.Element
33980 this.el = Roo.get(config.el);
33983 if(typeof config == "boolean"){
33984 this.tabPosition = config ? "bottom" : "top";
33986 Roo.apply(this, config);
33990 if(this.tabPosition == "bottom"){
33991 this.bodyEl = Roo.get(this.createBody(this.el.dom));
33992 this.el.addClass("roo-tabs-bottom");
33994 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
33995 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
33996 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
33998 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
34000 if(this.tabPosition != "bottom"){
34001 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
34002 * @type Roo.Element
34004 this.bodyEl = Roo.get(this.createBody(this.el.dom));
34005 this.el.addClass("roo-tabs-top");
34009 this.bodyEl.setStyle("position", "relative");
34011 this.active = null;
34012 this.activateDelegate = this.activate.createDelegate(this);
34017 * Fires when the active tab changes
34018 * @param {Roo.TabPanel} this
34019 * @param {Roo.TabPanelItem} activePanel The new active tab
34023 * @event beforetabchange
34024 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
34025 * @param {Roo.TabPanel} this
34026 * @param {Object} e Set cancel to true on this object to cancel the tab change
34027 * @param {Roo.TabPanelItem} tab The tab being changed to
34029 "beforetabchange" : true
34032 Roo.EventManager.onWindowResize(this.onResize, this);
34033 this.cpad = this.el.getPadding("lr");
34034 this.hiddenCount = 0;
34037 // toolbar on the tabbar support...
34038 if (this.toolbar) {
34039 alert("no toolbar support yet");
34040 this.toolbar = false;
34042 var tcfg = this.toolbar;
34043 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
34044 this.toolbar = new Roo.Toolbar(tcfg);
34045 if (Roo.isSafari) {
34046 var tbl = tcfg.container.child('table', true);
34047 tbl.setAttribute('width', '100%');
34055 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
34058 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
34060 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
34062 tabPosition : "top",
34064 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
34066 currentTabWidth : 0,
34068 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
34072 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
34076 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
34078 preferredTabWidth : 175,
34080 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
34082 resizeTabs : false,
34084 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
34086 monitorResize : true,
34088 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
34093 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
34094 * @param {String} id The id of the div to use <b>or create</b>
34095 * @param {String} text The text for the tab
34096 * @param {String} content (optional) Content to put in the TabPanelItem body
34097 * @param {Boolean} closable (optional) True to create a close icon on the tab
34098 * @return {Roo.TabPanelItem} The created TabPanelItem
34100 addTab : function(id, text, content, closable)
34102 var item = new Roo.bootstrap.panel.TabItem({
34106 closable : closable
34108 this.addTabItem(item);
34110 item.setContent(content);
34116 * Returns the {@link Roo.TabPanelItem} with the specified id/index
34117 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
34118 * @return {Roo.TabPanelItem}
34120 getTab : function(id){
34121 return this.items[id];
34125 * Hides the {@link Roo.TabPanelItem} with the specified id/index
34126 * @param {String/Number} id The id or index of the TabPanelItem to hide.
34128 hideTab : function(id){
34129 var t = this.items[id];
34132 this.hiddenCount++;
34133 this.autoSizeTabs();
34138 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
34139 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
34141 unhideTab : function(id){
34142 var t = this.items[id];
34144 t.setHidden(false);
34145 this.hiddenCount--;
34146 this.autoSizeTabs();
34151 * Adds an existing {@link Roo.TabPanelItem}.
34152 * @param {Roo.TabPanelItem} item The TabPanelItem to add
34154 addTabItem : function(item){
34155 this.items[item.id] = item;
34156 this.items.push(item);
34157 // if(this.resizeTabs){
34158 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
34159 // this.autoSizeTabs();
34161 // item.autoSize();
34166 * Removes a {@link Roo.TabPanelItem}.
34167 * @param {String/Number} id The id or index of the TabPanelItem to remove.
34169 removeTab : function(id){
34170 var items = this.items;
34171 var tab = items[id];
34172 if(!tab) { return; }
34173 var index = items.indexOf(tab);
34174 if(this.active == tab && items.length > 1){
34175 var newTab = this.getNextAvailable(index);
34180 this.stripEl.dom.removeChild(tab.pnode.dom);
34181 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
34182 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
34184 items.splice(index, 1);
34185 delete this.items[tab.id];
34186 tab.fireEvent("close", tab);
34187 tab.purgeListeners();
34188 this.autoSizeTabs();
34191 getNextAvailable : function(start){
34192 var items = this.items;
34194 // look for a next tab that will slide over to
34195 // replace the one being removed
34196 while(index < items.length){
34197 var item = items[++index];
34198 if(item && !item.isHidden()){
34202 // if one isn't found select the previous tab (on the left)
34205 var item = items[--index];
34206 if(item && !item.isHidden()){
34214 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
34215 * @param {String/Number} id The id or index of the TabPanelItem to disable.
34217 disableTab : function(id){
34218 var tab = this.items[id];
34219 if(tab && this.active != tab){
34225 * Enables a {@link Roo.TabPanelItem} that is disabled.
34226 * @param {String/Number} id The id or index of the TabPanelItem to enable.
34228 enableTab : function(id){
34229 var tab = this.items[id];
34234 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
34235 * @param {String/Number} id The id or index of the TabPanelItem to activate.
34236 * @return {Roo.TabPanelItem} The TabPanelItem.
34238 activate : function(id){
34239 var tab = this.items[id];
34243 if(tab == this.active || tab.disabled){
34247 this.fireEvent("beforetabchange", this, e, tab);
34248 if(e.cancel !== true && !tab.disabled){
34250 this.active.hide();
34252 this.active = this.items[id];
34253 this.active.show();
34254 this.fireEvent("tabchange", this, this.active);
34260 * Gets the active {@link Roo.TabPanelItem}.
34261 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
34263 getActiveTab : function(){
34264 return this.active;
34268 * Updates the tab body element to fit the height of the container element
34269 * for overflow scrolling
34270 * @param {Number} targetHeight (optional) Override the starting height from the elements height
34272 syncHeight : function(targetHeight){
34273 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34274 var bm = this.bodyEl.getMargins();
34275 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
34276 this.bodyEl.setHeight(newHeight);
34280 onResize : function(){
34281 if(this.monitorResize){
34282 this.autoSizeTabs();
34287 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
34289 beginUpdate : function(){
34290 this.updating = true;
34294 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
34296 endUpdate : function(){
34297 this.updating = false;
34298 this.autoSizeTabs();
34302 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
34304 autoSizeTabs : function(){
34305 var count = this.items.length;
34306 var vcount = count - this.hiddenCount;
34307 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
34310 var w = Math.max(this.el.getWidth() - this.cpad, 10);
34311 var availWidth = Math.floor(w / vcount);
34312 var b = this.stripBody;
34313 if(b.getWidth() > w){
34314 var tabs = this.items;
34315 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
34316 if(availWidth < this.minTabWidth){
34317 /*if(!this.sleft){ // incomplete scrolling code
34318 this.createScrollButtons();
34321 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
34324 if(this.currentTabWidth < this.preferredTabWidth){
34325 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
34331 * Returns the number of tabs in this TabPanel.
34334 getCount : function(){
34335 return this.items.length;
34339 * Resizes all the tabs to the passed width
34340 * @param {Number} The new width
34342 setTabWidth : function(width){
34343 this.currentTabWidth = width;
34344 for(var i = 0, len = this.items.length; i < len; i++) {
34345 if(!this.items[i].isHidden()) {
34346 this.items[i].setWidth(width);
34352 * Destroys this TabPanel
34353 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
34355 destroy : function(removeEl){
34356 Roo.EventManager.removeResizeListener(this.onResize, this);
34357 for(var i = 0, len = this.items.length; i < len; i++){
34358 this.items[i].purgeListeners();
34360 if(removeEl === true){
34361 this.el.update("");
34366 createStrip : function(container)
34368 var strip = document.createElement("nav");
34369 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
34370 container.appendChild(strip);
34374 createStripList : function(strip)
34376 // div wrapper for retard IE
34377 // returns the "tr" element.
34378 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
34379 //'<div class="x-tabs-strip-wrap">'+
34380 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
34381 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
34382 return strip.firstChild; //.firstChild.firstChild.firstChild;
34384 createBody : function(container)
34386 var body = document.createElement("div");
34387 Roo.id(body, "tab-body");
34388 //Roo.fly(body).addClass("x-tabs-body");
34389 Roo.fly(body).addClass("tab-content");
34390 container.appendChild(body);
34393 createItemBody :function(bodyEl, id){
34394 var body = Roo.getDom(id);
34396 body = document.createElement("div");
34399 //Roo.fly(body).addClass("x-tabs-item-body");
34400 Roo.fly(body).addClass("tab-pane");
34401 bodyEl.insertBefore(body, bodyEl.firstChild);
34405 createStripElements : function(stripEl, text, closable)
34407 var td = document.createElement("li"); // was td..
34408 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
34409 //stripEl.appendChild(td);
34411 td.className = "x-tabs-closable";
34412 if(!this.closeTpl){
34413 this.closeTpl = new Roo.Template(
34414 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34415 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
34416 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
34419 var el = this.closeTpl.overwrite(td, {"text": text});
34420 var close = el.getElementsByTagName("div")[0];
34421 var inner = el.getElementsByTagName("em")[0];
34422 return {"el": el, "close": close, "inner": inner};
34425 // not sure what this is..
34427 //this.tabTpl = new Roo.Template(
34428 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
34429 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
34431 this.tabTpl = new Roo.Template(
34433 '<span unselectable="on"' +
34434 (this.disableTooltips ? '' : ' title="{text}"') +
34435 ' >{text}</span></span></a>'
34439 var el = this.tabTpl.overwrite(td, {"text": text});
34440 var inner = el.getElementsByTagName("span")[0];
34441 return {"el": el, "inner": inner};
34449 * @class Roo.TabPanelItem
34450 * @extends Roo.util.Observable
34451 * Represents an individual item (tab plus body) in a TabPanel.
34452 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
34453 * @param {String} id The id of this TabPanelItem
34454 * @param {String} text The text for the tab of this TabPanelItem
34455 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
34457 Roo.bootstrap.panel.TabItem = function(config){
34459 * The {@link Roo.TabPanel} this TabPanelItem belongs to
34460 * @type Roo.TabPanel
34462 this.tabPanel = config.panel;
34464 * The id for this TabPanelItem
34467 this.id = config.id;
34469 this.disabled = false;
34471 this.text = config.text;
34473 this.loaded = false;
34474 this.closable = config.closable;
34477 * The body element for this TabPanelItem.
34478 * @type Roo.Element
34480 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
34481 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
34482 this.bodyEl.setStyle("display", "block");
34483 this.bodyEl.setStyle("zoom", "1");
34484 //this.hideAction();
34486 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable);
34488 this.el = Roo.get(els.el);
34489 this.inner = Roo.get(els.inner, true);
34490 this.textEl = Roo.get(this.el.dom.firstChild, true);
34491 this.pnode = Roo.get(els.el.parentNode, true);
34492 this.el.on("mousedown", this.onTabMouseDown, this);
34493 this.el.on("click", this.onTabClick, this);
34495 if(config.closable){
34496 var c = Roo.get(els.close, true);
34497 c.dom.title = this.closeText;
34498 c.addClassOnOver("close-over");
34499 c.on("click", this.closeClick, this);
34505 * Fires when this tab becomes the active tab.
34506 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34507 * @param {Roo.TabPanelItem} this
34511 * @event beforeclose
34512 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
34513 * @param {Roo.TabPanelItem} this
34514 * @param {Object} e Set cancel to true on this object to cancel the close.
34516 "beforeclose": true,
34519 * Fires when this tab is closed.
34520 * @param {Roo.TabPanelItem} this
34524 * @event deactivate
34525 * Fires when this tab is no longer the active tab.
34526 * @param {Roo.TabPanel} tabPanel The parent TabPanel
34527 * @param {Roo.TabPanelItem} this
34529 "deactivate" : true
34531 this.hidden = false;
34533 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
34536 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
34538 purgeListeners : function(){
34539 Roo.util.Observable.prototype.purgeListeners.call(this);
34540 this.el.removeAllListeners();
34543 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
34546 this.pnode.addClass("active");
34549 this.tabPanel.stripWrap.repaint();
34551 this.fireEvent("activate", this.tabPanel, this);
34555 * Returns true if this tab is the active tab.
34556 * @return {Boolean}
34558 isActive : function(){
34559 return this.tabPanel.getActiveTab() == this;
34563 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
34566 this.pnode.removeClass("active");
34568 this.fireEvent("deactivate", this.tabPanel, this);
34571 hideAction : function(){
34572 this.bodyEl.hide();
34573 this.bodyEl.setStyle("position", "absolute");
34574 this.bodyEl.setLeft("-20000px");
34575 this.bodyEl.setTop("-20000px");
34578 showAction : function(){
34579 this.bodyEl.setStyle("position", "relative");
34580 this.bodyEl.setTop("");
34581 this.bodyEl.setLeft("");
34582 this.bodyEl.show();
34586 * Set the tooltip for the tab.
34587 * @param {String} tooltip The tab's tooltip
34589 setTooltip : function(text){
34590 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
34591 this.textEl.dom.qtip = text;
34592 this.textEl.dom.removeAttribute('title');
34594 this.textEl.dom.title = text;
34598 onTabClick : function(e){
34599 e.preventDefault();
34600 this.tabPanel.activate(this.id);
34603 onTabMouseDown : function(e){
34604 e.preventDefault();
34605 this.tabPanel.activate(this.id);
34608 getWidth : function(){
34609 return this.inner.getWidth();
34612 setWidth : function(width){
34613 var iwidth = width - this.pnode.getPadding("lr");
34614 this.inner.setWidth(iwidth);
34615 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
34616 this.pnode.setWidth(width);
34620 * Show or hide the tab
34621 * @param {Boolean} hidden True to hide or false to show.
34623 setHidden : function(hidden){
34624 this.hidden = hidden;
34625 this.pnode.setStyle("display", hidden ? "none" : "");
34629 * Returns true if this tab is "hidden"
34630 * @return {Boolean}
34632 isHidden : function(){
34633 return this.hidden;
34637 * Returns the text for this tab
34640 getText : function(){
34644 autoSize : function(){
34645 //this.el.beginMeasure();
34646 this.textEl.setWidth(1);
34648 * #2804 [new] Tabs in Roojs
34649 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
34651 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
34652 //this.el.endMeasure();
34656 * Sets the text for the tab (Note: this also sets the tooltip text)
34657 * @param {String} text The tab's text and tooltip
34659 setText : function(text){
34661 this.textEl.update(text);
34662 this.setTooltip(text);
34663 //if(!this.tabPanel.resizeTabs){
34664 // this.autoSize();
34668 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
34670 activate : function(){
34671 this.tabPanel.activate(this.id);
34675 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
34677 disable : function(){
34678 if(this.tabPanel.active != this){
34679 this.disabled = true;
34680 this.pnode.addClass("disabled");
34685 * Enables this TabPanelItem if it was previously disabled.
34687 enable : function(){
34688 this.disabled = false;
34689 this.pnode.removeClass("disabled");
34693 * Sets the content for this TabPanelItem.
34694 * @param {String} content The content
34695 * @param {Boolean} loadScripts true to look for and load scripts
34697 setContent : function(content, loadScripts){
34698 this.bodyEl.update(content, loadScripts);
34702 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
34703 * @return {Roo.UpdateManager} The UpdateManager
34705 getUpdateManager : function(){
34706 return this.bodyEl.getUpdateManager();
34710 * Set a URL to be used to load the content for this TabPanelItem.
34711 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
34712 * @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)
34713 * @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)
34714 * @return {Roo.UpdateManager} The UpdateManager
34716 setUrl : function(url, params, loadOnce){
34717 if(this.refreshDelegate){
34718 this.un('activate', this.refreshDelegate);
34720 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34721 this.on("activate", this.refreshDelegate);
34722 return this.bodyEl.getUpdateManager();
34726 _handleRefresh : function(url, params, loadOnce){
34727 if(!loadOnce || !this.loaded){
34728 var updater = this.bodyEl.getUpdateManager();
34729 updater.update(url, params, this._setLoaded.createDelegate(this));
34734 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
34735 * Will fail silently if the setUrl method has not been called.
34736 * This does not activate the panel, just updates its content.
34738 refresh : function(){
34739 if(this.refreshDelegate){
34740 this.loaded = false;
34741 this.refreshDelegate();
34746 _setLoaded : function(){
34747 this.loaded = true;
34751 closeClick : function(e){
34754 this.fireEvent("beforeclose", this, o);
34755 if(o.cancel !== true){
34756 this.tabPanel.removeTab(this.id);
34760 * The text displayed in the tooltip for the close icon.
34763 closeText : "Close this tab"