4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 cn = Roo.factory(tree);
252 cn.parentType = this.xtype; //??
253 cn.parentId = this.id;
255 var build_from_html = Roo.XComponent.build_from_html;
258 // does the container contain child eleemnts with 'xtype' attributes.
259 // that match this xtype..
260 // note - when we render we create these as well..
261 // so we should check to see if body has xtype set.
262 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
264 var self_cntr_el = Roo.get(this[cntr](false));
265 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
267 //Roo.log(Roo.XComponent.build_from_html);
268 //Roo.log("got echild:");
271 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
272 // and are not displayed -this causes this to use up the wrong element when matching.
273 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
276 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
277 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
283 //echild.dom.removeAttribute('xtype');
285 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
286 Roo.debug && Roo.log(self_cntr_el);
287 Roo.debug && Roo.log(echild);
288 Roo.debug && Roo.log(cn);
294 // if object has flexy:if - then it may or may not be rendered.
295 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
296 // skip a flexy if element.
297 Roo.debug && Roo.log('skipping render');
298 Roo.debug && Roo.log(tree);
300 Roo.debug && Roo.log('skipping all children');
301 skip_children = true;
306 // actually if flexy:foreach is found, we really want to create
307 // multiple copies here...
309 //Roo.log(this[cntr]());
310 // some elements do not have render methods.. like the layouts...
311 cn.render && cn.render(this[cntr](true));
313 // then add the element..
321 if (typeof (tree.menu) != 'undefined') {
322 tree.menu.parentType = cn.xtype;
323 tree.menu.triggerEl = cn.el;
324 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
328 if (!tree.items || !tree.items.length) {
330 //Roo.log(["no children", this]);
335 var items = tree.items;
338 //Roo.log(items.length);
340 if (!skip_children) {
341 for(var i =0;i < items.length;i++) {
342 // Roo.log(['add child', items[i]]);
343 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
349 //Roo.log("fire childrenrendered");
351 cn.fireEvent('childrenrendered', this);
356 * Show a component - removes 'hidden' class
361 this.el.removeClass('hidden');
365 * Hide a component - adds 'hidden' class
369 if (this.el && !this.el.hasClass('hidden')) {
370 this.el.addClass('hidden');
384 * @class Roo.bootstrap.Body
385 * @extends Roo.bootstrap.Component
386 * Bootstrap Body class
390 * @param {Object} config The config object
393 Roo.bootstrap.Body = function(config){
395 config = config || {};
397 Roo.bootstrap.Body.superclass.constructor.call(this, config);
398 this.el = Roo.get(config.el ? config.el : document.body );
399 if (this.cls && this.cls.length) {
400 Roo.get(document.body).addClass(this.cls);
404 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
406 is_body : true,// just to make sure it's constructed?
411 onRender : function(ct, position)
413 /* Roo.log("Roo.bootstrap.Body - onRender");
414 if (this.cls && this.cls.length) {
415 Roo.get(document.body).addClass(this.cls);
434 * @class Roo.bootstrap.ButtonGroup
435 * @extends Roo.bootstrap.Component
436 * Bootstrap ButtonGroup class
437 * @cfg {String} size lg | sm | xs (default empty normal)
438 * @cfg {String} align vertical | justified (default none)
439 * @cfg {String} direction up | down (default down)
440 * @cfg {Boolean} toolbar false | true
441 * @cfg {Boolean} btn true | false
446 * @param {Object} config The config object
449 Roo.bootstrap.ButtonGroup = function(config){
450 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
453 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
461 getAutoCreate : function(){
467 cfg.html = this.html || cfg.html;
478 if (['vertical','justified'].indexOf(this.align)!==-1) {
479 cfg.cls = 'btn-group-' + this.align;
481 if (this.align == 'justified') {
482 console.log(this.items);
486 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
487 cfg.cls += ' btn-group-' + this.size;
490 if (this.direction == 'up') {
491 cfg.cls += ' dropup' ;
507 * @class Roo.bootstrap.Button
508 * @extends Roo.bootstrap.Component
509 * Bootstrap Button class
510 * @cfg {String} html The button content
511 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
512 * @cfg {String} size ( lg | sm | xs)
513 * @cfg {String} tag ( a | input | submit)
514 * @cfg {String} href empty or href
515 * @cfg {Boolean} disabled default false;
516 * @cfg {Boolean} isClose default false;
517 * @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)
518 * @cfg {String} badge text for badge
519 * @cfg {String} theme default
520 * @cfg {Boolean} inverse
521 * @cfg {Boolean} toggle
522 * @cfg {String} ontext text for on toggle state
523 * @cfg {String} offtext text for off toggle state
524 * @cfg {Boolean} defaulton
525 * @cfg {Boolean} preventDefault default true
526 * @cfg {Boolean} removeClass remove the standard class..
527 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
530 * Create a new button
531 * @param {Object} config The config object
535 Roo.bootstrap.Button = function(config){
536 Roo.bootstrap.Button.superclass.constructor.call(this, config);
541 * When a butotn is pressed
542 * @param {Roo.bootstrap.Button} this
543 * @param {Roo.EventObject} e
548 * After the button has been toggles
549 * @param {Roo.EventObject} e
550 * @param {boolean} pressed (also available as button.pressed)
556 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
574 preventDefault: true,
583 getAutoCreate : function(){
591 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
592 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
597 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
599 if (this.toggle == true) {
602 cls: 'slider-frame roo-button',
607 'data-off-text':'OFF',
608 cls: 'slider-button',
614 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
615 cfg.cls += ' '+this.weight;
624 cfg["aria-hidden"] = true;
626 cfg.html = "×";
632 if (this.theme==='default') {
633 cfg.cls = 'btn roo-button';
635 //if (this.parentType != 'Navbar') {
636 this.weight = this.weight.length ? this.weight : 'default';
638 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
640 cfg.cls += ' btn-' + this.weight;
642 } else if (this.theme==='glow') {
645 cfg.cls = 'btn-glow roo-button';
647 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
649 cfg.cls += ' ' + this.weight;
655 this.cls += ' inverse';
660 cfg.cls += ' active';
664 cfg.disabled = 'disabled';
668 Roo.log('changing to ul' );
670 this.glyphicon = 'caret';
673 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
675 //gsRoo.log(this.parentType);
676 if (this.parentType === 'Navbar' && !this.parent().bar) {
677 Roo.log('changing to li?');
686 href : this.href || '#'
689 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
690 cfg.cls += ' dropdown';
697 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
699 if (this.glyphicon) {
700 cfg.html = ' ' + cfg.html;
705 cls: 'glyphicon glyphicon-' + this.glyphicon
715 // cfg.cls='btn roo-button';
719 var value = cfg.html;
724 cls: 'glyphicon glyphicon-' + this.glyphicon,
743 cfg.cls += ' dropdown';
744 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
747 if (cfg.tag !== 'a' && this.href !== '') {
748 throw "Tag must be a to set href.";
749 } else if (this.href.length > 0) {
750 cfg.href = this.href;
753 if(this.removeClass){
758 cfg.target = this.target;
763 initEvents: function() {
764 // Roo.log('init events?');
765 // Roo.log(this.el.dom);
768 if (typeof (this.menu) != 'undefined') {
769 this.menu.parentType = this.xtype;
770 this.menu.triggerEl = this.el;
771 this.addxtype(Roo.apply({}, this.menu));
775 if (this.el.hasClass('roo-button')) {
776 this.el.on('click', this.onClick, this);
778 this.el.select('.roo-button').on('click', this.onClick, this);
781 if(this.removeClass){
782 this.el.on('click', this.onClick, this);
785 this.el.enableDisplayMode();
788 onClick : function(e)
795 Roo.log('button on click ');
796 if(this.preventDefault){
799 if (this.pressed === true || this.pressed === false) {
800 this.pressed = !this.pressed;
801 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
802 this.fireEvent('toggle', this, e, this.pressed);
806 this.fireEvent('click', this, e);
810 * Enables this button
814 this.disabled = false;
815 this.el.removeClass('disabled');
819 * Disable this button
823 this.disabled = true;
824 this.el.addClass('disabled');
827 * sets the active state on/off,
828 * @param {Boolean} state (optional) Force a particular state
830 setActive : function(v) {
832 this.el[v ? 'addClass' : 'removeClass']('active');
835 * toggles the current active state
837 toggleActive : function()
839 var active = this.el.hasClass('active');
840 this.setActive(!active);
844 setText : function(str)
846 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
850 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
873 * @class Roo.bootstrap.Column
874 * @extends Roo.bootstrap.Component
875 * Bootstrap Column class
876 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
877 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
878 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
879 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
880 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
881 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
882 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
883 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
886 * @cfg {Boolean} hidden (true|false) hide the element
887 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
888 * @cfg {String} fa (ban|check|...) font awesome icon
889 * @cfg {Number} fasize (1|2|....) font awsome size
891 * @cfg {String} icon (info-sign|check|...) glyphicon name
893 * @cfg {String} html content of column.
896 * Create a new Column
897 * @param {Object} config The config object
900 Roo.bootstrap.Column = function(config){
901 Roo.bootstrap.Column.superclass.constructor.call(this, config);
904 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
922 getAutoCreate : function(){
923 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
931 ['xs','sm','md','lg'].map(function(size){
932 //Roo.log( size + ':' + settings[size]);
934 if (settings[size+'off'] !== false) {
935 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
938 if (settings[size] === false) {
942 if (!settings[size]) { // 0 = hidden
943 cfg.cls += ' hidden-' + size;
946 cfg.cls += ' col-' + size + '-' + settings[size];
951 cfg.cls += ' hidden';
954 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
955 cfg.cls +=' alert alert-' + this.alert;
959 if (this.html.length) {
960 cfg.html = this.html;
964 if (this.fasize > 1) {
965 fasize = ' fa-' + this.fasize + 'x';
967 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
972 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
991 * @class Roo.bootstrap.Container
992 * @extends Roo.bootstrap.Component
993 * Bootstrap Container class
994 * @cfg {Boolean} jumbotron is it a jumbotron element
995 * @cfg {String} html content of element
996 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
997 * @cfg {String} panel (primary|success|info|warning|danger) render as panel - type - primary/success.....
998 * @cfg {String} header content of header (for panel)
999 * @cfg {String} footer content of footer (for panel)
1000 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1001 * @cfg {String} tag (header|aside|section) type of HTML tag.
1002 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1003 * @cfg {String} fa font awesome icon
1004 * @cfg {String} icon (info-sign|check|...) glyphicon name
1005 * @cfg {Boolean} hidden (true|false) hide the element
1006 * @cfg {Boolean} expandable (true|false) default false
1007 * @cfg {Boolean} expanded (true|false) default true
1008 * @cfg {String} rheader contet on the right of header
1009 * @cfg {Boolean} clickable (true|false) default false
1013 * Create a new Container
1014 * @param {Object} config The config object
1017 Roo.bootstrap.Container = function(config){
1018 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1024 * After the panel has been expand
1026 * @param {Roo.bootstrap.Container} this
1031 * After the panel has been collapsed
1033 * @param {Roo.bootstrap.Container} this
1038 * When a element is chick
1039 * @param {Roo.bootstrap.Container} this
1040 * @param {Roo.EventObject} e
1046 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1064 getChildContainer : function() {
1070 if (this.panel.length) {
1071 return this.el.select('.panel-body',true).first();
1078 getAutoCreate : function(){
1081 tag : this.tag || 'div',
1085 if (this.jumbotron) {
1086 cfg.cls = 'jumbotron';
1091 // - this is applied by the parent..
1093 // cfg.cls = this.cls + '';
1096 if (this.sticky.length) {
1098 var bd = Roo.get(document.body);
1099 if (!bd.hasClass('bootstrap-sticky')) {
1100 bd.addClass('bootstrap-sticky');
1101 Roo.select('html',true).setStyle('height', '100%');
1104 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1108 if (this.well.length) {
1109 switch (this.well) {
1112 cfg.cls +=' well well-' +this.well;
1121 cfg.cls += ' hidden';
1125 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1126 cfg.cls +=' alert alert-' + this.alert;
1131 if (this.panel.length) {
1132 cfg.cls += ' panel panel-' + this.panel;
1134 if (this.header.length) {
1138 if(this.expandable){
1140 cfg.cls = cfg.cls + ' expandable';
1144 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1152 cls : 'panel-title',
1153 html : (this.expandable ? ' ' : '') + this.header
1157 cls: 'panel-header-right',
1163 cls : 'panel-heading',
1164 style : this.expandable ? 'cursor: pointer' : '',
1172 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1177 if (this.footer.length) {
1179 cls : 'panel-footer',
1188 body.html = this.html || cfg.html;
1189 // prefix with the icons..
1191 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1194 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1199 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1200 cfg.cls = 'container';
1206 initEvents: function()
1208 if(this.expandable){
1209 var headerEl = this.headerEl();
1212 headerEl.on('click', this.onToggleClick, this);
1217 this.el.on('click', this.onClick, this);
1222 onToggleClick : function()
1224 var headerEl = this.headerEl();
1240 if(this.fireEvent('expand', this)) {
1242 this.expanded = true;
1244 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1246 this.el.select('.panel-body',true).first().removeClass('hide');
1248 var toggleEl = this.toggleEl();
1254 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1259 collapse : function()
1261 if(this.fireEvent('collapse', this)) {
1263 this.expanded = false;
1265 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1266 this.el.select('.panel-body',true).first().addClass('hide');
1268 var toggleEl = this.toggleEl();
1274 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1278 toggleEl : function()
1280 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1284 return this.el.select('.panel-heading .fa',true).first();
1287 headerEl : function()
1289 if(!this.el || !this.panel.length || !this.header.length){
1293 return this.el.select('.panel-heading',true).first()
1298 if(!this.el || !this.panel.length){
1302 return this.el.select('.panel-body',true).first()
1305 titleEl : function()
1307 if(!this.el || !this.panel.length || !this.header.length){
1311 return this.el.select('.panel-title',true).first();
1314 setTitle : function(v)
1316 var titleEl = this.titleEl();
1322 titleEl.dom.innerHTML = v;
1325 getTitle : function()
1328 var titleEl = this.titleEl();
1334 return titleEl.dom.innerHTML;
1337 setRightTitle : function(v)
1339 var t = this.el.select('.panel-header-right',true).first();
1345 t.dom.innerHTML = v;
1348 onClick : function(e)
1352 this.fireEvent('click', this, e);
1366 * @class Roo.bootstrap.Img
1367 * @extends Roo.bootstrap.Component
1368 * Bootstrap Img class
1369 * @cfg {Boolean} imgResponsive false | true
1370 * @cfg {String} border rounded | circle | thumbnail
1371 * @cfg {String} src image source
1372 * @cfg {String} alt image alternative text
1373 * @cfg {String} href a tag href
1374 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1375 * @cfg {String} xsUrl xs image source
1376 * @cfg {String} smUrl sm image source
1377 * @cfg {String} mdUrl md image source
1378 * @cfg {String} lgUrl lg image source
1381 * Create a new Input
1382 * @param {Object} config The config object
1385 Roo.bootstrap.Img = function(config){
1386 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1392 * The img click event for the img.
1393 * @param {Roo.EventObject} e
1399 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1401 imgResponsive: true,
1411 getAutoCreate : function()
1413 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1414 return this.createSingleImg();
1419 cls: 'roo-image-responsive-group',
1424 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1426 if(!_this[size + 'Url']){
1432 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1433 html: _this.html || cfg.html,
1434 src: _this[size + 'Url']
1437 img.cls += ' roo-image-responsive-' + size;
1439 var s = ['xs', 'sm', 'md', 'lg'];
1441 s.splice(s.indexOf(size), 1);
1443 Roo.each(s, function(ss){
1444 img.cls += ' hidden-' + ss;
1447 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1448 cfg.cls += ' img-' + _this.border;
1452 cfg.alt = _this.alt;
1465 a.target = _this.target;
1469 cfg.cn.push((_this.href) ? a : img);
1476 createSingleImg : function()
1480 cls: (this.imgResponsive) ? 'img-responsive' : '',
1482 src : 'about:blank' // just incase src get's set to undefined?!?
1485 cfg.html = this.html || cfg.html;
1487 cfg.src = this.src || cfg.src;
1489 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1490 cfg.cls += ' img-' + this.border;
1507 a.target = this.target;
1512 return (this.href) ? a : cfg;
1515 initEvents: function()
1518 this.el.on('click', this.onClick, this);
1523 onClick : function(e)
1525 Roo.log('img onclick');
1526 this.fireEvent('click', this, e);
1529 * Sets the url of the image - used to update it
1530 * @param {String} url the url of the image
1533 setSrc : function(url)
1537 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1538 this.el.dom.src = url;
1542 this.el.select('img', true).first().dom.src = url;
1558 * @class Roo.bootstrap.Link
1559 * @extends Roo.bootstrap.Component
1560 * Bootstrap Link Class
1561 * @cfg {String} alt image alternative text
1562 * @cfg {String} href a tag href
1563 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1564 * @cfg {String} html the content of the link.
1565 * @cfg {String} anchor name for the anchor link
1566 * @cfg {String} fa - favicon
1568 * @cfg {Boolean} preventDefault (true | false) default false
1572 * Create a new Input
1573 * @param {Object} config The config object
1576 Roo.bootstrap.Link = function(config){
1577 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1583 * The img click event for the img.
1584 * @param {Roo.EventObject} e
1590 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1594 preventDefault: false,
1600 getAutoCreate : function()
1602 var html = this.html || '';
1604 if (this.fa !== false) {
1605 html = '<i class="fa fa-' + this.fa + '"></i>';
1610 // anchor's do not require html/href...
1611 if (this.anchor === false) {
1613 cfg.href = this.href || '#';
1615 cfg.name = this.anchor;
1616 if (this.html !== false || this.fa !== false) {
1619 if (this.href !== false) {
1620 cfg.href = this.href;
1624 if(this.alt !== false){
1629 if(this.target !== false) {
1630 cfg.target = this.target;
1636 initEvents: function() {
1638 if(!this.href || this.preventDefault){
1639 this.el.on('click', this.onClick, this);
1643 onClick : function(e)
1645 if(this.preventDefault){
1648 //Roo.log('img onclick');
1649 this.fireEvent('click', this, e);
1662 * @class Roo.bootstrap.Header
1663 * @extends Roo.bootstrap.Component
1664 * Bootstrap Header class
1665 * @cfg {String} html content of header
1666 * @cfg {Number} level (1|2|3|4|5|6) default 1
1669 * Create a new Header
1670 * @param {Object} config The config object
1674 Roo.bootstrap.Header = function(config){
1675 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1678 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1686 getAutoCreate : function(){
1691 tag: 'h' + (1 *this.level),
1692 html: this.html || ''
1704 * Ext JS Library 1.1.1
1705 * Copyright(c) 2006-2007, Ext JS, LLC.
1707 * Originally Released Under LGPL - original licence link has changed is not relivant.
1710 * <script type="text/javascript">
1714 * @class Roo.bootstrap.MenuMgr
1715 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1718 Roo.bootstrap.MenuMgr = function(){
1719 var menus, active, groups = {}, attached = false, lastShow = new Date();
1721 // private - called when first menu is created
1724 active = new Roo.util.MixedCollection();
1725 Roo.get(document).addKeyListener(27, function(){
1726 if(active.length > 0){
1734 if(active && active.length > 0){
1735 var c = active.clone();
1745 if(active.length < 1){
1746 Roo.get(document).un("mouseup", onMouseDown);
1754 var last = active.last();
1755 lastShow = new Date();
1758 Roo.get(document).on("mouseup", onMouseDown);
1763 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1764 m.parentMenu.activeChild = m;
1765 }else if(last && last.isVisible()){
1766 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1771 function onBeforeHide(m){
1773 m.activeChild.hide();
1775 if(m.autoHideTimer){
1776 clearTimeout(m.autoHideTimer);
1777 delete m.autoHideTimer;
1782 function onBeforeShow(m){
1783 var pm = m.parentMenu;
1784 if(!pm && !m.allowOtherMenus){
1786 }else if(pm && pm.activeChild && active != m){
1787 pm.activeChild.hide();
1791 // private this should really trigger on mouseup..
1792 function onMouseDown(e){
1793 Roo.log("on Mouse Up");
1795 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1796 Roo.log("MenuManager hideAll");
1805 function onBeforeCheck(mi, state){
1807 var g = groups[mi.group];
1808 for(var i = 0, l = g.length; i < l; i++){
1810 g[i].setChecked(false);
1819 * Hides all menus that are currently visible
1821 hideAll : function(){
1826 register : function(menu){
1830 menus[menu.id] = menu;
1831 menu.on("beforehide", onBeforeHide);
1832 menu.on("hide", onHide);
1833 menu.on("beforeshow", onBeforeShow);
1834 menu.on("show", onShow);
1836 if(g && menu.events["checkchange"]){
1840 groups[g].push(menu);
1841 menu.on("checkchange", onCheck);
1846 * Returns a {@link Roo.menu.Menu} object
1847 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1848 * be used to generate and return a new Menu instance.
1850 get : function(menu){
1851 if(typeof menu == "string"){ // menu id
1853 }else if(menu.events){ // menu instance
1856 /*else if(typeof menu.length == 'number'){ // array of menu items?
1857 return new Roo.bootstrap.Menu({items:menu});
1858 }else{ // otherwise, must be a config
1859 return new Roo.bootstrap.Menu(menu);
1866 unregister : function(menu){
1867 delete menus[menu.id];
1868 menu.un("beforehide", onBeforeHide);
1869 menu.un("hide", onHide);
1870 menu.un("beforeshow", onBeforeShow);
1871 menu.un("show", onShow);
1873 if(g && menu.events["checkchange"]){
1874 groups[g].remove(menu);
1875 menu.un("checkchange", onCheck);
1880 registerCheckable : function(menuItem){
1881 var g = menuItem.group;
1886 groups[g].push(menuItem);
1887 menuItem.on("beforecheckchange", onBeforeCheck);
1892 unregisterCheckable : function(menuItem){
1893 var g = menuItem.group;
1895 groups[g].remove(menuItem);
1896 menuItem.un("beforecheckchange", onBeforeCheck);
1908 * @class Roo.bootstrap.Menu
1909 * @extends Roo.bootstrap.Component
1910 * Bootstrap Menu class - container for MenuItems
1911 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1912 * @cfg {bool} hidden if the menu should be hidden when rendered.
1913 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1914 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1918 * @param {Object} config The config object
1922 Roo.bootstrap.Menu = function(config){
1923 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1924 if (this.registerMenu && this.type != 'treeview') {
1925 Roo.bootstrap.MenuMgr.register(this);
1930 * Fires before this menu is displayed
1931 * @param {Roo.menu.Menu} this
1936 * Fires before this menu is hidden
1937 * @param {Roo.menu.Menu} this
1942 * Fires after this menu is displayed
1943 * @param {Roo.menu.Menu} this
1948 * Fires after this menu is hidden
1949 * @param {Roo.menu.Menu} this
1954 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1955 * @param {Roo.menu.Menu} this
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1957 * @param {Roo.EventObject} e
1962 * Fires when the mouse is hovering over this menu
1963 * @param {Roo.menu.Menu} this
1964 * @param {Roo.EventObject} e
1965 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1970 * Fires when the mouse exits this menu
1971 * @param {Roo.menu.Menu} this
1972 * @param {Roo.EventObject} e
1973 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1978 * Fires when a menu item contained in this menu is clicked
1979 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1980 * @param {Roo.EventObject} e
1984 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1987 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1991 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1994 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1996 registerMenu : true,
1998 menuItems :false, // stores the menu items..
2008 getChildContainer : function() {
2012 getAutoCreate : function(){
2014 //if (['right'].indexOf(this.align)!==-1) {
2015 // cfg.cn[1].cls += ' pull-right'
2021 cls : 'dropdown-menu' ,
2022 style : 'z-index:1000'
2026 if (this.type === 'submenu') {
2027 cfg.cls = 'submenu active';
2029 if (this.type === 'treeview') {
2030 cfg.cls = 'treeview-menu';
2035 initEvents : function() {
2037 // Roo.log("ADD event");
2038 // Roo.log(this.triggerEl.dom);
2040 this.triggerEl.on('click', this.onTriggerClick, this);
2042 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2044 this.triggerEl.addClass('dropdown-toggle');
2047 this.el.on('touchstart' , this.onTouch, this);
2049 this.el.on('click' , this.onClick, this);
2051 this.el.on("mouseover", this.onMouseOver, this);
2052 this.el.on("mouseout", this.onMouseOut, this);
2056 findTargetItem : function(e)
2058 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2062 //Roo.log(t); Roo.log(t.id);
2064 //Roo.log(this.menuitems);
2065 return this.menuitems.get(t.id);
2067 //return this.items.get(t.menuItemId);
2073 onTouch : function(e)
2075 Roo.log("menu.onTouch");
2076 //e.stopEvent(); this make the user popdown broken
2080 onClick : function(e)
2082 Roo.log("menu.onClick");
2084 var t = this.findTargetItem(e);
2085 if(!t || t.isContainer){
2090 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2091 if(t == this.activeItem && t.shouldDeactivate(e)){
2092 this.activeItem.deactivate();
2093 delete this.activeItem;
2097 this.setActiveItem(t, true);
2105 Roo.log('pass click event');
2109 this.fireEvent("click", this, t, e);
2113 (function() { _this.hide(); }).defer(100);
2116 onMouseOver : function(e){
2117 var t = this.findTargetItem(e);
2120 // if(t.canActivate && !t.disabled){
2121 // this.setActiveItem(t, true);
2125 this.fireEvent("mouseover", this, e, t);
2127 isVisible : function(){
2128 return !this.hidden;
2130 onMouseOut : function(e){
2131 var t = this.findTargetItem(e);
2134 // if(t == this.activeItem && t.shouldDeactivate(e)){
2135 // this.activeItem.deactivate();
2136 // delete this.activeItem;
2139 this.fireEvent("mouseout", this, e, t);
2144 * Displays this menu relative to another element
2145 * @param {String/HTMLElement/Roo.Element} element The element to align to
2146 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2147 * the element (defaults to this.defaultAlign)
2148 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2150 show : function(el, pos, parentMenu){
2151 this.parentMenu = parentMenu;
2155 this.fireEvent("beforeshow", this);
2156 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2159 * Displays this menu at a specific xy position
2160 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2161 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2163 showAt : function(xy, parentMenu, /* private: */_e){
2164 this.parentMenu = parentMenu;
2169 this.fireEvent("beforeshow", this);
2170 //xy = this.el.adjustForConstraints(xy);
2174 this.hideMenuItems();
2175 this.hidden = false;
2176 this.triggerEl.addClass('open');
2178 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2179 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2182 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2187 this.fireEvent("show", this);
2193 this.doFocus.defer(50, this);
2197 doFocus : function(){
2199 this.focusEl.focus();
2204 * Hides this menu and optionally all parent menus
2205 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2207 hide : function(deep)
2210 this.hideMenuItems();
2211 if(this.el && this.isVisible()){
2212 this.fireEvent("beforehide", this);
2213 if(this.activeItem){
2214 this.activeItem.deactivate();
2215 this.activeItem = null;
2217 this.triggerEl.removeClass('open');;
2219 this.fireEvent("hide", this);
2221 if(deep === true && this.parentMenu){
2222 this.parentMenu.hide(true);
2226 onTriggerClick : function(e)
2228 Roo.log('trigger click');
2230 var target = e.getTarget();
2232 Roo.log(target.nodeName.toLowerCase());
2234 if(target.nodeName.toLowerCase() === 'i'){
2240 onTriggerPress : function(e)
2242 Roo.log('trigger press');
2243 //Roo.log(e.getTarget());
2244 // Roo.log(this.triggerEl.dom);
2246 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2247 var pel = Roo.get(e.getTarget());
2248 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2249 Roo.log('is treeview or dropdown?');
2253 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2257 if (this.isVisible()) {
2262 this.show(this.triggerEl, false, false);
2265 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2272 hideMenuItems : function()
2274 Roo.log("hide Menu Items");
2278 //$(backdrop).remove()
2279 this.el.select('.open',true).each(function(aa) {
2281 aa.removeClass('open');
2282 //var parent = getParent($(this))
2283 //var relatedTarget = { relatedTarget: this }
2285 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2286 //if (e.isDefaultPrevented()) return
2287 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2290 addxtypeChild : function (tree, cntr) {
2291 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2293 this.menuitems.add(comp);
2314 * @class Roo.bootstrap.MenuItem
2315 * @extends Roo.bootstrap.Component
2316 * Bootstrap MenuItem class
2317 * @cfg {String} html the menu label
2318 * @cfg {String} href the link
2319 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2320 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2321 * @cfg {Boolean} active used on sidebars to highlight active itesm
2322 * @cfg {String} fa favicon to show on left of menu item.
2323 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2327 * Create a new MenuItem
2328 * @param {Object} config The config object
2332 Roo.bootstrap.MenuItem = function(config){
2333 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2338 * The raw click event for the entire grid.
2339 * @param {Roo.bootstrap.MenuItem} this
2340 * @param {Roo.EventObject} e
2346 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2350 preventDefault: false,
2351 isContainer : false,
2355 getAutoCreate : function(){
2357 if(this.isContainer){
2360 cls: 'dropdown-menu-item'
2374 if (this.fa !== false) {
2377 cls : 'fa fa-' + this.fa
2386 cls: 'dropdown-menu-item',
2389 if (this.parent().type == 'treeview') {
2390 cfg.cls = 'treeview-menu';
2393 cfg.cls += ' active';
2398 anc.href = this.href || cfg.cn[0].href ;
2399 ctag.html = this.html || cfg.cn[0].html ;
2403 initEvents: function()
2405 if (this.parent().type == 'treeview') {
2406 this.el.select('a').on('click', this.onClick, this);
2409 this.menu.parentType = this.xtype;
2410 this.menu.triggerEl = this.el;
2411 this.menu = this.addxtype(Roo.apply({}, this.menu));
2415 onClick : function(e)
2417 Roo.log('item on click ');
2419 if(this.preventDefault){
2422 //this.parent().hideMenuItems();
2424 this.fireEvent('click', this, e);
2443 * @class Roo.bootstrap.MenuSeparator
2444 * @extends Roo.bootstrap.Component
2445 * Bootstrap MenuSeparator class
2448 * Create a new MenuItem
2449 * @param {Object} config The config object
2453 Roo.bootstrap.MenuSeparator = function(config){
2454 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2457 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2459 getAutoCreate : function(){
2478 * @class Roo.bootstrap.Modal
2479 * @extends Roo.bootstrap.Component
2480 * Bootstrap Modal class
2481 * @cfg {String} title Title of dialog
2482 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2483 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2484 * @cfg {Boolean} specificTitle default false
2485 * @cfg {Array} buttons Array of buttons or standard button set..
2486 * @cfg {String} buttonPosition (left|right|center) default right
2487 * @cfg {Boolean} animate default true
2488 * @cfg {Boolean} allow_close default true
2489 * @cfg {Boolean} fitwindow default false
2490 * @cfg {String} size (sm|lg) default empty
2494 * Create a new Modal Dialog
2495 * @param {Object} config The config object
2498 Roo.bootstrap.Modal = function(config){
2499 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2504 * The raw btnclick event for the button
2505 * @param {Roo.EventObject} e
2510 * Fire when dialog resize
2511 * @param {Roo.bootstrap.Modal} this
2512 * @param {Roo.EventObject} e
2516 this.buttons = this.buttons || [];
2519 this.tmpl = Roo.factory(this.tmpl);
2524 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2526 title : 'test dialog',
2536 specificTitle: false,
2538 buttonPosition: 'right',
2557 onRender : function(ct, position)
2559 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2562 var cfg = Roo.apply({}, this.getAutoCreate());
2565 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2567 //if (!cfg.name.length) {
2571 cfg.cls += ' ' + this.cls;
2574 cfg.style = this.style;
2576 this.el = Roo.get(document.body).createChild(cfg, position);
2578 //var type = this.el.dom.type;
2581 if(this.tabIndex !== undefined){
2582 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2585 this.dialogEl = this.el.select('.modal-dialog',true).first();
2586 this.bodyEl = this.el.select('.modal-body',true).first();
2587 this.closeEl = this.el.select('.modal-header .close', true).first();
2588 this.headerEl = this.el.select('.modal-header',true).first();
2589 this.titleEl = this.el.select('.modal-title',true).first();
2590 this.footerEl = this.el.select('.modal-footer',true).first();
2592 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2593 this.maskEl.enableDisplayMode("block");
2595 //this.el.addClass("x-dlg-modal");
2597 if (this.buttons.length) {
2598 Roo.each(this.buttons, function(bb) {
2599 var b = Roo.apply({}, bb);
2600 b.xns = b.xns || Roo.bootstrap;
2601 b.xtype = b.xtype || 'Button';
2602 if (typeof(b.listeners) == 'undefined') {
2603 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2606 var btn = Roo.factory(b);
2608 btn.render(this.el.select('.modal-footer div').first());
2612 // render the children.
2615 if(typeof(this.items) != 'undefined'){
2616 var items = this.items;
2619 for(var i =0;i < items.length;i++) {
2620 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2624 this.items = nitems;
2626 // where are these used - they used to be body/close/footer
2630 //this.el.addClass([this.fieldClass, this.cls]);
2634 getAutoCreate : function(){
2639 html : this.html || ''
2644 cls : 'modal-title',
2648 if(this.specificTitle){
2654 if (this.allow_close) {
2666 if(this.size.length){
2667 size = 'modal-' + this.size;
2672 style : 'display: none',
2675 cls: "modal-dialog " + size,
2678 cls : "modal-content",
2681 cls : 'modal-header',
2686 cls : 'modal-footer',
2690 cls: 'btn-' + this.buttonPosition
2707 modal.cls += ' fade';
2713 getChildContainer : function() {
2718 getButtonContainer : function() {
2719 return this.el.select('.modal-footer div',true).first();
2722 initEvents : function()
2724 if (this.allow_close) {
2725 this.closeEl.on('click', this.hide, this);
2727 Roo.EventManager.onWindowResize(this.resize, this, true);
2734 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2735 if (this.fitwindow) {
2736 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2737 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2742 setSize : function(w,h)
2752 if (!this.rendered) {
2756 this.el.setStyle('display', 'block');
2758 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2761 this.el.addClass('in');
2764 this.el.addClass('in');
2768 // not sure how we can show data in here..
2770 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2773 Roo.get(document.body).addClass("x-body-masked");
2775 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2776 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2781 this.fireEvent('show', this);
2783 // set zindex here - otherwise it appears to be ignored...
2784 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2787 this.items.forEach( function(e) {
2788 e.layout ? e.layout() : false;
2796 if(this.fireEvent("beforehide", this) !== false){
2798 Roo.get(document.body).removeClass("x-body-masked");
2799 this.el.removeClass('in');
2800 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2802 if(this.animate){ // why
2804 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2806 this.el.setStyle('display', 'none');
2808 this.fireEvent('hide', this);
2812 addButton : function(str, cb)
2816 var b = Roo.apply({}, { html : str } );
2817 b.xns = b.xns || Roo.bootstrap;
2818 b.xtype = b.xtype || 'Button';
2819 if (typeof(b.listeners) == 'undefined') {
2820 b.listeners = { click : cb.createDelegate(this) };
2823 var btn = Roo.factory(b);
2825 btn.render(this.el.select('.modal-footer div').first());
2831 setDefaultButton : function(btn)
2833 //this.el.select('.modal-footer').()
2837 resizeTo: function(w,h)
2841 this.dialogEl.setWidth(w);
2842 if (this.diff === false) {
2843 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2846 this.bodyEl.setHeight(h-this.diff);
2848 this.fireEvent('resize', this);
2851 setContentSize : function(w, h)
2855 onButtonClick: function(btn,e)
2858 this.fireEvent('btnclick', btn.name, e);
2861 * Set the title of the Dialog
2862 * @param {String} str new Title
2864 setTitle: function(str) {
2865 this.titleEl.dom.innerHTML = str;
2868 * Set the body of the Dialog
2869 * @param {String} str new Title
2871 setBody: function(str) {
2872 this.bodyEl.dom.innerHTML = str;
2875 * Set the body of the Dialog using the template
2876 * @param {Obj} data - apply this data to the template and replace the body contents.
2878 applyBody: function(obj)
2881 Roo.log("Error - using apply Body without a template");
2884 this.tmpl.overwrite(this.bodyEl, obj);
2890 Roo.apply(Roo.bootstrap.Modal, {
2892 * Button config that displays a single OK button
2901 * Button config that displays Yes and No buttons
2917 * Button config that displays OK and Cancel buttons
2932 * Button config that displays Yes, No and Cancel buttons
2956 * messagebox - can be used as a replace
2960 * @class Roo.MessageBox
2961 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2965 Roo.Msg.alert('Status', 'Changes saved successfully.');
2967 // Prompt for user data:
2968 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2970 // process text value...
2974 // Show a dialog using config options:
2976 title:'Save Changes?',
2977 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2978 buttons: Roo.Msg.YESNOCANCEL,
2985 Roo.bootstrap.MessageBox = function(){
2986 var dlg, opt, mask, waitTimer;
2987 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2988 var buttons, activeTextEl, bwidth;
2992 var handleButton = function(button){
2994 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2998 var handleHide = function(){
3000 dlg.el.removeClass(opt.cls);
3003 // Roo.TaskMgr.stop(waitTimer);
3004 // waitTimer = null;
3009 var updateButtons = function(b){
3012 buttons["ok"].hide();
3013 buttons["cancel"].hide();
3014 buttons["yes"].hide();
3015 buttons["no"].hide();
3016 //dlg.footer.dom.style.display = 'none';
3019 dlg.footerEl.dom.style.display = '';
3020 for(var k in buttons){
3021 if(typeof buttons[k] != "function"){
3024 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3025 width += buttons[k].el.getWidth()+15;
3035 var handleEsc = function(d, k, e){
3036 if(opt && opt.closable !== false){
3046 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3047 * @return {Roo.BasicDialog} The BasicDialog element
3049 getDialog : function(){
3051 dlg = new Roo.bootstrap.Modal( {
3054 //constraintoviewport:false,
3056 //collapsible : false,
3061 //buttonAlign:"center",
3062 closeClick : function(){
3063 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3066 handleButton("cancel");
3071 dlg.on("hide", handleHide);
3073 //dlg.addKeyListener(27, handleEsc);
3075 this.buttons = buttons;
3076 var bt = this.buttonText;
3077 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3078 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3079 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3080 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3082 bodyEl = dlg.bodyEl.createChild({
3084 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3085 '<textarea class="roo-mb-textarea"></textarea>' +
3086 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3088 msgEl = bodyEl.dom.firstChild;
3089 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3090 textboxEl.enableDisplayMode();
3091 textboxEl.addKeyListener([10,13], function(){
3092 if(dlg.isVisible() && opt && opt.buttons){
3095 }else if(opt.buttons.yes){
3096 handleButton("yes");
3100 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3101 textareaEl.enableDisplayMode();
3102 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3103 progressEl.enableDisplayMode();
3105 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3106 //var pf = progressEl.dom.firstChild;
3108 //pp = Roo.get(pf.firstChild);
3109 //pp.setHeight(pf.offsetHeight);
3117 * Updates the message box body text
3118 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3119 * the XHTML-compliant non-breaking space character '&#160;')
3120 * @return {Roo.MessageBox} This message box
3122 updateText : function(text)
3124 if(!dlg.isVisible() && !opt.width){
3125 dlg.dialogEl.setWidth(this.maxWidth);
3126 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3128 msgEl.innerHTML = text || ' ';
3130 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3131 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3133 Math.min(opt.width || cw , this.maxWidth),
3134 Math.max(opt.minWidth || this.minWidth, bwidth)
3137 activeTextEl.setWidth(w);
3139 if(dlg.isVisible()){
3140 dlg.fixedcenter = false;
3142 // to big, make it scroll. = But as usual stupid IE does not support
3145 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3146 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3147 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3149 bodyEl.dom.style.height = '';
3150 bodyEl.dom.style.overflowY = '';
3153 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3155 bodyEl.dom.style.overflowX = '';
3158 dlg.setContentSize(w, bodyEl.getHeight());
3159 if(dlg.isVisible()){
3160 dlg.fixedcenter = true;
3166 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3167 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3168 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3169 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3170 * @return {Roo.MessageBox} This message box
3172 updateProgress : function(value, text){
3174 this.updateText(text);
3176 if (pp) { // weird bug on my firefox - for some reason this is not defined
3177 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3183 * Returns true if the message box is currently displayed
3184 * @return {Boolean} True if the message box is visible, else false
3186 isVisible : function(){
3187 return dlg && dlg.isVisible();
3191 * Hides the message box if it is displayed
3194 if(this.isVisible()){
3200 * Displays a new message box, or reinitializes an existing message box, based on the config options
3201 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3202 * The following config object properties are supported:
3204 Property Type Description
3205 ---------- --------------- ------------------------------------------------------------------------------------
3206 animEl String/Element An id or Element from which the message box should animate as it opens and
3207 closes (defaults to undefined)
3208 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3209 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3210 closable Boolean False to hide the top-right close button (defaults to true). Note that
3211 progress and wait dialogs will ignore this property and always hide the
3212 close button as they can only be closed programmatically.
3213 cls String A custom CSS class to apply to the message box element
3214 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3215 displayed (defaults to 75)
3216 fn Function A callback function to execute after closing the dialog. The arguments to the
3217 function will be btn (the name of the button that was clicked, if applicable,
3218 e.g. "ok"), and text (the value of the active text field, if applicable).
3219 Progress and wait dialogs will ignore this option since they do not respond to
3220 user actions and can only be closed programmatically, so any required function
3221 should be called by the same code after it closes the dialog.
3222 icon String A CSS class that provides a background image to be used as an icon for
3223 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3224 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3225 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3226 modal Boolean False to allow user interaction with the page while the message box is
3227 displayed (defaults to true)
3228 msg String A string that will replace the existing message box body text (defaults
3229 to the XHTML-compliant non-breaking space character ' ')
3230 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3231 progress Boolean True to display a progress bar (defaults to false)
3232 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3233 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3234 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3235 title String The title text
3236 value String The string value to set into the active textbox element if displayed
3237 wait Boolean True to display a progress bar (defaults to false)
3238 width Number The width of the dialog in pixels
3245 msg: 'Please enter your address:',
3247 buttons: Roo.MessageBox.OKCANCEL,
3250 animEl: 'addAddressBtn'
3253 * @param {Object} config Configuration options
3254 * @return {Roo.MessageBox} This message box
3256 show : function(options)
3259 // this causes nightmares if you show one dialog after another
3260 // especially on callbacks..
3262 if(this.isVisible()){
3265 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3266 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3267 Roo.log("New Dialog Message:" + options.msg )
3268 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3269 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3272 var d = this.getDialog();
3274 d.setTitle(opt.title || " ");
3275 d.closeEl.setDisplayed(opt.closable !== false);
3276 activeTextEl = textboxEl;
3277 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3282 textareaEl.setHeight(typeof opt.multiline == "number" ?
3283 opt.multiline : this.defaultTextHeight);
3284 activeTextEl = textareaEl;
3293 progressEl.setDisplayed(opt.progress === true);
3294 this.updateProgress(0);
3295 activeTextEl.dom.value = opt.value || "";
3297 dlg.setDefaultButton(activeTextEl);
3299 var bs = opt.buttons;
3303 }else if(bs && bs.yes){
3304 db = buttons["yes"];
3306 dlg.setDefaultButton(db);
3308 bwidth = updateButtons(opt.buttons);
3309 this.updateText(opt.msg);
3311 d.el.addClass(opt.cls);
3313 d.proxyDrag = opt.proxyDrag === true;
3314 d.modal = opt.modal !== false;
3315 d.mask = opt.modal !== false ? mask : false;
3317 // force it to the end of the z-index stack so it gets a cursor in FF
3318 document.body.appendChild(dlg.el.dom);
3319 d.animateTarget = null;
3320 d.show(options.animEl);
3326 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3327 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3328 * and closing the message box when the process is complete.
3329 * @param {String} title The title bar text
3330 * @param {String} msg The message box body text
3331 * @return {Roo.MessageBox} This message box
3333 progress : function(title, msg){
3340 minWidth: this.minProgressWidth,
3347 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3348 * If a callback function is passed it will be called after the user clicks the button, and the
3349 * id of the button that was clicked will be passed as the only parameter to the callback
3350 * (could also be the top-right close button).
3351 * @param {String} title The title bar text
3352 * @param {String} msg The message box body text
3353 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3354 * @param {Object} scope (optional) The scope of the callback function
3355 * @return {Roo.MessageBox} This message box
3357 alert : function(title, msg, fn, scope)
3372 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3373 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3374 * You are responsible for closing the message box when the process is complete.
3375 * @param {String} msg The message box body text
3376 * @param {String} title (optional) The title bar text
3377 * @return {Roo.MessageBox} This message box
3379 wait : function(msg, title){
3390 waitTimer = Roo.TaskMgr.start({
3392 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3400 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3401 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3402 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3403 * @param {String} title The title bar text
3404 * @param {String} msg The message box body text
3405 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3406 * @param {Object} scope (optional) The scope of the callback function
3407 * @return {Roo.MessageBox} This message box
3409 confirm : function(title, msg, fn, scope){
3413 buttons: this.YESNO,
3422 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3423 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3424 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3425 * (could also be the top-right close button) and the text that was entered will be passed as the two
3426 * parameters to the callback.
3427 * @param {String} title The title bar text
3428 * @param {String} msg The message box body text
3429 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3430 * @param {Object} scope (optional) The scope of the callback function
3431 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3432 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3433 * @return {Roo.MessageBox} This message box
3435 prompt : function(title, msg, fn, scope, multiline){
3439 buttons: this.OKCANCEL,
3444 multiline: multiline,
3451 * Button config that displays a single OK button
3456 * Button config that displays Yes and No buttons
3459 YESNO : {yes:true, no:true},
3461 * Button config that displays OK and Cancel buttons
3464 OKCANCEL : {ok:true, cancel:true},
3466 * Button config that displays Yes, No and Cancel buttons
3469 YESNOCANCEL : {yes:true, no:true, cancel:true},
3472 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3475 defaultTextHeight : 75,
3477 * The maximum width in pixels of the message box (defaults to 600)
3482 * The minimum width in pixels of the message box (defaults to 100)
3487 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3488 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3491 minProgressWidth : 250,
3493 * An object containing the default button text strings that can be overriden for localized language support.
3494 * Supported properties are: ok, cancel, yes and no.
3495 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3508 * Shorthand for {@link Roo.MessageBox}
3510 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3511 Roo.Msg = Roo.Msg || Roo.MessageBox;
3520 * @class Roo.bootstrap.Navbar
3521 * @extends Roo.bootstrap.Component
3522 * Bootstrap Navbar class
3525 * Create a new Navbar
3526 * @param {Object} config The config object
3530 Roo.bootstrap.Navbar = function(config){
3531 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3535 * @event beforetoggle
3536 * Fire before toggle the menu
3537 * @param {Roo.EventObject} e
3539 "beforetoggle" : true
3543 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3552 getAutoCreate : function(){
3555 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3559 initEvents :function ()
3561 //Roo.log(this.el.select('.navbar-toggle',true));
3562 this.el.select('.navbar-toggle',true).on('click', function() {
3563 if(this.fireEvent('beforetoggle', this) !== false){
3564 this.el.select('.navbar-collapse',true).toggleClass('in');
3574 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3576 var size = this.el.getSize();
3577 this.maskEl.setSize(size.width, size.height);
3578 this.maskEl.enableDisplayMode("block");
3587 getChildContainer : function()
3589 if (this.el.select('.collapse').getCount()) {
3590 return this.el.select('.collapse',true).first();
3623 * @class Roo.bootstrap.NavSimplebar
3624 * @extends Roo.bootstrap.Navbar
3625 * Bootstrap Sidebar class
3627 * @cfg {Boolean} inverse is inverted color
3629 * @cfg {String} type (nav | pills | tabs)
3630 * @cfg {Boolean} arrangement stacked | justified
3631 * @cfg {String} align (left | right) alignment
3633 * @cfg {Boolean} main (true|false) main nav bar? default false
3634 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3636 * @cfg {String} tag (header|footer|nav|div) default is nav
3642 * Create a new Sidebar
3643 * @param {Object} config The config object
3647 Roo.bootstrap.NavSimplebar = function(config){
3648 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3651 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3667 getAutoCreate : function(){
3671 tag : this.tag || 'div',
3684 this.type = this.type || 'nav';
3685 if (['tabs','pills'].indexOf(this.type)!==-1) {
3686 cfg.cn[0].cls += ' nav-' + this.type
3690 if (this.type!=='nav') {
3691 Roo.log('nav type must be nav/tabs/pills')
3693 cfg.cn[0].cls += ' navbar-nav'
3699 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3700 cfg.cn[0].cls += ' nav-' + this.arrangement;
3704 if (this.align === 'right') {
3705 cfg.cn[0].cls += ' navbar-right';
3709 cfg.cls += ' navbar-inverse';
3736 * @class Roo.bootstrap.NavHeaderbar
3737 * @extends Roo.bootstrap.NavSimplebar
3738 * Bootstrap Sidebar class
3740 * @cfg {String} brand what is brand
3741 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3742 * @cfg {String} brand_href href of the brand
3743 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3744 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3745 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3746 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3749 * Create a new Sidebar
3750 * @param {Object} config The config object
3754 Roo.bootstrap.NavHeaderbar = function(config){
3755 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3759 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3766 desktopCenter : false,
3769 getAutoCreate : function(){
3772 tag: this.nav || 'nav',
3779 if (this.desktopCenter) {
3780 cn.push({cls : 'container', cn : []});
3787 cls: 'navbar-header',
3792 cls: 'navbar-toggle',
3793 'data-toggle': 'collapse',
3798 html: 'Toggle navigation'
3820 cls: 'collapse navbar-collapse',
3824 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3826 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3827 cfg.cls += ' navbar-' + this.position;
3829 // tag can override this..
3831 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3834 if (this.brand !== '') {
3837 href: this.brand_href ? this.brand_href : '#',
3838 cls: 'navbar-brand',
3846 cfg.cls += ' main-nav';
3854 getHeaderChildContainer : function()
3856 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3857 return this.el.select('.navbar-header',true).first();
3860 return this.getChildContainer();
3864 initEvents : function()
3866 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3868 if (this.autohide) {
3873 Roo.get(document).on('scroll',function(e) {
3874 var ns = Roo.get(document).getScroll().top;
3875 var os = prevScroll;
3879 ft.removeClass('slideDown');
3880 ft.addClass('slideUp');
3883 ft.removeClass('slideUp');
3884 ft.addClass('slideDown');
3905 * @class Roo.bootstrap.NavSidebar
3906 * @extends Roo.bootstrap.Navbar
3907 * Bootstrap Sidebar class
3910 * Create a new Sidebar
3911 * @param {Object} config The config object
3915 Roo.bootstrap.NavSidebar = function(config){
3916 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3919 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3921 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3923 getAutoCreate : function(){
3928 cls: 'sidebar sidebar-nav'
3950 * @class Roo.bootstrap.NavGroup
3951 * @extends Roo.bootstrap.Component
3952 * Bootstrap NavGroup class
3953 * @cfg {String} align (left|right)
3954 * @cfg {Boolean} inverse
3955 * @cfg {String} type (nav|pills|tab) default nav
3956 * @cfg {String} navId - reference Id for navbar.
3960 * Create a new nav group
3961 * @param {Object} config The config object
3964 Roo.bootstrap.NavGroup = function(config){
3965 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3968 Roo.bootstrap.NavGroup.register(this);
3972 * Fires when the active item changes
3973 * @param {Roo.bootstrap.NavGroup} this
3974 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3975 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3982 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3993 getAutoCreate : function()
3995 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4002 if (['tabs','pills'].indexOf(this.type)!==-1) {
4003 cfg.cls += ' nav-' + this.type
4005 if (this.type!=='nav') {
4006 Roo.log('nav type must be nav/tabs/pills')
4008 cfg.cls += ' navbar-nav'
4011 if (this.parent().sidebar) {
4014 cls: 'dashboard-menu sidebar-menu'
4020 if (this.form === true) {
4026 if (this.align === 'right') {
4027 cfg.cls += ' navbar-right';
4029 cfg.cls += ' navbar-left';
4033 if (this.align === 'right') {
4034 cfg.cls += ' navbar-right';
4038 cfg.cls += ' navbar-inverse';
4046 * sets the active Navigation item
4047 * @param {Roo.bootstrap.NavItem} the new current navitem
4049 setActiveItem : function(item)
4052 Roo.each(this.navItems, function(v){
4057 v.setActive(false, true);
4064 item.setActive(true, true);
4065 this.fireEvent('changed', this, item, prev);
4070 * gets the active Navigation item
4071 * @return {Roo.bootstrap.NavItem} the current navitem
4073 getActive : function()
4077 Roo.each(this.navItems, function(v){
4088 indexOfNav : function()
4092 Roo.each(this.navItems, function(v,i){
4103 * adds a Navigation item
4104 * @param {Roo.bootstrap.NavItem} the navitem to add
4106 addItem : function(cfg)
4108 var cn = new Roo.bootstrap.NavItem(cfg);
4110 cn.parentId = this.id;
4111 cn.onRender(this.el, null);
4115 * register a Navigation item
4116 * @param {Roo.bootstrap.NavItem} the navitem to add
4118 register : function(item)
4120 this.navItems.push( item);
4121 item.navId = this.navId;
4126 * clear all the Navigation item
4129 clearAll : function()
4132 this.el.dom.innerHTML = '';
4135 getNavItem: function(tabId)
4138 Roo.each(this.navItems, function(e) {
4139 if (e.tabId == tabId) {
4149 setActiveNext : function()
4151 var i = this.indexOfNav(this.getActive());
4152 if (i > this.navItems.length) {
4155 this.setActiveItem(this.navItems[i+1]);
4157 setActivePrev : function()
4159 var i = this.indexOfNav(this.getActive());
4163 this.setActiveItem(this.navItems[i-1]);
4165 clearWasActive : function(except) {
4166 Roo.each(this.navItems, function(e) {
4167 if (e.tabId != except.tabId && e.was_active) {
4168 e.was_active = false;
4175 getWasActive : function ()
4178 Roo.each(this.navItems, function(e) {
4193 Roo.apply(Roo.bootstrap.NavGroup, {
4197 * register a Navigation Group
4198 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4200 register : function(navgrp)
4202 this.groups[navgrp.navId] = navgrp;
4206 * fetch a Navigation Group based on the navigation ID
4207 * @param {string} the navgroup to add
4208 * @returns {Roo.bootstrap.NavGroup} the navgroup
4210 get: function(navId) {
4211 if (typeof(this.groups[navId]) == 'undefined') {
4213 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4215 return this.groups[navId] ;
4230 * @class Roo.bootstrap.NavItem
4231 * @extends Roo.bootstrap.Component
4232 * Bootstrap Navbar.NavItem class
4233 * @cfg {String} href link to
4234 * @cfg {String} html content of button
4235 * @cfg {String} badge text inside badge
4236 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4237 * @cfg {String} glyphicon name of glyphicon
4238 * @cfg {String} icon name of font awesome icon
4239 * @cfg {Boolean} active Is item active
4240 * @cfg {Boolean} disabled Is item disabled
4242 * @cfg {Boolean} preventDefault (true | false) default false
4243 * @cfg {String} tabId the tab that this item activates.
4244 * @cfg {String} tagtype (a|span) render as a href or span?
4245 * @cfg {Boolean} animateRef (true|false) link to element default false
4248 * Create a new Navbar Item
4249 * @param {Object} config The config object
4251 Roo.bootstrap.NavItem = function(config){
4252 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4257 * The raw click event for the entire grid.
4258 * @param {Roo.EventObject} e
4263 * Fires when the active item active state changes
4264 * @param {Roo.bootstrap.NavItem} this
4265 * @param {boolean} state the new state
4271 * Fires when scroll to element
4272 * @param {Roo.bootstrap.NavItem} this
4273 * @param {Object} options
4274 * @param {Roo.EventObject} e
4282 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4290 preventDefault : false,
4297 getAutoCreate : function(){
4306 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4308 if (this.disabled) {
4309 cfg.cls += ' disabled';
4312 if (this.href || this.html || this.glyphicon || this.icon) {
4316 href : this.href || "#",
4317 html: this.html || ''
4322 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4325 if(this.glyphicon) {
4326 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4331 cfg.cn[0].html += " <span class='caret'></span>";
4335 if (this.badge !== '') {
4337 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4345 initEvents: function()
4347 if (typeof (this.menu) != 'undefined') {
4348 this.menu.parentType = this.xtype;
4349 this.menu.triggerEl = this.el;
4350 this.menu = this.addxtype(Roo.apply({}, this.menu));
4353 this.el.select('a',true).on('click', this.onClick, this);
4355 if(this.tagtype == 'span'){
4356 this.el.select('span',true).on('click', this.onClick, this);
4359 // at this point parent should be available..
4360 this.parent().register(this);
4363 onClick : function(e)
4365 if (e.getTarget('.dropdown-menu-item')) {
4366 // did you click on a menu itemm.... - then don't trigger onclick..
4371 this.preventDefault ||
4374 Roo.log("NavItem - prevent Default?");
4378 if (this.disabled) {
4382 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4383 if (tg && tg.transition) {
4384 Roo.log("waiting for the transitionend");
4390 //Roo.log("fire event clicked");
4391 if(this.fireEvent('click', this, e) === false){
4395 if(this.tagtype == 'span'){
4399 //Roo.log(this.href);
4400 var ael = this.el.select('a',true).first();
4403 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4404 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4405 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4406 return; // ignore... - it's a 'hash' to another page.
4408 Roo.log("NavItem - prevent Default?");
4410 this.scrollToElement(e);
4414 var p = this.parent();
4416 if (['tabs','pills'].indexOf(p.type)!==-1) {
4417 if (typeof(p.setActiveItem) !== 'undefined') {
4418 p.setActiveItem(this);
4422 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4423 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4424 // remove the collapsed menu expand...
4425 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4429 isActive: function () {
4432 setActive : function(state, fire, is_was_active)
4434 if (this.active && !state && this.navId) {
4435 this.was_active = true;
4436 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4438 nv.clearWasActive(this);
4442 this.active = state;
4445 this.el.removeClass('active');
4446 } else if (!this.el.hasClass('active')) {
4447 this.el.addClass('active');
4450 this.fireEvent('changed', this, state);
4453 // show a panel if it's registered and related..
4455 if (!this.navId || !this.tabId || !state || is_was_active) {
4459 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4463 var pan = tg.getPanelByName(this.tabId);
4467 // if we can not flip to new panel - go back to old nav highlight..
4468 if (false == tg.showPanel(pan)) {
4469 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4471 var onav = nv.getWasActive();
4473 onav.setActive(true, false, true);
4482 // this should not be here...
4483 setDisabled : function(state)
4485 this.disabled = state;
4487 this.el.removeClass('disabled');
4488 } else if (!this.el.hasClass('disabled')) {
4489 this.el.addClass('disabled');
4495 * Fetch the element to display the tooltip on.
4496 * @return {Roo.Element} defaults to this.el
4498 tooltipEl : function()
4500 return this.el.select('' + this.tagtype + '', true).first();
4503 scrollToElement : function(e)
4505 var c = document.body;
4508 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4510 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4511 c = document.documentElement;
4514 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4520 var o = target.calcOffsetsTo(c);
4527 this.fireEvent('scrollto', this, options, e);
4529 Roo.get(c).scrollTo('top', options.value, true);
4542 * <span> icon </span>
4543 * <span> text </span>
4544 * <span>badge </span>
4548 * @class Roo.bootstrap.NavSidebarItem
4549 * @extends Roo.bootstrap.NavItem
4550 * Bootstrap Navbar.NavSidebarItem class
4551 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4552 * {bool} open is the menu open
4554 * Create a new Navbar Button
4555 * @param {Object} config The config object
4557 Roo.bootstrap.NavSidebarItem = function(config){
4558 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4563 * The raw click event for the entire grid.
4564 * @param {Roo.EventObject} e
4569 * Fires when the active item active state changes
4570 * @param {Roo.bootstrap.NavSidebarItem} this
4571 * @param {boolean} state the new state
4579 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4581 badgeWeight : 'default',
4585 getAutoCreate : function(){
4590 href : this.href || '#',
4602 html : this.html || ''
4607 cfg.cls += ' active';
4610 if (this.disabled) {
4611 cfg.cls += ' disabled';
4614 cfg.cls += ' open x-open';
4617 if (this.glyphicon || this.icon) {
4618 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4619 a.cn.push({ tag : 'i', cls : c }) ;
4624 if (this.badge !== '') {
4626 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4630 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4631 a.cls += 'dropdown-toggle treeview' ;
4639 initEvents : function()
4641 if (typeof (this.menu) != 'undefined') {
4642 this.menu.parentType = this.xtype;
4643 this.menu.triggerEl = this.el;
4644 this.menu = this.addxtype(Roo.apply({}, this.menu));
4647 this.el.on('click', this.onClick, this);
4650 if(this.badge !== ''){
4652 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4657 onClick : function(e)
4664 if(this.preventDefault){
4668 this.fireEvent('click', this);
4671 disable : function()
4673 this.setDisabled(true);
4678 this.setDisabled(false);
4681 setDisabled : function(state)
4683 if(this.disabled == state){
4687 this.disabled = state;
4690 this.el.addClass('disabled');
4694 this.el.removeClass('disabled');
4699 setActive : function(state)
4701 if(this.active == state){
4705 this.active = state;
4708 this.el.addClass('active');
4712 this.el.removeClass('active');
4717 isActive: function ()
4722 setBadge : function(str)
4728 this.badgeEl.dom.innerHTML = str;
4745 * @class Roo.bootstrap.Row
4746 * @extends Roo.bootstrap.Component
4747 * Bootstrap Row class (contains columns...)
4751 * @param {Object} config The config object
4754 Roo.bootstrap.Row = function(config){
4755 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4758 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4760 getAutoCreate : function(){
4779 * @class Roo.bootstrap.Element
4780 * @extends Roo.bootstrap.Component
4781 * Bootstrap Element class
4782 * @cfg {String} html contents of the element
4783 * @cfg {String} tag tag of the element
4784 * @cfg {String} cls class of the element
4785 * @cfg {Boolean} preventDefault (true|false) default false
4786 * @cfg {Boolean} clickable (true|false) default false
4789 * Create a new Element
4790 * @param {Object} config The config object
4793 Roo.bootstrap.Element = function(config){
4794 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4800 * When a element is chick
4801 * @param {Roo.bootstrap.Element} this
4802 * @param {Roo.EventObject} e
4808 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4813 preventDefault: false,
4816 getAutoCreate : function(){
4827 initEvents: function()
4829 Roo.bootstrap.Element.superclass.initEvents.call(this);
4832 this.el.on('click', this.onClick, this);
4837 onClick : function(e)
4839 if(this.preventDefault){
4843 this.fireEvent('click', this, e);
4846 getValue : function()
4848 return this.el.dom.innerHTML;
4851 setValue : function(value)
4853 this.el.dom.innerHTML = value;
4868 * @class Roo.bootstrap.Pagination
4869 * @extends Roo.bootstrap.Component
4870 * Bootstrap Pagination class
4871 * @cfg {String} size xs | sm | md | lg
4872 * @cfg {Boolean} inverse false | true
4875 * Create a new Pagination
4876 * @param {Object} config The config object
4879 Roo.bootstrap.Pagination = function(config){
4880 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4883 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4889 getAutoCreate : function(){
4895 cfg.cls += ' inverse';
4901 cfg.cls += " " + this.cls;
4919 * @class Roo.bootstrap.PaginationItem
4920 * @extends Roo.bootstrap.Component
4921 * Bootstrap PaginationItem class
4922 * @cfg {String} html text
4923 * @cfg {String} href the link
4924 * @cfg {Boolean} preventDefault (true | false) default true
4925 * @cfg {Boolean} active (true | false) default false
4926 * @cfg {Boolean} disabled default false
4930 * Create a new PaginationItem
4931 * @param {Object} config The config object
4935 Roo.bootstrap.PaginationItem = function(config){
4936 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4941 * The raw click event for the entire grid.
4942 * @param {Roo.EventObject} e
4948 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4952 preventDefault: true,
4957 getAutoCreate : function(){
4963 href : this.href ? this.href : '#',
4964 html : this.html ? this.html : ''
4974 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4978 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4984 initEvents: function() {
4986 this.el.on('click', this.onClick, this);
4989 onClick : function(e)
4991 Roo.log('PaginationItem on click ');
4992 if(this.preventDefault){
5000 this.fireEvent('click', this, e);
5016 * @class Roo.bootstrap.Slider
5017 * @extends Roo.bootstrap.Component
5018 * Bootstrap Slider class
5021 * Create a new Slider
5022 * @param {Object} config The config object
5025 Roo.bootstrap.Slider = function(config){
5026 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5029 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5031 getAutoCreate : function(){
5035 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5039 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5051 * Ext JS Library 1.1.1
5052 * Copyright(c) 2006-2007, Ext JS, LLC.
5054 * Originally Released Under LGPL - original licence link has changed is not relivant.
5057 * <script type="text/javascript">
5062 * @class Roo.grid.ColumnModel
5063 * @extends Roo.util.Observable
5064 * This is the default implementation of a ColumnModel used by the Grid. It defines
5065 * the columns in the grid.
5068 var colModel = new Roo.grid.ColumnModel([
5069 {header: "Ticker", width: 60, sortable: true, locked: true},
5070 {header: "Company Name", width: 150, sortable: true},
5071 {header: "Market Cap.", width: 100, sortable: true},
5072 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5073 {header: "Employees", width: 100, sortable: true, resizable: false}
5078 * The config options listed for this class are options which may appear in each
5079 * individual column definition.
5080 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5082 * @param {Object} config An Array of column config objects. See this class's
5083 * config objects for details.
5085 Roo.grid.ColumnModel = function(config){
5087 * The config passed into the constructor
5089 this.config = config;
5092 // if no id, create one
5093 // if the column does not have a dataIndex mapping,
5094 // map it to the order it is in the config
5095 for(var i = 0, len = config.length; i < len; i++){
5097 if(typeof c.dataIndex == "undefined"){
5100 if(typeof c.renderer == "string"){
5101 c.renderer = Roo.util.Format[c.renderer];
5103 if(typeof c.id == "undefined"){
5106 if(c.editor && c.editor.xtype){
5107 c.editor = Roo.factory(c.editor, Roo.grid);
5109 if(c.editor && c.editor.isFormField){
5110 c.editor = new Roo.grid.GridEditor(c.editor);
5112 this.lookup[c.id] = c;
5116 * The width of columns which have no width specified (defaults to 100)
5119 this.defaultWidth = 100;
5122 * Default sortable of columns which have no sortable specified (defaults to false)
5125 this.defaultSortable = false;
5129 * @event widthchange
5130 * Fires when the width of a column changes.
5131 * @param {ColumnModel} this
5132 * @param {Number} columnIndex The column index
5133 * @param {Number} newWidth The new width
5135 "widthchange": true,
5137 * @event headerchange
5138 * Fires when the text of a header changes.
5139 * @param {ColumnModel} this
5140 * @param {Number} columnIndex The column index
5141 * @param {Number} newText The new header text
5143 "headerchange": true,
5145 * @event hiddenchange
5146 * Fires when a column is hidden or "unhidden".
5147 * @param {ColumnModel} this
5148 * @param {Number} columnIndex The column index
5149 * @param {Boolean} hidden true if hidden, false otherwise
5151 "hiddenchange": true,
5153 * @event columnmoved
5154 * Fires when a column is moved.
5155 * @param {ColumnModel} this
5156 * @param {Number} oldIndex
5157 * @param {Number} newIndex
5159 "columnmoved" : true,
5161 * @event columlockchange
5162 * Fires when a column's locked state is changed
5163 * @param {ColumnModel} this
5164 * @param {Number} colIndex
5165 * @param {Boolean} locked true if locked
5167 "columnlockchange" : true
5169 Roo.grid.ColumnModel.superclass.constructor.call(this);
5171 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5173 * @cfg {String} header The header text to display in the Grid view.
5176 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5177 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5178 * specified, the column's index is used as an index into the Record's data Array.
5181 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5182 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5185 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5186 * Defaults to the value of the {@link #defaultSortable} property.
5187 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5190 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5193 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5196 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5199 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5202 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5203 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5204 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5205 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5208 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5211 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5214 * @cfg {String} cursor (Optional)
5217 * @cfg {String} tooltip (Optional)
5220 * @cfg {Number} xs (Optional)
5223 * @cfg {Number} sm (Optional)
5226 * @cfg {Number} md (Optional)
5229 * @cfg {Number} lg (Optional)
5232 * Returns the id of the column at the specified index.
5233 * @param {Number} index The column index
5234 * @return {String} the id
5236 getColumnId : function(index){
5237 return this.config[index].id;
5241 * Returns the column for a specified id.
5242 * @param {String} id The column id
5243 * @return {Object} the column
5245 getColumnById : function(id){
5246 return this.lookup[id];
5251 * Returns the column for a specified dataIndex.
5252 * @param {String} dataIndex The column dataIndex
5253 * @return {Object|Boolean} the column or false if not found
5255 getColumnByDataIndex: function(dataIndex){
5256 var index = this.findColumnIndex(dataIndex);
5257 return index > -1 ? this.config[index] : false;
5261 * Returns the index for a specified column id.
5262 * @param {String} id The column id
5263 * @return {Number} the index, or -1 if not found
5265 getIndexById : function(id){
5266 for(var i = 0, len = this.config.length; i < len; i++){
5267 if(this.config[i].id == id){
5275 * Returns the index for a specified column dataIndex.
5276 * @param {String} dataIndex The column dataIndex
5277 * @return {Number} the index, or -1 if not found
5280 findColumnIndex : function(dataIndex){
5281 for(var i = 0, len = this.config.length; i < len; i++){
5282 if(this.config[i].dataIndex == dataIndex){
5290 moveColumn : function(oldIndex, newIndex){
5291 var c = this.config[oldIndex];
5292 this.config.splice(oldIndex, 1);
5293 this.config.splice(newIndex, 0, c);
5294 this.dataMap = null;
5295 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5298 isLocked : function(colIndex){
5299 return this.config[colIndex].locked === true;
5302 setLocked : function(colIndex, value, suppressEvent){
5303 if(this.isLocked(colIndex) == value){
5306 this.config[colIndex].locked = value;
5308 this.fireEvent("columnlockchange", this, colIndex, value);
5312 getTotalLockedWidth : function(){
5314 for(var i = 0; i < this.config.length; i++){
5315 if(this.isLocked(i) && !this.isHidden(i)){
5316 this.totalWidth += this.getColumnWidth(i);
5322 getLockedCount : function(){
5323 for(var i = 0, len = this.config.length; i < len; i++){
5324 if(!this.isLocked(i)){
5329 return this.config.length;
5333 * Returns the number of columns.
5336 getColumnCount : function(visibleOnly){
5337 if(visibleOnly === true){
5339 for(var i = 0, len = this.config.length; i < len; i++){
5340 if(!this.isHidden(i)){
5346 return this.config.length;
5350 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5351 * @param {Function} fn
5352 * @param {Object} scope (optional)
5353 * @return {Array} result
5355 getColumnsBy : function(fn, scope){
5357 for(var i = 0, len = this.config.length; i < len; i++){
5358 var c = this.config[i];
5359 if(fn.call(scope||this, c, i) === true){
5367 * Returns true if the specified column is sortable.
5368 * @param {Number} col The column index
5371 isSortable : function(col){
5372 if(typeof this.config[col].sortable == "undefined"){
5373 return this.defaultSortable;
5375 return this.config[col].sortable;
5379 * Returns the rendering (formatting) function defined for the column.
5380 * @param {Number} col The column index.
5381 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5383 getRenderer : function(col){
5384 if(!this.config[col].renderer){
5385 return Roo.grid.ColumnModel.defaultRenderer;
5387 return this.config[col].renderer;
5391 * Sets the rendering (formatting) function for a column.
5392 * @param {Number} col The column index
5393 * @param {Function} fn The function to use to process the cell's raw data
5394 * to return HTML markup for the grid view. The render function is called with
5395 * the following parameters:<ul>
5396 * <li>Data value.</li>
5397 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5398 * <li>css A CSS style string to apply to the table cell.</li>
5399 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5400 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5401 * <li>Row index</li>
5402 * <li>Column index</li>
5403 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5405 setRenderer : function(col, fn){
5406 this.config[col].renderer = fn;
5410 * Returns the width for the specified column.
5411 * @param {Number} col The column index
5414 getColumnWidth : function(col){
5415 return this.config[col].width * 1 || this.defaultWidth;
5419 * Sets the width for a column.
5420 * @param {Number} col The column index
5421 * @param {Number} width The new width
5423 setColumnWidth : function(col, width, suppressEvent){
5424 this.config[col].width = width;
5425 this.totalWidth = null;
5427 this.fireEvent("widthchange", this, col, width);
5432 * Returns the total width of all columns.
5433 * @param {Boolean} includeHidden True to include hidden column widths
5436 getTotalWidth : function(includeHidden){
5437 if(!this.totalWidth){
5438 this.totalWidth = 0;
5439 for(var i = 0, len = this.config.length; i < len; i++){
5440 if(includeHidden || !this.isHidden(i)){
5441 this.totalWidth += this.getColumnWidth(i);
5445 return this.totalWidth;
5449 * Returns the header for the specified column.
5450 * @param {Number} col The column index
5453 getColumnHeader : function(col){
5454 return this.config[col].header;
5458 * Sets the header for a column.
5459 * @param {Number} col The column index
5460 * @param {String} header The new header
5462 setColumnHeader : function(col, header){
5463 this.config[col].header = header;
5464 this.fireEvent("headerchange", this, col, header);
5468 * Returns the tooltip for the specified column.
5469 * @param {Number} col The column index
5472 getColumnTooltip : function(col){
5473 return this.config[col].tooltip;
5476 * Sets the tooltip for a column.
5477 * @param {Number} col The column index
5478 * @param {String} tooltip The new tooltip
5480 setColumnTooltip : function(col, tooltip){
5481 this.config[col].tooltip = tooltip;
5485 * Returns the dataIndex for the specified column.
5486 * @param {Number} col The column index
5489 getDataIndex : function(col){
5490 return this.config[col].dataIndex;
5494 * Sets the dataIndex for a column.
5495 * @param {Number} col The column index
5496 * @param {Number} dataIndex The new dataIndex
5498 setDataIndex : function(col, dataIndex){
5499 this.config[col].dataIndex = dataIndex;
5505 * Returns true if the cell is editable.
5506 * @param {Number} colIndex The column index
5507 * @param {Number} rowIndex The row index - this is nto actually used..?
5510 isCellEditable : function(colIndex, rowIndex){
5511 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5515 * Returns the editor defined for the cell/column.
5516 * return false or null to disable editing.
5517 * @param {Number} colIndex The column index
5518 * @param {Number} rowIndex The row index
5521 getCellEditor : function(colIndex, rowIndex){
5522 return this.config[colIndex].editor;
5526 * Sets if a column is editable.
5527 * @param {Number} col The column index
5528 * @param {Boolean} editable True if the column is editable
5530 setEditable : function(col, editable){
5531 this.config[col].editable = editable;
5536 * Returns true if the column is hidden.
5537 * @param {Number} colIndex The column index
5540 isHidden : function(colIndex){
5541 return this.config[colIndex].hidden;
5546 * Returns true if the column width cannot be changed
5548 isFixed : function(colIndex){
5549 return this.config[colIndex].fixed;
5553 * Returns true if the column can be resized
5556 isResizable : function(colIndex){
5557 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5560 * Sets if a column is hidden.
5561 * @param {Number} colIndex The column index
5562 * @param {Boolean} hidden True if the column is hidden
5564 setHidden : function(colIndex, hidden){
5565 this.config[colIndex].hidden = hidden;
5566 this.totalWidth = null;
5567 this.fireEvent("hiddenchange", this, colIndex, hidden);
5571 * Sets the editor for a column.
5572 * @param {Number} col The column index
5573 * @param {Object} editor The editor object
5575 setEditor : function(col, editor){
5576 this.config[col].editor = editor;
5580 Roo.grid.ColumnModel.defaultRenderer = function(value)
5582 if(typeof value == "object") {
5585 if(typeof value == "string" && value.length < 1){
5589 return String.format("{0}", value);
5592 // Alias for backwards compatibility
5593 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5596 * Ext JS Library 1.1.1
5597 * Copyright(c) 2006-2007, Ext JS, LLC.
5599 * Originally Released Under LGPL - original licence link has changed is not relivant.
5602 * <script type="text/javascript">
5606 * @class Roo.LoadMask
5607 * A simple utility class for generically masking elements while loading data. If the element being masked has
5608 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5609 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5610 * element's UpdateManager load indicator and will be destroyed after the initial load.
5612 * Create a new LoadMask
5613 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5614 * @param {Object} config The config object
5616 Roo.LoadMask = function(el, config){
5617 this.el = Roo.get(el);
5618 Roo.apply(this, config);
5620 this.store.on('beforeload', this.onBeforeLoad, this);
5621 this.store.on('load', this.onLoad, this);
5622 this.store.on('loadexception', this.onLoadException, this);
5623 this.removeMask = false;
5625 var um = this.el.getUpdateManager();
5626 um.showLoadIndicator = false; // disable the default indicator
5627 um.on('beforeupdate', this.onBeforeLoad, this);
5628 um.on('update', this.onLoad, this);
5629 um.on('failure', this.onLoad, this);
5630 this.removeMask = true;
5634 Roo.LoadMask.prototype = {
5636 * @cfg {Boolean} removeMask
5637 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5638 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5642 * The text to display in a centered loading message box (defaults to 'Loading...')
5646 * @cfg {String} msgCls
5647 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5649 msgCls : 'x-mask-loading',
5652 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5658 * Disables the mask to prevent it from being displayed
5660 disable : function(){
5661 this.disabled = true;
5665 * Enables the mask so that it can be displayed
5667 enable : function(){
5668 this.disabled = false;
5671 onLoadException : function()
5675 if (typeof(arguments[3]) != 'undefined') {
5676 Roo.MessageBox.alert("Error loading",arguments[3]);
5680 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5681 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5690 this.el.unmask(this.removeMask);
5695 this.el.unmask(this.removeMask);
5699 onBeforeLoad : function(){
5701 (function() { this.el.mask(this.msg, this.msgCls) }).defer(50, this);
5706 destroy : function(){
5708 this.store.un('beforeload', this.onBeforeLoad, this);
5709 this.store.un('load', this.onLoad, this);
5710 this.store.un('loadexception', this.onLoadException, this);
5712 var um = this.el.getUpdateManager();
5713 um.un('beforeupdate', this.onBeforeLoad, this);
5714 um.un('update', this.onLoad, this);
5715 um.un('failure', this.onLoad, this);
5726 * @class Roo.bootstrap.Table
5727 * @extends Roo.bootstrap.Component
5728 * Bootstrap Table class
5729 * @cfg {String} cls table class
5730 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5731 * @cfg {String} bgcolor Specifies the background color for a table
5732 * @cfg {Number} border Specifies whether the table cells should have borders or not
5733 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5734 * @cfg {Number} cellspacing Specifies the space between cells
5735 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5736 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5737 * @cfg {String} sortable Specifies that the table should be sortable
5738 * @cfg {String} summary Specifies a summary of the content of a table
5739 * @cfg {Number} width Specifies the width of a table
5740 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5742 * @cfg {boolean} striped Should the rows be alternative striped
5743 * @cfg {boolean} bordered Add borders to the table
5744 * @cfg {boolean} hover Add hover highlighting
5745 * @cfg {boolean} condensed Format condensed
5746 * @cfg {boolean} responsive Format condensed
5747 * @cfg {Boolean} loadMask (true|false) default false
5748 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5749 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5750 * @cfg {Boolean} rowSelection (true|false) default false
5751 * @cfg {Boolean} cellSelection (true|false) default false
5752 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5753 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5757 * Create a new Table
5758 * @param {Object} config The config object
5761 Roo.bootstrap.Table = function(config){
5762 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5767 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5768 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5769 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5770 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5772 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5774 this.sm.grid = this;
5775 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5776 this.sm = this.selModel;
5777 this.sm.xmodule = this.xmodule || false;
5780 if (this.cm && typeof(this.cm.config) == 'undefined') {
5781 this.colModel = new Roo.grid.ColumnModel(this.cm);
5782 this.cm = this.colModel;
5783 this.cm.xmodule = this.xmodule || false;
5786 this.store= Roo.factory(this.store, Roo.data);
5787 this.ds = this.store;
5788 this.ds.xmodule = this.xmodule || false;
5791 if (this.footer && this.store) {
5792 this.footer.dataSource = this.ds;
5793 this.footer = Roo.factory(this.footer);
5800 * Fires when a cell is clicked
5801 * @param {Roo.bootstrap.Table} this
5802 * @param {Roo.Element} el
5803 * @param {Number} rowIndex
5804 * @param {Number} columnIndex
5805 * @param {Roo.EventObject} e
5809 * @event celldblclick
5810 * Fires when a cell is double clicked
5811 * @param {Roo.bootstrap.Table} this
5812 * @param {Roo.Element} el
5813 * @param {Number} rowIndex
5814 * @param {Number} columnIndex
5815 * @param {Roo.EventObject} e
5817 "celldblclick" : true,
5820 * Fires when a row is clicked
5821 * @param {Roo.bootstrap.Table} this
5822 * @param {Roo.Element} el
5823 * @param {Number} rowIndex
5824 * @param {Roo.EventObject} e
5828 * @event rowdblclick
5829 * Fires when a row is double clicked
5830 * @param {Roo.bootstrap.Table} this
5831 * @param {Roo.Element} el
5832 * @param {Number} rowIndex
5833 * @param {Roo.EventObject} e
5835 "rowdblclick" : true,
5838 * Fires when a mouseover occur
5839 * @param {Roo.bootstrap.Table} this
5840 * @param {Roo.Element} el
5841 * @param {Number} rowIndex
5842 * @param {Number} columnIndex
5843 * @param {Roo.EventObject} e
5848 * Fires when a mouseout occur
5849 * @param {Roo.bootstrap.Table} this
5850 * @param {Roo.Element} el
5851 * @param {Number} rowIndex
5852 * @param {Number} columnIndex
5853 * @param {Roo.EventObject} e
5858 * Fires when a row is rendered, so you can change add a style to it.
5859 * @param {Roo.bootstrap.Table} this
5860 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5864 * @event rowsrendered
5865 * Fires when all the rows have been rendered
5866 * @param {Roo.bootstrap.Table} this
5868 'rowsrendered' : true,
5870 * @event contextmenu
5871 * The raw contextmenu event for the entire grid.
5872 * @param {Roo.EventObject} e
5874 "contextmenu" : true,
5876 * @event rowcontextmenu
5877 * Fires when a row is right clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Number} rowIndex
5880 * @param {Roo.EventObject} e
5882 "rowcontextmenu" : true,
5884 * @event cellcontextmenu
5885 * Fires when a cell is right clicked
5886 * @param {Roo.bootstrap.Table} this
5887 * @param {Number} rowIndex
5888 * @param {Number} cellIndex
5889 * @param {Roo.EventObject} e
5891 "cellcontextmenu" : true,
5893 * @event headercontextmenu
5894 * Fires when a header is right clicked
5895 * @param {Roo.bootstrap.Table} this
5896 * @param {Number} columnIndex
5897 * @param {Roo.EventObject} e
5899 "headercontextmenu" : true
5903 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5929 rowSelection : false,
5930 cellSelection : false,
5933 // Roo.Element - the tbody
5935 // Roo.Element - thead element
5938 container: false, // used by gridpanel...
5940 getAutoCreate : function()
5942 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5949 if (this.scrollBody) {
5950 cfg.cls += ' table-body-fixed';
5953 cfg.cls += ' table-striped';
5957 cfg.cls += ' table-hover';
5959 if (this.bordered) {
5960 cfg.cls += ' table-bordered';
5962 if (this.condensed) {
5963 cfg.cls += ' table-condensed';
5965 if (this.responsive) {
5966 cfg.cls += ' table-responsive';
5970 cfg.cls+= ' ' +this.cls;
5973 // this lot should be simplifed...
5976 cfg.align=this.align;
5979 cfg.bgcolor=this.bgcolor;
5982 cfg.border=this.border;
5984 if (this.cellpadding) {
5985 cfg.cellpadding=this.cellpadding;
5987 if (this.cellspacing) {
5988 cfg.cellspacing=this.cellspacing;
5991 cfg.frame=this.frame;
5994 cfg.rules=this.rules;
5996 if (this.sortable) {
5997 cfg.sortable=this.sortable;
6000 cfg.summary=this.summary;
6003 cfg.width=this.width;
6006 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6009 if(this.store || this.cm){
6010 if(this.headerShow){
6011 cfg.cn.push(this.renderHeader());
6014 cfg.cn.push(this.renderBody());
6016 if(this.footerShow){
6017 cfg.cn.push(this.renderFooter());
6019 // where does this come from?
6020 //cfg.cls+= ' TableGrid';
6023 return { cn : [ cfg ] };
6026 initEvents : function()
6028 if(!this.store || !this.cm){
6031 if (this.selModel) {
6032 this.selModel.initEvents();
6036 //Roo.log('initEvents with ds!!!!');
6038 this.mainBody = this.el.select('tbody', true).first();
6039 this.mainHead = this.el.select('thead', true).first();
6046 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6047 e.on('click', _this.sort, _this);
6050 this.mainBody.on("click", this.onClick, this);
6051 this.mainBody.on("dblclick", this.onDblClick, this);
6053 // why is this done????? = it breaks dialogs??
6054 //this.parent().el.setStyle('position', 'relative');
6058 this.footer.parentId = this.id;
6059 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6062 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6064 this.store.on('load', this.onLoad, this);
6065 this.store.on('beforeload', this.onBeforeLoad, this);
6066 this.store.on('update', this.onUpdate, this);
6067 this.store.on('add', this.onAdd, this);
6068 this.store.on("clear", this.clear, this);
6070 this.el.on("contextmenu", this.onContextMenu, this);
6072 this.mainBody.on('scroll', this.onBodyScroll, this);
6077 onContextMenu : function(e, t)
6079 this.processEvent("contextmenu", e);
6082 processEvent : function(name, e)
6084 if (name != 'touchstart' ) {
6085 this.fireEvent(name, e);
6088 var t = e.getTarget();
6090 var cell = Roo.get(t);
6096 if(cell.findParent('tfoot', false, true)){
6100 if(cell.findParent('thead', false, true)){
6102 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6103 cell = Roo.get(t).findParent('th', false, true);
6105 Roo.log("failed to find th in thead?");
6106 Roo.log(e.getTarget());
6111 var cellIndex = cell.dom.cellIndex;
6113 var ename = name == 'touchstart' ? 'click' : name;
6114 this.fireEvent("header" + ename, this, cellIndex, e);
6119 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6120 cell = Roo.get(t).findParent('td', false, true);
6122 Roo.log("failed to find th in tbody?");
6123 Roo.log(e.getTarget());
6128 var row = cell.findParent('tr', false, true);
6129 var cellIndex = cell.dom.cellIndex;
6130 var rowIndex = row.dom.rowIndex - 1;
6134 this.fireEvent("row" + name, this, rowIndex, e);
6138 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6144 onMouseover : function(e, el)
6146 var cell = Roo.get(el);
6152 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6153 cell = cell.findParent('td', false, true);
6156 var row = cell.findParent('tr', false, true);
6157 var cellIndex = cell.dom.cellIndex;
6158 var rowIndex = row.dom.rowIndex - 1; // start from 0
6160 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6164 onMouseout : function(e, el)
6166 var cell = Roo.get(el);
6172 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6173 cell = cell.findParent('td', false, true);
6176 var row = cell.findParent('tr', false, true);
6177 var cellIndex = cell.dom.cellIndex;
6178 var rowIndex = row.dom.rowIndex - 1; // start from 0
6180 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6184 onClick : function(e, el)
6186 var cell = Roo.get(el);
6188 if(!cell || (!this.cellSelection && !this.rowSelection)){
6192 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6193 cell = cell.findParent('td', false, true);
6196 if(!cell || typeof(cell) == 'undefined'){
6200 var row = cell.findParent('tr', false, true);
6202 if(!row || typeof(row) == 'undefined'){
6206 var cellIndex = cell.dom.cellIndex;
6207 var rowIndex = this.getRowIndex(row);
6209 // why??? - should these not be based on SelectionModel?
6210 if(this.cellSelection){
6211 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6214 if(this.rowSelection){
6215 this.fireEvent('rowclick', this, row, rowIndex, e);
6221 onDblClick : function(e,el)
6223 var cell = Roo.get(el);
6225 if(!cell || (!this.cellSelection && !this.rowSelection)){
6229 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6230 cell = cell.findParent('td', false, true);
6233 if(!cell || typeof(cell) == 'undefined'){
6237 var row = cell.findParent('tr', false, true);
6239 if(!row || typeof(row) == 'undefined'){
6243 var cellIndex = cell.dom.cellIndex;
6244 var rowIndex = this.getRowIndex(row);
6246 if(this.cellSelection){
6247 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6250 if(this.rowSelection){
6251 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6255 sort : function(e,el)
6257 var col = Roo.get(el);
6259 if(!col.hasClass('sortable')){
6263 var sort = col.attr('sort');
6266 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6270 this.store.sortInfo = {field : sort, direction : dir};
6273 Roo.log("calling footer first");
6274 this.footer.onClick('first');
6277 this.store.load({ params : { start : 0 } });
6281 renderHeader : function()
6289 this.totalWidth = 0;
6291 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6293 var config = cm.config[i];
6298 html: cm.getColumnHeader(i)
6303 if(typeof(config.sortable) != 'undefined' && config.sortable){
6305 c.html = '<i class="glyphicon"></i>' + c.html;
6308 if(typeof(config.lgHeader) != 'undefined'){
6309 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6312 if(typeof(config.mdHeader) != 'undefined'){
6313 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6316 if(typeof(config.smHeader) != 'undefined'){
6317 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6320 if(typeof(config.xsHeader) != 'undefined'){
6321 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6328 if(typeof(config.tooltip) != 'undefined'){
6329 c.tooltip = config.tooltip;
6332 if(typeof(config.colspan) != 'undefined'){
6333 c.colspan = config.colspan;
6336 if(typeof(config.hidden) != 'undefined' && config.hidden){
6337 c.style += ' display:none;';
6340 if(typeof(config.dataIndex) != 'undefined'){
6341 c.sort = config.dataIndex;
6346 if(typeof(config.align) != 'undefined' && config.align.length){
6347 c.style += ' text-align:' + config.align + ';';
6350 if(typeof(config.width) != 'undefined'){
6351 c.style += ' width:' + config.width + 'px;';
6352 this.totalWidth += config.width;
6354 this.totalWidth += 100; // assume minimum of 100 per column?
6357 if(typeof(config.cls) != 'undefined'){
6358 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6361 ['xs','sm','md','lg'].map(function(size){
6363 if(typeof(config[size]) == 'undefined'){
6367 if (!config[size]) { // 0 = hidden
6368 c.cls += ' hidden-' + size;
6372 c.cls += ' col-' + size + '-' + config[size];
6382 renderBody : function()
6392 colspan : this.cm.getColumnCount()
6402 renderFooter : function()
6412 colspan : this.cm.getColumnCount()
6426 // Roo.log('ds onload');
6431 var ds = this.store;
6433 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6434 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6435 if (_this.store.sortInfo) {
6437 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6438 e.select('i', true).addClass(['glyphicon-arrow-up']);
6441 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6442 e.select('i', true).addClass(['glyphicon-arrow-down']);
6447 var tbody = this.mainBody;
6449 if(ds.getCount() > 0){
6450 ds.data.each(function(d,rowIndex){
6451 var row = this.renderRow(cm, ds, rowIndex);
6453 tbody.createChild(row);
6457 if(row.cellObjects.length){
6458 Roo.each(row.cellObjects, function(r){
6459 _this.renderCellObject(r);
6466 Roo.each(this.el.select('tbody td', true).elements, function(e){
6467 e.on('mouseover', _this.onMouseover, _this);
6470 Roo.each(this.el.select('tbody td', true).elements, function(e){
6471 e.on('mouseout', _this.onMouseout, _this);
6473 this.fireEvent('rowsrendered', this);
6474 //if(this.loadMask){
6475 // this.maskEl.hide();
6482 onUpdate : function(ds,record)
6484 this.refreshRow(record);
6488 onRemove : function(ds, record, index, isUpdate){
6489 if(isUpdate !== true){
6490 this.fireEvent("beforerowremoved", this, index, record);
6492 var bt = this.mainBody.dom;
6494 var rows = this.el.select('tbody > tr', true).elements;
6496 if(typeof(rows[index]) != 'undefined'){
6497 bt.removeChild(rows[index].dom);
6500 // if(bt.rows[index]){
6501 // bt.removeChild(bt.rows[index]);
6504 if(isUpdate !== true){
6505 //this.stripeRows(index);
6506 //this.syncRowHeights(index, index);
6508 this.fireEvent("rowremoved", this, index, record);
6512 onAdd : function(ds, records, rowIndex)
6514 //Roo.log('on Add called');
6515 // - note this does not handle multiple adding very well..
6516 var bt = this.mainBody.dom;
6517 for (var i =0 ; i < records.length;i++) {
6518 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6519 //Roo.log(records[i]);
6520 //Roo.log(this.store.getAt(rowIndex+i));
6521 this.insertRow(this.store, rowIndex + i, false);
6528 refreshRow : function(record){
6529 var ds = this.store, index;
6530 if(typeof record == 'number'){
6532 record = ds.getAt(index);
6534 index = ds.indexOf(record);
6536 this.insertRow(ds, index, true);
6538 this.onRemove(ds, record, index+1, true);
6540 //this.syncRowHeights(index, index);
6542 this.fireEvent("rowupdated", this, index, record);
6545 insertRow : function(dm, rowIndex, isUpdate){
6548 this.fireEvent("beforerowsinserted", this, rowIndex);
6550 //var s = this.getScrollState();
6551 var row = this.renderRow(this.cm, this.store, rowIndex);
6552 // insert before rowIndex..
6553 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6557 if(row.cellObjects.length){
6558 Roo.each(row.cellObjects, function(r){
6559 _this.renderCellObject(r);
6564 this.fireEvent("rowsinserted", this, rowIndex);
6565 //this.syncRowHeights(firstRow, lastRow);
6566 //this.stripeRows(firstRow);
6573 getRowDom : function(rowIndex)
6575 var rows = this.el.select('tbody > tr', true).elements;
6577 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6580 // returns the object tree for a tr..
6583 renderRow : function(cm, ds, rowIndex)
6586 var d = ds.getAt(rowIndex);
6593 var cellObjects = [];
6595 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6596 var config = cm.config[i];
6598 var renderer = cm.getRenderer(i);
6602 if(typeof(renderer) !== 'undefined'){
6603 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6605 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6606 // and are rendered into the cells after the row is rendered - using the id for the element.
6608 if(typeof(value) === 'object'){
6618 rowIndex : rowIndex,
6623 this.fireEvent('rowclass', this, rowcfg);
6627 cls : rowcfg.rowClass,
6629 html: (typeof(value) === 'object') ? '' : value
6636 if(typeof(config.colspan) != 'undefined'){
6637 td.colspan = config.colspan;
6640 if(typeof(config.hidden) != 'undefined' && config.hidden){
6641 td.style += ' display:none;';
6644 if(typeof(config.align) != 'undefined' && config.align.length){
6645 td.style += ' text-align:' + config.align + ';';
6648 if(typeof(config.width) != 'undefined'){
6649 td.style += ' width:' + config.width + 'px;';
6652 if(typeof(config.cursor) != 'undefined'){
6653 td.style += ' cursor:' + config.cursor + ';';
6656 if(typeof(config.cls) != 'undefined'){
6657 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6660 ['xs','sm','md','lg'].map(function(size){
6662 if(typeof(config[size]) == 'undefined'){
6666 if (!config[size]) { // 0 = hidden
6667 td.cls += ' hidden-' + size;
6671 td.cls += ' col-' + size + '-' + config[size];
6679 row.cellObjects = cellObjects;
6687 onBeforeLoad : function()
6689 //Roo.log('ds onBeforeLoad');
6693 //if(this.loadMask){
6694 // this.maskEl.show();
6702 this.el.select('tbody', true).first().dom.innerHTML = '';
6705 * Show or hide a row.
6706 * @param {Number} rowIndex to show or hide
6707 * @param {Boolean} state hide
6709 setRowVisibility : function(rowIndex, state)
6711 var bt = this.mainBody.dom;
6713 var rows = this.el.select('tbody > tr', true).elements;
6715 if(typeof(rows[rowIndex]) == 'undefined'){
6718 rows[rowIndex].dom.style.display = state ? '' : 'none';
6722 getSelectionModel : function(){
6724 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6726 return this.selModel;
6729 * Render the Roo.bootstrap object from renderder
6731 renderCellObject : function(r)
6735 var t = r.cfg.render(r.container);
6738 Roo.each(r.cfg.cn, function(c){
6740 container: t.getChildContainer(),
6743 _this.renderCellObject(child);
6748 getRowIndex : function(row)
6752 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6763 * Returns the grid's underlying element = used by panel.Grid
6764 * @return {Element} The element
6766 getGridEl : function(){
6770 * Forces a resize - used by panel.Grid
6771 * @return {Element} The element
6773 autoSize : function()
6775 //var ctr = Roo.get(this.container.dom.parentElement);
6776 var ctr = Roo.get(this.el.dom);
6778 var thd = this.getGridEl().select('thead',true).first();
6779 var tbd = this.getGridEl().select('tbody', true).first();
6780 var tfd = this.getGridEl().select('tfoot', true).first();
6782 var cw = ctr.getWidth();
6786 tbd.setSize(ctr.getWidth(),
6787 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6789 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6792 cw = Math.max(cw, this.totalWidth);
6793 this.getGridEl().select('tr',true).setWidth(cw);
6794 // resize 'expandable coloumn?
6796 return; // we doe not have a view in this design..
6799 onBodyScroll: function()
6802 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6803 this.mainHead.setStyle({
6804 'position' : 'relative',
6805 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6822 * @class Roo.bootstrap.TableCell
6823 * @extends Roo.bootstrap.Component
6824 * Bootstrap TableCell class
6825 * @cfg {String} html cell contain text
6826 * @cfg {String} cls cell class
6827 * @cfg {String} tag cell tag (td|th) default td
6828 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6829 * @cfg {String} align Aligns the content in a cell
6830 * @cfg {String} axis Categorizes cells
6831 * @cfg {String} bgcolor Specifies the background color of a cell
6832 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6833 * @cfg {Number} colspan Specifies the number of columns a cell should span
6834 * @cfg {String} headers Specifies one or more header cells a cell is related to
6835 * @cfg {Number} height Sets the height of a cell
6836 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6837 * @cfg {Number} rowspan Sets the number of rows a cell should span
6838 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6839 * @cfg {String} valign Vertical aligns the content in a cell
6840 * @cfg {Number} width Specifies the width of a cell
6843 * Create a new TableCell
6844 * @param {Object} config The config object
6847 Roo.bootstrap.TableCell = function(config){
6848 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6851 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6871 getAutoCreate : function(){
6872 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6892 cfg.align=this.align
6898 cfg.bgcolor=this.bgcolor
6901 cfg.charoff=this.charoff
6904 cfg.colspan=this.colspan
6907 cfg.headers=this.headers
6910 cfg.height=this.height
6913 cfg.nowrap=this.nowrap
6916 cfg.rowspan=this.rowspan
6919 cfg.scope=this.scope
6922 cfg.valign=this.valign
6925 cfg.width=this.width
6944 * @class Roo.bootstrap.TableRow
6945 * @extends Roo.bootstrap.Component
6946 * Bootstrap TableRow class
6947 * @cfg {String} cls row class
6948 * @cfg {String} align Aligns the content in a table row
6949 * @cfg {String} bgcolor Specifies a background color for a table row
6950 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6951 * @cfg {String} valign Vertical aligns the content in a table row
6954 * Create a new TableRow
6955 * @param {Object} config The config object
6958 Roo.bootstrap.TableRow = function(config){
6959 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6962 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6970 getAutoCreate : function(){
6971 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6981 cfg.align = this.align;
6984 cfg.bgcolor = this.bgcolor;
6987 cfg.charoff = this.charoff;
6990 cfg.valign = this.valign;
7008 * @class Roo.bootstrap.TableBody
7009 * @extends Roo.bootstrap.Component
7010 * Bootstrap TableBody class
7011 * @cfg {String} cls element class
7012 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7013 * @cfg {String} align Aligns the content inside the element
7014 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7015 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7018 * Create a new TableBody
7019 * @param {Object} config The config object
7022 Roo.bootstrap.TableBody = function(config){
7023 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7026 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7034 getAutoCreate : function(){
7035 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7049 cfg.align = this.align;
7052 cfg.charoff = this.charoff;
7055 cfg.valign = this.valign;
7062 // initEvents : function()
7069 // this.store = Roo.factory(this.store, Roo.data);
7070 // this.store.on('load', this.onLoad, this);
7072 // this.store.load();
7076 // onLoad: function ()
7078 // this.fireEvent('load', this);
7088 * Ext JS Library 1.1.1
7089 * Copyright(c) 2006-2007, Ext JS, LLC.
7091 * Originally Released Under LGPL - original licence link has changed is not relivant.
7094 * <script type="text/javascript">
7097 // as we use this in bootstrap.
7098 Roo.namespace('Roo.form');
7100 * @class Roo.form.Action
7101 * Internal Class used to handle form actions
7103 * @param {Roo.form.BasicForm} el The form element or its id
7104 * @param {Object} config Configuration options
7109 // define the action interface
7110 Roo.form.Action = function(form, options){
7112 this.options = options || {};
7115 * Client Validation Failed
7118 Roo.form.Action.CLIENT_INVALID = 'client';
7120 * Server Validation Failed
7123 Roo.form.Action.SERVER_INVALID = 'server';
7125 * Connect to Server Failed
7128 Roo.form.Action.CONNECT_FAILURE = 'connect';
7130 * Reading Data from Server Failed
7133 Roo.form.Action.LOAD_FAILURE = 'load';
7135 Roo.form.Action.prototype = {
7137 failureType : undefined,
7138 response : undefined,
7142 run : function(options){
7147 success : function(response){
7152 handleResponse : function(response){
7156 // default connection failure
7157 failure : function(response){
7159 this.response = response;
7160 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7161 this.form.afterAction(this, false);
7164 processResponse : function(response){
7165 this.response = response;
7166 if(!response.responseText){
7169 this.result = this.handleResponse(response);
7173 // utility functions used internally
7174 getUrl : function(appendParams){
7175 var url = this.options.url || this.form.url || this.form.el.dom.action;
7177 var p = this.getParams();
7179 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7185 getMethod : function(){
7186 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7189 getParams : function(){
7190 var bp = this.form.baseParams;
7191 var p = this.options.params;
7193 if(typeof p == "object"){
7194 p = Roo.urlEncode(Roo.applyIf(p, bp));
7195 }else if(typeof p == 'string' && bp){
7196 p += '&' + Roo.urlEncode(bp);
7199 p = Roo.urlEncode(bp);
7204 createCallback : function(){
7206 success: this.success,
7207 failure: this.failure,
7209 timeout: (this.form.timeout*1000),
7210 upload: this.form.fileUpload ? this.success : undefined
7215 Roo.form.Action.Submit = function(form, options){
7216 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7219 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7222 haveProgress : false,
7223 uploadComplete : false,
7225 // uploadProgress indicator.
7226 uploadProgress : function()
7228 if (!this.form.progressUrl) {
7232 if (!this.haveProgress) {
7233 Roo.MessageBox.progress("Uploading", "Uploading");
7235 if (this.uploadComplete) {
7236 Roo.MessageBox.hide();
7240 this.haveProgress = true;
7242 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7244 var c = new Roo.data.Connection();
7246 url : this.form.progressUrl,
7251 success : function(req){
7252 //console.log(data);
7256 rdata = Roo.decode(req.responseText)
7258 Roo.log("Invalid data from server..");
7262 if (!rdata || !rdata.success) {
7264 Roo.MessageBox.alert(Roo.encode(rdata));
7267 var data = rdata.data;
7269 if (this.uploadComplete) {
7270 Roo.MessageBox.hide();
7275 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7276 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7279 this.uploadProgress.defer(2000,this);
7282 failure: function(data) {
7283 Roo.log('progress url failed ');
7294 // run get Values on the form, so it syncs any secondary forms.
7295 this.form.getValues();
7297 var o = this.options;
7298 var method = this.getMethod();
7299 var isPost = method == 'POST';
7300 if(o.clientValidation === false || this.form.isValid()){
7302 if (this.form.progressUrl) {
7303 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7304 (new Date() * 1) + '' + Math.random());
7309 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7310 form:this.form.el.dom,
7311 url:this.getUrl(!isPost),
7313 params:isPost ? this.getParams() : null,
7314 isUpload: this.form.fileUpload
7317 this.uploadProgress();
7319 }else if (o.clientValidation !== false){ // client validation failed
7320 this.failureType = Roo.form.Action.CLIENT_INVALID;
7321 this.form.afterAction(this, false);
7325 success : function(response)
7327 this.uploadComplete= true;
7328 if (this.haveProgress) {
7329 Roo.MessageBox.hide();
7333 var result = this.processResponse(response);
7334 if(result === true || result.success){
7335 this.form.afterAction(this, true);
7339 this.form.markInvalid(result.errors);
7340 this.failureType = Roo.form.Action.SERVER_INVALID;
7342 this.form.afterAction(this, false);
7344 failure : function(response)
7346 this.uploadComplete= true;
7347 if (this.haveProgress) {
7348 Roo.MessageBox.hide();
7351 this.response = response;
7352 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7353 this.form.afterAction(this, false);
7356 handleResponse : function(response){
7357 if(this.form.errorReader){
7358 var rs = this.form.errorReader.read(response);
7361 for(var i = 0, len = rs.records.length; i < len; i++) {
7362 var r = rs.records[i];
7366 if(errors.length < 1){
7370 success : rs.success,
7376 ret = Roo.decode(response.responseText);
7380 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7390 Roo.form.Action.Load = function(form, options){
7391 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7392 this.reader = this.form.reader;
7395 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7400 Roo.Ajax.request(Roo.apply(
7401 this.createCallback(), {
7402 method:this.getMethod(),
7403 url:this.getUrl(false),
7404 params:this.getParams()
7408 success : function(response){
7410 var result = this.processResponse(response);
7411 if(result === true || !result.success || !result.data){
7412 this.failureType = Roo.form.Action.LOAD_FAILURE;
7413 this.form.afterAction(this, false);
7416 this.form.clearInvalid();
7417 this.form.setValues(result.data);
7418 this.form.afterAction(this, true);
7421 handleResponse : function(response){
7422 if(this.form.reader){
7423 var rs = this.form.reader.read(response);
7424 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7426 success : rs.success,
7430 return Roo.decode(response.responseText);
7434 Roo.form.Action.ACTION_TYPES = {
7435 'load' : Roo.form.Action.Load,
7436 'submit' : Roo.form.Action.Submit
7445 * @class Roo.bootstrap.Form
7446 * @extends Roo.bootstrap.Component
7447 * Bootstrap Form class
7448 * @cfg {String} method GET | POST (default POST)
7449 * @cfg {String} labelAlign top | left (default top)
7450 * @cfg {String} align left | right - for navbars
7451 * @cfg {Boolean} loadMask load mask when submit (default true)
7456 * @param {Object} config The config object
7460 Roo.bootstrap.Form = function(config){
7461 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7463 Roo.bootstrap.Form.popover.apply();
7467 * @event clientvalidation
7468 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7469 * @param {Form} this
7470 * @param {Boolean} valid true if the form has passed client-side validation
7472 clientvalidation: true,
7474 * @event beforeaction
7475 * Fires before any action is performed. Return false to cancel the action.
7476 * @param {Form} this
7477 * @param {Action} action The action to be performed
7481 * @event actionfailed
7482 * Fires when an action fails.
7483 * @param {Form} this
7484 * @param {Action} action The action that failed
7486 actionfailed : true,
7488 * @event actioncomplete
7489 * Fires when an action is completed.
7490 * @param {Form} this
7491 * @param {Action} action The action that completed
7493 actioncomplete : true
7498 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7501 * @cfg {String} method
7502 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7507 * The URL to use for form actions if one isn't supplied in the action options.
7510 * @cfg {Boolean} fileUpload
7511 * Set to true if this form is a file upload.
7515 * @cfg {Object} baseParams
7516 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7520 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7524 * @cfg {Sting} align (left|right) for navbar forms
7529 activeAction : null,
7532 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7533 * element by passing it or its id or mask the form itself by passing in true.
7536 waitMsgTarget : false,
7541 * @cfg {Boolean} errorMask (true|false) default false
7545 getAutoCreate : function(){
7549 method : this.method || 'POST',
7550 id : this.id || Roo.id(),
7553 if (this.parent().xtype.match(/^Nav/)) {
7554 cfg.cls = 'navbar-form navbar-' + this.align;
7558 if (this.labelAlign == 'left' ) {
7559 cfg.cls += ' form-horizontal';
7565 initEvents : function()
7567 this.el.on('submit', this.onSubmit, this);
7568 // this was added as random key presses on the form where triggering form submit.
7569 this.el.on('keypress', function(e) {
7570 if (e.getCharCode() != 13) {
7573 // we might need to allow it for textareas.. and some other items.
7574 // check e.getTarget().
7576 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7580 Roo.log("keypress blocked");
7588 onSubmit : function(e){
7593 * Returns true if client-side validation on the form is successful.
7596 isValid : function(){
7597 var items = this.getItems();
7601 items.each(function(f){
7608 if(!target && f.el.isVisible(true)){
7614 if(this.errorMask && !valid){
7615 Roo.bootstrap.Form.popover.mask(this, target);
7622 * Returns true if any fields in this form have changed since their original load.
7625 isDirty : function(){
7627 var items = this.getItems();
7628 items.each(function(f){
7638 * Performs a predefined action (submit or load) or custom actions you define on this form.
7639 * @param {String} actionName The name of the action type
7640 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7641 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7642 * accept other config options):
7644 Property Type Description
7645 ---------------- --------------- ----------------------------------------------------------------------------------
7646 url String The url for the action (defaults to the form's url)
7647 method String The form method to use (defaults to the form's method, or POST if not defined)
7648 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7649 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7650 validate the form on the client (defaults to false)
7652 * @return {BasicForm} this
7654 doAction : function(action, options){
7655 if(typeof action == 'string'){
7656 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7658 if(this.fireEvent('beforeaction', this, action) !== false){
7659 this.beforeAction(action);
7660 action.run.defer(100, action);
7666 beforeAction : function(action){
7667 var o = action.options;
7670 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7672 // not really supported yet.. ??
7674 //if(this.waitMsgTarget === true){
7675 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7676 //}else if(this.waitMsgTarget){
7677 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7678 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7680 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7686 afterAction : function(action, success){
7687 this.activeAction = null;
7688 var o = action.options;
7690 //if(this.waitMsgTarget === true){
7692 //}else if(this.waitMsgTarget){
7693 // this.waitMsgTarget.unmask();
7695 // Roo.MessageBox.updateProgress(1);
7696 // Roo.MessageBox.hide();
7703 Roo.callback(o.success, o.scope, [this, action]);
7704 this.fireEvent('actioncomplete', this, action);
7708 // failure condition..
7709 // we have a scenario where updates need confirming.
7710 // eg. if a locking scenario exists..
7711 // we look for { errors : { needs_confirm : true }} in the response.
7713 (typeof(action.result) != 'undefined') &&
7714 (typeof(action.result.errors) != 'undefined') &&
7715 (typeof(action.result.errors.needs_confirm) != 'undefined')
7718 Roo.log("not supported yet");
7721 Roo.MessageBox.confirm(
7722 "Change requires confirmation",
7723 action.result.errorMsg,
7728 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7738 Roo.callback(o.failure, o.scope, [this, action]);
7739 // show an error message if no failed handler is set..
7740 if (!this.hasListener('actionfailed')) {
7741 Roo.log("need to add dialog support");
7743 Roo.MessageBox.alert("Error",
7744 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7745 action.result.errorMsg :
7746 "Saving Failed, please check your entries or try again"
7751 this.fireEvent('actionfailed', this, action);
7756 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7757 * @param {String} id The value to search for
7760 findField : function(id){
7761 var items = this.getItems();
7762 var field = items.get(id);
7764 items.each(function(f){
7765 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7772 return field || null;
7775 * Mark fields in this form invalid in bulk.
7776 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7777 * @return {BasicForm} this
7779 markInvalid : function(errors){
7780 if(errors instanceof Array){
7781 for(var i = 0, len = errors.length; i < len; i++){
7782 var fieldError = errors[i];
7783 var f = this.findField(fieldError.id);
7785 f.markInvalid(fieldError.msg);
7791 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7792 field.markInvalid(errors[id]);
7796 //Roo.each(this.childForms || [], function (f) {
7797 // f.markInvalid(errors);
7804 * Set values for fields in this form in bulk.
7805 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7806 * @return {BasicForm} this
7808 setValues : function(values){
7809 if(values instanceof Array){ // array of objects
7810 for(var i = 0, len = values.length; i < len; i++){
7812 var f = this.findField(v.id);
7814 f.setValue(v.value);
7815 if(this.trackResetOnLoad){
7816 f.originalValue = f.getValue();
7820 }else{ // object hash
7823 if(typeof values[id] != 'function' && (field = this.findField(id))){
7825 if (field.setFromData &&
7827 field.displayField &&
7828 // combos' with local stores can
7829 // be queried via setValue()
7830 // to set their value..
7831 (field.store && !field.store.isLocal)
7835 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7836 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7837 field.setFromData(sd);
7840 field.setValue(values[id]);
7844 if(this.trackResetOnLoad){
7845 field.originalValue = field.getValue();
7851 //Roo.each(this.childForms || [], function (f) {
7852 // f.setValues(values);
7859 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7860 * they are returned as an array.
7861 * @param {Boolean} asString
7864 getValues : function(asString){
7865 //if (this.childForms) {
7866 // copy values from the child forms
7867 // Roo.each(this.childForms, function (f) {
7868 // this.setValues(f.getValues());
7874 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7875 if(asString === true){
7878 return Roo.urlDecode(fs);
7882 * Returns the fields in this form as an object with key/value pairs.
7883 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7886 getFieldValues : function(with_hidden)
7888 var items = this.getItems();
7890 items.each(function(f){
7894 var v = f.getValue();
7895 if (f.inputType =='radio') {
7896 if (typeof(ret[f.getName()]) == 'undefined') {
7897 ret[f.getName()] = ''; // empty..
7900 if (!f.el.dom.checked) {
7908 // not sure if this supported any more..
7909 if ((typeof(v) == 'object') && f.getRawValue) {
7910 v = f.getRawValue() ; // dates..
7912 // combo boxes where name != hiddenName...
7913 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7914 ret[f.name] = f.getRawValue();
7916 ret[f.getName()] = v;
7923 * Clears all invalid messages in this form.
7924 * @return {BasicForm} this
7926 clearInvalid : function(){
7927 var items = this.getItems();
7929 items.each(function(f){
7940 * @return {BasicForm} this
7943 var items = this.getItems();
7944 items.each(function(f){
7948 Roo.each(this.childForms || [], function (f) {
7955 getItems : function()
7957 var r=new Roo.util.MixedCollection(false, function(o){
7958 return o.id || (o.id = Roo.id());
7960 var iter = function(el) {
7967 Roo.each(el.items,function(e) {
7984 Roo.apply(Roo.bootstrap.Form, {
8011 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8012 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8013 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8014 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8017 this.maskEl.top.enableDisplayMode("block");
8018 this.maskEl.left.enableDisplayMode("block");
8019 this.maskEl.bottom.enableDisplayMode("block");
8020 this.maskEl.right.enableDisplayMode("block");
8022 this.toolTip = new Roo.bootstrap.Tooltip({
8023 cls : 'roo-form-error-popover',
8025 'left' : ['r-l', [-2,0], 'right'],
8026 'right' : ['l-r', [2,0], 'left'],
8027 'bottom' : ['tl-bl', [0,2], 'top'],
8028 'top' : [ 'bl-tl', [0,-2], 'bottom']
8032 this.toolTip.render(Roo.get(document.body));
8034 this.toolTip.el.enableDisplayMode("block");
8036 Roo.get(document.body).on('click', function(){
8040 this.isApplied = true
8043 mask : function(form, target)
8047 this.target = target;
8049 if(!this.form.errorMask || !target.el){
8053 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8055 var scrolled = scrollable.getScroll();
8057 var ot = this.target.el.calcOffsetsTo(scrollable);
8059 scrollTo = ot[1] - 100;
8061 scrollable.scrollTo('top', scrollTo);
8063 var box = this.target.el.getBox();
8065 var zIndex = Roo.bootstrap.Modal.zIndex++;
8067 this.maskEl.top.setStyle('position', 'fixed');
8068 this.maskEl.top.setStyle('z-index', zIndex);
8069 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8070 this.maskEl.top.setXY([0, 0]);
8071 this.maskEl.top.show();
8073 this.maskEl.left.setStyle('position', 'fixed');
8074 this.maskEl.left.setStyle('z-index', zIndex);
8075 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8076 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8077 this.maskEl.left.show();
8079 this.maskEl.bottom.setStyle('position', 'fixed');
8080 this.maskEl.bottom.setStyle('z-index', zIndex);
8081 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8082 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8083 this.maskEl.bottom.show();
8085 this.maskEl.right.setStyle('position', 'fixed');
8086 this.maskEl.right.setStyle('z-index', zIndex);
8087 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8088 this.maskEl.right.setXY([0, box.y - this.padding]);
8089 this.maskEl.right.show();
8092 this.toolTip.bindEl = this.target.el;
8094 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8096 var tip = this.target.blankText;
8098 if(this.target.getValue() !== '' && this.target.regexText.length){
8099 tip = this.target.regexText;
8102 this.toolTip.show(tip);
8104 this.intervalID = window.setInterval(function() {
8105 Roo.bootstrap.Form.popover.unmask();
8108 window.onwheel = function(){ return false;};
8110 (function(){ this.isMasked = true; }).defer(500, this);
8118 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8122 this.maskEl.top.setStyle('position', 'absolute');
8123 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8124 this.maskEl.top.hide();
8126 this.maskEl.left.setStyle('position', 'absolute');
8127 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8128 this.maskEl.left.hide();
8130 this.maskEl.bottom.setStyle('position', 'absolute');
8131 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8132 this.maskEl.bottom.hide();
8134 this.maskEl.right.setStyle('position', 'absolute');
8135 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8136 this.maskEl.right.hide();
8138 this.toolTip.hide();
8140 this.toolTip.el.hide();
8142 window.onwheel = function(){ return true;};
8144 if(this.intervalID){
8145 window.clearInterval(this.intervalID);
8146 this.intervalID = false;
8149 this.isMasked = false;
8159 * Ext JS Library 1.1.1
8160 * Copyright(c) 2006-2007, Ext JS, LLC.
8162 * Originally Released Under LGPL - original licence link has changed is not relivant.
8165 * <script type="text/javascript">
8168 * @class Roo.form.VTypes
8169 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8172 Roo.form.VTypes = function(){
8173 // closure these in so they are only created once.
8174 var alpha = /^[a-zA-Z_]+$/;
8175 var alphanum = /^[a-zA-Z0-9_]+$/;
8176 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8177 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8179 // All these messages and functions are configurable
8182 * The function used to validate email addresses
8183 * @param {String} value The email address
8185 'email' : function(v){
8186 return email.test(v);
8189 * The error text to display when the email validation function returns false
8192 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8194 * The keystroke filter mask to be applied on email input
8197 'emailMask' : /[a-z0-9_\.\-@]/i,
8200 * The function used to validate URLs
8201 * @param {String} value The URL
8203 'url' : function(v){
8207 * The error text to display when the url validation function returns false
8210 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8213 * The function used to validate alpha values
8214 * @param {String} value The value
8216 'alpha' : function(v){
8217 return alpha.test(v);
8220 * The error text to display when the alpha validation function returns false
8223 'alphaText' : 'This field should only contain letters and _',
8225 * The keystroke filter mask to be applied on alpha input
8228 'alphaMask' : /[a-z_]/i,
8231 * The function used to validate alphanumeric values
8232 * @param {String} value The value
8234 'alphanum' : function(v){
8235 return alphanum.test(v);
8238 * The error text to display when the alphanumeric validation function returns false
8241 'alphanumText' : 'This field should only contain letters, numbers and _',
8243 * The keystroke filter mask to be applied on alphanumeric input
8246 'alphanumMask' : /[a-z0-9_]/i
8256 * @class Roo.bootstrap.Input
8257 * @extends Roo.bootstrap.Component
8258 * Bootstrap Input class
8259 * @cfg {Boolean} disabled is it disabled
8260 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8261 * @cfg {String} name name of the input
8262 * @cfg {string} fieldLabel - the label associated
8263 * @cfg {string} placeholder - placeholder to put in text.
8264 * @cfg {string} before - input group add on before
8265 * @cfg {string} after - input group add on after
8266 * @cfg {string} size - (lg|sm) or leave empty..
8267 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8268 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8269 * @cfg {Number} md colspan out of 12 for computer-sized screens
8270 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8271 * @cfg {string} value default value of the input
8272 * @cfg {Number} labelWidth set the width of label
8273 * @cfg {Number} labellg set the width of label (1-12)
8274 * @cfg {Number} labelmd set the width of label (1-12)
8275 * @cfg {Number} labelsm set the width of label (1-12)
8276 * @cfg {Number} labelxs set the width of label (1-12)
8277 * @cfg {String} labelAlign (top|left)
8278 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8279 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8280 * @cfg {String} indicatorpos (left|right) default left
8282 * @cfg {String} align (left|center|right) Default left
8283 * @cfg {Boolean} forceFeedback (true|false) Default false
8289 * Create a new Input
8290 * @param {Object} config The config object
8293 Roo.bootstrap.Input = function(config){
8295 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8300 * Fires when this field receives input focus.
8301 * @param {Roo.form.Field} this
8306 * Fires when this field loses input focus.
8307 * @param {Roo.form.Field} this
8312 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8313 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8314 * @param {Roo.form.Field} this
8315 * @param {Roo.EventObject} e The event object
8320 * Fires just before the field blurs if the field value has changed.
8321 * @param {Roo.form.Field} this
8322 * @param {Mixed} newValue The new value
8323 * @param {Mixed} oldValue The original value
8328 * Fires after the field has been marked as invalid.
8329 * @param {Roo.form.Field} this
8330 * @param {String} msg The validation message
8335 * Fires after the field has been validated with no errors.
8336 * @param {Roo.form.Field} this
8341 * Fires after the key up
8342 * @param {Roo.form.Field} this
8343 * @param {Roo.EventObject} e The event Object
8349 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8351 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8352 automatic validation (defaults to "keyup").
8354 validationEvent : "keyup",
8356 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8358 validateOnBlur : true,
8360 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8362 validationDelay : 250,
8364 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8366 focusClass : "x-form-focus", // not needed???
8370 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8372 invalidClass : "has-warning",
8375 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8377 validClass : "has-success",
8380 * @cfg {Boolean} hasFeedback (true|false) default true
8385 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8387 invalidFeedbackClass : "glyphicon-warning-sign",
8390 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8392 validFeedbackClass : "glyphicon-ok",
8395 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8397 selectOnFocus : false,
8400 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8404 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8409 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8411 disableKeyFilter : false,
8414 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8418 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8422 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8424 blankText : "Please complete this mandatory field",
8427 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8431 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8433 maxLength : Number.MAX_VALUE,
8435 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8437 minLengthText : "The minimum length for this field is {0}",
8439 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8441 maxLengthText : "The maximum length for this field is {0}",
8445 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8446 * If available, this function will be called only after the basic validators all return true, and will be passed the
8447 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8451 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8452 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8453 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8457 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8461 autocomplete: false,
8480 formatedValue : false,
8481 forceFeedback : false,
8483 indicatorpos : 'left',
8490 parentLabelAlign : function()
8493 while (parent.parent()) {
8494 parent = parent.parent();
8495 if (typeof(parent.labelAlign) !='undefined') {
8496 return parent.labelAlign;
8503 getAutoCreate : function()
8505 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8511 if(this.inputType != 'hidden'){
8512 cfg.cls = 'form-group' //input-group
8518 type : this.inputType,
8520 cls : 'form-control',
8521 placeholder : this.placeholder || '',
8522 autocomplete : this.autocomplete || 'new-password'
8526 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8529 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8530 input.maxLength = this.maxLength;
8533 if (this.disabled) {
8534 input.disabled=true;
8537 if (this.readOnly) {
8538 input.readonly=true;
8542 input.name = this.name;
8546 input.cls += ' input-' + this.size;
8550 ['xs','sm','md','lg'].map(function(size){
8551 if (settings[size]) {
8552 cfg.cls += ' col-' + size + '-' + settings[size];
8556 var inputblock = input;
8560 cls: 'glyphicon form-control-feedback'
8563 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8566 cls : 'has-feedback',
8574 if (this.before || this.after) {
8577 cls : 'input-group',
8581 if (this.before && typeof(this.before) == 'string') {
8583 inputblock.cn.push({
8585 cls : 'roo-input-before input-group-addon',
8589 if (this.before && typeof(this.before) == 'object') {
8590 this.before = Roo.factory(this.before);
8592 inputblock.cn.push({
8594 cls : 'roo-input-before input-group-' +
8595 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8599 inputblock.cn.push(input);
8601 if (this.after && typeof(this.after) == 'string') {
8602 inputblock.cn.push({
8604 cls : 'roo-input-after input-group-addon',
8608 if (this.after && typeof(this.after) == 'object') {
8609 this.after = Roo.factory(this.after);
8611 inputblock.cn.push({
8613 cls : 'roo-input-after input-group-' +
8614 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8618 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8619 inputblock.cls += ' has-feedback';
8620 inputblock.cn.push(feedback);
8624 if (align ==='left' && this.fieldLabel.length) {
8626 cfg.cls += ' roo-form-group-label-left';
8631 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8632 tooltip : 'This field is required'
8637 cls : 'control-label',
8638 html : this.fieldLabel
8649 var labelCfg = cfg.cn[1];
8650 var contentCfg = cfg.cn[2];
8652 if(this.indicatorpos == 'right'){
8657 cls : 'control-label',
8658 html : this.fieldLabel
8663 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8664 tooltip : 'This field is required'
8675 labelCfg = cfg.cn[0];
8676 contentCfg = cfg.cn[2];
8680 if(this.labelWidth > 12){
8681 labelCfg.style = "width: " + this.labelWidth + 'px';
8684 if(this.labelWidth < 13 && this.labelmd == 0){
8685 this.labelmd = this.labelWidth;
8688 if(this.labellg > 0){
8689 labelCfg.cls += ' col-lg-' + this.labellg;
8690 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8693 if(this.labelmd > 0){
8694 labelCfg.cls += ' col-md-' + this.labelmd;
8695 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8698 if(this.labelsm > 0){
8699 labelCfg.cls += ' col-sm-' + this.labelsm;
8700 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8703 if(this.labelxs > 0){
8704 labelCfg.cls += ' col-xs-' + this.labelxs;
8705 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8709 } else if ( this.fieldLabel.length) {
8714 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8715 tooltip : 'This field is required'
8719 //cls : 'input-group-addon',
8720 html : this.fieldLabel
8728 if(this.indicatorpos == 'right'){
8733 //cls : 'input-group-addon',
8734 html : this.fieldLabel
8739 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8740 tooltip : 'This field is required'
8760 if (this.parentType === 'Navbar' && this.parent().bar) {
8761 cfg.cls += ' navbar-form';
8764 if (this.parentType === 'NavGroup') {
8765 cfg.cls += ' navbar-form';
8773 * return the real input element.
8775 inputEl: function ()
8777 return this.el.select('input.form-control',true).first();
8780 tooltipEl : function()
8782 return this.inputEl();
8785 indicatorEl : function()
8787 var indicator = this.el.select('i.roo-required-indicator',true).first();
8797 setDisabled : function(v)
8799 var i = this.inputEl().dom;
8801 i.removeAttribute('disabled');
8805 i.setAttribute('disabled','true');
8807 initEvents : function()
8810 this.inputEl().on("keydown" , this.fireKey, this);
8811 this.inputEl().on("focus", this.onFocus, this);
8812 this.inputEl().on("blur", this.onBlur, this);
8814 this.inputEl().relayEvent('keyup', this);
8816 this.indicator = this.indicatorEl();
8819 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8820 this.indicator.hide();
8823 // reference to original value for reset
8824 this.originalValue = this.getValue();
8825 //Roo.form.TextField.superclass.initEvents.call(this);
8826 if(this.validationEvent == 'keyup'){
8827 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8828 this.inputEl().on('keyup', this.filterValidation, this);
8830 else if(this.validationEvent !== false){
8831 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8834 if(this.selectOnFocus){
8835 this.on("focus", this.preFocus, this);
8838 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8839 this.inputEl().on("keypress", this.filterKeys, this);
8841 this.inputEl().relayEvent('keypress', this);
8844 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8845 this.el.on("click", this.autoSize, this);
8848 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8849 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8852 if (typeof(this.before) == 'object') {
8853 this.before.render(this.el.select('.roo-input-before',true).first());
8855 if (typeof(this.after) == 'object') {
8856 this.after.render(this.el.select('.roo-input-after',true).first());
8861 filterValidation : function(e){
8862 if(!e.isNavKeyPress()){
8863 this.validationTask.delay(this.validationDelay);
8867 * Validates the field value
8868 * @return {Boolean} True if the value is valid, else false
8870 validate : function(){
8871 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8872 if(this.disabled || this.validateValue(this.getRawValue())){
8883 * Validates a value according to the field's validation rules and marks the field as invalid
8884 * if the validation fails
8885 * @param {Mixed} value The value to validate
8886 * @return {Boolean} True if the value is valid, else false
8888 validateValue : function(value){
8889 if(value.length < 1) { // if it's blank
8890 if(this.allowBlank){
8896 if(value.length < this.minLength){
8899 if(value.length > this.maxLength){
8903 var vt = Roo.form.VTypes;
8904 if(!vt[this.vtype](value, this)){
8908 if(typeof this.validator == "function"){
8909 var msg = this.validator(value);
8915 if(this.regex && !this.regex.test(value)){
8925 fireKey : function(e){
8926 //Roo.log('field ' + e.getKey());
8927 if(e.isNavKeyPress()){
8928 this.fireEvent("specialkey", this, e);
8931 focus : function (selectText){
8933 this.inputEl().focus();
8934 if(selectText === true){
8935 this.inputEl().dom.select();
8941 onFocus : function(){
8942 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8943 // this.el.addClass(this.focusClass);
8946 this.hasFocus = true;
8947 this.startValue = this.getValue();
8948 this.fireEvent("focus", this);
8952 beforeBlur : Roo.emptyFn,
8956 onBlur : function(){
8958 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8959 //this.el.removeClass(this.focusClass);
8961 this.hasFocus = false;
8962 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8965 var v = this.getValue();
8966 if(String(v) !== String(this.startValue)){
8967 this.fireEvent('change', this, v, this.startValue);
8969 this.fireEvent("blur", this);
8973 * Resets the current field value to the originally loaded value and clears any validation messages
8976 this.setValue(this.originalValue);
8980 * Returns the name of the field
8981 * @return {Mixed} name The name field
8983 getName: function(){
8987 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8988 * @return {Mixed} value The field value
8990 getValue : function(){
8992 var v = this.inputEl().getValue();
8997 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8998 * @return {Mixed} value The field value
9000 getRawValue : function(){
9001 var v = this.inputEl().getValue();
9007 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9008 * @param {Mixed} value The value to set
9010 setRawValue : function(v){
9011 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9014 selectText : function(start, end){
9015 var v = this.getRawValue();
9017 start = start === undefined ? 0 : start;
9018 end = end === undefined ? v.length : end;
9019 var d = this.inputEl().dom;
9020 if(d.setSelectionRange){
9021 d.setSelectionRange(start, end);
9022 }else if(d.createTextRange){
9023 var range = d.createTextRange();
9024 range.moveStart("character", start);
9025 range.moveEnd("character", v.length-end);
9032 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9033 * @param {Mixed} value The value to set
9035 setValue : function(v){
9038 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9044 processValue : function(value){
9045 if(this.stripCharsRe){
9046 var newValue = value.replace(this.stripCharsRe, '');
9047 if(newValue !== value){
9048 this.setRawValue(newValue);
9055 preFocus : function(){
9057 if(this.selectOnFocus){
9058 this.inputEl().dom.select();
9061 filterKeys : function(e){
9063 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9066 var c = e.getCharCode(), cc = String.fromCharCode(c);
9067 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9070 if(!this.maskRe.test(cc)){
9075 * Clear any invalid styles/messages for this field
9077 clearInvalid : function(){
9079 if(!this.el || this.preventMark){ // not rendered
9084 this.indicator.hide();
9087 this.el.removeClass(this.invalidClass);
9089 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9091 var feedback = this.el.select('.form-control-feedback', true).first();
9094 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9099 this.fireEvent('valid', this);
9103 * Mark this field as valid
9105 markValid : function()
9107 if(!this.el || this.preventMark){ // not rendered...
9111 this.el.removeClass([this.invalidClass, this.validClass]);
9113 var feedback = this.el.select('.form-control-feedback', true).first();
9116 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9123 if(this.allowBlank && !this.getRawValue().length){
9128 this.indicator.hide();
9131 this.el.addClass(this.validClass);
9133 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9135 var feedback = this.el.select('.form-control-feedback', true).first();
9138 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9139 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9144 this.fireEvent('valid', this);
9148 * Mark this field as invalid
9149 * @param {String} msg The validation message
9151 markInvalid : function(msg)
9153 if(!this.el || this.preventMark){ // not rendered
9157 this.el.removeClass([this.invalidClass, this.validClass]);
9159 var feedback = this.el.select('.form-control-feedback', true).first();
9162 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9169 if(this.allowBlank && !this.getRawValue().length){
9174 this.indicator.show();
9177 this.el.addClass(this.invalidClass);
9179 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9181 var feedback = this.el.select('.form-control-feedback', true).first();
9184 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9186 if(this.getValue().length || this.forceFeedback){
9187 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9194 this.fireEvent('invalid', this, msg);
9197 SafariOnKeyDown : function(event)
9199 // this is a workaround for a password hang bug on chrome/ webkit.
9200 if (this.inputEl().dom.type != 'password') {
9204 var isSelectAll = false;
9206 if(this.inputEl().dom.selectionEnd > 0){
9207 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9209 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9210 event.preventDefault();
9215 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9217 event.preventDefault();
9218 // this is very hacky as keydown always get's upper case.
9220 var cc = String.fromCharCode(event.getCharCode());
9221 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9225 adjustWidth : function(tag, w){
9226 tag = tag.toLowerCase();
9227 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9228 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9232 if(tag == 'textarea'){
9235 }else if(Roo.isOpera){
9239 if(tag == 'textarea'){
9258 * @class Roo.bootstrap.TextArea
9259 * @extends Roo.bootstrap.Input
9260 * Bootstrap TextArea class
9261 * @cfg {Number} cols Specifies the visible width of a text area
9262 * @cfg {Number} rows Specifies the visible number of lines in a text area
9263 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9264 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9265 * @cfg {string} html text
9268 * Create a new TextArea
9269 * @param {Object} config The config object
9272 Roo.bootstrap.TextArea = function(config){
9273 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9277 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9287 getAutoCreate : function(){
9289 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9300 value : this.value || '',
9301 html: this.html || '',
9302 cls : 'form-control',
9303 placeholder : this.placeholder || ''
9307 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9308 input.maxLength = this.maxLength;
9312 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9316 input.cols = this.cols;
9319 if (this.readOnly) {
9320 input.readonly = true;
9324 input.name = this.name;
9328 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9332 ['xs','sm','md','lg'].map(function(size){
9333 if (settings[size]) {
9334 cfg.cls += ' col-' + size + '-' + settings[size];
9338 var inputblock = input;
9340 if(this.hasFeedback && !this.allowBlank){
9344 cls: 'glyphicon form-control-feedback'
9348 cls : 'has-feedback',
9357 if (this.before || this.after) {
9360 cls : 'input-group',
9364 inputblock.cn.push({
9366 cls : 'input-group-addon',
9371 inputblock.cn.push(input);
9373 if(this.hasFeedback && !this.allowBlank){
9374 inputblock.cls += ' has-feedback';
9375 inputblock.cn.push(feedback);
9379 inputblock.cn.push({
9381 cls : 'input-group-addon',
9388 if (align ==='left' && this.fieldLabel.length) {
9393 cls : 'control-label',
9394 html : this.fieldLabel
9405 if(this.labelWidth > 12){
9406 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9409 if(this.labelWidth < 13 && this.labelmd == 0){
9410 this.labelmd = this.labelWidth;
9413 if(this.labellg > 0){
9414 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9415 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9418 if(this.labelmd > 0){
9419 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9420 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9423 if(this.labelsm > 0){
9424 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9425 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9428 if(this.labelxs > 0){
9429 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9430 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9433 } else if ( this.fieldLabel.length) {
9438 //cls : 'input-group-addon',
9439 html : this.fieldLabel
9457 if (this.disabled) {
9458 input.disabled=true;
9465 * return the real textarea element.
9467 inputEl: function ()
9469 return this.el.select('textarea.form-control',true).first();
9473 * Clear any invalid styles/messages for this field
9475 clearInvalid : function()
9478 if(!this.el || this.preventMark){ // not rendered
9482 var label = this.el.select('label', true).first();
9483 var icon = this.el.select('i.fa-star', true).first();
9489 this.el.removeClass(this.invalidClass);
9491 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9493 var feedback = this.el.select('.form-control-feedback', true).first();
9496 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9501 this.fireEvent('valid', this);
9505 * Mark this field as valid
9507 markValid : function()
9509 if(!this.el || this.preventMark){ // not rendered
9513 this.el.removeClass([this.invalidClass, this.validClass]);
9515 var feedback = this.el.select('.form-control-feedback', true).first();
9518 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9521 if(this.disabled || this.allowBlank){
9525 var label = this.el.select('label', true).first();
9526 var icon = this.el.select('i.fa-star', true).first();
9532 this.el.addClass(this.validClass);
9534 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9536 var feedback = this.el.select('.form-control-feedback', true).first();
9539 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9540 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9545 this.fireEvent('valid', this);
9549 * Mark this field as invalid
9550 * @param {String} msg The validation message
9552 markInvalid : function(msg)
9554 if(!this.el || this.preventMark){ // not rendered
9558 this.el.removeClass([this.invalidClass, this.validClass]);
9560 var feedback = this.el.select('.form-control-feedback', true).first();
9563 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9566 if(this.disabled || this.allowBlank){
9570 var label = this.el.select('label', true).first();
9571 var icon = this.el.select('i.fa-star', true).first();
9573 if(!this.getValue().length && label && !icon){
9574 this.el.createChild({
9576 cls : 'text-danger fa fa-lg fa-star',
9577 tooltip : 'This field is required',
9578 style : 'margin-right:5px;'
9582 this.el.addClass(this.invalidClass);
9584 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9586 var feedback = this.el.select('.form-control-feedback', true).first();
9589 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9591 if(this.getValue().length || this.forceFeedback){
9592 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9599 this.fireEvent('invalid', this, msg);
9607 * trigger field - base class for combo..
9612 * @class Roo.bootstrap.TriggerField
9613 * @extends Roo.bootstrap.Input
9614 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9615 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9616 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9617 * for which you can provide a custom implementation. For example:
9619 var trigger = new Roo.bootstrap.TriggerField();
9620 trigger.onTriggerClick = myTriggerFn;
9621 trigger.applyTo('my-field');
9624 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9625 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9626 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9627 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9628 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9631 * Create a new TriggerField.
9632 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9633 * to the base TextField)
9635 Roo.bootstrap.TriggerField = function(config){
9636 this.mimicing = false;
9637 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9640 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9642 * @cfg {String} triggerClass A CSS class to apply to the trigger
9645 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9650 * @cfg {Boolean} removable (true|false) special filter default false
9654 /** @cfg {Boolean} grow @hide */
9655 /** @cfg {Number} growMin @hide */
9656 /** @cfg {Number} growMax @hide */
9662 autoSize: Roo.emptyFn,
9669 actionMode : 'wrap',
9674 getAutoCreate : function(){
9676 var align = this.labelAlign || this.parentLabelAlign();
9681 cls: 'form-group' //input-group
9688 type : this.inputType,
9689 cls : 'form-control',
9690 autocomplete: 'new-password',
9691 placeholder : this.placeholder || ''
9695 input.name = this.name;
9698 input.cls += ' input-' + this.size;
9701 if (this.disabled) {
9702 input.disabled=true;
9705 var inputblock = input;
9707 if(this.hasFeedback && !this.allowBlank){
9711 cls: 'glyphicon form-control-feedback'
9714 if(this.removable && !this.editable && !this.tickable){
9716 cls : 'has-feedback',
9722 cls : 'roo-combo-removable-btn close'
9729 cls : 'has-feedback',
9738 if(this.removable && !this.editable && !this.tickable){
9740 cls : 'roo-removable',
9746 cls : 'roo-combo-removable-btn close'
9753 if (this.before || this.after) {
9756 cls : 'input-group',
9760 inputblock.cn.push({
9762 cls : 'input-group-addon',
9767 inputblock.cn.push(input);
9769 if(this.hasFeedback && !this.allowBlank){
9770 inputblock.cls += ' has-feedback';
9771 inputblock.cn.push(feedback);
9775 inputblock.cn.push({
9777 cls : 'input-group-addon',
9790 cls: 'form-hidden-field'
9804 cls: 'form-hidden-field'
9808 cls: 'roo-select2-choices',
9812 cls: 'roo-select2-search-field',
9825 cls: 'roo-select2-container input-group',
9830 // cls: 'typeahead typeahead-long dropdown-menu',
9831 // style: 'display:none'
9836 if(!this.multiple && this.showToggleBtn){
9842 if (this.caret != false) {
9845 cls: 'fa fa-' + this.caret
9852 cls : 'input-group-addon btn dropdown-toggle',
9857 cls: 'combobox-clear',
9871 combobox.cls += ' roo-select2-container-multi';
9874 if (align ==='left' && this.fieldLabel.length) {
9876 cfg.cls += ' roo-form-group-label-left';
9881 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9882 tooltip : 'This field is required'
9887 cls : 'control-label',
9888 html : this.fieldLabel
9900 var labelCfg = cfg.cn[1];
9901 var contentCfg = cfg.cn[2];
9903 if(this.indicatorpos == 'right'){
9908 cls : 'control-label',
9912 html : this.fieldLabel
9916 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9917 tooltip : 'This field is required'
9930 labelCfg = cfg.cn[0];
9931 contentCfg = cfg.cn[1];
9934 if(this.labelWidth > 12){
9935 labelCfg.style = "width: " + this.labelWidth + 'px';
9938 if(this.labelWidth < 13 && this.labelmd == 0){
9939 this.labelmd = this.labelWidth;
9942 if(this.labellg > 0){
9943 labelCfg.cls += ' col-lg-' + this.labellg;
9944 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9947 if(this.labelmd > 0){
9948 labelCfg.cls += ' col-md-' + this.labelmd;
9949 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9952 if(this.labelsm > 0){
9953 labelCfg.cls += ' col-sm-' + this.labelsm;
9954 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9957 if(this.labelxs > 0){
9958 labelCfg.cls += ' col-xs-' + this.labelxs;
9959 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9962 } else if ( this.fieldLabel.length) {
9963 // Roo.log(" label");
9967 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9968 tooltip : 'This field is required'
9972 //cls : 'input-group-addon',
9973 html : this.fieldLabel
9981 if(this.indicatorpos == 'right'){
9989 html : this.fieldLabel
9993 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9994 tooltip : 'This field is required'
10007 // Roo.log(" no label && no align");
10014 ['xs','sm','md','lg'].map(function(size){
10015 if (settings[size]) {
10016 cfg.cls += ' col-' + size + '-' + settings[size];
10027 onResize : function(w, h){
10028 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10029 // if(typeof w == 'number'){
10030 // var x = w - this.trigger.getWidth();
10031 // this.inputEl().setWidth(this.adjustWidth('input', x));
10032 // this.trigger.setStyle('left', x+'px');
10037 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10040 getResizeEl : function(){
10041 return this.inputEl();
10045 getPositionEl : function(){
10046 return this.inputEl();
10050 alignErrorIcon : function(){
10051 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10055 initEvents : function(){
10059 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10060 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10061 if(!this.multiple && this.showToggleBtn){
10062 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10063 if(this.hideTrigger){
10064 this.trigger.setDisplayed(false);
10066 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10070 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10073 if(this.removable && !this.editable && !this.tickable){
10074 var close = this.closeTriggerEl();
10077 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10078 close.on('click', this.removeBtnClick, this, close);
10082 //this.trigger.addClassOnOver('x-form-trigger-over');
10083 //this.trigger.addClassOnClick('x-form-trigger-click');
10086 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10090 closeTriggerEl : function()
10092 var close = this.el.select('.roo-combo-removable-btn', true).first();
10093 return close ? close : false;
10096 removeBtnClick : function(e, h, el)
10098 e.preventDefault();
10100 if(this.fireEvent("remove", this) !== false){
10102 this.fireEvent("afterremove", this)
10106 createList : function()
10108 this.list = Roo.get(document.body).createChild({
10110 cls: 'typeahead typeahead-long dropdown-menu',
10111 style: 'display:none'
10114 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10119 initTrigger : function(){
10124 onDestroy : function(){
10126 this.trigger.removeAllListeners();
10127 // this.trigger.remove();
10130 // this.wrap.remove();
10132 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10136 onFocus : function(){
10137 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10139 if(!this.mimicing){
10140 this.wrap.addClass('x-trigger-wrap-focus');
10141 this.mimicing = true;
10142 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10143 if(this.monitorTab){
10144 this.el.on("keydown", this.checkTab, this);
10151 checkTab : function(e){
10152 if(e.getKey() == e.TAB){
10153 this.triggerBlur();
10158 onBlur : function(){
10163 mimicBlur : function(e, t){
10165 if(!this.wrap.contains(t) && this.validateBlur()){
10166 this.triggerBlur();
10172 triggerBlur : function(){
10173 this.mimicing = false;
10174 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10175 if(this.monitorTab){
10176 this.el.un("keydown", this.checkTab, this);
10178 //this.wrap.removeClass('x-trigger-wrap-focus');
10179 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10183 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10184 validateBlur : function(e, t){
10189 onDisable : function(){
10190 this.inputEl().dom.disabled = true;
10191 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10193 // this.wrap.addClass('x-item-disabled');
10198 onEnable : function(){
10199 this.inputEl().dom.disabled = false;
10200 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10202 // this.el.removeClass('x-item-disabled');
10207 onShow : function(){
10208 var ae = this.getActionEl();
10211 ae.dom.style.display = '';
10212 ae.dom.style.visibility = 'visible';
10218 onHide : function(){
10219 var ae = this.getActionEl();
10220 ae.dom.style.display = 'none';
10224 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10225 * by an implementing function.
10227 * @param {EventObject} e
10229 onTriggerClick : Roo.emptyFn
10233 * Ext JS Library 1.1.1
10234 * Copyright(c) 2006-2007, Ext JS, LLC.
10236 * Originally Released Under LGPL - original licence link has changed is not relivant.
10239 * <script type="text/javascript">
10244 * @class Roo.data.SortTypes
10246 * Defines the default sorting (casting?) comparison functions used when sorting data.
10248 Roo.data.SortTypes = {
10250 * Default sort that does nothing
10251 * @param {Mixed} s The value being converted
10252 * @return {Mixed} The comparison value
10254 none : function(s){
10259 * The regular expression used to strip tags
10263 stripTagsRE : /<\/?[^>]+>/gi,
10266 * Strips all HTML tags to sort on text only
10267 * @param {Mixed} s The value being converted
10268 * @return {String} The comparison value
10270 asText : function(s){
10271 return String(s).replace(this.stripTagsRE, "");
10275 * Strips all HTML tags to sort on text only - Case insensitive
10276 * @param {Mixed} s The value being converted
10277 * @return {String} The comparison value
10279 asUCText : function(s){
10280 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10284 * Case insensitive string
10285 * @param {Mixed} s The value being converted
10286 * @return {String} The comparison value
10288 asUCString : function(s) {
10289 return String(s).toUpperCase();
10294 * @param {Mixed} s The value being converted
10295 * @return {Number} The comparison value
10297 asDate : function(s) {
10301 if(s instanceof Date){
10302 return s.getTime();
10304 return Date.parse(String(s));
10309 * @param {Mixed} s The value being converted
10310 * @return {Float} The comparison value
10312 asFloat : function(s) {
10313 var val = parseFloat(String(s).replace(/,/g, ""));
10322 * @param {Mixed} s The value being converted
10323 * @return {Number} The comparison value
10325 asInt : function(s) {
10326 var val = parseInt(String(s).replace(/,/g, ""));
10334 * Ext JS Library 1.1.1
10335 * Copyright(c) 2006-2007, Ext JS, LLC.
10337 * Originally Released Under LGPL - original licence link has changed is not relivant.
10340 * <script type="text/javascript">
10344 * @class Roo.data.Record
10345 * Instances of this class encapsulate both record <em>definition</em> information, and record
10346 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10347 * to access Records cached in an {@link Roo.data.Store} object.<br>
10349 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10350 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10353 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10355 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10356 * {@link #create}. The parameters are the same.
10357 * @param {Array} data An associative Array of data values keyed by the field name.
10358 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10359 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10360 * not specified an integer id is generated.
10362 Roo.data.Record = function(data, id){
10363 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10368 * Generate a constructor for a specific record layout.
10369 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10370 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10371 * Each field definition object may contain the following properties: <ul>
10372 * <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,
10373 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10374 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10375 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10376 * is being used, then this is a string containing the javascript expression to reference the data relative to
10377 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10378 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10379 * this may be omitted.</p></li>
10380 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10381 * <ul><li>auto (Default, implies no conversion)</li>
10386 * <li>date</li></ul></p></li>
10387 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10388 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10389 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10390 * by the Reader into an object that will be stored in the Record. It is passed the
10391 * following parameters:<ul>
10392 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10394 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10396 * <br>usage:<br><pre><code>
10397 var TopicRecord = Roo.data.Record.create(
10398 {name: 'title', mapping: 'topic_title'},
10399 {name: 'author', mapping: 'username'},
10400 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10401 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10402 {name: 'lastPoster', mapping: 'user2'},
10403 {name: 'excerpt', mapping: 'post_text'}
10406 var myNewRecord = new TopicRecord({
10407 title: 'Do my job please',
10410 lastPost: new Date(),
10411 lastPoster: 'Animal',
10412 excerpt: 'No way dude!'
10414 myStore.add(myNewRecord);
10419 Roo.data.Record.create = function(o){
10420 var f = function(){
10421 f.superclass.constructor.apply(this, arguments);
10423 Roo.extend(f, Roo.data.Record);
10424 var p = f.prototype;
10425 p.fields = new Roo.util.MixedCollection(false, function(field){
10428 for(var i = 0, len = o.length; i < len; i++){
10429 p.fields.add(new Roo.data.Field(o[i]));
10431 f.getField = function(name){
10432 return p.fields.get(name);
10437 Roo.data.Record.AUTO_ID = 1000;
10438 Roo.data.Record.EDIT = 'edit';
10439 Roo.data.Record.REJECT = 'reject';
10440 Roo.data.Record.COMMIT = 'commit';
10442 Roo.data.Record.prototype = {
10444 * Readonly flag - true if this record has been modified.
10453 join : function(store){
10454 this.store = store;
10458 * Set the named field to the specified value.
10459 * @param {String} name The name of the field to set.
10460 * @param {Object} value The value to set the field to.
10462 set : function(name, value){
10463 if(this.data[name] == value){
10467 if(!this.modified){
10468 this.modified = {};
10470 if(typeof this.modified[name] == 'undefined'){
10471 this.modified[name] = this.data[name];
10473 this.data[name] = value;
10474 if(!this.editing && this.store){
10475 this.store.afterEdit(this);
10480 * Get the value of the named field.
10481 * @param {String} name The name of the field to get the value of.
10482 * @return {Object} The value of the field.
10484 get : function(name){
10485 return this.data[name];
10489 beginEdit : function(){
10490 this.editing = true;
10491 this.modified = {};
10495 cancelEdit : function(){
10496 this.editing = false;
10497 delete this.modified;
10501 endEdit : function(){
10502 this.editing = false;
10503 if(this.dirty && this.store){
10504 this.store.afterEdit(this);
10509 * Usually called by the {@link Roo.data.Store} which owns the Record.
10510 * Rejects all changes made to the Record since either creation, or the last commit operation.
10511 * Modified fields are reverted to their original values.
10513 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10514 * of reject operations.
10516 reject : function(){
10517 var m = this.modified;
10519 if(typeof m[n] != "function"){
10520 this.data[n] = m[n];
10523 this.dirty = false;
10524 delete this.modified;
10525 this.editing = false;
10527 this.store.afterReject(this);
10532 * Usually called by the {@link Roo.data.Store} which owns the Record.
10533 * Commits all changes made to the Record since either creation, or the last commit operation.
10535 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10536 * of commit operations.
10538 commit : function(){
10539 this.dirty = false;
10540 delete this.modified;
10541 this.editing = false;
10543 this.store.afterCommit(this);
10548 hasError : function(){
10549 return this.error != null;
10553 clearError : function(){
10558 * Creates a copy of this record.
10559 * @param {String} id (optional) A new record id if you don't want to use this record's id
10562 copy : function(newId) {
10563 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10567 * Ext JS Library 1.1.1
10568 * Copyright(c) 2006-2007, Ext JS, LLC.
10570 * Originally Released Under LGPL - original licence link has changed is not relivant.
10573 * <script type="text/javascript">
10579 * @class Roo.data.Store
10580 * @extends Roo.util.Observable
10581 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10582 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10584 * 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
10585 * has no knowledge of the format of the data returned by the Proxy.<br>
10587 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10588 * instances from the data object. These records are cached and made available through accessor functions.
10590 * Creates a new Store.
10591 * @param {Object} config A config object containing the objects needed for the Store to access data,
10592 * and read the data into Records.
10594 Roo.data.Store = function(config){
10595 this.data = new Roo.util.MixedCollection(false);
10596 this.data.getKey = function(o){
10599 this.baseParams = {};
10601 this.paramNames = {
10606 "multisort" : "_multisort"
10609 if(config && config.data){
10610 this.inlineData = config.data;
10611 delete config.data;
10614 Roo.apply(this, config);
10616 if(this.reader){ // reader passed
10617 this.reader = Roo.factory(this.reader, Roo.data);
10618 this.reader.xmodule = this.xmodule || false;
10619 if(!this.recordType){
10620 this.recordType = this.reader.recordType;
10622 if(this.reader.onMetaChange){
10623 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10627 if(this.recordType){
10628 this.fields = this.recordType.prototype.fields;
10630 this.modified = [];
10634 * @event datachanged
10635 * Fires when the data cache has changed, and a widget which is using this Store
10636 * as a Record cache should refresh its view.
10637 * @param {Store} this
10639 datachanged : true,
10641 * @event metachange
10642 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10643 * @param {Store} this
10644 * @param {Object} meta The JSON metadata
10649 * Fires when Records have been added to the Store
10650 * @param {Store} this
10651 * @param {Roo.data.Record[]} records The array of Records added
10652 * @param {Number} index The index at which the record(s) were added
10657 * Fires when a Record has been removed from the Store
10658 * @param {Store} this
10659 * @param {Roo.data.Record} record The Record that was removed
10660 * @param {Number} index The index at which the record was removed
10665 * Fires when a Record has been updated
10666 * @param {Store} this
10667 * @param {Roo.data.Record} record The Record that was updated
10668 * @param {String} operation The update operation being performed. Value may be one of:
10670 Roo.data.Record.EDIT
10671 Roo.data.Record.REJECT
10672 Roo.data.Record.COMMIT
10678 * Fires when the data cache has been cleared.
10679 * @param {Store} this
10683 * @event beforeload
10684 * Fires before a request is made for a new data object. If the beforeload handler returns false
10685 * the load action will be canceled.
10686 * @param {Store} this
10687 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10691 * @event beforeloadadd
10692 * Fires after a new set of Records has been loaded.
10693 * @param {Store} this
10694 * @param {Roo.data.Record[]} records The Records that were loaded
10695 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10697 beforeloadadd : true,
10700 * Fires after a new set of Records has been loaded, before they are added to the store.
10701 * @param {Store} this
10702 * @param {Roo.data.Record[]} records The Records that were loaded
10703 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10704 * @params {Object} return from reader
10708 * @event loadexception
10709 * Fires if an exception occurs in the Proxy during loading.
10710 * Called with the signature of the Proxy's "loadexception" event.
10711 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10714 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10715 * @param {Object} load options
10716 * @param {Object} jsonData from your request (normally this contains the Exception)
10718 loadexception : true
10722 this.proxy = Roo.factory(this.proxy, Roo.data);
10723 this.proxy.xmodule = this.xmodule || false;
10724 this.relayEvents(this.proxy, ["loadexception"]);
10726 this.sortToggle = {};
10727 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10729 Roo.data.Store.superclass.constructor.call(this);
10731 if(this.inlineData){
10732 this.loadData(this.inlineData);
10733 delete this.inlineData;
10737 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10739 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10740 * without a remote query - used by combo/forms at present.
10744 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10747 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10750 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10751 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10754 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10755 * on any HTTP request
10758 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10761 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10765 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10766 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10768 remoteSort : false,
10771 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10772 * loaded or when a record is removed. (defaults to false).
10774 pruneModifiedRecords : false,
10777 lastOptions : null,
10780 * Add Records to the Store and fires the add event.
10781 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10783 add : function(records){
10784 records = [].concat(records);
10785 for(var i = 0, len = records.length; i < len; i++){
10786 records[i].join(this);
10788 var index = this.data.length;
10789 this.data.addAll(records);
10790 this.fireEvent("add", this, records, index);
10794 * Remove a Record from the Store and fires the remove event.
10795 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10797 remove : function(record){
10798 var index = this.data.indexOf(record);
10799 this.data.removeAt(index);
10800 if(this.pruneModifiedRecords){
10801 this.modified.remove(record);
10803 this.fireEvent("remove", this, record, index);
10807 * Remove all Records from the Store and fires the clear event.
10809 removeAll : function(){
10811 if(this.pruneModifiedRecords){
10812 this.modified = [];
10814 this.fireEvent("clear", this);
10818 * Inserts Records to the Store at the given index and fires the add event.
10819 * @param {Number} index The start index at which to insert the passed Records.
10820 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10822 insert : function(index, records){
10823 records = [].concat(records);
10824 for(var i = 0, len = records.length; i < len; i++){
10825 this.data.insert(index, records[i]);
10826 records[i].join(this);
10828 this.fireEvent("add", this, records, index);
10832 * Get the index within the cache of the passed Record.
10833 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10834 * @return {Number} The index of the passed Record. Returns -1 if not found.
10836 indexOf : function(record){
10837 return this.data.indexOf(record);
10841 * Get the index within the cache of the Record with the passed id.
10842 * @param {String} id The id of the Record to find.
10843 * @return {Number} The index of the Record. Returns -1 if not found.
10845 indexOfId : function(id){
10846 return this.data.indexOfKey(id);
10850 * Get the Record with the specified id.
10851 * @param {String} id The id of the Record to find.
10852 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10854 getById : function(id){
10855 return this.data.key(id);
10859 * Get the Record at the specified index.
10860 * @param {Number} index The index of the Record to find.
10861 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10863 getAt : function(index){
10864 return this.data.itemAt(index);
10868 * Returns a range of Records between specified indices.
10869 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10870 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10871 * @return {Roo.data.Record[]} An array of Records
10873 getRange : function(start, end){
10874 return this.data.getRange(start, end);
10878 storeOptions : function(o){
10879 o = Roo.apply({}, o);
10882 this.lastOptions = o;
10886 * Loads the Record cache from the configured Proxy using the configured Reader.
10888 * If using remote paging, then the first load call must specify the <em>start</em>
10889 * and <em>limit</em> properties in the options.params property to establish the initial
10890 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10892 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10893 * and this call will return before the new data has been loaded. Perform any post-processing
10894 * in a callback function, or in a "load" event handler.</strong>
10896 * @param {Object} options An object containing properties which control loading options:<ul>
10897 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10898 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10899 * passed the following arguments:<ul>
10900 * <li>r : Roo.data.Record[]</li>
10901 * <li>options: Options object from the load call</li>
10902 * <li>success: Boolean success indicator</li></ul></li>
10903 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10904 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10907 load : function(options){
10908 options = options || {};
10909 if(this.fireEvent("beforeload", this, options) !== false){
10910 this.storeOptions(options);
10911 var p = Roo.apply(options.params || {}, this.baseParams);
10912 // if meta was not loaded from remote source.. try requesting it.
10913 if (!this.reader.metaFromRemote) {
10914 p._requestMeta = 1;
10916 if(this.sortInfo && this.remoteSort){
10917 var pn = this.paramNames;
10918 p[pn["sort"]] = this.sortInfo.field;
10919 p[pn["dir"]] = this.sortInfo.direction;
10921 if (this.multiSort) {
10922 var pn = this.paramNames;
10923 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10926 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10931 * Reloads the Record cache from the configured Proxy using the configured Reader and
10932 * the options from the last load operation performed.
10933 * @param {Object} options (optional) An object containing properties which may override the options
10934 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10935 * the most recently used options are reused).
10937 reload : function(options){
10938 this.load(Roo.applyIf(options||{}, this.lastOptions));
10942 // Called as a callback by the Reader during a load operation.
10943 loadRecords : function(o, options, success){
10944 if(!o || success === false){
10945 if(success !== false){
10946 this.fireEvent("load", this, [], options, o);
10948 if(options.callback){
10949 options.callback.call(options.scope || this, [], options, false);
10953 // if data returned failure - throw an exception.
10954 if (o.success === false) {
10955 // show a message if no listener is registered.
10956 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10957 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10959 // loadmask wil be hooked into this..
10960 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10963 var r = o.records, t = o.totalRecords || r.length;
10965 this.fireEvent("beforeloadadd", this, r, options, o);
10967 if(!options || options.add !== true){
10968 if(this.pruneModifiedRecords){
10969 this.modified = [];
10971 for(var i = 0, len = r.length; i < len; i++){
10975 this.data = this.snapshot;
10976 delete this.snapshot;
10979 this.data.addAll(r);
10980 this.totalLength = t;
10982 this.fireEvent("datachanged", this);
10984 this.totalLength = Math.max(t, this.data.length+r.length);
10987 this.fireEvent("load", this, r, options, o);
10988 if(options.callback){
10989 options.callback.call(options.scope || this, r, options, true);
10995 * Loads data from a passed data block. A Reader which understands the format of the data
10996 * must have been configured in the constructor.
10997 * @param {Object} data The data block from which to read the Records. The format of the data expected
10998 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10999 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11001 loadData : function(o, append){
11002 var r = this.reader.readRecords(o);
11003 this.loadRecords(r, {add: append}, true);
11007 * Gets the number of cached records.
11009 * <em>If using paging, this may not be the total size of the dataset. If the data object
11010 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11011 * the data set size</em>
11013 getCount : function(){
11014 return this.data.length || 0;
11018 * Gets the total number of records in the dataset as returned by the server.
11020 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11021 * the dataset size</em>
11023 getTotalCount : function(){
11024 return this.totalLength || 0;
11028 * Returns the sort state of the Store as an object with two properties:
11030 field {String} The name of the field by which the Records are sorted
11031 direction {String} The sort order, "ASC" or "DESC"
11034 getSortState : function(){
11035 return this.sortInfo;
11039 applySort : function(){
11040 if(this.sortInfo && !this.remoteSort){
11041 var s = this.sortInfo, f = s.field;
11042 var st = this.fields.get(f).sortType;
11043 var fn = function(r1, r2){
11044 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11045 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11047 this.data.sort(s.direction, fn);
11048 if(this.snapshot && this.snapshot != this.data){
11049 this.snapshot.sort(s.direction, fn);
11055 * Sets the default sort column and order to be used by the next load operation.
11056 * @param {String} fieldName The name of the field to sort by.
11057 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11059 setDefaultSort : function(field, dir){
11060 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11064 * Sort the Records.
11065 * If remote sorting is used, the sort is performed on the server, and the cache is
11066 * reloaded. If local sorting is used, the cache is sorted internally.
11067 * @param {String} fieldName The name of the field to sort by.
11068 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11070 sort : function(fieldName, dir){
11071 var f = this.fields.get(fieldName);
11073 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11075 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11076 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11081 this.sortToggle[f.name] = dir;
11082 this.sortInfo = {field: f.name, direction: dir};
11083 if(!this.remoteSort){
11085 this.fireEvent("datachanged", this);
11087 this.load(this.lastOptions);
11092 * Calls the specified function for each of the Records in the cache.
11093 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11094 * Returning <em>false</em> aborts and exits the iteration.
11095 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11097 each : function(fn, scope){
11098 this.data.each(fn, scope);
11102 * Gets all records modified since the last commit. Modified records are persisted across load operations
11103 * (e.g., during paging).
11104 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11106 getModifiedRecords : function(){
11107 return this.modified;
11111 createFilterFn : function(property, value, anyMatch){
11112 if(!value.exec){ // not a regex
11113 value = String(value);
11114 if(value.length == 0){
11117 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11119 return function(r){
11120 return value.test(r.data[property]);
11125 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11126 * @param {String} property A field on your records
11127 * @param {Number} start The record index to start at (defaults to 0)
11128 * @param {Number} end The last record index to include (defaults to length - 1)
11129 * @return {Number} The sum
11131 sum : function(property, start, end){
11132 var rs = this.data.items, v = 0;
11133 start = start || 0;
11134 end = (end || end === 0) ? end : rs.length-1;
11136 for(var i = start; i <= end; i++){
11137 v += (rs[i].data[property] || 0);
11143 * Filter the records by a specified property.
11144 * @param {String} field A field on your records
11145 * @param {String/RegExp} value Either a string that the field
11146 * should start with or a RegExp to test against the field
11147 * @param {Boolean} anyMatch True to match any part not just the beginning
11149 filter : function(property, value, anyMatch){
11150 var fn = this.createFilterFn(property, value, anyMatch);
11151 return fn ? this.filterBy(fn) : this.clearFilter();
11155 * Filter by a function. The specified function will be called with each
11156 * record in this data source. If the function returns true the record is included,
11157 * otherwise it is filtered.
11158 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11159 * @param {Object} scope (optional) The scope of the function (defaults to this)
11161 filterBy : function(fn, scope){
11162 this.snapshot = this.snapshot || this.data;
11163 this.data = this.queryBy(fn, scope||this);
11164 this.fireEvent("datachanged", this);
11168 * Query the records by a specified property.
11169 * @param {String} field A field on your records
11170 * @param {String/RegExp} value Either a string that the field
11171 * should start with or a RegExp to test against the field
11172 * @param {Boolean} anyMatch True to match any part not just the beginning
11173 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11175 query : function(property, value, anyMatch){
11176 var fn = this.createFilterFn(property, value, anyMatch);
11177 return fn ? this.queryBy(fn) : this.data.clone();
11181 * Query by a function. The specified function will be called with each
11182 * record in this data source. If the function returns true the record is included
11184 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11185 * @param {Object} scope (optional) The scope of the function (defaults to this)
11186 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11188 queryBy : function(fn, scope){
11189 var data = this.snapshot || this.data;
11190 return data.filterBy(fn, scope||this);
11194 * Collects unique values for a particular dataIndex from this store.
11195 * @param {String} dataIndex The property to collect
11196 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11197 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11198 * @return {Array} An array of the unique values
11200 collect : function(dataIndex, allowNull, bypassFilter){
11201 var d = (bypassFilter === true && this.snapshot) ?
11202 this.snapshot.items : this.data.items;
11203 var v, sv, r = [], l = {};
11204 for(var i = 0, len = d.length; i < len; i++){
11205 v = d[i].data[dataIndex];
11207 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11216 * Revert to a view of the Record cache with no filtering applied.
11217 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11219 clearFilter : function(suppressEvent){
11220 if(this.snapshot && this.snapshot != this.data){
11221 this.data = this.snapshot;
11222 delete this.snapshot;
11223 if(suppressEvent !== true){
11224 this.fireEvent("datachanged", this);
11230 afterEdit : function(record){
11231 if(this.modified.indexOf(record) == -1){
11232 this.modified.push(record);
11234 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11238 afterReject : function(record){
11239 this.modified.remove(record);
11240 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11244 afterCommit : function(record){
11245 this.modified.remove(record);
11246 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11250 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11251 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11253 commitChanges : function(){
11254 var m = this.modified.slice(0);
11255 this.modified = [];
11256 for(var i = 0, len = m.length; i < len; i++){
11262 * Cancel outstanding changes on all changed records.
11264 rejectChanges : function(){
11265 var m = this.modified.slice(0);
11266 this.modified = [];
11267 for(var i = 0, len = m.length; i < len; i++){
11272 onMetaChange : function(meta, rtype, o){
11273 this.recordType = rtype;
11274 this.fields = rtype.prototype.fields;
11275 delete this.snapshot;
11276 this.sortInfo = meta.sortInfo || this.sortInfo;
11277 this.modified = [];
11278 this.fireEvent('metachange', this, this.reader.meta);
11281 moveIndex : function(data, type)
11283 var index = this.indexOf(data);
11285 var newIndex = index + type;
11289 this.insert(newIndex, data);
11294 * Ext JS Library 1.1.1
11295 * Copyright(c) 2006-2007, Ext JS, LLC.
11297 * Originally Released Under LGPL - original licence link has changed is not relivant.
11300 * <script type="text/javascript">
11304 * @class Roo.data.SimpleStore
11305 * @extends Roo.data.Store
11306 * Small helper class to make creating Stores from Array data easier.
11307 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11308 * @cfg {Array} fields An array of field definition objects, or field name strings.
11309 * @cfg {Array} data The multi-dimensional array of data
11311 * @param {Object} config
11313 Roo.data.SimpleStore = function(config){
11314 Roo.data.SimpleStore.superclass.constructor.call(this, {
11316 reader: new Roo.data.ArrayReader({
11319 Roo.data.Record.create(config.fields)
11321 proxy : new Roo.data.MemoryProxy(config.data)
11325 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11327 * Ext JS Library 1.1.1
11328 * Copyright(c) 2006-2007, Ext JS, LLC.
11330 * Originally Released Under LGPL - original licence link has changed is not relivant.
11333 * <script type="text/javascript">
11338 * @extends Roo.data.Store
11339 * @class Roo.data.JsonStore
11340 * Small helper class to make creating Stores for JSON data easier. <br/>
11342 var store = new Roo.data.JsonStore({
11343 url: 'get-images.php',
11345 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11348 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11349 * JsonReader and HttpProxy (unless inline data is provided).</b>
11350 * @cfg {Array} fields An array of field definition objects, or field name strings.
11352 * @param {Object} config
11354 Roo.data.JsonStore = function(c){
11355 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11356 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11357 reader: new Roo.data.JsonReader(c, c.fields)
11360 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11362 * Ext JS Library 1.1.1
11363 * Copyright(c) 2006-2007, Ext JS, LLC.
11365 * Originally Released Under LGPL - original licence link has changed is not relivant.
11368 * <script type="text/javascript">
11372 Roo.data.Field = function(config){
11373 if(typeof config == "string"){
11374 config = {name: config};
11376 Roo.apply(this, config);
11379 this.type = "auto";
11382 var st = Roo.data.SortTypes;
11383 // named sortTypes are supported, here we look them up
11384 if(typeof this.sortType == "string"){
11385 this.sortType = st[this.sortType];
11388 // set default sortType for strings and dates
11389 if(!this.sortType){
11392 this.sortType = st.asUCString;
11395 this.sortType = st.asDate;
11398 this.sortType = st.none;
11403 var stripRe = /[\$,%]/g;
11405 // prebuilt conversion function for this field, instead of
11406 // switching every time we're reading a value
11408 var cv, dateFormat = this.dateFormat;
11413 cv = function(v){ return v; };
11416 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11420 return v !== undefined && v !== null && v !== '' ?
11421 parseInt(String(v).replace(stripRe, ""), 10) : '';
11426 return v !== undefined && v !== null && v !== '' ?
11427 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11432 cv = function(v){ return v === true || v === "true" || v == 1; };
11439 if(v instanceof Date){
11443 if(dateFormat == "timestamp"){
11444 return new Date(v*1000);
11446 return Date.parseDate(v, dateFormat);
11448 var parsed = Date.parse(v);
11449 return parsed ? new Date(parsed) : null;
11458 Roo.data.Field.prototype = {
11466 * Ext JS Library 1.1.1
11467 * Copyright(c) 2006-2007, Ext JS, LLC.
11469 * Originally Released Under LGPL - original licence link has changed is not relivant.
11472 * <script type="text/javascript">
11475 // Base class for reading structured data from a data source. This class is intended to be
11476 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11479 * @class Roo.data.DataReader
11480 * Base class for reading structured data from a data source. This class is intended to be
11481 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11484 Roo.data.DataReader = function(meta, recordType){
11488 this.recordType = recordType instanceof Array ?
11489 Roo.data.Record.create(recordType) : recordType;
11492 Roo.data.DataReader.prototype = {
11494 * Create an empty record
11495 * @param {Object} data (optional) - overlay some values
11496 * @return {Roo.data.Record} record created.
11498 newRow : function(d) {
11500 this.recordType.prototype.fields.each(function(c) {
11502 case 'int' : da[c.name] = 0; break;
11503 case 'date' : da[c.name] = new Date(); break;
11504 case 'float' : da[c.name] = 0.0; break;
11505 case 'boolean' : da[c.name] = false; break;
11506 default : da[c.name] = ""; break;
11510 return new this.recordType(Roo.apply(da, d));
11515 * Ext JS Library 1.1.1
11516 * Copyright(c) 2006-2007, Ext JS, LLC.
11518 * Originally Released Under LGPL - original licence link has changed is not relivant.
11521 * <script type="text/javascript">
11525 * @class Roo.data.DataProxy
11526 * @extends Roo.data.Observable
11527 * This class is an abstract base class for implementations which provide retrieval of
11528 * unformatted data objects.<br>
11530 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11531 * (of the appropriate type which knows how to parse the data object) to provide a block of
11532 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11534 * Custom implementations must implement the load method as described in
11535 * {@link Roo.data.HttpProxy#load}.
11537 Roo.data.DataProxy = function(){
11540 * @event beforeload
11541 * Fires before a network request is made to retrieve a data object.
11542 * @param {Object} This DataProxy object.
11543 * @param {Object} params The params parameter to the load function.
11548 * Fires before the load method's callback is called.
11549 * @param {Object} This DataProxy object.
11550 * @param {Object} o The data object.
11551 * @param {Object} arg The callback argument object passed to the load function.
11555 * @event loadexception
11556 * Fires if an Exception occurs during data retrieval.
11557 * @param {Object} This DataProxy object.
11558 * @param {Object} o The data object.
11559 * @param {Object} arg The callback argument object passed to the load function.
11560 * @param {Object} e The Exception.
11562 loadexception : true
11564 Roo.data.DataProxy.superclass.constructor.call(this);
11567 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11570 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11574 * Ext JS Library 1.1.1
11575 * Copyright(c) 2006-2007, Ext JS, LLC.
11577 * Originally Released Under LGPL - original licence link has changed is not relivant.
11580 * <script type="text/javascript">
11583 * @class Roo.data.MemoryProxy
11584 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11585 * to the Reader when its load method is called.
11587 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11589 Roo.data.MemoryProxy = function(data){
11593 Roo.data.MemoryProxy.superclass.constructor.call(this);
11597 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11600 * Load data from the requested source (in this case an in-memory
11601 * data object passed to the constructor), read the data object into
11602 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11603 * process that block using the passed callback.
11604 * @param {Object} params This parameter is not used by the MemoryProxy class.
11605 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11606 * object into a block of Roo.data.Records.
11607 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11608 * The function must be passed <ul>
11609 * <li>The Record block object</li>
11610 * <li>The "arg" argument from the load function</li>
11611 * <li>A boolean success indicator</li>
11613 * @param {Object} scope The scope in which to call the callback
11614 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11616 load : function(params, reader, callback, scope, arg){
11617 params = params || {};
11620 result = reader.readRecords(this.data);
11622 this.fireEvent("loadexception", this, arg, null, e);
11623 callback.call(scope, null, arg, false);
11626 callback.call(scope, result, arg, true);
11630 update : function(params, records){
11635 * Ext JS Library 1.1.1
11636 * Copyright(c) 2006-2007, Ext JS, LLC.
11638 * Originally Released Under LGPL - original licence link has changed is not relivant.
11641 * <script type="text/javascript">
11644 * @class Roo.data.HttpProxy
11645 * @extends Roo.data.DataProxy
11646 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11647 * configured to reference a certain URL.<br><br>
11649 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11650 * from which the running page was served.<br><br>
11652 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11654 * Be aware that to enable the browser to parse an XML document, the server must set
11655 * the Content-Type header in the HTTP response to "text/xml".
11657 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11658 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11659 * will be used to make the request.
11661 Roo.data.HttpProxy = function(conn){
11662 Roo.data.HttpProxy.superclass.constructor.call(this);
11663 // is conn a conn config or a real conn?
11665 this.useAjax = !conn || !conn.events;
11669 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11670 // thse are take from connection...
11673 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11676 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11677 * extra parameters to each request made by this object. (defaults to undefined)
11680 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11681 * to each request made by this object. (defaults to undefined)
11684 * @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)
11687 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11690 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11696 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11700 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11701 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11702 * a finer-grained basis than the DataProxy events.
11704 getConnection : function(){
11705 return this.useAjax ? Roo.Ajax : this.conn;
11709 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11710 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11711 * process that block using the passed callback.
11712 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11713 * for the request to the remote server.
11714 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11715 * object into a block of Roo.data.Records.
11716 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11717 * The function must be passed <ul>
11718 * <li>The Record block object</li>
11719 * <li>The "arg" argument from the load function</li>
11720 * <li>A boolean success indicator</li>
11722 * @param {Object} scope The scope in which to call the callback
11723 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11725 load : function(params, reader, callback, scope, arg){
11726 if(this.fireEvent("beforeload", this, params) !== false){
11728 params : params || {},
11730 callback : callback,
11735 callback : this.loadResponse,
11739 Roo.applyIf(o, this.conn);
11740 if(this.activeRequest){
11741 Roo.Ajax.abort(this.activeRequest);
11743 this.activeRequest = Roo.Ajax.request(o);
11745 this.conn.request(o);
11748 callback.call(scope||this, null, arg, false);
11753 loadResponse : function(o, success, response){
11754 delete this.activeRequest;
11756 this.fireEvent("loadexception", this, o, response);
11757 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11762 result = o.reader.read(response);
11764 this.fireEvent("loadexception", this, o, response, e);
11765 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11769 this.fireEvent("load", this, o, o.request.arg);
11770 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11774 update : function(dataSet){
11779 updateResponse : function(dataSet){
11784 * Ext JS Library 1.1.1
11785 * Copyright(c) 2006-2007, Ext JS, LLC.
11787 * Originally Released Under LGPL - original licence link has changed is not relivant.
11790 * <script type="text/javascript">
11794 * @class Roo.data.ScriptTagProxy
11795 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11796 * other than the originating domain of the running page.<br><br>
11798 * <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
11799 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11801 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11802 * source code that is used as the source inside a <script> tag.<br><br>
11804 * In order for the browser to process the returned data, the server must wrap the data object
11805 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11806 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11807 * depending on whether the callback name was passed:
11810 boolean scriptTag = false;
11811 String cb = request.getParameter("callback");
11814 response.setContentType("text/javascript");
11816 response.setContentType("application/x-json");
11818 Writer out = response.getWriter();
11820 out.write(cb + "(");
11822 out.print(dataBlock.toJsonString());
11829 * @param {Object} config A configuration object.
11831 Roo.data.ScriptTagProxy = function(config){
11832 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11833 Roo.apply(this, config);
11834 this.head = document.getElementsByTagName("head")[0];
11837 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11839 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11841 * @cfg {String} url The URL from which to request the data object.
11844 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11848 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11849 * the server the name of the callback function set up by the load call to process the returned data object.
11850 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11851 * javascript output which calls this named function passing the data object as its only parameter.
11853 callbackParam : "callback",
11855 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11856 * name to the request.
11861 * Load data from the configured URL, read the data object into
11862 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11863 * process that block using the passed callback.
11864 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11865 * for the request to the remote server.
11866 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11867 * object into a block of Roo.data.Records.
11868 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11869 * The function must be passed <ul>
11870 * <li>The Record block object</li>
11871 * <li>The "arg" argument from the load function</li>
11872 * <li>A boolean success indicator</li>
11874 * @param {Object} scope The scope in which to call the callback
11875 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11877 load : function(params, reader, callback, scope, arg){
11878 if(this.fireEvent("beforeload", this, params) !== false){
11880 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11882 var url = this.url;
11883 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11885 url += "&_dc=" + (new Date().getTime());
11887 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11890 cb : "stcCallback"+transId,
11891 scriptId : "stcScript"+transId,
11895 callback : callback,
11901 window[trans.cb] = function(o){
11902 conn.handleResponse(o, trans);
11905 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11907 if(this.autoAbort !== false){
11911 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11913 var script = document.createElement("script");
11914 script.setAttribute("src", url);
11915 script.setAttribute("type", "text/javascript");
11916 script.setAttribute("id", trans.scriptId);
11917 this.head.appendChild(script);
11919 this.trans = trans;
11921 callback.call(scope||this, null, arg, false);
11926 isLoading : function(){
11927 return this.trans ? true : false;
11931 * Abort the current server request.
11933 abort : function(){
11934 if(this.isLoading()){
11935 this.destroyTrans(this.trans);
11940 destroyTrans : function(trans, isLoaded){
11941 this.head.removeChild(document.getElementById(trans.scriptId));
11942 clearTimeout(trans.timeoutId);
11944 window[trans.cb] = undefined;
11946 delete window[trans.cb];
11949 // if hasn't been loaded, wait for load to remove it to prevent script error
11950 window[trans.cb] = function(){
11951 window[trans.cb] = undefined;
11953 delete window[trans.cb];
11960 handleResponse : function(o, trans){
11961 this.trans = false;
11962 this.destroyTrans(trans, true);
11965 result = trans.reader.readRecords(o);
11967 this.fireEvent("loadexception", this, o, trans.arg, e);
11968 trans.callback.call(trans.scope||window, null, trans.arg, false);
11971 this.fireEvent("load", this, o, trans.arg);
11972 trans.callback.call(trans.scope||window, result, trans.arg, true);
11976 handleFailure : function(trans){
11977 this.trans = false;
11978 this.destroyTrans(trans, false);
11979 this.fireEvent("loadexception", this, null, trans.arg);
11980 trans.callback.call(trans.scope||window, null, trans.arg, false);
11984 * Ext JS Library 1.1.1
11985 * Copyright(c) 2006-2007, Ext JS, LLC.
11987 * Originally Released Under LGPL - original licence link has changed is not relivant.
11990 * <script type="text/javascript">
11994 * @class Roo.data.JsonReader
11995 * @extends Roo.data.DataReader
11996 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11997 * based on mappings in a provided Roo.data.Record constructor.
11999 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12000 * in the reply previously.
12005 var RecordDef = Roo.data.Record.create([
12006 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12007 {name: 'occupation'} // This field will use "occupation" as the mapping.
12009 var myReader = new Roo.data.JsonReader({
12010 totalProperty: "results", // The property which contains the total dataset size (optional)
12011 root: "rows", // The property which contains an Array of row objects
12012 id: "id" // The property within each row object that provides an ID for the record (optional)
12016 * This would consume a JSON file like this:
12018 { 'results': 2, 'rows': [
12019 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12020 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12023 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12024 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12025 * paged from the remote server.
12026 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12027 * @cfg {String} root name of the property which contains the Array of row objects.
12028 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12029 * @cfg {Array} fields Array of field definition objects
12031 * Create a new JsonReader
12032 * @param {Object} meta Metadata configuration options
12033 * @param {Object} recordType Either an Array of field definition objects,
12034 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12036 Roo.data.JsonReader = function(meta, recordType){
12039 // set some defaults:
12040 Roo.applyIf(meta, {
12041 totalProperty: 'total',
12042 successProperty : 'success',
12047 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12049 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12052 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12053 * Used by Store query builder to append _requestMeta to params.
12056 metaFromRemote : false,
12058 * This method is only used by a DataProxy which has retrieved data from a remote server.
12059 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12060 * @return {Object} data A data block which is used by an Roo.data.Store object as
12061 * a cache of Roo.data.Records.
12063 read : function(response){
12064 var json = response.responseText;
12066 var o = /* eval:var:o */ eval("("+json+")");
12068 throw {message: "JsonReader.read: Json object not found"};
12074 this.metaFromRemote = true;
12075 this.meta = o.metaData;
12076 this.recordType = Roo.data.Record.create(o.metaData.fields);
12077 this.onMetaChange(this.meta, this.recordType, o);
12079 return this.readRecords(o);
12082 // private function a store will implement
12083 onMetaChange : function(meta, recordType, o){
12090 simpleAccess: function(obj, subsc) {
12097 getJsonAccessor: function(){
12099 return function(expr) {
12101 return(re.test(expr))
12102 ? new Function("obj", "return obj." + expr)
12107 return Roo.emptyFn;
12112 * Create a data block containing Roo.data.Records from an XML document.
12113 * @param {Object} o An object which contains an Array of row objects in the property specified
12114 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12115 * which contains the total size of the dataset.
12116 * @return {Object} data A data block which is used by an Roo.data.Store object as
12117 * a cache of Roo.data.Records.
12119 readRecords : function(o){
12121 * After any data loads, the raw JSON data is available for further custom processing.
12125 var s = this.meta, Record = this.recordType,
12126 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12128 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12130 if(s.totalProperty) {
12131 this.getTotal = this.getJsonAccessor(s.totalProperty);
12133 if(s.successProperty) {
12134 this.getSuccess = this.getJsonAccessor(s.successProperty);
12136 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12138 var g = this.getJsonAccessor(s.id);
12139 this.getId = function(rec) {
12141 return (r === undefined || r === "") ? null : r;
12144 this.getId = function(){return null;};
12147 for(var jj = 0; jj < fl; jj++){
12149 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12150 this.ef[jj] = this.getJsonAccessor(map);
12154 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12155 if(s.totalProperty){
12156 var vt = parseInt(this.getTotal(o), 10);
12161 if(s.successProperty){
12162 var vs = this.getSuccess(o);
12163 if(vs === false || vs === 'false'){
12168 for(var i = 0; i < c; i++){
12171 var id = this.getId(n);
12172 for(var j = 0; j < fl; j++){
12174 var v = this.ef[j](n);
12176 Roo.log('missing convert for ' + f.name);
12180 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12182 var record = new Record(values, id);
12184 records[i] = record;
12190 totalRecords : totalRecords
12195 * Ext JS Library 1.1.1
12196 * Copyright(c) 2006-2007, Ext JS, LLC.
12198 * Originally Released Under LGPL - original licence link has changed is not relivant.
12201 * <script type="text/javascript">
12205 * @class Roo.data.ArrayReader
12206 * @extends Roo.data.DataReader
12207 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12208 * Each element of that Array represents a row of data fields. The
12209 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12210 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12214 var RecordDef = Roo.data.Record.create([
12215 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12216 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12218 var myReader = new Roo.data.ArrayReader({
12219 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12223 * This would consume an Array like this:
12225 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12227 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12229 * Create a new JsonReader
12230 * @param {Object} meta Metadata configuration options.
12231 * @param {Object} recordType Either an Array of field definition objects
12232 * as specified to {@link Roo.data.Record#create},
12233 * or an {@link Roo.data.Record} object
12234 * created using {@link Roo.data.Record#create}.
12236 Roo.data.ArrayReader = function(meta, recordType){
12237 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12240 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12242 * Create a data block containing Roo.data.Records from an XML document.
12243 * @param {Object} o An Array of row objects which represents the dataset.
12244 * @return {Object} data A data block which is used by an Roo.data.Store object as
12245 * a cache of Roo.data.Records.
12247 readRecords : function(o){
12248 var sid = this.meta ? this.meta.id : null;
12249 var recordType = this.recordType, fields = recordType.prototype.fields;
12252 for(var i = 0; i < root.length; i++){
12255 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12256 for(var j = 0, jlen = fields.length; j < jlen; j++){
12257 var f = fields.items[j];
12258 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12259 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12261 values[f.name] = v;
12263 var record = new recordType(values, id);
12265 records[records.length] = record;
12269 totalRecords : records.length
12278 * @class Roo.bootstrap.ComboBox
12279 * @extends Roo.bootstrap.TriggerField
12280 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12281 * @cfg {Boolean} append (true|false) default false
12282 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12283 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12284 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12285 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12286 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12287 * @cfg {Boolean} animate default true
12288 * @cfg {Boolean} emptyResultText only for touch device
12289 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12291 * Create a new ComboBox.
12292 * @param {Object} config Configuration options
12294 Roo.bootstrap.ComboBox = function(config){
12295 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12299 * Fires when the dropdown list is expanded
12300 * @param {Roo.bootstrap.ComboBox} combo This combo box
12305 * Fires when the dropdown list is collapsed
12306 * @param {Roo.bootstrap.ComboBox} combo This combo box
12310 * @event beforeselect
12311 * Fires before a list item is selected. Return false to cancel the selection.
12312 * @param {Roo.bootstrap.ComboBox} combo This combo box
12313 * @param {Roo.data.Record} record The data record returned from the underlying store
12314 * @param {Number} index The index of the selected item in the dropdown list
12316 'beforeselect' : true,
12319 * Fires when a list item is selected
12320 * @param {Roo.bootstrap.ComboBox} combo This combo box
12321 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12322 * @param {Number} index The index of the selected item in the dropdown list
12326 * @event beforequery
12327 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12328 * The event object passed has these properties:
12329 * @param {Roo.bootstrap.ComboBox} combo This combo box
12330 * @param {String} query The query
12331 * @param {Boolean} forceAll true to force "all" query
12332 * @param {Boolean} cancel true to cancel the query
12333 * @param {Object} e The query event object
12335 'beforequery': true,
12338 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12339 * @param {Roo.bootstrap.ComboBox} combo This combo box
12344 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12345 * @param {Roo.bootstrap.ComboBox} combo This combo box
12346 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12351 * Fires when the remove value from the combobox array
12352 * @param {Roo.bootstrap.ComboBox} combo This combo box
12356 * @event afterremove
12357 * Fires when the remove value from the combobox array
12358 * @param {Roo.bootstrap.ComboBox} combo This combo box
12360 'afterremove' : true,
12362 * @event specialfilter
12363 * Fires when specialfilter
12364 * @param {Roo.bootstrap.ComboBox} combo This combo box
12366 'specialfilter' : true,
12369 * Fires when tick the element
12370 * @param {Roo.bootstrap.ComboBox} combo This combo box
12374 * @event touchviewdisplay
12375 * Fires when touch view require special display (default is using displayField)
12376 * @param {Roo.bootstrap.ComboBox} combo This combo box
12377 * @param {Object} cfg set html .
12379 'touchviewdisplay' : true
12384 this.tickItems = [];
12386 this.selectedIndex = -1;
12387 if(this.mode == 'local'){
12388 if(config.queryDelay === undefined){
12389 this.queryDelay = 10;
12391 if(config.minChars === undefined){
12397 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12400 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12401 * rendering into an Roo.Editor, defaults to false)
12404 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12405 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12408 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12411 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12412 * the dropdown list (defaults to undefined, with no header element)
12416 * @cfg {String/Roo.Template} tpl The template to use to render the output
12420 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12422 listWidth: undefined,
12424 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12425 * mode = 'remote' or 'text' if mode = 'local')
12427 displayField: undefined,
12430 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12431 * mode = 'remote' or 'value' if mode = 'local').
12432 * Note: use of a valueField requires the user make a selection
12433 * in order for a value to be mapped.
12435 valueField: undefined,
12437 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12442 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12443 * field's data value (defaults to the underlying DOM element's name)
12445 hiddenName: undefined,
12447 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12451 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12453 selectedClass: 'active',
12456 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12460 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12461 * anchor positions (defaults to 'tl-bl')
12463 listAlign: 'tl-bl?',
12465 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12469 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12470 * query specified by the allQuery config option (defaults to 'query')
12472 triggerAction: 'query',
12474 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12475 * (defaults to 4, does not apply if editable = false)
12479 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12480 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12484 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12485 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12489 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12490 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12494 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12495 * when editable = true (defaults to false)
12497 selectOnFocus:false,
12499 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12501 queryParam: 'query',
12503 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12504 * when mode = 'remote' (defaults to 'Loading...')
12506 loadingText: 'Loading...',
12508 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12512 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12516 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12517 * traditional select (defaults to true)
12521 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12525 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12529 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12530 * listWidth has a higher value)
12534 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12535 * allow the user to set arbitrary text into the field (defaults to false)
12537 forceSelection:false,
12539 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12540 * if typeAhead = true (defaults to 250)
12542 typeAheadDelay : 250,
12544 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12545 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12547 valueNotFoundText : undefined,
12549 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12551 blockFocus : false,
12554 * @cfg {Boolean} disableClear Disable showing of clear button.
12556 disableClear : false,
12558 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12560 alwaysQuery : false,
12563 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12568 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12570 invalidClass : "has-warning",
12573 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12575 validClass : "has-success",
12578 * @cfg {Boolean} specialFilter (true|false) special filter default false
12580 specialFilter : false,
12583 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12585 mobileTouchView : true,
12588 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12590 useNativeIOS : false,
12592 ios_options : false,
12604 btnPosition : 'right',
12605 triggerList : true,
12606 showToggleBtn : true,
12608 emptyResultText: 'Empty',
12609 triggerText : 'Select',
12611 // element that contains real text value.. (when hidden is used..)
12613 getAutoCreate : function()
12618 * Render classic select for iso
12621 if(Roo.isIOS && this.useNativeIOS){
12622 cfg = this.getAutoCreateNativeIOS();
12630 if(Roo.isTouch && this.mobileTouchView){
12631 cfg = this.getAutoCreateTouchView();
12638 if(!this.tickable){
12639 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12640 if(this.name == 'info_year_invest_id_display_name'){
12641 Roo.log('cfg.................................................');
12648 * ComboBox with tickable selections
12651 var align = this.labelAlign || this.parentLabelAlign();
12654 cls : 'form-group roo-combobox-tickable' //input-group
12657 var btn_text_select = '';
12658 var btn_text_done = '';
12659 var btn_text_cancel = '';
12661 if (this.btn_text_show) {
12662 btn_text_select = 'Select';
12663 btn_text_done = 'Done';
12664 btn_text_cancel = 'Cancel';
12669 cls : 'tickable-buttons',
12674 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12675 //html : this.triggerText
12676 html: btn_text_select
12682 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12684 html: btn_text_done
12690 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12692 html: btn_text_cancel
12698 buttons.cn.unshift({
12700 cls: 'roo-select2-search-field-input'
12706 Roo.each(buttons.cn, function(c){
12708 c.cls += ' btn-' + _this.size;
12711 if (_this.disabled) {
12722 cls: 'form-hidden-field'
12726 cls: 'roo-select2-choices',
12730 cls: 'roo-select2-search-field',
12741 cls: 'roo-select2-container input-group roo-select2-container-multi',
12746 // cls: 'typeahead typeahead-long dropdown-menu',
12747 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12752 if(this.hasFeedback && !this.allowBlank){
12756 cls: 'glyphicon form-control-feedback'
12759 combobox.cn.push(feedback);
12763 if (align ==='left' && this.fieldLabel.length) {
12765 cfg.cls += ' roo-form-group-label-left';
12770 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12771 tooltip : 'This field is required'
12776 cls : 'control-label',
12777 html : this.fieldLabel
12789 var labelCfg = cfg.cn[1];
12790 var contentCfg = cfg.cn[2];
12793 if(this.indicatorpos == 'right'){
12799 cls : 'control-label',
12803 html : this.fieldLabel
12807 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12808 tooltip : 'This field is required'
12823 labelCfg = cfg.cn[0];
12824 contentCfg = cfg.cn[1];
12828 if(this.labelWidth > 12){
12829 labelCfg.style = "width: " + this.labelWidth + 'px';
12832 if(this.labelWidth < 13 && this.labelmd == 0){
12833 this.labelmd = this.labelWidth;
12836 if(this.labellg > 0){
12837 labelCfg.cls += ' col-lg-' + this.labellg;
12838 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12841 if(this.labelmd > 0){
12842 labelCfg.cls += ' col-md-' + this.labelmd;
12843 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12846 if(this.labelsm > 0){
12847 labelCfg.cls += ' col-sm-' + this.labelsm;
12848 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12851 if(this.labelxs > 0){
12852 labelCfg.cls += ' col-xs-' + this.labelxs;
12853 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12857 } else if ( this.fieldLabel.length) {
12858 // Roo.log(" label");
12862 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12863 tooltip : 'This field is required'
12867 //cls : 'input-group-addon',
12868 html : this.fieldLabel
12876 if(this.indicatorpos == 'right'){
12881 //cls : 'input-group-addon',
12885 html : this.fieldLabel
12889 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12890 tooltip : 'This field is required'
12905 // Roo.log(" no label && no align");
12912 ['xs','sm','md','lg'].map(function(size){
12913 if (settings[size]) {
12914 cfg.cls += ' col-' + size + '-' + settings[size];
12922 _initEventsCalled : false,
12925 initEvents: function()
12927 if (this._initEventsCalled) { // as we call render... prevent looping...
12930 this._initEventsCalled = true;
12933 throw "can not find store for combo";
12936 this.store = Roo.factory(this.store, Roo.data);
12938 // if we are building from html. then this element is so complex, that we can not really
12939 // use the rendered HTML.
12940 // so we have to trash and replace the previous code.
12941 if (Roo.XComponent.build_from_html) {
12943 // remove this element....
12944 var e = this.el.dom, k=0;
12945 while (e ) { e = e.previousSibling; ++k;}
12950 this.rendered = false;
12952 this.render(this.parent().getChildContainer(true), k);
12958 if(Roo.isIOS && this.useNativeIOS){
12959 this.initIOSView();
12967 if(Roo.isTouch && this.mobileTouchView){
12968 this.initTouchView();
12973 this.initTickableEvents();
12977 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12979 if(this.hiddenName){
12981 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12983 this.hiddenField.dom.value =
12984 this.hiddenValue !== undefined ? this.hiddenValue :
12985 this.value !== undefined ? this.value : '';
12987 // prevent input submission
12988 this.el.dom.removeAttribute('name');
12989 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12994 // this.el.dom.setAttribute('autocomplete', 'off');
12997 var cls = 'x-combo-list';
12999 //this.list = new Roo.Layer({
13000 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13006 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13007 _this.list.setWidth(lw);
13010 this.list.on('mouseover', this.onViewOver, this);
13011 this.list.on('mousemove', this.onViewMove, this);
13013 this.list.on('scroll', this.onViewScroll, this);
13016 this.list.swallowEvent('mousewheel');
13017 this.assetHeight = 0;
13020 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13021 this.assetHeight += this.header.getHeight();
13024 this.innerList = this.list.createChild({cls:cls+'-inner'});
13025 this.innerList.on('mouseover', this.onViewOver, this);
13026 this.innerList.on('mousemove', this.onViewMove, this);
13027 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13029 if(this.allowBlank && !this.pageSize && !this.disableClear){
13030 this.footer = this.list.createChild({cls:cls+'-ft'});
13031 this.pageTb = new Roo.Toolbar(this.footer);
13035 this.footer = this.list.createChild({cls:cls+'-ft'});
13036 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13037 {pageSize: this.pageSize});
13041 if (this.pageTb && this.allowBlank && !this.disableClear) {
13043 this.pageTb.add(new Roo.Toolbar.Fill(), {
13044 cls: 'x-btn-icon x-btn-clear',
13046 handler: function()
13049 _this.clearValue();
13050 _this.onSelect(false, -1);
13055 this.assetHeight += this.footer.getHeight();
13060 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13063 this.view = new Roo.View(this.list, this.tpl, {
13064 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13066 //this.view.wrapEl.setDisplayed(false);
13067 this.view.on('click', this.onViewClick, this);
13071 this.store.on('beforeload', this.onBeforeLoad, this);
13072 this.store.on('load', this.onLoad, this);
13073 this.store.on('loadexception', this.onLoadException, this);
13075 if(this.resizable){
13076 this.resizer = new Roo.Resizable(this.list, {
13077 pinned:true, handles:'se'
13079 this.resizer.on('resize', function(r, w, h){
13080 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13081 this.listWidth = w;
13082 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13083 this.restrictHeight();
13085 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13088 if(!this.editable){
13089 this.editable = true;
13090 this.setEditable(false);
13095 if (typeof(this.events.add.listeners) != 'undefined') {
13097 this.addicon = this.wrap.createChild(
13098 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13100 this.addicon.on('click', function(e) {
13101 this.fireEvent('add', this);
13104 if (typeof(this.events.edit.listeners) != 'undefined') {
13106 this.editicon = this.wrap.createChild(
13107 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13108 if (this.addicon) {
13109 this.editicon.setStyle('margin-left', '40px');
13111 this.editicon.on('click', function(e) {
13113 // we fire even if inothing is selected..
13114 this.fireEvent('edit', this, this.lastData );
13120 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13121 "up" : function(e){
13122 this.inKeyMode = true;
13126 "down" : function(e){
13127 if(!this.isExpanded()){
13128 this.onTriggerClick();
13130 this.inKeyMode = true;
13135 "enter" : function(e){
13136 // this.onViewClick();
13140 if(this.fireEvent("specialkey", this, e)){
13141 this.onViewClick(false);
13147 "esc" : function(e){
13151 "tab" : function(e){
13154 if(this.fireEvent("specialkey", this, e)){
13155 this.onViewClick(false);
13163 doRelay : function(foo, bar, hname){
13164 if(hname == 'down' || this.scope.isExpanded()){
13165 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13174 this.queryDelay = Math.max(this.queryDelay || 10,
13175 this.mode == 'local' ? 10 : 250);
13178 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13180 if(this.typeAhead){
13181 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13183 if(this.editable !== false){
13184 this.inputEl().on("keyup", this.onKeyUp, this);
13186 if(this.forceSelection){
13187 this.inputEl().on('blur', this.doForce, this);
13191 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13192 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13196 initTickableEvents: function()
13200 if(this.hiddenName){
13202 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13204 this.hiddenField.dom.value =
13205 this.hiddenValue !== undefined ? this.hiddenValue :
13206 this.value !== undefined ? this.value : '';
13208 // prevent input submission
13209 this.el.dom.removeAttribute('name');
13210 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13215 // this.list = this.el.select('ul.dropdown-menu',true).first();
13217 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13218 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13219 if(this.triggerList){
13220 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13223 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13224 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13226 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13227 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13229 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13230 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13232 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13233 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13234 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13237 this.cancelBtn.hide();
13242 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13243 _this.list.setWidth(lw);
13246 this.list.on('mouseover', this.onViewOver, this);
13247 this.list.on('mousemove', this.onViewMove, this);
13249 this.list.on('scroll', this.onViewScroll, this);
13252 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></div></li>';
13255 this.view = new Roo.View(this.list, this.tpl, {
13256 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13259 //this.view.wrapEl.setDisplayed(false);
13260 this.view.on('click', this.onViewClick, this);
13264 this.store.on('beforeload', this.onBeforeLoad, this);
13265 this.store.on('load', this.onLoad, this);
13266 this.store.on('loadexception', this.onLoadException, this);
13269 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13270 "up" : function(e){
13271 this.inKeyMode = true;
13275 "down" : function(e){
13276 this.inKeyMode = true;
13280 "enter" : function(e){
13281 if(this.fireEvent("specialkey", this, e)){
13282 this.onViewClick(false);
13288 "esc" : function(e){
13289 this.onTickableFooterButtonClick(e, false, false);
13292 "tab" : function(e){
13293 this.fireEvent("specialkey", this, e);
13295 this.onTickableFooterButtonClick(e, false, false);
13302 doRelay : function(e, fn, key){
13303 if(this.scope.isExpanded()){
13304 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13313 this.queryDelay = Math.max(this.queryDelay || 10,
13314 this.mode == 'local' ? 10 : 250);
13317 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13319 if(this.typeAhead){
13320 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13323 if(this.editable !== false){
13324 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13327 this.indicator = this.indicatorEl();
13329 if(this.indicator){
13330 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13331 this.indicator.hide();
13336 onDestroy : function(){
13338 this.view.setStore(null);
13339 this.view.el.removeAllListeners();
13340 this.view.el.remove();
13341 this.view.purgeListeners();
13344 this.list.dom.innerHTML = '';
13348 this.store.un('beforeload', this.onBeforeLoad, this);
13349 this.store.un('load', this.onLoad, this);
13350 this.store.un('loadexception', this.onLoadException, this);
13352 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13356 fireKey : function(e){
13357 if(e.isNavKeyPress() && !this.list.isVisible()){
13358 this.fireEvent("specialkey", this, e);
13363 onResize: function(w, h){
13364 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13366 // if(typeof w != 'number'){
13367 // // we do not handle it!?!?
13370 // var tw = this.trigger.getWidth();
13371 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13372 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13374 // this.inputEl().setWidth( this.adjustWidth('input', x));
13376 // //this.trigger.setStyle('left', x+'px');
13378 // if(this.list && this.listWidth === undefined){
13379 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13380 // this.list.setWidth(lw);
13381 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13389 * Allow or prevent the user from directly editing the field text. If false is passed,
13390 * the user will only be able to select from the items defined in the dropdown list. This method
13391 * is the runtime equivalent of setting the 'editable' config option at config time.
13392 * @param {Boolean} value True to allow the user to directly edit the field text
13394 setEditable : function(value){
13395 if(value == this.editable){
13398 this.editable = value;
13400 this.inputEl().dom.setAttribute('readOnly', true);
13401 this.inputEl().on('mousedown', this.onTriggerClick, this);
13402 this.inputEl().addClass('x-combo-noedit');
13404 this.inputEl().dom.setAttribute('readOnly', false);
13405 this.inputEl().un('mousedown', this.onTriggerClick, this);
13406 this.inputEl().removeClass('x-combo-noedit');
13412 onBeforeLoad : function(combo,opts){
13413 if(!this.hasFocus){
13417 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13419 this.restrictHeight();
13420 this.selectedIndex = -1;
13424 onLoad : function(){
13426 this.hasQuery = false;
13428 if(!this.hasFocus){
13432 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13433 this.loading.hide();
13436 if(this.store.getCount() > 0){
13438 this.restrictHeight();
13439 if(this.lastQuery == this.allQuery){
13440 if(this.editable && !this.tickable){
13441 this.inputEl().dom.select();
13445 !this.selectByValue(this.value, true) &&
13448 !this.store.lastOptions ||
13449 typeof(this.store.lastOptions.add) == 'undefined' ||
13450 this.store.lastOptions.add != true
13453 this.select(0, true);
13456 if(this.autoFocus){
13459 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13460 this.taTask.delay(this.typeAheadDelay);
13464 this.onEmptyResults();
13470 onLoadException : function()
13472 this.hasQuery = false;
13474 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13475 this.loading.hide();
13478 if(this.tickable && this.editable){
13483 // only causes errors at present
13484 //Roo.log(this.store.reader.jsonData);
13485 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13487 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13493 onTypeAhead : function(){
13494 if(this.store.getCount() > 0){
13495 var r = this.store.getAt(0);
13496 var newValue = r.data[this.displayField];
13497 var len = newValue.length;
13498 var selStart = this.getRawValue().length;
13500 if(selStart != len){
13501 this.setRawValue(newValue);
13502 this.selectText(selStart, newValue.length);
13508 onSelect : function(record, index){
13510 if(this.fireEvent('beforeselect', this, record, index) !== false){
13512 this.setFromData(index > -1 ? record.data : false);
13515 this.fireEvent('select', this, record, index);
13520 * Returns the currently selected field value or empty string if no value is set.
13521 * @return {String} value The selected value
13523 getValue : function()
13525 if(Roo.isIOS && this.useNativeIOS){
13526 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13530 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13533 if(this.valueField){
13534 return typeof this.value != 'undefined' ? this.value : '';
13536 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13540 getRawValue : function()
13542 if(Roo.isIOS && this.useNativeIOS){
13543 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13546 var v = this.inputEl().getValue();
13552 * Clears any text/value currently set in the field
13554 clearValue : function(){
13556 if(this.hiddenField){
13557 this.hiddenField.dom.value = '';
13560 this.setRawValue('');
13561 this.lastSelectionText = '';
13562 this.lastData = false;
13564 var close = this.closeTriggerEl();
13575 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13576 * will be displayed in the field. If the value does not match the data value of an existing item,
13577 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13578 * Otherwise the field will be blank (although the value will still be set).
13579 * @param {String} value The value to match
13581 setValue : function(v)
13583 if(Roo.isIOS && this.useNativeIOS){
13584 this.setIOSValue(v);
13594 if(this.valueField){
13595 var r = this.findRecord(this.valueField, v);
13597 text = r.data[this.displayField];
13598 }else if(this.valueNotFoundText !== undefined){
13599 text = this.valueNotFoundText;
13602 this.lastSelectionText = text;
13603 if(this.hiddenField){
13604 this.hiddenField.dom.value = v;
13606 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13609 var close = this.closeTriggerEl();
13612 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13618 * @property {Object} the last set data for the element
13623 * Sets the value of the field based on a object which is related to the record format for the store.
13624 * @param {Object} value the value to set as. or false on reset?
13626 setFromData : function(o){
13633 var dv = ''; // display value
13634 var vv = ''; // value value..
13636 if (this.displayField) {
13637 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13639 // this is an error condition!!!
13640 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13643 if(this.valueField){
13644 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13647 var close = this.closeTriggerEl();
13650 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13653 if(this.hiddenField){
13654 this.hiddenField.dom.value = vv;
13656 this.lastSelectionText = dv;
13657 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13661 // no hidden field.. - we store the value in 'value', but still display
13662 // display field!!!!
13663 this.lastSelectionText = dv;
13664 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13671 reset : function(){
13672 // overridden so that last data is reset..
13679 this.setValue(this.originalValue);
13680 //this.clearInvalid();
13681 this.lastData = false;
13683 this.view.clearSelections();
13689 findRecord : function(prop, value){
13691 if(this.store.getCount() > 0){
13692 this.store.each(function(r){
13693 if(r.data[prop] == value){
13703 getName: function()
13705 // returns hidden if it's set..
13706 if (!this.rendered) {return ''};
13707 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13711 onViewMove : function(e, t){
13712 this.inKeyMode = false;
13716 onViewOver : function(e, t){
13717 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13720 var item = this.view.findItemFromChild(t);
13723 var index = this.view.indexOf(item);
13724 this.select(index, false);
13729 onViewClick : function(view, doFocus, el, e)
13731 var index = this.view.getSelectedIndexes()[0];
13733 var r = this.store.getAt(index);
13737 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13744 Roo.each(this.tickItems, function(v,k){
13746 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13748 _this.tickItems.splice(k, 1);
13750 if(typeof(e) == 'undefined' && view == false){
13751 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13763 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13764 this.tickItems.push(r.data);
13767 if(typeof(e) == 'undefined' && view == false){
13768 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13775 this.onSelect(r, index);
13777 if(doFocus !== false && !this.blockFocus){
13778 this.inputEl().focus();
13783 restrictHeight : function(){
13784 //this.innerList.dom.style.height = '';
13785 //var inner = this.innerList.dom;
13786 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13787 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13788 //this.list.beginUpdate();
13789 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13790 this.list.alignTo(this.inputEl(), this.listAlign);
13791 this.list.alignTo(this.inputEl(), this.listAlign);
13792 //this.list.endUpdate();
13796 onEmptyResults : function(){
13798 if(this.tickable && this.editable){
13799 this.restrictHeight();
13807 * Returns true if the dropdown list is expanded, else false.
13809 isExpanded : function(){
13810 return this.list.isVisible();
13814 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13815 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13816 * @param {String} value The data value of the item to select
13817 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13818 * selected item if it is not currently in view (defaults to true)
13819 * @return {Boolean} True if the value matched an item in the list, else false
13821 selectByValue : function(v, scrollIntoView){
13822 if(v !== undefined && v !== null){
13823 var r = this.findRecord(this.valueField || this.displayField, v);
13825 this.select(this.store.indexOf(r), scrollIntoView);
13833 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13834 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13835 * @param {Number} index The zero-based index of the list item to select
13836 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13837 * selected item if it is not currently in view (defaults to true)
13839 select : function(index, scrollIntoView){
13840 this.selectedIndex = index;
13841 this.view.select(index);
13842 if(scrollIntoView !== false){
13843 var el = this.view.getNode(index);
13845 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13848 this.list.scrollChildIntoView(el, false);
13854 selectNext : function(){
13855 var ct = this.store.getCount();
13857 if(this.selectedIndex == -1){
13859 }else if(this.selectedIndex < ct-1){
13860 this.select(this.selectedIndex+1);
13866 selectPrev : function(){
13867 var ct = this.store.getCount();
13869 if(this.selectedIndex == -1){
13871 }else if(this.selectedIndex != 0){
13872 this.select(this.selectedIndex-1);
13878 onKeyUp : function(e){
13879 if(this.editable !== false && !e.isSpecialKey()){
13880 this.lastKey = e.getKey();
13881 this.dqTask.delay(this.queryDelay);
13886 validateBlur : function(){
13887 return !this.list || !this.list.isVisible();
13891 initQuery : function(){
13893 var v = this.getRawValue();
13895 if(this.tickable && this.editable){
13896 v = this.tickableInputEl().getValue();
13903 doForce : function(){
13904 if(this.inputEl().dom.value.length > 0){
13905 this.inputEl().dom.value =
13906 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13912 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13913 * query allowing the query action to be canceled if needed.
13914 * @param {String} query The SQL query to execute
13915 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13916 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13917 * saved in the current store (defaults to false)
13919 doQuery : function(q, forceAll){
13921 if(q === undefined || q === null){
13926 forceAll: forceAll,
13930 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13935 forceAll = qe.forceAll;
13936 if(forceAll === true || (q.length >= this.minChars)){
13938 this.hasQuery = true;
13940 if(this.lastQuery != q || this.alwaysQuery){
13941 this.lastQuery = q;
13942 if(this.mode == 'local'){
13943 this.selectedIndex = -1;
13945 this.store.clearFilter();
13948 if(this.specialFilter){
13949 this.fireEvent('specialfilter', this);
13954 this.store.filter(this.displayField, q);
13957 this.store.fireEvent("datachanged", this.store);
13964 this.store.baseParams[this.queryParam] = q;
13966 var options = {params : this.getParams(q)};
13969 options.add = true;
13970 options.params.start = this.page * this.pageSize;
13973 this.store.load(options);
13976 * this code will make the page width larger, at the beginning, the list not align correctly,
13977 * we should expand the list on onLoad
13978 * so command out it
13983 this.selectedIndex = -1;
13988 this.loadNext = false;
13992 getParams : function(q){
13994 //p[this.queryParam] = q;
13998 p.limit = this.pageSize;
14004 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14006 collapse : function(){
14007 if(!this.isExpanded()){
14013 this.hasFocus = false;
14017 this.cancelBtn.hide();
14018 this.trigger.show();
14021 this.tickableInputEl().dom.value = '';
14022 this.tickableInputEl().blur();
14027 Roo.get(document).un('mousedown', this.collapseIf, this);
14028 Roo.get(document).un('mousewheel', this.collapseIf, this);
14029 if (!this.editable) {
14030 Roo.get(document).un('keydown', this.listKeyPress, this);
14032 this.fireEvent('collapse', this);
14038 collapseIf : function(e){
14039 var in_combo = e.within(this.el);
14040 var in_list = e.within(this.list);
14041 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14043 if (in_combo || in_list || is_list) {
14044 //e.stopPropagation();
14049 this.onTickableFooterButtonClick(e, false, false);
14057 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14059 expand : function(){
14061 if(this.isExpanded() || !this.hasFocus){
14065 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14066 this.list.setWidth(lw);
14072 this.restrictHeight();
14076 this.tickItems = Roo.apply([], this.item);
14079 this.cancelBtn.show();
14080 this.trigger.hide();
14083 this.tickableInputEl().focus();
14088 Roo.get(document).on('mousedown', this.collapseIf, this);
14089 Roo.get(document).on('mousewheel', this.collapseIf, this);
14090 if (!this.editable) {
14091 Roo.get(document).on('keydown', this.listKeyPress, this);
14094 this.fireEvent('expand', this);
14098 // Implements the default empty TriggerField.onTriggerClick function
14099 onTriggerClick : function(e)
14101 Roo.log('trigger click');
14103 if(this.disabled || !this.triggerList){
14108 this.loadNext = false;
14110 if(this.isExpanded()){
14112 if (!this.blockFocus) {
14113 this.inputEl().focus();
14117 this.hasFocus = true;
14118 if(this.triggerAction == 'all') {
14119 this.doQuery(this.allQuery, true);
14121 this.doQuery(this.getRawValue());
14123 if (!this.blockFocus) {
14124 this.inputEl().focus();
14129 onTickableTriggerClick : function(e)
14136 this.loadNext = false;
14137 this.hasFocus = true;
14139 if(this.triggerAction == 'all') {
14140 this.doQuery(this.allQuery, true);
14142 this.doQuery(this.getRawValue());
14146 onSearchFieldClick : function(e)
14148 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14149 this.onTickableFooterButtonClick(e, false, false);
14153 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14158 this.loadNext = false;
14159 this.hasFocus = true;
14161 if(this.triggerAction == 'all') {
14162 this.doQuery(this.allQuery, true);
14164 this.doQuery(this.getRawValue());
14168 listKeyPress : function(e)
14170 //Roo.log('listkeypress');
14171 // scroll to first matching element based on key pres..
14172 if (e.isSpecialKey()) {
14175 var k = String.fromCharCode(e.getKey()).toUpperCase();
14178 var csel = this.view.getSelectedNodes();
14179 var cselitem = false;
14181 var ix = this.view.indexOf(csel[0]);
14182 cselitem = this.store.getAt(ix);
14183 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14189 this.store.each(function(v) {
14191 // start at existing selection.
14192 if (cselitem.id == v.id) {
14198 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14199 match = this.store.indexOf(v);
14205 if (match === false) {
14206 return true; // no more action?
14209 this.view.select(match);
14210 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14211 sn.scrollIntoView(sn.dom.parentNode, false);
14214 onViewScroll : function(e, t){
14216 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){
14220 this.hasQuery = true;
14222 this.loading = this.list.select('.loading', true).first();
14224 if(this.loading === null){
14225 this.list.createChild({
14227 cls: 'loading roo-select2-more-results roo-select2-active',
14228 html: 'Loading more results...'
14231 this.loading = this.list.select('.loading', true).first();
14233 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14235 this.loading.hide();
14238 this.loading.show();
14243 this.loadNext = true;
14245 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14250 addItem : function(o)
14252 var dv = ''; // display value
14254 if (this.displayField) {
14255 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14257 // this is an error condition!!!
14258 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14265 var choice = this.choices.createChild({
14267 cls: 'roo-select2-search-choice',
14276 cls: 'roo-select2-search-choice-close',
14281 }, this.searchField);
14283 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14285 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14293 this.inputEl().dom.value = '';
14298 onRemoveItem : function(e, _self, o)
14300 e.preventDefault();
14302 this.lastItem = Roo.apply([], this.item);
14304 var index = this.item.indexOf(o.data) * 1;
14307 Roo.log('not this item?!');
14311 this.item.splice(index, 1);
14316 this.fireEvent('remove', this, e);
14322 syncValue : function()
14324 if(!this.item.length){
14331 Roo.each(this.item, function(i){
14332 if(_this.valueField){
14333 value.push(i[_this.valueField]);
14340 this.value = value.join(',');
14342 if(this.hiddenField){
14343 this.hiddenField.dom.value = this.value;
14346 this.store.fireEvent("datachanged", this.store);
14351 clearItem : function()
14353 if(!this.multiple){
14359 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14367 if(this.tickable && !Roo.isTouch){
14368 this.view.refresh();
14372 inputEl: function ()
14374 if(Roo.isIOS && this.useNativeIOS){
14375 return this.el.select('select.roo-ios-select', true).first();
14378 if(Roo.isTouch && this.mobileTouchView){
14379 return this.el.select('input.form-control',true).first();
14383 return this.searchField;
14386 return this.el.select('input.form-control',true).first();
14389 onTickableFooterButtonClick : function(e, btn, el)
14391 e.preventDefault();
14393 this.lastItem = Roo.apply([], this.item);
14395 if(btn && btn.name == 'cancel'){
14396 this.tickItems = Roo.apply([], this.item);
14405 Roo.each(this.tickItems, function(o){
14413 validate : function()
14415 var v = this.getRawValue();
14418 v = this.getValue();
14421 if(this.disabled || this.allowBlank || v.length){
14426 this.markInvalid();
14430 tickableInputEl : function()
14432 if(!this.tickable || !this.editable){
14433 return this.inputEl();
14436 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14440 getAutoCreateTouchView : function()
14445 cls: 'form-group' //input-group
14451 type : this.inputType,
14452 cls : 'form-control x-combo-noedit',
14453 autocomplete: 'new-password',
14454 placeholder : this.placeholder || '',
14459 input.name = this.name;
14463 input.cls += ' input-' + this.size;
14466 if (this.disabled) {
14467 input.disabled = true;
14478 inputblock.cls += ' input-group';
14480 inputblock.cn.unshift({
14482 cls : 'input-group-addon',
14487 if(this.removable && !this.multiple){
14488 inputblock.cls += ' roo-removable';
14490 inputblock.cn.push({
14493 cls : 'roo-combo-removable-btn close'
14497 if(this.hasFeedback && !this.allowBlank){
14499 inputblock.cls += ' has-feedback';
14501 inputblock.cn.push({
14503 cls: 'glyphicon form-control-feedback'
14510 inputblock.cls += (this.before) ? '' : ' input-group';
14512 inputblock.cn.push({
14514 cls : 'input-group-addon',
14525 cls: 'form-hidden-field'
14539 cls: 'form-hidden-field'
14543 cls: 'roo-select2-choices',
14547 cls: 'roo-select2-search-field',
14560 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14566 if(!this.multiple && this.showToggleBtn){
14573 if (this.caret != false) {
14576 cls: 'fa fa-' + this.caret
14583 cls : 'input-group-addon btn dropdown-toggle',
14588 cls: 'combobox-clear',
14602 combobox.cls += ' roo-select2-container-multi';
14605 var align = this.labelAlign || this.parentLabelAlign();
14607 if (align ==='left' && this.fieldLabel.length) {
14612 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14613 tooltip : 'This field is required'
14617 cls : 'control-label',
14618 html : this.fieldLabel
14629 var labelCfg = cfg.cn[1];
14630 var contentCfg = cfg.cn[2];
14633 if(this.indicatorpos == 'right'){
14637 cls : 'control-label',
14638 html : this.fieldLabel,
14642 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14643 tooltip : 'This field is required'
14656 labelCfg = cfg.cn[0];
14657 contentCfg = cfg.cn[2];
14659 if(this.labelWidth > 12){
14660 labelCfg.style = "width: " + this.labelWidth + 'px';
14663 if(this.labelWidth < 13 && this.labelmd == 0){
14664 this.labelmd = this.labelWidth;
14667 if(this.labellg > 0){
14668 labelCfg.cls += ' col-lg-' + this.labellg;
14669 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14672 if(this.labelmd > 0){
14673 labelCfg.cls += ' col-md-' + this.labelmd;
14674 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14677 if(this.labelsm > 0){
14678 labelCfg.cls += ' col-sm-' + this.labelsm;
14679 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14682 if(this.labelxs > 0){
14683 labelCfg.cls += ' col-xs-' + this.labelxs;
14684 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14688 } else if ( this.fieldLabel.length) {
14692 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14693 tooltip : 'This field is required'
14697 cls : 'control-label',
14698 html : this.fieldLabel
14709 if(this.indicatorpos == 'right'){
14713 cls : 'control-label',
14714 html : this.fieldLabel,
14718 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14719 tooltip : 'This field is required'
14736 var settings = this;
14738 ['xs','sm','md','lg'].map(function(size){
14739 if (settings[size]) {
14740 cfg.cls += ' col-' + size + '-' + settings[size];
14747 initTouchView : function()
14749 this.renderTouchView();
14751 this.touchViewEl.on('scroll', function(){
14752 this.el.dom.scrollTop = 0;
14755 this.originalValue = this.getValue();
14757 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14759 this.inputEl().on("click", this.showTouchView, this);
14760 if (this.triggerEl) {
14761 this.triggerEl.on("click", this.showTouchView, this);
14765 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14766 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14768 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14770 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14771 this.store.on('load', this.onTouchViewLoad, this);
14772 this.store.on('loadexception', this.onTouchViewLoadException, this);
14774 if(this.hiddenName){
14776 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14778 this.hiddenField.dom.value =
14779 this.hiddenValue !== undefined ? this.hiddenValue :
14780 this.value !== undefined ? this.value : '';
14782 this.el.dom.removeAttribute('name');
14783 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14787 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14788 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14791 if(this.removable && !this.multiple){
14792 var close = this.closeTriggerEl();
14794 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14795 close.on('click', this.removeBtnClick, this, close);
14799 * fix the bug in Safari iOS8
14801 this.inputEl().on("focus", function(e){
14802 document.activeElement.blur();
14810 renderTouchView : function()
14812 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14813 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14815 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14816 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14818 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14819 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14820 this.touchViewBodyEl.setStyle('overflow', 'auto');
14822 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14823 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14825 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14826 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14830 showTouchView : function()
14836 this.touchViewHeaderEl.hide();
14838 if(this.modalTitle.length){
14839 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14840 this.touchViewHeaderEl.show();
14843 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14844 this.touchViewEl.show();
14846 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14847 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14848 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14850 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14852 if(this.modalTitle.length){
14853 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14856 this.touchViewBodyEl.setHeight(bodyHeight);
14860 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14862 this.touchViewEl.addClass('in');
14865 this.doTouchViewQuery();
14869 hideTouchView : function()
14871 this.touchViewEl.removeClass('in');
14875 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14877 this.touchViewEl.setStyle('display', 'none');
14882 setTouchViewValue : function()
14889 Roo.each(this.tickItems, function(o){
14894 this.hideTouchView();
14897 doTouchViewQuery : function()
14906 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14910 if(!this.alwaysQuery || this.mode == 'local'){
14911 this.onTouchViewLoad();
14918 onTouchViewBeforeLoad : function(combo,opts)
14924 onTouchViewLoad : function()
14926 if(this.store.getCount() < 1){
14927 this.onTouchViewEmptyResults();
14931 this.clearTouchView();
14933 var rawValue = this.getRawValue();
14935 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14937 this.tickItems = [];
14939 this.store.data.each(function(d, rowIndex){
14940 var row = this.touchViewListGroup.createChild(template);
14942 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14943 row.addClass(d.data.cls);
14946 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14949 html : d.data[this.displayField]
14952 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14953 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14956 row.removeClass('selected');
14957 if(!this.multiple && this.valueField &&
14958 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14961 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14962 row.addClass('selected');
14965 if(this.multiple && this.valueField &&
14966 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14970 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14971 this.tickItems.push(d.data);
14974 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14978 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14980 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14982 if(this.modalTitle.length){
14983 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14986 var listHeight = this.touchViewListGroup.getHeight();
14990 if(firstChecked && listHeight > bodyHeight){
14991 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14996 onTouchViewLoadException : function()
14998 this.hideTouchView();
15001 onTouchViewEmptyResults : function()
15003 this.clearTouchView();
15005 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15007 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15011 clearTouchView : function()
15013 this.touchViewListGroup.dom.innerHTML = '';
15016 onTouchViewClick : function(e, el, o)
15018 e.preventDefault();
15021 var rowIndex = o.rowIndex;
15023 var r = this.store.getAt(rowIndex);
15025 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15027 if(!this.multiple){
15028 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15029 c.dom.removeAttribute('checked');
15032 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15034 this.setFromData(r.data);
15036 var close = this.closeTriggerEl();
15042 this.hideTouchView();
15044 this.fireEvent('select', this, r, rowIndex);
15049 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15050 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15051 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15055 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15056 this.addItem(r.data);
15057 this.tickItems.push(r.data);
15061 getAutoCreateNativeIOS : function()
15064 cls: 'form-group' //input-group,
15069 cls : 'roo-ios-select'
15073 combobox.name = this.name;
15076 if (this.disabled) {
15077 combobox.disabled = true;
15080 var settings = this;
15082 ['xs','sm','md','lg'].map(function(size){
15083 if (settings[size]) {
15084 cfg.cls += ' col-' + size + '-' + settings[size];
15094 initIOSView : function()
15096 this.store.on('load', this.onIOSViewLoad, this);
15101 onIOSViewLoad : function()
15103 if(this.store.getCount() < 1){
15107 this.clearIOSView();
15109 if(this.allowBlank) {
15111 var default_text = '-- SELECT --';
15113 var opt = this.inputEl().createChild({
15116 html : default_text
15120 o[this.valueField] = 0;
15121 o[this.displayField] = default_text;
15123 this.ios_options.push({
15130 this.store.data.each(function(d, rowIndex){
15134 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15135 html = d.data[this.displayField];
15140 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15141 value = d.data[this.valueField];
15150 if(this.value == d.data[this.valueField]){
15151 option['selected'] = true;
15154 var opt = this.inputEl().createChild(option);
15156 this.ios_options.push({
15163 this.inputEl().on('change', function(){
15164 this.fireEvent('select', this);
15169 clearIOSView: function()
15171 this.inputEl().dom.innerHTML = '';
15173 this.ios_options = [];
15176 setIOSValue: function(v)
15180 if(!this.ios_options){
15184 Roo.each(this.ios_options, function(opts){
15186 opts.el.dom.removeAttribute('selected');
15188 if(opts.data[this.valueField] != v){
15192 opts.el.dom.setAttribute('selected', true);
15198 * @cfg {Boolean} grow
15202 * @cfg {Number} growMin
15206 * @cfg {Number} growMax
15215 Roo.apply(Roo.bootstrap.ComboBox, {
15219 cls: 'modal-header',
15241 cls: 'list-group-item',
15245 cls: 'roo-combobox-list-group-item-value'
15249 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15263 listItemCheckbox : {
15265 cls: 'list-group-item',
15269 cls: 'roo-combobox-list-group-item-value'
15273 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15289 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15294 cls: 'modal-footer',
15302 cls: 'col-xs-6 text-left',
15305 cls: 'btn btn-danger roo-touch-view-cancel',
15311 cls: 'col-xs-6 text-right',
15314 cls: 'btn btn-success roo-touch-view-ok',
15325 Roo.apply(Roo.bootstrap.ComboBox, {
15327 touchViewTemplate : {
15329 cls: 'modal fade roo-combobox-touch-view',
15333 cls: 'modal-dialog',
15334 style : 'position:fixed', // we have to fix position....
15338 cls: 'modal-content',
15340 Roo.bootstrap.ComboBox.header,
15341 Roo.bootstrap.ComboBox.body,
15342 Roo.bootstrap.ComboBox.footer
15351 * Ext JS Library 1.1.1
15352 * Copyright(c) 2006-2007, Ext JS, LLC.
15354 * Originally Released Under LGPL - original licence link has changed is not relivant.
15357 * <script type="text/javascript">
15362 * @extends Roo.util.Observable
15363 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15364 * This class also supports single and multi selection modes. <br>
15365 * Create a data model bound view:
15367 var store = new Roo.data.Store(...);
15369 var view = new Roo.View({
15371 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15373 singleSelect: true,
15374 selectedClass: "ydataview-selected",
15378 // listen for node click?
15379 view.on("click", function(vw, index, node, e){
15380 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15384 dataModel.load("foobar.xml");
15386 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15388 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15389 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15391 * Note: old style constructor is still suported (container, template, config)
15394 * Create a new View
15395 * @param {Object} config The config object
15398 Roo.View = function(config, depreciated_tpl, depreciated_config){
15400 this.parent = false;
15402 if (typeof(depreciated_tpl) == 'undefined') {
15403 // new way.. - universal constructor.
15404 Roo.apply(this, config);
15405 this.el = Roo.get(this.el);
15408 this.el = Roo.get(config);
15409 this.tpl = depreciated_tpl;
15410 Roo.apply(this, depreciated_config);
15412 this.wrapEl = this.el.wrap().wrap();
15413 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15416 if(typeof(this.tpl) == "string"){
15417 this.tpl = new Roo.Template(this.tpl);
15419 // support xtype ctors..
15420 this.tpl = new Roo.factory(this.tpl, Roo);
15424 this.tpl.compile();
15429 * @event beforeclick
15430 * Fires before a click is processed. Returns false to cancel the default action.
15431 * @param {Roo.View} this
15432 * @param {Number} index The index of the target node
15433 * @param {HTMLElement} node The target node
15434 * @param {Roo.EventObject} e The raw event object
15436 "beforeclick" : true,
15439 * Fires when a template node is clicked.
15440 * @param {Roo.View} this
15441 * @param {Number} index The index of the target node
15442 * @param {HTMLElement} node The target node
15443 * @param {Roo.EventObject} e The raw event object
15448 * Fires when a template node is double clicked.
15449 * @param {Roo.View} this
15450 * @param {Number} index The index of the target node
15451 * @param {HTMLElement} node The target node
15452 * @param {Roo.EventObject} e The raw event object
15456 * @event contextmenu
15457 * Fires when a template node is right clicked.
15458 * @param {Roo.View} this
15459 * @param {Number} index The index of the target node
15460 * @param {HTMLElement} node The target node
15461 * @param {Roo.EventObject} e The raw event object
15463 "contextmenu" : true,
15465 * @event selectionchange
15466 * Fires when the selected nodes change.
15467 * @param {Roo.View} this
15468 * @param {Array} selections Array of the selected nodes
15470 "selectionchange" : true,
15473 * @event beforeselect
15474 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15475 * @param {Roo.View} this
15476 * @param {HTMLElement} node The node to be selected
15477 * @param {Array} selections Array of currently selected nodes
15479 "beforeselect" : true,
15481 * @event preparedata
15482 * Fires on every row to render, to allow you to change the data.
15483 * @param {Roo.View} this
15484 * @param {Object} data to be rendered (change this)
15486 "preparedata" : true
15494 "click": this.onClick,
15495 "dblclick": this.onDblClick,
15496 "contextmenu": this.onContextMenu,
15500 this.selections = [];
15502 this.cmp = new Roo.CompositeElementLite([]);
15504 this.store = Roo.factory(this.store, Roo.data);
15505 this.setStore(this.store, true);
15508 if ( this.footer && this.footer.xtype) {
15510 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15512 this.footer.dataSource = this.store;
15513 this.footer.container = fctr;
15514 this.footer = Roo.factory(this.footer, Roo);
15515 fctr.insertFirst(this.el);
15517 // this is a bit insane - as the paging toolbar seems to detach the el..
15518 // dom.parentNode.parentNode.parentNode
15519 // they get detached?
15523 Roo.View.superclass.constructor.call(this);
15528 Roo.extend(Roo.View, Roo.util.Observable, {
15531 * @cfg {Roo.data.Store} store Data store to load data from.
15536 * @cfg {String|Roo.Element} el The container element.
15541 * @cfg {String|Roo.Template} tpl The template used by this View
15545 * @cfg {String} dataName the named area of the template to use as the data area
15546 * Works with domtemplates roo-name="name"
15550 * @cfg {String} selectedClass The css class to add to selected nodes
15552 selectedClass : "x-view-selected",
15554 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15559 * @cfg {String} text to display on mask (default Loading)
15563 * @cfg {Boolean} multiSelect Allow multiple selection
15565 multiSelect : false,
15567 * @cfg {Boolean} singleSelect Allow single selection
15569 singleSelect: false,
15572 * @cfg {Boolean} toggleSelect - selecting
15574 toggleSelect : false,
15577 * @cfg {Boolean} tickable - selecting
15582 * Returns the element this view is bound to.
15583 * @return {Roo.Element}
15585 getEl : function(){
15586 return this.wrapEl;
15592 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15594 refresh : function(){
15595 //Roo.log('refresh');
15598 // if we are using something like 'domtemplate', then
15599 // the what gets used is:
15600 // t.applySubtemplate(NAME, data, wrapping data..)
15601 // the outer template then get' applied with
15602 // the store 'extra data'
15603 // and the body get's added to the
15604 // roo-name="data" node?
15605 // <span class='roo-tpl-{name}'></span> ?????
15609 this.clearSelections();
15610 this.el.update("");
15612 var records = this.store.getRange();
15613 if(records.length < 1) {
15615 // is this valid?? = should it render a template??
15617 this.el.update(this.emptyText);
15621 if (this.dataName) {
15622 this.el.update(t.apply(this.store.meta)); //????
15623 el = this.el.child('.roo-tpl-' + this.dataName);
15626 for(var i = 0, len = records.length; i < len; i++){
15627 var data = this.prepareData(records[i].data, i, records[i]);
15628 this.fireEvent("preparedata", this, data, i, records[i]);
15630 var d = Roo.apply({}, data);
15633 Roo.apply(d, {'roo-id' : Roo.id()});
15637 Roo.each(this.parent.item, function(item){
15638 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15641 Roo.apply(d, {'roo-data-checked' : 'checked'});
15645 html[html.length] = Roo.util.Format.trim(
15647 t.applySubtemplate(this.dataName, d, this.store.meta) :
15654 el.update(html.join(""));
15655 this.nodes = el.dom.childNodes;
15656 this.updateIndexes(0);
15661 * Function to override to reformat the data that is sent to
15662 * the template for each node.
15663 * DEPRICATED - use the preparedata event handler.
15664 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15665 * a JSON object for an UpdateManager bound view).
15667 prepareData : function(data, index, record)
15669 this.fireEvent("preparedata", this, data, index, record);
15673 onUpdate : function(ds, record){
15674 // Roo.log('on update');
15675 this.clearSelections();
15676 var index = this.store.indexOf(record);
15677 var n = this.nodes[index];
15678 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15679 n.parentNode.removeChild(n);
15680 this.updateIndexes(index, index);
15686 onAdd : function(ds, records, index)
15688 //Roo.log(['on Add', ds, records, index] );
15689 this.clearSelections();
15690 if(this.nodes.length == 0){
15694 var n = this.nodes[index];
15695 for(var i = 0, len = records.length; i < len; i++){
15696 var d = this.prepareData(records[i].data, i, records[i]);
15698 this.tpl.insertBefore(n, d);
15701 this.tpl.append(this.el, d);
15704 this.updateIndexes(index);
15707 onRemove : function(ds, record, index){
15708 // Roo.log('onRemove');
15709 this.clearSelections();
15710 var el = this.dataName ?
15711 this.el.child('.roo-tpl-' + this.dataName) :
15714 el.dom.removeChild(this.nodes[index]);
15715 this.updateIndexes(index);
15719 * Refresh an individual node.
15720 * @param {Number} index
15722 refreshNode : function(index){
15723 this.onUpdate(this.store, this.store.getAt(index));
15726 updateIndexes : function(startIndex, endIndex){
15727 var ns = this.nodes;
15728 startIndex = startIndex || 0;
15729 endIndex = endIndex || ns.length - 1;
15730 for(var i = startIndex; i <= endIndex; i++){
15731 ns[i].nodeIndex = i;
15736 * Changes the data store this view uses and refresh the view.
15737 * @param {Store} store
15739 setStore : function(store, initial){
15740 if(!initial && this.store){
15741 this.store.un("datachanged", this.refresh);
15742 this.store.un("add", this.onAdd);
15743 this.store.un("remove", this.onRemove);
15744 this.store.un("update", this.onUpdate);
15745 this.store.un("clear", this.refresh);
15746 this.store.un("beforeload", this.onBeforeLoad);
15747 this.store.un("load", this.onLoad);
15748 this.store.un("loadexception", this.onLoad);
15752 store.on("datachanged", this.refresh, this);
15753 store.on("add", this.onAdd, this);
15754 store.on("remove", this.onRemove, this);
15755 store.on("update", this.onUpdate, this);
15756 store.on("clear", this.refresh, this);
15757 store.on("beforeload", this.onBeforeLoad, this);
15758 store.on("load", this.onLoad, this);
15759 store.on("loadexception", this.onLoad, this);
15767 * onbeforeLoad - masks the loading area.
15770 onBeforeLoad : function(store,opts)
15772 //Roo.log('onBeforeLoad');
15774 this.el.update("");
15776 this.el.mask(this.mask ? this.mask : "Loading" );
15778 onLoad : function ()
15785 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15786 * @param {HTMLElement} node
15787 * @return {HTMLElement} The template node
15789 findItemFromChild : function(node){
15790 var el = this.dataName ?
15791 this.el.child('.roo-tpl-' + this.dataName,true) :
15794 if(!node || node.parentNode == el){
15797 var p = node.parentNode;
15798 while(p && p != el){
15799 if(p.parentNode == el){
15808 onClick : function(e){
15809 var item = this.findItemFromChild(e.getTarget());
15811 var index = this.indexOf(item);
15812 if(this.onItemClick(item, index, e) !== false){
15813 this.fireEvent("click", this, index, item, e);
15816 this.clearSelections();
15821 onContextMenu : function(e){
15822 var item = this.findItemFromChild(e.getTarget());
15824 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15829 onDblClick : function(e){
15830 var item = this.findItemFromChild(e.getTarget());
15832 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15836 onItemClick : function(item, index, e)
15838 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15841 if (this.toggleSelect) {
15842 var m = this.isSelected(item) ? 'unselect' : 'select';
15845 _t[m](item, true, false);
15848 if(this.multiSelect || this.singleSelect){
15849 if(this.multiSelect && e.shiftKey && this.lastSelection){
15850 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15852 this.select(item, this.multiSelect && e.ctrlKey);
15853 this.lastSelection = item;
15856 if(!this.tickable){
15857 e.preventDefault();
15865 * Get the number of selected nodes.
15868 getSelectionCount : function(){
15869 return this.selections.length;
15873 * Get the currently selected nodes.
15874 * @return {Array} An array of HTMLElements
15876 getSelectedNodes : function(){
15877 return this.selections;
15881 * Get the indexes of the selected nodes.
15884 getSelectedIndexes : function(){
15885 var indexes = [], s = this.selections;
15886 for(var i = 0, len = s.length; i < len; i++){
15887 indexes.push(s[i].nodeIndex);
15893 * Clear all selections
15894 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15896 clearSelections : function(suppressEvent){
15897 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15898 this.cmp.elements = this.selections;
15899 this.cmp.removeClass(this.selectedClass);
15900 this.selections = [];
15901 if(!suppressEvent){
15902 this.fireEvent("selectionchange", this, this.selections);
15908 * Returns true if the passed node is selected
15909 * @param {HTMLElement/Number} node The node or node index
15910 * @return {Boolean}
15912 isSelected : function(node){
15913 var s = this.selections;
15917 node = this.getNode(node);
15918 return s.indexOf(node) !== -1;
15923 * @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
15924 * @param {Boolean} keepExisting (optional) true to keep existing selections
15925 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15927 select : function(nodeInfo, keepExisting, suppressEvent){
15928 if(nodeInfo instanceof Array){
15930 this.clearSelections(true);
15932 for(var i = 0, len = nodeInfo.length; i < len; i++){
15933 this.select(nodeInfo[i], true, true);
15937 var node = this.getNode(nodeInfo);
15938 if(!node || this.isSelected(node)){
15939 return; // already selected.
15942 this.clearSelections(true);
15945 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15946 Roo.fly(node).addClass(this.selectedClass);
15947 this.selections.push(node);
15948 if(!suppressEvent){
15949 this.fireEvent("selectionchange", this, this.selections);
15957 * @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
15958 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15959 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15961 unselect : function(nodeInfo, keepExisting, suppressEvent)
15963 if(nodeInfo instanceof Array){
15964 Roo.each(this.selections, function(s) {
15965 this.unselect(s, nodeInfo);
15969 var node = this.getNode(nodeInfo);
15970 if(!node || !this.isSelected(node)){
15971 //Roo.log("not selected");
15972 return; // not selected.
15976 Roo.each(this.selections, function(s) {
15978 Roo.fly(node).removeClass(this.selectedClass);
15985 this.selections= ns;
15986 this.fireEvent("selectionchange", this, this.selections);
15990 * Gets a template node.
15991 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15992 * @return {HTMLElement} The node or null if it wasn't found
15994 getNode : function(nodeInfo){
15995 if(typeof nodeInfo == "string"){
15996 return document.getElementById(nodeInfo);
15997 }else if(typeof nodeInfo == "number"){
15998 return this.nodes[nodeInfo];
16004 * Gets a range template nodes.
16005 * @param {Number} startIndex
16006 * @param {Number} endIndex
16007 * @return {Array} An array of nodes
16009 getNodes : function(start, end){
16010 var ns = this.nodes;
16011 start = start || 0;
16012 end = typeof end == "undefined" ? ns.length - 1 : end;
16015 for(var i = start; i <= end; i++){
16019 for(var i = start; i >= end; i--){
16027 * Finds the index of the passed node
16028 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16029 * @return {Number} The index of the node or -1
16031 indexOf : function(node){
16032 node = this.getNode(node);
16033 if(typeof node.nodeIndex == "number"){
16034 return node.nodeIndex;
16036 var ns = this.nodes;
16037 for(var i = 0, len = ns.length; i < len; i++){
16048 * based on jquery fullcalendar
16052 Roo.bootstrap = Roo.bootstrap || {};
16054 * @class Roo.bootstrap.Calendar
16055 * @extends Roo.bootstrap.Component
16056 * Bootstrap Calendar class
16057 * @cfg {Boolean} loadMask (true|false) default false
16058 * @cfg {Object} header generate the user specific header of the calendar, default false
16061 * Create a new Container
16062 * @param {Object} config The config object
16067 Roo.bootstrap.Calendar = function(config){
16068 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16072 * Fires when a date is selected
16073 * @param {DatePicker} this
16074 * @param {Date} date The selected date
16078 * @event monthchange
16079 * Fires when the displayed month changes
16080 * @param {DatePicker} this
16081 * @param {Date} date The selected month
16083 'monthchange': true,
16085 * @event evententer
16086 * Fires when mouse over an event
16087 * @param {Calendar} this
16088 * @param {event} Event
16090 'evententer': true,
16092 * @event eventleave
16093 * Fires when the mouse leaves an
16094 * @param {Calendar} this
16097 'eventleave': true,
16099 * @event eventclick
16100 * Fires when the mouse click an
16101 * @param {Calendar} this
16110 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16113 * @cfg {Number} startDay
16114 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16122 getAutoCreate : function(){
16125 var fc_button = function(name, corner, style, content ) {
16126 return Roo.apply({},{
16128 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16130 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16133 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16144 style : 'width:100%',
16151 cls : 'fc-header-left',
16153 fc_button('prev', 'left', 'arrow', '‹' ),
16154 fc_button('next', 'right', 'arrow', '›' ),
16155 { tag: 'span', cls: 'fc-header-space' },
16156 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16164 cls : 'fc-header-center',
16168 cls: 'fc-header-title',
16171 html : 'month / year'
16179 cls : 'fc-header-right',
16181 /* fc_button('month', 'left', '', 'month' ),
16182 fc_button('week', '', '', 'week' ),
16183 fc_button('day', 'right', '', 'day' )
16195 header = this.header;
16198 var cal_heads = function() {
16200 // fixme - handle this.
16202 for (var i =0; i < Date.dayNames.length; i++) {
16203 var d = Date.dayNames[i];
16206 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16207 html : d.substring(0,3)
16211 ret[0].cls += ' fc-first';
16212 ret[6].cls += ' fc-last';
16215 var cal_cell = function(n) {
16218 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16223 cls: 'fc-day-number',
16227 cls: 'fc-day-content',
16231 style: 'position: relative;' // height: 17px;
16243 var cal_rows = function() {
16246 for (var r = 0; r < 6; r++) {
16253 for (var i =0; i < Date.dayNames.length; i++) {
16254 var d = Date.dayNames[i];
16255 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16258 row.cn[0].cls+=' fc-first';
16259 row.cn[0].cn[0].style = 'min-height:90px';
16260 row.cn[6].cls+=' fc-last';
16264 ret[0].cls += ' fc-first';
16265 ret[4].cls += ' fc-prev-last';
16266 ret[5].cls += ' fc-last';
16273 cls: 'fc-border-separate',
16274 style : 'width:100%',
16282 cls : 'fc-first fc-last',
16300 cls : 'fc-content',
16301 style : "position: relative;",
16304 cls : 'fc-view fc-view-month fc-grid',
16305 style : 'position: relative',
16306 unselectable : 'on',
16309 cls : 'fc-event-container',
16310 style : 'position:absolute;z-index:8;top:0;left:0;'
16328 initEvents : function()
16331 throw "can not find store for calendar";
16337 style: "text-align:center",
16341 style: "background-color:white;width:50%;margin:250 auto",
16345 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16356 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16358 var size = this.el.select('.fc-content', true).first().getSize();
16359 this.maskEl.setSize(size.width, size.height);
16360 this.maskEl.enableDisplayMode("block");
16361 if(!this.loadMask){
16362 this.maskEl.hide();
16365 this.store = Roo.factory(this.store, Roo.data);
16366 this.store.on('load', this.onLoad, this);
16367 this.store.on('beforeload', this.onBeforeLoad, this);
16371 this.cells = this.el.select('.fc-day',true);
16372 //Roo.log(this.cells);
16373 this.textNodes = this.el.query('.fc-day-number');
16374 this.cells.addClassOnOver('fc-state-hover');
16376 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16377 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16378 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16379 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16381 this.on('monthchange', this.onMonthChange, this);
16383 this.update(new Date().clearTime());
16386 resize : function() {
16387 var sz = this.el.getSize();
16389 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16390 this.el.select('.fc-day-content div',true).setHeight(34);
16395 showPrevMonth : function(e){
16396 this.update(this.activeDate.add("mo", -1));
16398 showToday : function(e){
16399 this.update(new Date().clearTime());
16402 showNextMonth : function(e){
16403 this.update(this.activeDate.add("mo", 1));
16407 showPrevYear : function(){
16408 this.update(this.activeDate.add("y", -1));
16412 showNextYear : function(){
16413 this.update(this.activeDate.add("y", 1));
16418 update : function(date)
16420 var vd = this.activeDate;
16421 this.activeDate = date;
16422 // if(vd && this.el){
16423 // var t = date.getTime();
16424 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16425 // Roo.log('using add remove');
16427 // this.fireEvent('monthchange', this, date);
16429 // this.cells.removeClass("fc-state-highlight");
16430 // this.cells.each(function(c){
16431 // if(c.dateValue == t){
16432 // c.addClass("fc-state-highlight");
16433 // setTimeout(function(){
16434 // try{c.dom.firstChild.focus();}catch(e){}
16444 var days = date.getDaysInMonth();
16446 var firstOfMonth = date.getFirstDateOfMonth();
16447 var startingPos = firstOfMonth.getDay()-this.startDay;
16449 if(startingPos < this.startDay){
16453 var pm = date.add(Date.MONTH, -1);
16454 var prevStart = pm.getDaysInMonth()-startingPos;
16456 this.cells = this.el.select('.fc-day',true);
16457 this.textNodes = this.el.query('.fc-day-number');
16458 this.cells.addClassOnOver('fc-state-hover');
16460 var cells = this.cells.elements;
16461 var textEls = this.textNodes;
16463 Roo.each(cells, function(cell){
16464 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16467 days += startingPos;
16469 // convert everything to numbers so it's fast
16470 var day = 86400000;
16471 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16474 //Roo.log(prevStart);
16476 var today = new Date().clearTime().getTime();
16477 var sel = date.clearTime().getTime();
16478 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16479 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16480 var ddMatch = this.disabledDatesRE;
16481 var ddText = this.disabledDatesText;
16482 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16483 var ddaysText = this.disabledDaysText;
16484 var format = this.format;
16486 var setCellClass = function(cal, cell){
16490 //Roo.log('set Cell Class');
16492 var t = d.getTime();
16496 cell.dateValue = t;
16498 cell.className += " fc-today";
16499 cell.className += " fc-state-highlight";
16500 cell.title = cal.todayText;
16503 // disable highlight in other month..
16504 //cell.className += " fc-state-highlight";
16509 cell.className = " fc-state-disabled";
16510 cell.title = cal.minText;
16514 cell.className = " fc-state-disabled";
16515 cell.title = cal.maxText;
16519 if(ddays.indexOf(d.getDay()) != -1){
16520 cell.title = ddaysText;
16521 cell.className = " fc-state-disabled";
16524 if(ddMatch && format){
16525 var fvalue = d.dateFormat(format);
16526 if(ddMatch.test(fvalue)){
16527 cell.title = ddText.replace("%0", fvalue);
16528 cell.className = " fc-state-disabled";
16532 if (!cell.initialClassName) {
16533 cell.initialClassName = cell.dom.className;
16536 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16541 for(; i < startingPos; i++) {
16542 textEls[i].innerHTML = (++prevStart);
16543 d.setDate(d.getDate()+1);
16545 cells[i].className = "fc-past fc-other-month";
16546 setCellClass(this, cells[i]);
16551 for(; i < days; i++){
16552 intDay = i - startingPos + 1;
16553 textEls[i].innerHTML = (intDay);
16554 d.setDate(d.getDate()+1);
16556 cells[i].className = ''; // "x-date-active";
16557 setCellClass(this, cells[i]);
16561 for(; i < 42; i++) {
16562 textEls[i].innerHTML = (++extraDays);
16563 d.setDate(d.getDate()+1);
16565 cells[i].className = "fc-future fc-other-month";
16566 setCellClass(this, cells[i]);
16569 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16571 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16573 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16574 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16576 if(totalRows != 6){
16577 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16578 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16581 this.fireEvent('monthchange', this, date);
16585 if(!this.internalRender){
16586 var main = this.el.dom.firstChild;
16587 var w = main.offsetWidth;
16588 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16589 Roo.fly(main).setWidth(w);
16590 this.internalRender = true;
16591 // opera does not respect the auto grow header center column
16592 // then, after it gets a width opera refuses to recalculate
16593 // without a second pass
16594 if(Roo.isOpera && !this.secondPass){
16595 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16596 this.secondPass = true;
16597 this.update.defer(10, this, [date]);
16604 findCell : function(dt) {
16605 dt = dt.clearTime().getTime();
16607 this.cells.each(function(c){
16608 //Roo.log("check " +c.dateValue + '?=' + dt);
16609 if(c.dateValue == dt){
16619 findCells : function(ev) {
16620 var s = ev.start.clone().clearTime().getTime();
16622 var e= ev.end.clone().clearTime().getTime();
16625 this.cells.each(function(c){
16626 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16628 if(c.dateValue > e){
16631 if(c.dateValue < s){
16640 // findBestRow: function(cells)
16644 // for (var i =0 ; i < cells.length;i++) {
16645 // ret = Math.max(cells[i].rows || 0,ret);
16652 addItem : function(ev)
16654 // look for vertical location slot in
16655 var cells = this.findCells(ev);
16657 // ev.row = this.findBestRow(cells);
16659 // work out the location.
16663 for(var i =0; i < cells.length; i++) {
16665 cells[i].row = cells[0].row;
16668 cells[i].row = cells[i].row + 1;
16678 if (crow.start.getY() == cells[i].getY()) {
16680 crow.end = cells[i];
16697 cells[0].events.push(ev);
16699 this.calevents.push(ev);
16702 clearEvents: function() {
16704 if(!this.calevents){
16708 Roo.each(this.cells.elements, function(c){
16714 Roo.each(this.calevents, function(e) {
16715 Roo.each(e.els, function(el) {
16716 el.un('mouseenter' ,this.onEventEnter, this);
16717 el.un('mouseleave' ,this.onEventLeave, this);
16722 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16728 renderEvents: function()
16732 this.cells.each(function(c) {
16741 if(c.row != c.events.length){
16742 r = 4 - (4 - (c.row - c.events.length));
16745 c.events = ev.slice(0, r);
16746 c.more = ev.slice(r);
16748 if(c.more.length && c.more.length == 1){
16749 c.events.push(c.more.pop());
16752 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16756 this.cells.each(function(c) {
16758 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16761 for (var e = 0; e < c.events.length; e++){
16762 var ev = c.events[e];
16763 var rows = ev.rows;
16765 for(var i = 0; i < rows.length; i++) {
16767 // how many rows should it span..
16770 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16771 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16773 unselectable : "on",
16776 cls: 'fc-event-inner',
16780 // cls: 'fc-event-time',
16781 // html : cells.length > 1 ? '' : ev.time
16785 cls: 'fc-event-title',
16786 html : String.format('{0}', ev.title)
16793 cls: 'ui-resizable-handle ui-resizable-e',
16794 html : '  '
16801 cfg.cls += ' fc-event-start';
16803 if ((i+1) == rows.length) {
16804 cfg.cls += ' fc-event-end';
16807 var ctr = _this.el.select('.fc-event-container',true).first();
16808 var cg = ctr.createChild(cfg);
16810 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16811 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16813 var r = (c.more.length) ? 1 : 0;
16814 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16815 cg.setWidth(ebox.right - sbox.x -2);
16817 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16818 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16819 cg.on('click', _this.onEventClick, _this, ev);
16830 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16831 style : 'position: absolute',
16832 unselectable : "on",
16835 cls: 'fc-event-inner',
16839 cls: 'fc-event-title',
16847 cls: 'ui-resizable-handle ui-resizable-e',
16848 html : '  '
16854 var ctr = _this.el.select('.fc-event-container',true).first();
16855 var cg = ctr.createChild(cfg);
16857 var sbox = c.select('.fc-day-content',true).first().getBox();
16858 var ebox = c.select('.fc-day-content',true).first().getBox();
16860 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16861 cg.setWidth(ebox.right - sbox.x -2);
16863 cg.on('click', _this.onMoreEventClick, _this, c.more);
16873 onEventEnter: function (e, el,event,d) {
16874 this.fireEvent('evententer', this, el, event);
16877 onEventLeave: function (e, el,event,d) {
16878 this.fireEvent('eventleave', this, el, event);
16881 onEventClick: function (e, el,event,d) {
16882 this.fireEvent('eventclick', this, el, event);
16885 onMonthChange: function () {
16889 onMoreEventClick: function(e, el, more)
16893 this.calpopover.placement = 'right';
16894 this.calpopover.setTitle('More');
16896 this.calpopover.setContent('');
16898 var ctr = this.calpopover.el.select('.popover-content', true).first();
16900 Roo.each(more, function(m){
16902 cls : 'fc-event-hori fc-event-draggable',
16905 var cg = ctr.createChild(cfg);
16907 cg.on('click', _this.onEventClick, _this, m);
16910 this.calpopover.show(el);
16915 onLoad: function ()
16917 this.calevents = [];
16920 if(this.store.getCount() > 0){
16921 this.store.data.each(function(d){
16924 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16925 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16926 time : d.data.start_time,
16927 title : d.data.title,
16928 description : d.data.description,
16929 venue : d.data.venue
16934 this.renderEvents();
16936 if(this.calevents.length && this.loadMask){
16937 this.maskEl.hide();
16941 onBeforeLoad: function()
16943 this.clearEvents();
16945 this.maskEl.show();
16959 * @class Roo.bootstrap.Popover
16960 * @extends Roo.bootstrap.Component
16961 * Bootstrap Popover class
16962 * @cfg {String} html contents of the popover (or false to use children..)
16963 * @cfg {String} title of popover (or false to hide)
16964 * @cfg {String} placement how it is placed
16965 * @cfg {String} trigger click || hover (or false to trigger manually)
16966 * @cfg {String} over what (parent or false to trigger manually.)
16967 * @cfg {Number} delay - delay before showing
16970 * Create a new Popover
16971 * @param {Object} config The config object
16974 Roo.bootstrap.Popover = function(config){
16975 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16981 * After the popover show
16983 * @param {Roo.bootstrap.Popover} this
16988 * After the popover hide
16990 * @param {Roo.bootstrap.Popover} this
16996 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16998 title: 'Fill in a title',
17001 placement : 'right',
17002 trigger : 'hover', // hover
17008 can_build_overlaid : false,
17010 getChildContainer : function()
17012 return this.el.select('.popover-content',true).first();
17015 getAutoCreate : function(){
17018 cls : 'popover roo-dynamic',
17019 style: 'display:block',
17025 cls : 'popover-inner',
17029 cls: 'popover-title',
17033 cls : 'popover-content',
17044 setTitle: function(str)
17047 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17049 setContent: function(str)
17052 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17054 // as it get's added to the bottom of the page.
17055 onRender : function(ct, position)
17057 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17059 var cfg = Roo.apply({}, this.getAutoCreate());
17063 cfg.cls += ' ' + this.cls;
17066 cfg.style = this.style;
17068 //Roo.log("adding to ");
17069 this.el = Roo.get(document.body).createChild(cfg, position);
17070 // Roo.log(this.el);
17075 initEvents : function()
17077 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17078 this.el.enableDisplayMode('block');
17080 if (this.over === false) {
17083 if (this.triggers === false) {
17086 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17087 var triggers = this.trigger ? this.trigger.split(' ') : [];
17088 Roo.each(triggers, function(trigger) {
17090 if (trigger == 'click') {
17091 on_el.on('click', this.toggle, this);
17092 } else if (trigger != 'manual') {
17093 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17094 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17096 on_el.on(eventIn ,this.enter, this);
17097 on_el.on(eventOut, this.leave, this);
17108 toggle : function () {
17109 this.hoverState == 'in' ? this.leave() : this.enter();
17112 enter : function () {
17114 clearTimeout(this.timeout);
17116 this.hoverState = 'in';
17118 if (!this.delay || !this.delay.show) {
17123 this.timeout = setTimeout(function () {
17124 if (_t.hoverState == 'in') {
17127 }, this.delay.show)
17130 leave : function() {
17131 clearTimeout(this.timeout);
17133 this.hoverState = 'out';
17135 if (!this.delay || !this.delay.hide) {
17140 this.timeout = setTimeout(function () {
17141 if (_t.hoverState == 'out') {
17144 }, this.delay.hide)
17147 show : function (on_el)
17150 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17154 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17155 if (this.html !== false) {
17156 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17158 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17159 if (!this.title.length) {
17160 this.el.select('.popover-title',true).hide();
17163 var placement = typeof this.placement == 'function' ?
17164 this.placement.call(this, this.el, on_el) :
17167 var autoToken = /\s?auto?\s?/i;
17168 var autoPlace = autoToken.test(placement);
17170 placement = placement.replace(autoToken, '') || 'top';
17174 //this.el.setXY([0,0]);
17176 this.el.dom.style.display='block';
17177 this.el.addClass(placement);
17179 //this.el.appendTo(on_el);
17181 var p = this.getPosition();
17182 var box = this.el.getBox();
17187 var align = Roo.bootstrap.Popover.alignment[placement];
17188 this.el.alignTo(on_el, align[0],align[1]);
17189 //var arrow = this.el.select('.arrow',true).first();
17190 //arrow.set(align[2],
17192 this.el.addClass('in');
17195 if (this.el.hasClass('fade')) {
17199 this.hoverState = 'in';
17201 this.fireEvent('show', this);
17206 this.el.setXY([0,0]);
17207 this.el.removeClass('in');
17209 this.hoverState = null;
17211 this.fireEvent('hide', this);
17216 Roo.bootstrap.Popover.alignment = {
17217 'left' : ['r-l', [-10,0], 'right'],
17218 'right' : ['l-r', [10,0], 'left'],
17219 'bottom' : ['t-b', [0,10], 'top'],
17220 'top' : [ 'b-t', [0,-10], 'bottom']
17231 * @class Roo.bootstrap.Progress
17232 * @extends Roo.bootstrap.Component
17233 * Bootstrap Progress class
17234 * @cfg {Boolean} striped striped of the progress bar
17235 * @cfg {Boolean} active animated of the progress bar
17239 * Create a new Progress
17240 * @param {Object} config The config object
17243 Roo.bootstrap.Progress = function(config){
17244 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17247 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17252 getAutoCreate : function(){
17260 cfg.cls += ' progress-striped';
17264 cfg.cls += ' active';
17283 * @class Roo.bootstrap.ProgressBar
17284 * @extends Roo.bootstrap.Component
17285 * Bootstrap ProgressBar class
17286 * @cfg {Number} aria_valuenow aria-value now
17287 * @cfg {Number} aria_valuemin aria-value min
17288 * @cfg {Number} aria_valuemax aria-value max
17289 * @cfg {String} label label for the progress bar
17290 * @cfg {String} panel (success | info | warning | danger )
17291 * @cfg {String} role role of the progress bar
17292 * @cfg {String} sr_only text
17296 * Create a new ProgressBar
17297 * @param {Object} config The config object
17300 Roo.bootstrap.ProgressBar = function(config){
17301 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17304 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17308 aria_valuemax : 100,
17314 getAutoCreate : function()
17319 cls: 'progress-bar',
17320 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17332 cfg.role = this.role;
17335 if(this.aria_valuenow){
17336 cfg['aria-valuenow'] = this.aria_valuenow;
17339 if(this.aria_valuemin){
17340 cfg['aria-valuemin'] = this.aria_valuemin;
17343 if(this.aria_valuemax){
17344 cfg['aria-valuemax'] = this.aria_valuemax;
17347 if(this.label && !this.sr_only){
17348 cfg.html = this.label;
17352 cfg.cls += ' progress-bar-' + this.panel;
17358 update : function(aria_valuenow)
17360 this.aria_valuenow = aria_valuenow;
17362 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17377 * @class Roo.bootstrap.TabGroup
17378 * @extends Roo.bootstrap.Column
17379 * Bootstrap Column class
17380 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17381 * @cfg {Boolean} carousel true to make the group behave like a carousel
17382 * @cfg {Boolean} bullets show bullets for the panels
17383 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17384 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17385 * @cfg {Boolean} showarrow (true|false) show arrow default true
17388 * Create a new TabGroup
17389 * @param {Object} config The config object
17392 Roo.bootstrap.TabGroup = function(config){
17393 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17395 this.navId = Roo.id();
17398 Roo.bootstrap.TabGroup.register(this);
17402 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17405 transition : false,
17410 slideOnTouch : false,
17413 getAutoCreate : function()
17415 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17417 cfg.cls += ' tab-content';
17419 if (this.carousel) {
17420 cfg.cls += ' carousel slide';
17423 cls : 'carousel-inner',
17427 if(this.bullets && !Roo.isTouch){
17430 cls : 'carousel-bullets',
17434 if(this.bullets_cls){
17435 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17442 cfg.cn[0].cn.push(bullets);
17445 if(this.showarrow){
17446 cfg.cn[0].cn.push({
17448 class : 'carousel-arrow',
17452 class : 'carousel-prev',
17456 class : 'fa fa-chevron-left'
17462 class : 'carousel-next',
17466 class : 'fa fa-chevron-right'
17479 initEvents: function()
17481 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17482 // this.el.on("touchstart", this.onTouchStart, this);
17485 if(this.autoslide){
17488 this.slideFn = window.setInterval(function() {
17489 _this.showPanelNext();
17493 if(this.showarrow){
17494 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17495 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17501 // onTouchStart : function(e, el, o)
17503 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17507 // this.showPanelNext();
17511 getChildContainer : function()
17513 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17517 * register a Navigation item
17518 * @param {Roo.bootstrap.NavItem} the navitem to add
17520 register : function(item)
17522 this.tabs.push( item);
17523 item.navId = this.navId; // not really needed..
17528 getActivePanel : function()
17531 Roo.each(this.tabs, function(t) {
17541 getPanelByName : function(n)
17544 Roo.each(this.tabs, function(t) {
17545 if (t.tabId == n) {
17553 indexOfPanel : function(p)
17556 Roo.each(this.tabs, function(t,i) {
17557 if (t.tabId == p.tabId) {
17566 * show a specific panel
17567 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17568 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17570 showPanel : function (pan)
17572 if(this.transition || typeof(pan) == 'undefined'){
17573 Roo.log("waiting for the transitionend");
17577 if (typeof(pan) == 'number') {
17578 pan = this.tabs[pan];
17581 if (typeof(pan) == 'string') {
17582 pan = this.getPanelByName(pan);
17585 var cur = this.getActivePanel();
17588 Roo.log('pan or acitve pan is undefined');
17592 if (pan.tabId == this.getActivePanel().tabId) {
17596 if (false === cur.fireEvent('beforedeactivate')) {
17600 if(this.bullets > 0 && !Roo.isTouch){
17601 this.setActiveBullet(this.indexOfPanel(pan));
17604 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17606 this.transition = true;
17607 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17608 var lr = dir == 'next' ? 'left' : 'right';
17609 pan.el.addClass(dir); // or prev
17610 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17611 cur.el.addClass(lr); // or right
17612 pan.el.addClass(lr);
17615 cur.el.on('transitionend', function() {
17616 Roo.log("trans end?");
17618 pan.el.removeClass([lr,dir]);
17619 pan.setActive(true);
17621 cur.el.removeClass([lr]);
17622 cur.setActive(false);
17624 _this.transition = false;
17626 }, this, { single: true } );
17631 cur.setActive(false);
17632 pan.setActive(true);
17637 showPanelNext : function()
17639 var i = this.indexOfPanel(this.getActivePanel());
17641 if (i >= this.tabs.length - 1 && !this.autoslide) {
17645 if (i >= this.tabs.length - 1 && this.autoslide) {
17649 this.showPanel(this.tabs[i+1]);
17652 showPanelPrev : function()
17654 var i = this.indexOfPanel(this.getActivePanel());
17656 if (i < 1 && !this.autoslide) {
17660 if (i < 1 && this.autoslide) {
17661 i = this.tabs.length;
17664 this.showPanel(this.tabs[i-1]);
17668 addBullet: function()
17670 if(!this.bullets || Roo.isTouch){
17673 var ctr = this.el.select('.carousel-bullets',true).first();
17674 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17675 var bullet = ctr.createChild({
17676 cls : 'bullet bullet-' + i
17677 },ctr.dom.lastChild);
17682 bullet.on('click', (function(e, el, o, ii, t){
17684 e.preventDefault();
17686 this.showPanel(ii);
17688 if(this.autoslide && this.slideFn){
17689 clearInterval(this.slideFn);
17690 this.slideFn = window.setInterval(function() {
17691 _this.showPanelNext();
17695 }).createDelegate(this, [i, bullet], true));
17700 setActiveBullet : function(i)
17706 Roo.each(this.el.select('.bullet', true).elements, function(el){
17707 el.removeClass('selected');
17710 var bullet = this.el.select('.bullet-' + i, true).first();
17716 bullet.addClass('selected');
17727 Roo.apply(Roo.bootstrap.TabGroup, {
17731 * register a Navigation Group
17732 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17734 register : function(navgrp)
17736 this.groups[navgrp.navId] = navgrp;
17740 * fetch a Navigation Group based on the navigation ID
17741 * if one does not exist , it will get created.
17742 * @param {string} the navgroup to add
17743 * @returns {Roo.bootstrap.NavGroup} the navgroup
17745 get: function(navId) {
17746 if (typeof(this.groups[navId]) == 'undefined') {
17747 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17749 return this.groups[navId] ;
17764 * @class Roo.bootstrap.TabPanel
17765 * @extends Roo.bootstrap.Component
17766 * Bootstrap TabPanel class
17767 * @cfg {Boolean} active panel active
17768 * @cfg {String} html panel content
17769 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17770 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17771 * @cfg {String} href click to link..
17775 * Create a new TabPanel
17776 * @param {Object} config The config object
17779 Roo.bootstrap.TabPanel = function(config){
17780 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17784 * Fires when the active status changes
17785 * @param {Roo.bootstrap.TabPanel} this
17786 * @param {Boolean} state the new state
17791 * @event beforedeactivate
17792 * Fires before a tab is de-activated - can be used to do validation on a form.
17793 * @param {Roo.bootstrap.TabPanel} this
17794 * @return {Boolean} false if there is an error
17797 'beforedeactivate': true
17800 this.tabId = this.tabId || Roo.id();
17804 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17812 getAutoCreate : function(){
17815 // item is needed for carousel - not sure if it has any effect otherwise
17816 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17817 html: this.html || ''
17821 cfg.cls += ' active';
17825 cfg.tabId = this.tabId;
17832 initEvents: function()
17834 var p = this.parent();
17836 this.navId = this.navId || p.navId;
17838 if (typeof(this.navId) != 'undefined') {
17839 // not really needed.. but just in case.. parent should be a NavGroup.
17840 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17844 var i = tg.tabs.length - 1;
17846 if(this.active && tg.bullets > 0 && i < tg.bullets){
17847 tg.setActiveBullet(i);
17851 this.el.on('click', this.onClick, this);
17854 this.el.on("touchstart", this.onTouchStart, this);
17855 this.el.on("touchmove", this.onTouchMove, this);
17856 this.el.on("touchend", this.onTouchEnd, this);
17861 onRender : function(ct, position)
17863 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17866 setActive : function(state)
17868 Roo.log("panel - set active " + this.tabId + "=" + state);
17870 this.active = state;
17872 this.el.removeClass('active');
17874 } else if (!this.el.hasClass('active')) {
17875 this.el.addClass('active');
17878 this.fireEvent('changed', this, state);
17881 onClick : function(e)
17883 e.preventDefault();
17885 if(!this.href.length){
17889 window.location.href = this.href;
17898 onTouchStart : function(e)
17900 this.swiping = false;
17902 this.startX = e.browserEvent.touches[0].clientX;
17903 this.startY = e.browserEvent.touches[0].clientY;
17906 onTouchMove : function(e)
17908 this.swiping = true;
17910 this.endX = e.browserEvent.touches[0].clientX;
17911 this.endY = e.browserEvent.touches[0].clientY;
17914 onTouchEnd : function(e)
17921 var tabGroup = this.parent();
17923 if(this.endX > this.startX){ // swiping right
17924 tabGroup.showPanelPrev();
17928 if(this.startX > this.endX){ // swiping left
17929 tabGroup.showPanelNext();
17948 * @class Roo.bootstrap.DateField
17949 * @extends Roo.bootstrap.Input
17950 * Bootstrap DateField class
17951 * @cfg {Number} weekStart default 0
17952 * @cfg {String} viewMode default empty, (months|years)
17953 * @cfg {String} minViewMode default empty, (months|years)
17954 * @cfg {Number} startDate default -Infinity
17955 * @cfg {Number} endDate default Infinity
17956 * @cfg {Boolean} todayHighlight default false
17957 * @cfg {Boolean} todayBtn default false
17958 * @cfg {Boolean} calendarWeeks default false
17959 * @cfg {Object} daysOfWeekDisabled default empty
17960 * @cfg {Boolean} singleMode default false (true | false)
17962 * @cfg {Boolean} keyboardNavigation default true
17963 * @cfg {String} language default en
17966 * Create a new DateField
17967 * @param {Object} config The config object
17970 Roo.bootstrap.DateField = function(config){
17971 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17975 * Fires when this field show.
17976 * @param {Roo.bootstrap.DateField} this
17977 * @param {Mixed} date The date value
17982 * Fires when this field hide.
17983 * @param {Roo.bootstrap.DateField} this
17984 * @param {Mixed} date The date value
17989 * Fires when select a date.
17990 * @param {Roo.bootstrap.DateField} this
17991 * @param {Mixed} date The date value
17995 * @event beforeselect
17996 * Fires when before select a date.
17997 * @param {Roo.bootstrap.DateField} this
17998 * @param {Mixed} date The date value
18000 beforeselect : true
18004 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18007 * @cfg {String} format
18008 * The default date format string which can be overriden for localization support. The format must be
18009 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18013 * @cfg {String} altFormats
18014 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18015 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18017 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18025 todayHighlight : false,
18031 keyboardNavigation: true,
18033 calendarWeeks: false,
18035 startDate: -Infinity,
18039 daysOfWeekDisabled: [],
18043 singleMode : false,
18045 UTCDate: function()
18047 return new Date(Date.UTC.apply(Date, arguments));
18050 UTCToday: function()
18052 var today = new Date();
18053 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18056 getDate: function() {
18057 var d = this.getUTCDate();
18058 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18061 getUTCDate: function() {
18065 setDate: function(d) {
18066 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18069 setUTCDate: function(d) {
18071 this.setValue(this.formatDate(this.date));
18074 onRender: function(ct, position)
18077 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18079 this.language = this.language || 'en';
18080 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18081 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18083 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18084 this.format = this.format || 'm/d/y';
18085 this.isInline = false;
18086 this.isInput = true;
18087 this.component = this.el.select('.add-on', true).first() || false;
18088 this.component = (this.component && this.component.length === 0) ? false : this.component;
18089 this.hasInput = this.component && this.inputEl().length;
18091 if (typeof(this.minViewMode === 'string')) {
18092 switch (this.minViewMode) {
18094 this.minViewMode = 1;
18097 this.minViewMode = 2;
18100 this.minViewMode = 0;
18105 if (typeof(this.viewMode === 'string')) {
18106 switch (this.viewMode) {
18119 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18121 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18123 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18125 this.picker().on('mousedown', this.onMousedown, this);
18126 this.picker().on('click', this.onClick, this);
18128 this.picker().addClass('datepicker-dropdown');
18130 this.startViewMode = this.viewMode;
18132 if(this.singleMode){
18133 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18134 v.setVisibilityMode(Roo.Element.DISPLAY);
18138 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18139 v.setStyle('width', '189px');
18143 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18144 if(!this.calendarWeeks){
18149 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18150 v.attr('colspan', function(i, val){
18151 return parseInt(val) + 1;
18156 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18158 this.setStartDate(this.startDate);
18159 this.setEndDate(this.endDate);
18161 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18168 if(this.isInline) {
18173 picker : function()
18175 return this.pickerEl;
18176 // return this.el.select('.datepicker', true).first();
18179 fillDow: function()
18181 var dowCnt = this.weekStart;
18190 if(this.calendarWeeks){
18198 while (dowCnt < this.weekStart + 7) {
18202 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18206 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18209 fillMonths: function()
18212 var months = this.picker().select('>.datepicker-months td', true).first();
18214 months.dom.innerHTML = '';
18220 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18223 months.createChild(month);
18230 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;
18232 if (this.date < this.startDate) {
18233 this.viewDate = new Date(this.startDate);
18234 } else if (this.date > this.endDate) {
18235 this.viewDate = new Date(this.endDate);
18237 this.viewDate = new Date(this.date);
18245 var d = new Date(this.viewDate),
18246 year = d.getUTCFullYear(),
18247 month = d.getUTCMonth(),
18248 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18249 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18250 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18251 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18252 currentDate = this.date && this.date.valueOf(),
18253 today = this.UTCToday();
18255 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18257 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18259 // this.picker.select('>tfoot th.today').
18260 // .text(dates[this.language].today)
18261 // .toggle(this.todayBtn !== false);
18263 this.updateNavArrows();
18266 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18268 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18270 prevMonth.setUTCDate(day);
18272 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18274 var nextMonth = new Date(prevMonth);
18276 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18278 nextMonth = nextMonth.valueOf();
18280 var fillMonths = false;
18282 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18284 while(prevMonth.valueOf() < nextMonth) {
18287 if (prevMonth.getUTCDay() === this.weekStart) {
18289 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18297 if(this.calendarWeeks){
18298 // ISO 8601: First week contains first thursday.
18299 // ISO also states week starts on Monday, but we can be more abstract here.
18301 // Start of current week: based on weekstart/current date
18302 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18303 // Thursday of this week
18304 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18305 // First Thursday of year, year from thursday
18306 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18307 // Calendar week: ms between thursdays, div ms per day, div 7 days
18308 calWeek = (th - yth) / 864e5 / 7 + 1;
18310 fillMonths.cn.push({
18318 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18320 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18323 if (this.todayHighlight &&
18324 prevMonth.getUTCFullYear() == today.getFullYear() &&
18325 prevMonth.getUTCMonth() == today.getMonth() &&
18326 prevMonth.getUTCDate() == today.getDate()) {
18327 clsName += ' today';
18330 if (currentDate && prevMonth.valueOf() === currentDate) {
18331 clsName += ' active';
18334 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18335 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18336 clsName += ' disabled';
18339 fillMonths.cn.push({
18341 cls: 'day ' + clsName,
18342 html: prevMonth.getDate()
18345 prevMonth.setDate(prevMonth.getDate()+1);
18348 var currentYear = this.date && this.date.getUTCFullYear();
18349 var currentMonth = this.date && this.date.getUTCMonth();
18351 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18353 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18354 v.removeClass('active');
18356 if(currentYear === year && k === currentMonth){
18357 v.addClass('active');
18360 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18361 v.addClass('disabled');
18367 year = parseInt(year/10, 10) * 10;
18369 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18371 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18374 for (var i = -1; i < 11; i++) {
18375 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18377 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18385 showMode: function(dir)
18388 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18391 Roo.each(this.picker().select('>div',true).elements, function(v){
18392 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18395 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18400 if(this.isInline) {
18404 this.picker().removeClass(['bottom', 'top']);
18406 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18408 * place to the top of element!
18412 this.picker().addClass('top');
18413 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18418 this.picker().addClass('bottom');
18420 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18423 parseDate : function(value)
18425 if(!value || value instanceof Date){
18428 var v = Date.parseDate(value, this.format);
18429 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18430 v = Date.parseDate(value, 'Y-m-d');
18432 if(!v && this.altFormats){
18433 if(!this.altFormatsArray){
18434 this.altFormatsArray = this.altFormats.split("|");
18436 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18437 v = Date.parseDate(value, this.altFormatsArray[i]);
18443 formatDate : function(date, fmt)
18445 return (!date || !(date instanceof Date)) ?
18446 date : date.dateFormat(fmt || this.format);
18449 onFocus : function()
18451 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18455 onBlur : function()
18457 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18459 var d = this.inputEl().getValue();
18468 this.picker().show();
18472 this.fireEvent('show', this, this.date);
18477 if(this.isInline) {
18480 this.picker().hide();
18481 this.viewMode = this.startViewMode;
18484 this.fireEvent('hide', this, this.date);
18488 onMousedown: function(e)
18490 e.stopPropagation();
18491 e.preventDefault();
18496 Roo.bootstrap.DateField.superclass.keyup.call(this);
18500 setValue: function(v)
18502 if(this.fireEvent('beforeselect', this, v) !== false){
18503 var d = new Date(this.parseDate(v) ).clearTime();
18505 if(isNaN(d.getTime())){
18506 this.date = this.viewDate = '';
18507 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18511 v = this.formatDate(d);
18513 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18515 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18519 this.fireEvent('select', this, this.date);
18523 getValue: function()
18525 return this.formatDate(this.date);
18528 fireKey: function(e)
18530 if (!this.picker().isVisible()){
18531 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18537 var dateChanged = false,
18539 newDate, newViewDate;
18544 e.preventDefault();
18548 if (!this.keyboardNavigation) {
18551 dir = e.keyCode == 37 ? -1 : 1;
18554 newDate = this.moveYear(this.date, dir);
18555 newViewDate = this.moveYear(this.viewDate, dir);
18556 } else if (e.shiftKey){
18557 newDate = this.moveMonth(this.date, dir);
18558 newViewDate = this.moveMonth(this.viewDate, dir);
18560 newDate = new Date(this.date);
18561 newDate.setUTCDate(this.date.getUTCDate() + dir);
18562 newViewDate = new Date(this.viewDate);
18563 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18565 if (this.dateWithinRange(newDate)){
18566 this.date = newDate;
18567 this.viewDate = newViewDate;
18568 this.setValue(this.formatDate(this.date));
18570 e.preventDefault();
18571 dateChanged = true;
18576 if (!this.keyboardNavigation) {
18579 dir = e.keyCode == 38 ? -1 : 1;
18581 newDate = this.moveYear(this.date, dir);
18582 newViewDate = this.moveYear(this.viewDate, dir);
18583 } else if (e.shiftKey){
18584 newDate = this.moveMonth(this.date, dir);
18585 newViewDate = this.moveMonth(this.viewDate, dir);
18587 newDate = new Date(this.date);
18588 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18589 newViewDate = new Date(this.viewDate);
18590 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18592 if (this.dateWithinRange(newDate)){
18593 this.date = newDate;
18594 this.viewDate = newViewDate;
18595 this.setValue(this.formatDate(this.date));
18597 e.preventDefault();
18598 dateChanged = true;
18602 this.setValue(this.formatDate(this.date));
18604 e.preventDefault();
18607 this.setValue(this.formatDate(this.date));
18621 onClick: function(e)
18623 e.stopPropagation();
18624 e.preventDefault();
18626 var target = e.getTarget();
18628 if(target.nodeName.toLowerCase() === 'i'){
18629 target = Roo.get(target).dom.parentNode;
18632 var nodeName = target.nodeName;
18633 var className = target.className;
18634 var html = target.innerHTML;
18635 //Roo.log(nodeName);
18637 switch(nodeName.toLowerCase()) {
18639 switch(className) {
18645 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18646 switch(this.viewMode){
18648 this.viewDate = this.moveMonth(this.viewDate, dir);
18652 this.viewDate = this.moveYear(this.viewDate, dir);
18658 var date = new Date();
18659 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18661 this.setValue(this.formatDate(this.date));
18668 if (className.indexOf('disabled') < 0) {
18669 this.viewDate.setUTCDate(1);
18670 if (className.indexOf('month') > -1) {
18671 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18673 var year = parseInt(html, 10) || 0;
18674 this.viewDate.setUTCFullYear(year);
18678 if(this.singleMode){
18679 this.setValue(this.formatDate(this.viewDate));
18690 //Roo.log(className);
18691 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18692 var day = parseInt(html, 10) || 1;
18693 var year = this.viewDate.getUTCFullYear(),
18694 month = this.viewDate.getUTCMonth();
18696 if (className.indexOf('old') > -1) {
18703 } else if (className.indexOf('new') > -1) {
18711 //Roo.log([year,month,day]);
18712 this.date = this.UTCDate(year, month, day,0,0,0,0);
18713 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18715 //Roo.log(this.formatDate(this.date));
18716 this.setValue(this.formatDate(this.date));
18723 setStartDate: function(startDate)
18725 this.startDate = startDate || -Infinity;
18726 if (this.startDate !== -Infinity) {
18727 this.startDate = this.parseDate(this.startDate);
18730 this.updateNavArrows();
18733 setEndDate: function(endDate)
18735 this.endDate = endDate || Infinity;
18736 if (this.endDate !== Infinity) {
18737 this.endDate = this.parseDate(this.endDate);
18740 this.updateNavArrows();
18743 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18745 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18746 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18747 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18749 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18750 return parseInt(d, 10);
18753 this.updateNavArrows();
18756 updateNavArrows: function()
18758 if(this.singleMode){
18762 var d = new Date(this.viewDate),
18763 year = d.getUTCFullYear(),
18764 month = d.getUTCMonth();
18766 Roo.each(this.picker().select('.prev', true).elements, function(v){
18768 switch (this.viewMode) {
18771 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18777 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18784 Roo.each(this.picker().select('.next', true).elements, function(v){
18786 switch (this.viewMode) {
18789 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18795 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18803 moveMonth: function(date, dir)
18808 var new_date = new Date(date.valueOf()),
18809 day = new_date.getUTCDate(),
18810 month = new_date.getUTCMonth(),
18811 mag = Math.abs(dir),
18813 dir = dir > 0 ? 1 : -1;
18816 // If going back one month, make sure month is not current month
18817 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18819 return new_date.getUTCMonth() == month;
18821 // If going forward one month, make sure month is as expected
18822 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18824 return new_date.getUTCMonth() != new_month;
18826 new_month = month + dir;
18827 new_date.setUTCMonth(new_month);
18828 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18829 if (new_month < 0 || new_month > 11) {
18830 new_month = (new_month + 12) % 12;
18833 // For magnitudes >1, move one month at a time...
18834 for (var i=0; i<mag; i++) {
18835 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18836 new_date = this.moveMonth(new_date, dir);
18838 // ...then reset the day, keeping it in the new month
18839 new_month = new_date.getUTCMonth();
18840 new_date.setUTCDate(day);
18842 return new_month != new_date.getUTCMonth();
18845 // Common date-resetting loop -- if date is beyond end of month, make it
18848 new_date.setUTCDate(--day);
18849 new_date.setUTCMonth(new_month);
18854 moveYear: function(date, dir)
18856 return this.moveMonth(date, dir*12);
18859 dateWithinRange: function(date)
18861 return date >= this.startDate && date <= this.endDate;
18867 this.picker().remove();
18870 validateValue : function(value)
18872 if(value.length < 1) {
18873 if(this.allowBlank){
18879 if(value.length < this.minLength){
18882 if(value.length > this.maxLength){
18886 var vt = Roo.form.VTypes;
18887 if(!vt[this.vtype](value, this)){
18891 if(typeof this.validator == "function"){
18892 var msg = this.validator(value);
18898 if(this.regex && !this.regex.test(value)){
18902 if(typeof(this.parseDate(value)) == 'undefined'){
18906 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18910 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18920 Roo.apply(Roo.bootstrap.DateField, {
18931 html: '<i class="fa fa-arrow-left"/>'
18941 html: '<i class="fa fa-arrow-right"/>'
18983 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18984 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18985 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18986 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18987 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19000 navFnc: 'FullYear',
19005 navFnc: 'FullYear',
19010 Roo.apply(Roo.bootstrap.DateField, {
19014 cls: 'datepicker dropdown-menu roo-dynamic',
19018 cls: 'datepicker-days',
19022 cls: 'table-condensed',
19024 Roo.bootstrap.DateField.head,
19028 Roo.bootstrap.DateField.footer
19035 cls: 'datepicker-months',
19039 cls: 'table-condensed',
19041 Roo.bootstrap.DateField.head,
19042 Roo.bootstrap.DateField.content,
19043 Roo.bootstrap.DateField.footer
19050 cls: 'datepicker-years',
19054 cls: 'table-condensed',
19056 Roo.bootstrap.DateField.head,
19057 Roo.bootstrap.DateField.content,
19058 Roo.bootstrap.DateField.footer
19077 * @class Roo.bootstrap.TimeField
19078 * @extends Roo.bootstrap.Input
19079 * Bootstrap DateField class
19083 * Create a new TimeField
19084 * @param {Object} config The config object
19087 Roo.bootstrap.TimeField = function(config){
19088 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19092 * Fires when this field show.
19093 * @param {Roo.bootstrap.DateField} thisthis
19094 * @param {Mixed} date The date value
19099 * Fires when this field hide.
19100 * @param {Roo.bootstrap.DateField} this
19101 * @param {Mixed} date The date value
19106 * Fires when select a date.
19107 * @param {Roo.bootstrap.DateField} this
19108 * @param {Mixed} date The date value
19114 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19117 * @cfg {String} format
19118 * The default time format string which can be overriden for localization support. The format must be
19119 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19123 onRender: function(ct, position)
19126 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19128 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19130 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19132 this.pop = this.picker().select('>.datepicker-time',true).first();
19133 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19135 this.picker().on('mousedown', this.onMousedown, this);
19136 this.picker().on('click', this.onClick, this);
19138 this.picker().addClass('datepicker-dropdown');
19143 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19144 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19145 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19146 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19147 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19148 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19152 fireKey: function(e){
19153 if (!this.picker().isVisible()){
19154 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19160 e.preventDefault();
19168 this.onTogglePeriod();
19171 this.onIncrementMinutes();
19174 this.onDecrementMinutes();
19183 onClick: function(e) {
19184 e.stopPropagation();
19185 e.preventDefault();
19188 picker : function()
19190 return this.el.select('.datepicker', true).first();
19193 fillTime: function()
19195 var time = this.pop.select('tbody', true).first();
19197 time.dom.innerHTML = '';
19212 cls: 'hours-up glyphicon glyphicon-chevron-up'
19232 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19253 cls: 'timepicker-hour',
19268 cls: 'timepicker-minute',
19283 cls: 'btn btn-primary period',
19305 cls: 'hours-down glyphicon glyphicon-chevron-down'
19325 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19343 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19350 var hours = this.time.getHours();
19351 var minutes = this.time.getMinutes();
19364 hours = hours - 12;
19368 hours = '0' + hours;
19372 minutes = '0' + minutes;
19375 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19376 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19377 this.pop.select('button', true).first().dom.innerHTML = period;
19383 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19385 var cls = ['bottom'];
19387 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19394 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19399 this.picker().addClass(cls.join('-'));
19403 Roo.each(cls, function(c){
19405 _this.picker().setTop(_this.inputEl().getHeight());
19409 _this.picker().setTop(0 - _this.picker().getHeight());
19414 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19418 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19425 onFocus : function()
19427 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19431 onBlur : function()
19433 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19439 this.picker().show();
19444 this.fireEvent('show', this, this.date);
19449 this.picker().hide();
19452 this.fireEvent('hide', this, this.date);
19455 setTime : function()
19458 this.setValue(this.time.format(this.format));
19460 this.fireEvent('select', this, this.date);
19465 onMousedown: function(e){
19466 e.stopPropagation();
19467 e.preventDefault();
19470 onIncrementHours: function()
19472 Roo.log('onIncrementHours');
19473 this.time = this.time.add(Date.HOUR, 1);
19478 onDecrementHours: function()
19480 Roo.log('onDecrementHours');
19481 this.time = this.time.add(Date.HOUR, -1);
19485 onIncrementMinutes: function()
19487 Roo.log('onIncrementMinutes');
19488 this.time = this.time.add(Date.MINUTE, 1);
19492 onDecrementMinutes: function()
19494 Roo.log('onDecrementMinutes');
19495 this.time = this.time.add(Date.MINUTE, -1);
19499 onTogglePeriod: function()
19501 Roo.log('onTogglePeriod');
19502 this.time = this.time.add(Date.HOUR, 12);
19509 Roo.apply(Roo.bootstrap.TimeField, {
19539 cls: 'btn btn-info ok',
19551 Roo.apply(Roo.bootstrap.TimeField, {
19555 cls: 'datepicker dropdown-menu',
19559 cls: 'datepicker-time',
19563 cls: 'table-condensed',
19565 Roo.bootstrap.TimeField.content,
19566 Roo.bootstrap.TimeField.footer
19585 * @class Roo.bootstrap.MonthField
19586 * @extends Roo.bootstrap.Input
19587 * Bootstrap MonthField class
19589 * @cfg {String} language default en
19592 * Create a new MonthField
19593 * @param {Object} config The config object
19596 Roo.bootstrap.MonthField = function(config){
19597 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19602 * Fires when this field show.
19603 * @param {Roo.bootstrap.MonthField} this
19604 * @param {Mixed} date The date value
19609 * Fires when this field hide.
19610 * @param {Roo.bootstrap.MonthField} this
19611 * @param {Mixed} date The date value
19616 * Fires when select a date.
19617 * @param {Roo.bootstrap.MonthField} this
19618 * @param {String} oldvalue The old value
19619 * @param {String} newvalue The new value
19625 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19627 onRender: function(ct, position)
19630 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19632 this.language = this.language || 'en';
19633 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19634 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19636 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19637 this.isInline = false;
19638 this.isInput = true;
19639 this.component = this.el.select('.add-on', true).first() || false;
19640 this.component = (this.component && this.component.length === 0) ? false : this.component;
19641 this.hasInput = this.component && this.inputEL().length;
19643 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19645 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19647 this.picker().on('mousedown', this.onMousedown, this);
19648 this.picker().on('click', this.onClick, this);
19650 this.picker().addClass('datepicker-dropdown');
19652 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19653 v.setStyle('width', '189px');
19660 if(this.isInline) {
19666 setValue: function(v, suppressEvent)
19668 var o = this.getValue();
19670 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19674 if(suppressEvent !== true){
19675 this.fireEvent('select', this, o, v);
19680 getValue: function()
19685 onClick: function(e)
19687 e.stopPropagation();
19688 e.preventDefault();
19690 var target = e.getTarget();
19692 if(target.nodeName.toLowerCase() === 'i'){
19693 target = Roo.get(target).dom.parentNode;
19696 var nodeName = target.nodeName;
19697 var className = target.className;
19698 var html = target.innerHTML;
19700 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19704 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19706 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19712 picker : function()
19714 return this.pickerEl;
19717 fillMonths: function()
19720 var months = this.picker().select('>.datepicker-months td', true).first();
19722 months.dom.innerHTML = '';
19728 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19731 months.createChild(month);
19740 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19741 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19744 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19745 e.removeClass('active');
19747 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19748 e.addClass('active');
19755 if(this.isInline) {
19759 this.picker().removeClass(['bottom', 'top']);
19761 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19763 * place to the top of element!
19767 this.picker().addClass('top');
19768 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19773 this.picker().addClass('bottom');
19775 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19778 onFocus : function()
19780 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19784 onBlur : function()
19786 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19788 var d = this.inputEl().getValue();
19797 this.picker().show();
19798 this.picker().select('>.datepicker-months', true).first().show();
19802 this.fireEvent('show', this, this.date);
19807 if(this.isInline) {
19810 this.picker().hide();
19811 this.fireEvent('hide', this, this.date);
19815 onMousedown: function(e)
19817 e.stopPropagation();
19818 e.preventDefault();
19823 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19827 fireKey: function(e)
19829 if (!this.picker().isVisible()){
19830 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19841 e.preventDefault();
19845 dir = e.keyCode == 37 ? -1 : 1;
19847 this.vIndex = this.vIndex + dir;
19849 if(this.vIndex < 0){
19853 if(this.vIndex > 11){
19857 if(isNaN(this.vIndex)){
19861 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19867 dir = e.keyCode == 38 ? -1 : 1;
19869 this.vIndex = this.vIndex + dir * 4;
19871 if(this.vIndex < 0){
19875 if(this.vIndex > 11){
19879 if(isNaN(this.vIndex)){
19883 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19888 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19889 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19893 e.preventDefault();
19896 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19897 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19913 this.picker().remove();
19918 Roo.apply(Roo.bootstrap.MonthField, {
19937 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19938 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19943 Roo.apply(Roo.bootstrap.MonthField, {
19947 cls: 'datepicker dropdown-menu roo-dynamic',
19951 cls: 'datepicker-months',
19955 cls: 'table-condensed',
19957 Roo.bootstrap.DateField.content
19977 * @class Roo.bootstrap.CheckBox
19978 * @extends Roo.bootstrap.Input
19979 * Bootstrap CheckBox class
19981 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19982 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19983 * @cfg {String} boxLabel The text that appears beside the checkbox
19984 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19985 * @cfg {Boolean} checked initnal the element
19986 * @cfg {Boolean} inline inline the element (default false)
19987 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19990 * Create a new CheckBox
19991 * @param {Object} config The config object
19994 Roo.bootstrap.CheckBox = function(config){
19995 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20000 * Fires when the element is checked or unchecked.
20001 * @param {Roo.bootstrap.CheckBox} this This input
20002 * @param {Boolean} checked The new checked value
20009 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20011 inputType: 'checkbox',
20019 getAutoCreate : function()
20021 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20027 cfg.cls = 'form-group ' + this.inputType; //input-group
20030 cfg.cls += ' ' + this.inputType + '-inline';
20036 type : this.inputType,
20037 value : this.inputValue,
20038 cls : 'roo-' + this.inputType, //'form-box',
20039 placeholder : this.placeholder || ''
20043 if(this.inputType != 'radio'){
20047 cls : 'roo-hidden-value',
20048 value : this.checked ? this.valueOff : this.inputValue
20053 if (this.weight) { // Validity check?
20054 cfg.cls += " " + this.inputType + "-" + this.weight;
20057 if (this.disabled) {
20058 input.disabled=true;
20062 input.checked = this.checked;
20069 input.name = this.name;
20071 if(this.inputType != 'radio'){
20072 hidden.name = this.name;
20073 input.name = '_hidden_' + this.name;
20078 input.cls += ' input-' + this.size;
20083 ['xs','sm','md','lg'].map(function(size){
20084 if (settings[size]) {
20085 cfg.cls += ' col-' + size + '-' + settings[size];
20089 var inputblock = input;
20091 if (this.before || this.after) {
20094 cls : 'input-group',
20099 inputblock.cn.push({
20101 cls : 'input-group-addon',
20106 inputblock.cn.push(input);
20108 if(this.inputType != 'radio'){
20109 inputblock.cn.push(hidden);
20113 inputblock.cn.push({
20115 cls : 'input-group-addon',
20122 if (align ==='left' && this.fieldLabel.length) {
20123 // Roo.log("left and has label");
20128 cls : 'control-label',
20129 html : this.fieldLabel
20140 if(this.labelWidth > 12){
20141 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20144 if(this.labelWidth < 13 && this.labelmd == 0){
20145 this.labelmd = this.labelWidth;
20148 if(this.labellg > 0){
20149 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20150 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20153 if(this.labelmd > 0){
20154 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20155 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20158 if(this.labelsm > 0){
20159 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20160 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20163 if(this.labelxs > 0){
20164 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20165 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20168 } else if ( this.fieldLabel.length) {
20169 // Roo.log(" label");
20173 tag: this.boxLabel ? 'span' : 'label',
20175 cls: 'control-label box-input-label',
20176 //cls : 'input-group-addon',
20177 html : this.fieldLabel
20187 // Roo.log(" no label && no align");
20188 cfg.cn = [ inputblock ] ;
20194 var boxLabelCfg = {
20196 //'for': id, // box label is handled by onclick - so no for...
20198 html: this.boxLabel
20202 boxLabelCfg.tooltip = this.tooltip;
20205 cfg.cn.push(boxLabelCfg);
20208 if(this.inputType != 'radio'){
20209 cfg.cn.push(hidden);
20217 * return the real input element.
20219 inputEl: function ()
20221 return this.el.select('input.roo-' + this.inputType,true).first();
20223 hiddenEl: function ()
20225 return this.el.select('input.roo-hidden-value',true).first();
20228 labelEl: function()
20230 return this.el.select('label.control-label',true).first();
20232 /* depricated... */
20236 return this.labelEl();
20239 boxLabelEl: function()
20241 return this.el.select('label.box-label',true).first();
20244 initEvents : function()
20246 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20248 this.inputEl().on('click', this.onClick, this);
20250 if (this.boxLabel) {
20251 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20254 this.startValue = this.getValue();
20257 Roo.bootstrap.CheckBox.register(this);
20261 onClick : function()
20263 this.setChecked(!this.checked);
20266 setChecked : function(state,suppressEvent)
20268 this.startValue = this.getValue();
20270 if(this.inputType == 'radio'){
20272 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20273 e.dom.checked = false;
20276 this.inputEl().dom.checked = true;
20278 this.inputEl().dom.value = this.inputValue;
20280 if(suppressEvent !== true){
20281 this.fireEvent('check', this, true);
20289 this.checked = state;
20291 this.inputEl().dom.checked = state;
20294 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20296 if(suppressEvent !== true){
20297 this.fireEvent('check', this, state);
20303 getValue : function()
20305 if(this.inputType == 'radio'){
20306 return this.getGroupValue();
20309 return this.hiddenEl().dom.value;
20313 getGroupValue : function()
20315 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20319 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20322 setValue : function(v,suppressEvent)
20324 if(this.inputType == 'radio'){
20325 this.setGroupValue(v, suppressEvent);
20329 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20334 setGroupValue : function(v, suppressEvent)
20336 this.startValue = this.getValue();
20338 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20339 e.dom.checked = false;
20341 if(e.dom.value == v){
20342 e.dom.checked = true;
20346 if(suppressEvent !== true){
20347 this.fireEvent('check', this, true);
20355 validate : function()
20359 (this.inputType == 'radio' && this.validateRadio()) ||
20360 (this.inputType == 'checkbox' && this.validateCheckbox())
20366 this.markInvalid();
20370 validateRadio : function()
20372 if(this.allowBlank){
20378 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20379 if(!e.dom.checked){
20391 validateCheckbox : function()
20394 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20395 //return (this.getValue() == this.inputValue) ? true : false;
20398 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20406 for(var i in group){
20411 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20418 * Mark this field as valid
20420 markValid : function()
20424 this.fireEvent('valid', this);
20426 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20429 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20436 if(this.inputType == 'radio'){
20437 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20438 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20439 e.findParent('.form-group', false, true).addClass(_this.validClass);
20446 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20447 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20451 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20457 for(var i in group){
20458 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20459 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20464 * Mark this field as invalid
20465 * @param {String} msg The validation message
20467 markInvalid : function(msg)
20469 if(this.allowBlank){
20475 this.fireEvent('invalid', this, msg);
20477 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20480 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20484 label.markInvalid();
20487 if(this.inputType == 'radio'){
20488 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20489 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20490 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20497 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20498 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20502 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20508 for(var i in group){
20509 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20510 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20515 clearInvalid : function()
20517 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20519 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20521 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20524 label.iconEl.removeClass(label.validClass);
20525 label.iconEl.removeClass(label.invalidClass);
20529 disable : function()
20531 if(this.inputType != 'radio'){
20532 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20539 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20540 _this.getActionEl().addClass(this.disabledClass);
20541 e.dom.disabled = true;
20545 this.disabled = true;
20546 this.fireEvent("disable", this);
20550 enable : function()
20552 if(this.inputType != 'radio'){
20553 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20560 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20561 _this.getActionEl().removeClass(this.disabledClass);
20562 e.dom.disabled = false;
20566 this.disabled = false;
20567 this.fireEvent("enable", this);
20573 Roo.apply(Roo.bootstrap.CheckBox, {
20578 * register a CheckBox Group
20579 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20581 register : function(checkbox)
20583 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20584 this.groups[checkbox.groupId] = {};
20587 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20591 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20595 * fetch a CheckBox Group based on the group ID
20596 * @param {string} the group ID
20597 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20599 get: function(groupId) {
20600 if (typeof(this.groups[groupId]) == 'undefined') {
20604 return this.groups[groupId] ;
20617 * @class Roo.bootstrap.Radio
20618 * @extends Roo.bootstrap.Component
20619 * Bootstrap Radio class
20620 * @cfg {String} boxLabel - the label associated
20621 * @cfg {String} value - the value of radio
20624 * Create a new Radio
20625 * @param {Object} config The config object
20627 Roo.bootstrap.Radio = function(config){
20628 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20632 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20638 getAutoCreate : function()
20642 cls : 'form-group radio',
20647 html : this.boxLabel
20655 initEvents : function()
20657 this.parent().register(this);
20659 this.el.on('click', this.onClick, this);
20663 onClick : function()
20665 this.setChecked(true);
20668 setChecked : function(state, suppressEvent)
20670 this.parent().setValue(this.value, suppressEvent);
20677 //<script type="text/javascript">
20680 * Based Ext JS Library 1.1.1
20681 * Copyright(c) 2006-2007, Ext JS, LLC.
20687 * @class Roo.HtmlEditorCore
20688 * @extends Roo.Component
20689 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20691 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20694 Roo.HtmlEditorCore = function(config){
20697 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20702 * @event initialize
20703 * Fires when the editor is fully initialized (including the iframe)
20704 * @param {Roo.HtmlEditorCore} this
20709 * Fires when the editor is first receives the focus. Any insertion must wait
20710 * until after this event.
20711 * @param {Roo.HtmlEditorCore} this
20715 * @event beforesync
20716 * Fires before the textarea is updated with content from the editor iframe. Return false
20717 * to cancel the sync.
20718 * @param {Roo.HtmlEditorCore} this
20719 * @param {String} html
20723 * @event beforepush
20724 * Fires before the iframe editor is updated with content from the textarea. Return false
20725 * to cancel the push.
20726 * @param {Roo.HtmlEditorCore} this
20727 * @param {String} html
20732 * Fires when the textarea is updated with content from the editor iframe.
20733 * @param {Roo.HtmlEditorCore} this
20734 * @param {String} html
20739 * Fires when the iframe editor is updated with content from the textarea.
20740 * @param {Roo.HtmlEditorCore} this
20741 * @param {String} html
20746 * @event editorevent
20747 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20748 * @param {Roo.HtmlEditorCore} this
20754 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20756 // defaults : white / black...
20757 this.applyBlacklists();
20764 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20768 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20774 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20779 * @cfg {Number} height (in pixels)
20783 * @cfg {Number} width (in pixels)
20788 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20791 stylesheets: false,
20796 // private properties
20797 validationEvent : false,
20799 initialized : false,
20801 sourceEditMode : false,
20802 onFocus : Roo.emptyFn,
20804 hideMode:'offsets',
20808 // blacklist + whitelisted elements..
20815 * Protected method that will not generally be called directly. It
20816 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20817 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20819 getDocMarkup : function(){
20823 // inherit styels from page...??
20824 if (this.stylesheets === false) {
20826 Roo.get(document.head).select('style').each(function(node) {
20827 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20830 Roo.get(document.head).select('link').each(function(node) {
20831 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20834 } else if (!this.stylesheets.length) {
20836 st = '<style type="text/css">' +
20837 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20843 st += '<style type="text/css">' +
20844 'IMG { cursor: pointer } ' +
20848 return '<html><head>' + st +
20849 //<style type="text/css">' +
20850 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20852 ' </head><body class="roo-htmleditor-body"></body></html>';
20856 onRender : function(ct, position)
20859 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20860 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20863 this.el.dom.style.border = '0 none';
20864 this.el.dom.setAttribute('tabIndex', -1);
20865 this.el.addClass('x-hidden hide');
20869 if(Roo.isIE){ // fix IE 1px bogus margin
20870 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20874 this.frameId = Roo.id();
20878 var iframe = this.owner.wrap.createChild({
20880 cls: 'form-control', // bootstrap..
20882 name: this.frameId,
20883 frameBorder : 'no',
20884 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20889 this.iframe = iframe.dom;
20891 this.assignDocWin();
20893 this.doc.designMode = 'on';
20896 this.doc.write(this.getDocMarkup());
20900 var task = { // must defer to wait for browser to be ready
20902 //console.log("run task?" + this.doc.readyState);
20903 this.assignDocWin();
20904 if(this.doc.body || this.doc.readyState == 'complete'){
20906 this.doc.designMode="on";
20910 Roo.TaskMgr.stop(task);
20911 this.initEditor.defer(10, this);
20918 Roo.TaskMgr.start(task);
20923 onResize : function(w, h)
20925 Roo.log('resize: ' +w + ',' + h );
20926 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20930 if(typeof w == 'number'){
20932 this.iframe.style.width = w + 'px';
20934 if(typeof h == 'number'){
20936 this.iframe.style.height = h + 'px';
20938 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20945 * Toggles the editor between standard and source edit mode.
20946 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20948 toggleSourceEdit : function(sourceEditMode){
20950 this.sourceEditMode = sourceEditMode === true;
20952 if(this.sourceEditMode){
20954 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20957 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20958 //this.iframe.className = '';
20961 //this.setSize(this.owner.wrap.getSize());
20962 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20969 * Protected method that will not generally be called directly. If you need/want
20970 * custom HTML cleanup, this is the method you should override.
20971 * @param {String} html The HTML to be cleaned
20972 * return {String} The cleaned HTML
20974 cleanHtml : function(html){
20975 html = String(html);
20976 if(html.length > 5){
20977 if(Roo.isSafari){ // strip safari nonsense
20978 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20981 if(html == ' '){
20988 * HTML Editor -> Textarea
20989 * Protected method that will not generally be called directly. Syncs the contents
20990 * of the editor iframe with the textarea.
20992 syncValue : function(){
20993 if(this.initialized){
20994 var bd = (this.doc.body || this.doc.documentElement);
20995 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20996 var html = bd.innerHTML;
20998 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20999 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21001 html = '<div style="'+m[0]+'">' + html + '</div>';
21004 html = this.cleanHtml(html);
21005 // fix up the special chars.. normaly like back quotes in word...
21006 // however we do not want to do this with chinese..
21007 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21008 var cc = b.charCodeAt();
21010 (cc >= 0x4E00 && cc < 0xA000 ) ||
21011 (cc >= 0x3400 && cc < 0x4E00 ) ||
21012 (cc >= 0xf900 && cc < 0xfb00 )
21018 if(this.owner.fireEvent('beforesync', this, html) !== false){
21019 this.el.dom.value = html;
21020 this.owner.fireEvent('sync', this, html);
21026 * Protected method that will not generally be called directly. Pushes the value of the textarea
21027 * into the iframe editor.
21029 pushValue : function(){
21030 if(this.initialized){
21031 var v = this.el.dom.value.trim();
21033 // if(v.length < 1){
21037 if(this.owner.fireEvent('beforepush', this, v) !== false){
21038 var d = (this.doc.body || this.doc.documentElement);
21040 this.cleanUpPaste();
21041 this.el.dom.value = d.innerHTML;
21042 this.owner.fireEvent('push', this, v);
21048 deferFocus : function(){
21049 this.focus.defer(10, this);
21053 focus : function(){
21054 if(this.win && !this.sourceEditMode){
21061 assignDocWin: function()
21063 var iframe = this.iframe;
21066 this.doc = iframe.contentWindow.document;
21067 this.win = iframe.contentWindow;
21069 // if (!Roo.get(this.frameId)) {
21072 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21073 // this.win = Roo.get(this.frameId).dom.contentWindow;
21075 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21079 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21080 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21085 initEditor : function(){
21086 //console.log("INIT EDITOR");
21087 this.assignDocWin();
21091 this.doc.designMode="on";
21093 this.doc.write(this.getDocMarkup());
21096 var dbody = (this.doc.body || this.doc.documentElement);
21097 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21098 // this copies styles from the containing element into thsi one..
21099 // not sure why we need all of this..
21100 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21102 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21103 //ss['background-attachment'] = 'fixed'; // w3c
21104 dbody.bgProperties = 'fixed'; // ie
21105 //Roo.DomHelper.applyStyles(dbody, ss);
21106 Roo.EventManager.on(this.doc, {
21107 //'mousedown': this.onEditorEvent,
21108 'mouseup': this.onEditorEvent,
21109 'dblclick': this.onEditorEvent,
21110 'click': this.onEditorEvent,
21111 'keyup': this.onEditorEvent,
21116 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21118 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21119 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21121 this.initialized = true;
21123 this.owner.fireEvent('initialize', this);
21128 onDestroy : function(){
21134 //for (var i =0; i < this.toolbars.length;i++) {
21135 // // fixme - ask toolbars for heights?
21136 // this.toolbars[i].onDestroy();
21139 //this.wrap.dom.innerHTML = '';
21140 //this.wrap.remove();
21145 onFirstFocus : function(){
21147 this.assignDocWin();
21150 this.activated = true;
21153 if(Roo.isGecko){ // prevent silly gecko errors
21155 var s = this.win.getSelection();
21156 if(!s.focusNode || s.focusNode.nodeType != 3){
21157 var r = s.getRangeAt(0);
21158 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21163 this.execCmd('useCSS', true);
21164 this.execCmd('styleWithCSS', false);
21167 this.owner.fireEvent('activate', this);
21171 adjustFont: function(btn){
21172 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21173 //if(Roo.isSafari){ // safari
21176 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21177 if(Roo.isSafari){ // safari
21178 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21179 v = (v < 10) ? 10 : v;
21180 v = (v > 48) ? 48 : v;
21181 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21186 v = Math.max(1, v+adjust);
21188 this.execCmd('FontSize', v );
21191 onEditorEvent : function(e)
21193 this.owner.fireEvent('editorevent', this, e);
21194 // this.updateToolbar();
21195 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21198 insertTag : function(tg)
21200 // could be a bit smarter... -> wrap the current selected tRoo..
21201 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21203 range = this.createRange(this.getSelection());
21204 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21205 wrappingNode.appendChild(range.extractContents());
21206 range.insertNode(wrappingNode);
21213 this.execCmd("formatblock", tg);
21217 insertText : function(txt)
21221 var range = this.createRange();
21222 range.deleteContents();
21223 //alert(Sender.getAttribute('label'));
21225 range.insertNode(this.doc.createTextNode(txt));
21231 * Executes a Midas editor command on the editor document and performs necessary focus and
21232 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21233 * @param {String} cmd The Midas command
21234 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21236 relayCmd : function(cmd, value){
21238 this.execCmd(cmd, value);
21239 this.owner.fireEvent('editorevent', this);
21240 //this.updateToolbar();
21241 this.owner.deferFocus();
21245 * Executes a Midas editor command directly on the editor document.
21246 * For visual commands, you should use {@link #relayCmd} instead.
21247 * <b>This should only be called after the editor is initialized.</b>
21248 * @param {String} cmd The Midas command
21249 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21251 execCmd : function(cmd, value){
21252 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21259 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21261 * @param {String} text | dom node..
21263 insertAtCursor : function(text)
21268 if(!this.activated){
21274 var r = this.doc.selection.createRange();
21285 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21289 // from jquery ui (MIT licenced)
21291 var win = this.win;
21293 if (win.getSelection && win.getSelection().getRangeAt) {
21294 range = win.getSelection().getRangeAt(0);
21295 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21296 range.insertNode(node);
21297 } else if (win.document.selection && win.document.selection.createRange) {
21298 // no firefox support
21299 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21300 win.document.selection.createRange().pasteHTML(txt);
21302 // no firefox support
21303 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21304 this.execCmd('InsertHTML', txt);
21313 mozKeyPress : function(e){
21315 var c = e.getCharCode(), cmd;
21318 c = String.fromCharCode(c).toLowerCase();
21332 this.cleanUpPaste.defer(100, this);
21340 e.preventDefault();
21348 fixKeys : function(){ // load time branching for fastest keydown performance
21350 return function(e){
21351 var k = e.getKey(), r;
21354 r = this.doc.selection.createRange();
21357 r.pasteHTML('    ');
21364 r = this.doc.selection.createRange();
21366 var target = r.parentElement();
21367 if(!target || target.tagName.toLowerCase() != 'li'){
21369 r.pasteHTML('<br />');
21375 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21376 this.cleanUpPaste.defer(100, this);
21382 }else if(Roo.isOpera){
21383 return function(e){
21384 var k = e.getKey();
21388 this.execCmd('InsertHTML','    ');
21391 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21392 this.cleanUpPaste.defer(100, this);
21397 }else if(Roo.isSafari){
21398 return function(e){
21399 var k = e.getKey();
21403 this.execCmd('InsertText','\t');
21407 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21408 this.cleanUpPaste.defer(100, this);
21416 getAllAncestors: function()
21418 var p = this.getSelectedNode();
21421 a.push(p); // push blank onto stack..
21422 p = this.getParentElement();
21426 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21430 a.push(this.doc.body);
21434 lastSelNode : false,
21437 getSelection : function()
21439 this.assignDocWin();
21440 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21443 getSelectedNode: function()
21445 // this may only work on Gecko!!!
21447 // should we cache this!!!!
21452 var range = this.createRange(this.getSelection()).cloneRange();
21455 var parent = range.parentElement();
21457 var testRange = range.duplicate();
21458 testRange.moveToElementText(parent);
21459 if (testRange.inRange(range)) {
21462 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21465 parent = parent.parentElement;
21470 // is ancestor a text element.
21471 var ac = range.commonAncestorContainer;
21472 if (ac.nodeType == 3) {
21473 ac = ac.parentNode;
21476 var ar = ac.childNodes;
21479 var other_nodes = [];
21480 var has_other_nodes = false;
21481 for (var i=0;i<ar.length;i++) {
21482 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21485 // fullly contained node.
21487 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21492 // probably selected..
21493 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21494 other_nodes.push(ar[i]);
21498 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21503 has_other_nodes = true;
21505 if (!nodes.length && other_nodes.length) {
21506 nodes= other_nodes;
21508 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21514 createRange: function(sel)
21516 // this has strange effects when using with
21517 // top toolbar - not sure if it's a great idea.
21518 //this.editor.contentWindow.focus();
21519 if (typeof sel != "undefined") {
21521 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21523 return this.doc.createRange();
21526 return this.doc.createRange();
21529 getParentElement: function()
21532 this.assignDocWin();
21533 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21535 var range = this.createRange(sel);
21538 var p = range.commonAncestorContainer;
21539 while (p.nodeType == 3) { // text node
21550 * Range intersection.. the hard stuff...
21554 * [ -- selected range --- ]
21558 * if end is before start or hits it. fail.
21559 * if start is after end or hits it fail.
21561 * if either hits (but other is outside. - then it's not
21567 // @see http://www.thismuchiknow.co.uk/?p=64.
21568 rangeIntersectsNode : function(range, node)
21570 var nodeRange = node.ownerDocument.createRange();
21572 nodeRange.selectNode(node);
21574 nodeRange.selectNodeContents(node);
21577 var rangeStartRange = range.cloneRange();
21578 rangeStartRange.collapse(true);
21580 var rangeEndRange = range.cloneRange();
21581 rangeEndRange.collapse(false);
21583 var nodeStartRange = nodeRange.cloneRange();
21584 nodeStartRange.collapse(true);
21586 var nodeEndRange = nodeRange.cloneRange();
21587 nodeEndRange.collapse(false);
21589 return rangeStartRange.compareBoundaryPoints(
21590 Range.START_TO_START, nodeEndRange) == -1 &&
21591 rangeEndRange.compareBoundaryPoints(
21592 Range.START_TO_START, nodeStartRange) == 1;
21596 rangeCompareNode : function(range, node)
21598 var nodeRange = node.ownerDocument.createRange();
21600 nodeRange.selectNode(node);
21602 nodeRange.selectNodeContents(node);
21606 range.collapse(true);
21608 nodeRange.collapse(true);
21610 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21611 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21613 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21615 var nodeIsBefore = ss == 1;
21616 var nodeIsAfter = ee == -1;
21618 if (nodeIsBefore && nodeIsAfter) {
21621 if (!nodeIsBefore && nodeIsAfter) {
21622 return 1; //right trailed.
21625 if (nodeIsBefore && !nodeIsAfter) {
21626 return 2; // left trailed.
21632 // private? - in a new class?
21633 cleanUpPaste : function()
21635 // cleans up the whole document..
21636 Roo.log('cleanuppaste');
21638 this.cleanUpChildren(this.doc.body);
21639 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21640 if (clean != this.doc.body.innerHTML) {
21641 this.doc.body.innerHTML = clean;
21646 cleanWordChars : function(input) {// change the chars to hex code
21647 var he = Roo.HtmlEditorCore;
21649 var output = input;
21650 Roo.each(he.swapCodes, function(sw) {
21651 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21653 output = output.replace(swapper, sw[1]);
21660 cleanUpChildren : function (n)
21662 if (!n.childNodes.length) {
21665 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21666 this.cleanUpChild(n.childNodes[i]);
21673 cleanUpChild : function (node)
21676 //console.log(node);
21677 if (node.nodeName == "#text") {
21678 // clean up silly Windows -- stuff?
21681 if (node.nodeName == "#comment") {
21682 node.parentNode.removeChild(node);
21683 // clean up silly Windows -- stuff?
21686 var lcname = node.tagName.toLowerCase();
21687 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21688 // whitelist of tags..
21690 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21692 node.parentNode.removeChild(node);
21697 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21699 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21700 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21702 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21703 // remove_keep_children = true;
21706 if (remove_keep_children) {
21707 this.cleanUpChildren(node);
21708 // inserts everything just before this node...
21709 while (node.childNodes.length) {
21710 var cn = node.childNodes[0];
21711 node.removeChild(cn);
21712 node.parentNode.insertBefore(cn, node);
21714 node.parentNode.removeChild(node);
21718 if (!node.attributes || !node.attributes.length) {
21719 this.cleanUpChildren(node);
21723 function cleanAttr(n,v)
21726 if (v.match(/^\./) || v.match(/^\//)) {
21729 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21732 if (v.match(/^#/)) {
21735 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21736 node.removeAttribute(n);
21740 var cwhite = this.cwhite;
21741 var cblack = this.cblack;
21743 function cleanStyle(n,v)
21745 if (v.match(/expression/)) { //XSS?? should we even bother..
21746 node.removeAttribute(n);
21750 var parts = v.split(/;/);
21753 Roo.each(parts, function(p) {
21754 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21758 var l = p.split(':').shift().replace(/\s+/g,'');
21759 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21761 if ( cwhite.length && cblack.indexOf(l) > -1) {
21762 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21763 //node.removeAttribute(n);
21767 // only allow 'c whitelisted system attributes'
21768 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21769 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21770 //node.removeAttribute(n);
21780 if (clean.length) {
21781 node.setAttribute(n, clean.join(';'));
21783 node.removeAttribute(n);
21789 for (var i = node.attributes.length-1; i > -1 ; i--) {
21790 var a = node.attributes[i];
21793 if (a.name.toLowerCase().substr(0,2)=='on') {
21794 node.removeAttribute(a.name);
21797 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21798 node.removeAttribute(a.name);
21801 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21802 cleanAttr(a.name,a.value); // fixme..
21805 if (a.name == 'style') {
21806 cleanStyle(a.name,a.value);
21809 /// clean up MS crap..
21810 // tecnically this should be a list of valid class'es..
21813 if (a.name == 'class') {
21814 if (a.value.match(/^Mso/)) {
21815 node.className = '';
21818 if (a.value.match(/body/)) {
21819 node.className = '';
21830 this.cleanUpChildren(node);
21836 * Clean up MS wordisms...
21838 cleanWord : function(node)
21843 this.cleanWord(this.doc.body);
21846 if (node.nodeName == "#text") {
21847 // clean up silly Windows -- stuff?
21850 if (node.nodeName == "#comment") {
21851 node.parentNode.removeChild(node);
21852 // clean up silly Windows -- stuff?
21856 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21857 node.parentNode.removeChild(node);
21861 // remove - but keep children..
21862 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21863 while (node.childNodes.length) {
21864 var cn = node.childNodes[0];
21865 node.removeChild(cn);
21866 node.parentNode.insertBefore(cn, node);
21868 node.parentNode.removeChild(node);
21869 this.iterateChildren(node, this.cleanWord);
21873 if (node.className.length) {
21875 var cn = node.className.split(/\W+/);
21877 Roo.each(cn, function(cls) {
21878 if (cls.match(/Mso[a-zA-Z]+/)) {
21883 node.className = cna.length ? cna.join(' ') : '';
21885 node.removeAttribute("class");
21889 if (node.hasAttribute("lang")) {
21890 node.removeAttribute("lang");
21893 if (node.hasAttribute("style")) {
21895 var styles = node.getAttribute("style").split(";");
21897 Roo.each(styles, function(s) {
21898 if (!s.match(/:/)) {
21901 var kv = s.split(":");
21902 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21905 // what ever is left... we allow.
21908 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21909 if (!nstyle.length) {
21910 node.removeAttribute('style');
21913 this.iterateChildren(node, this.cleanWord);
21919 * iterateChildren of a Node, calling fn each time, using this as the scole..
21920 * @param {DomNode} node node to iterate children of.
21921 * @param {Function} fn method of this class to call on each item.
21923 iterateChildren : function(node, fn)
21925 if (!node.childNodes.length) {
21928 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21929 fn.call(this, node.childNodes[i])
21935 * cleanTableWidths.
21937 * Quite often pasting from word etc.. results in tables with column and widths.
21938 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21941 cleanTableWidths : function(node)
21946 this.cleanTableWidths(this.doc.body);
21951 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21954 Roo.log(node.tagName);
21955 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21956 this.iterateChildren(node, this.cleanTableWidths);
21959 if (node.hasAttribute('width')) {
21960 node.removeAttribute('width');
21964 if (node.hasAttribute("style")) {
21967 var styles = node.getAttribute("style").split(";");
21969 Roo.each(styles, function(s) {
21970 if (!s.match(/:/)) {
21973 var kv = s.split(":");
21974 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21977 // what ever is left... we allow.
21980 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21981 if (!nstyle.length) {
21982 node.removeAttribute('style');
21986 this.iterateChildren(node, this.cleanTableWidths);
21994 domToHTML : function(currentElement, depth, nopadtext) {
21996 depth = depth || 0;
21997 nopadtext = nopadtext || false;
21999 if (!currentElement) {
22000 return this.domToHTML(this.doc.body);
22003 //Roo.log(currentElement);
22005 var allText = false;
22006 var nodeName = currentElement.nodeName;
22007 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22009 if (nodeName == '#text') {
22011 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22016 if (nodeName != 'BODY') {
22019 // Prints the node tagName, such as <A>, <IMG>, etc
22022 for(i = 0; i < currentElement.attributes.length;i++) {
22024 var aname = currentElement.attributes.item(i).name;
22025 if (!currentElement.attributes.item(i).value.length) {
22028 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22031 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22040 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22043 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22048 // Traverse the tree
22050 var currentElementChild = currentElement.childNodes.item(i);
22051 var allText = true;
22052 var innerHTML = '';
22054 while (currentElementChild) {
22055 // Formatting code (indent the tree so it looks nice on the screen)
22056 var nopad = nopadtext;
22057 if (lastnode == 'SPAN') {
22061 if (currentElementChild.nodeName == '#text') {
22062 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22063 toadd = nopadtext ? toadd : toadd.trim();
22064 if (!nopad && toadd.length > 80) {
22065 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22067 innerHTML += toadd;
22070 currentElementChild = currentElement.childNodes.item(i);
22076 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22078 // Recursively traverse the tree structure of the child node
22079 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22080 lastnode = currentElementChild.nodeName;
22082 currentElementChild=currentElement.childNodes.item(i);
22088 // The remaining code is mostly for formatting the tree
22089 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22094 ret+= "</"+tagName+">";
22100 applyBlacklists : function()
22102 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22103 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22107 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22108 if (b.indexOf(tag) > -1) {
22111 this.white.push(tag);
22115 Roo.each(w, function(tag) {
22116 if (b.indexOf(tag) > -1) {
22119 if (this.white.indexOf(tag) > -1) {
22122 this.white.push(tag);
22127 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22128 if (w.indexOf(tag) > -1) {
22131 this.black.push(tag);
22135 Roo.each(b, function(tag) {
22136 if (w.indexOf(tag) > -1) {
22139 if (this.black.indexOf(tag) > -1) {
22142 this.black.push(tag);
22147 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22148 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22152 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22153 if (b.indexOf(tag) > -1) {
22156 this.cwhite.push(tag);
22160 Roo.each(w, function(tag) {
22161 if (b.indexOf(tag) > -1) {
22164 if (this.cwhite.indexOf(tag) > -1) {
22167 this.cwhite.push(tag);
22172 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22173 if (w.indexOf(tag) > -1) {
22176 this.cblack.push(tag);
22180 Roo.each(b, function(tag) {
22181 if (w.indexOf(tag) > -1) {
22184 if (this.cblack.indexOf(tag) > -1) {
22187 this.cblack.push(tag);
22192 setStylesheets : function(stylesheets)
22194 if(typeof(stylesheets) == 'string'){
22195 Roo.get(this.iframe.contentDocument.head).createChild({
22197 rel : 'stylesheet',
22206 Roo.each(stylesheets, function(s) {
22211 Roo.get(_this.iframe.contentDocument.head).createChild({
22213 rel : 'stylesheet',
22222 removeStylesheets : function()
22226 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22231 // hide stuff that is not compatible
22245 * @event specialkey
22249 * @cfg {String} fieldClass @hide
22252 * @cfg {String} focusClass @hide
22255 * @cfg {String} autoCreate @hide
22258 * @cfg {String} inputType @hide
22261 * @cfg {String} invalidClass @hide
22264 * @cfg {String} invalidText @hide
22267 * @cfg {String} msgFx @hide
22270 * @cfg {String} validateOnBlur @hide
22274 Roo.HtmlEditorCore.white = [
22275 'area', 'br', 'img', 'input', 'hr', 'wbr',
22277 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22278 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22279 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22280 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22281 'table', 'ul', 'xmp',
22283 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22286 'dir', 'menu', 'ol', 'ul', 'dl',
22292 Roo.HtmlEditorCore.black = [
22293 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22295 'base', 'basefont', 'bgsound', 'blink', 'body',
22296 'frame', 'frameset', 'head', 'html', 'ilayer',
22297 'iframe', 'layer', 'link', 'meta', 'object',
22298 'script', 'style' ,'title', 'xml' // clean later..
22300 Roo.HtmlEditorCore.clean = [
22301 'script', 'style', 'title', 'xml'
22303 Roo.HtmlEditorCore.remove = [
22308 Roo.HtmlEditorCore.ablack = [
22312 Roo.HtmlEditorCore.aclean = [
22313 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22317 Roo.HtmlEditorCore.pwhite= [
22318 'http', 'https', 'mailto'
22321 // white listed style attributes.
22322 Roo.HtmlEditorCore.cwhite= [
22323 // 'text-align', /// default is to allow most things..
22329 // black listed style attributes.
22330 Roo.HtmlEditorCore.cblack= [
22331 // 'font-size' -- this can be set by the project
22335 Roo.HtmlEditorCore.swapCodes =[
22354 * @class Roo.bootstrap.HtmlEditor
22355 * @extends Roo.bootstrap.TextArea
22356 * Bootstrap HtmlEditor class
22359 * Create a new HtmlEditor
22360 * @param {Object} config The config object
22363 Roo.bootstrap.HtmlEditor = function(config){
22364 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22365 if (!this.toolbars) {
22366 this.toolbars = [];
22368 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22371 * @event initialize
22372 * Fires when the editor is fully initialized (including the iframe)
22373 * @param {HtmlEditor} this
22378 * Fires when the editor is first receives the focus. Any insertion must wait
22379 * until after this event.
22380 * @param {HtmlEditor} this
22384 * @event beforesync
22385 * Fires before the textarea is updated with content from the editor iframe. Return false
22386 * to cancel the sync.
22387 * @param {HtmlEditor} this
22388 * @param {String} html
22392 * @event beforepush
22393 * Fires before the iframe editor is updated with content from the textarea. Return false
22394 * to cancel the push.
22395 * @param {HtmlEditor} this
22396 * @param {String} html
22401 * Fires when the textarea is updated with content from the editor iframe.
22402 * @param {HtmlEditor} this
22403 * @param {String} html
22408 * Fires when the iframe editor is updated with content from the textarea.
22409 * @param {HtmlEditor} this
22410 * @param {String} html
22414 * @event editmodechange
22415 * Fires when the editor switches edit modes
22416 * @param {HtmlEditor} this
22417 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22419 editmodechange: true,
22421 * @event editorevent
22422 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22423 * @param {HtmlEditor} this
22427 * @event firstfocus
22428 * Fires when on first focus - needed by toolbars..
22429 * @param {HtmlEditor} this
22434 * Auto save the htmlEditor value as a file into Events
22435 * @param {HtmlEditor} this
22439 * @event savedpreview
22440 * preview the saved version of htmlEditor
22441 * @param {HtmlEditor} this
22448 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22452 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22457 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22462 * @cfg {Number} height (in pixels)
22466 * @cfg {Number} width (in pixels)
22471 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22474 stylesheets: false,
22479 // private properties
22480 validationEvent : false,
22482 initialized : false,
22485 onFocus : Roo.emptyFn,
22487 hideMode:'offsets',
22490 tbContainer : false,
22492 toolbarContainer :function() {
22493 return this.wrap.select('.x-html-editor-tb',true).first();
22497 * Protected method that will not generally be called directly. It
22498 * is called when the editor creates its toolbar. Override this method if you need to
22499 * add custom toolbar buttons.
22500 * @param {HtmlEditor} editor
22502 createToolbar : function(){
22504 Roo.log("create toolbars");
22506 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22507 this.toolbars[0].render(this.toolbarContainer());
22511 // if (!editor.toolbars || !editor.toolbars.length) {
22512 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22515 // for (var i =0 ; i < editor.toolbars.length;i++) {
22516 // editor.toolbars[i] = Roo.factory(
22517 // typeof(editor.toolbars[i]) == 'string' ?
22518 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22519 // Roo.bootstrap.HtmlEditor);
22520 // editor.toolbars[i].init(editor);
22526 onRender : function(ct, position)
22528 // Roo.log("Call onRender: " + this.xtype);
22530 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22532 this.wrap = this.inputEl().wrap({
22533 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22536 this.editorcore.onRender(ct, position);
22538 if (this.resizable) {
22539 this.resizeEl = new Roo.Resizable(this.wrap, {
22543 minHeight : this.height,
22544 height: this.height,
22545 handles : this.resizable,
22548 resize : function(r, w, h) {
22549 _t.onResize(w,h); // -something
22555 this.createToolbar(this);
22558 if(!this.width && this.resizable){
22559 this.setSize(this.wrap.getSize());
22561 if (this.resizeEl) {
22562 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22563 // should trigger onReize..
22569 onResize : function(w, h)
22571 Roo.log('resize: ' +w + ',' + h );
22572 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22576 if(this.inputEl() ){
22577 if(typeof w == 'number'){
22578 var aw = w - this.wrap.getFrameWidth('lr');
22579 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22582 if(typeof h == 'number'){
22583 var tbh = -11; // fixme it needs to tool bar size!
22584 for (var i =0; i < this.toolbars.length;i++) {
22585 // fixme - ask toolbars for heights?
22586 tbh += this.toolbars[i].el.getHeight();
22587 //if (this.toolbars[i].footer) {
22588 // tbh += this.toolbars[i].footer.el.getHeight();
22596 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22597 ah -= 5; // knock a few pixes off for look..
22598 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22602 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22603 this.editorcore.onResize(ew,eh);
22608 * Toggles the editor between standard and source edit mode.
22609 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22611 toggleSourceEdit : function(sourceEditMode)
22613 this.editorcore.toggleSourceEdit(sourceEditMode);
22615 if(this.editorcore.sourceEditMode){
22616 Roo.log('editor - showing textarea');
22619 // Roo.log(this.syncValue());
22621 this.inputEl().removeClass(['hide', 'x-hidden']);
22622 this.inputEl().dom.removeAttribute('tabIndex');
22623 this.inputEl().focus();
22625 Roo.log('editor - hiding textarea');
22627 // Roo.log(this.pushValue());
22630 this.inputEl().addClass(['hide', 'x-hidden']);
22631 this.inputEl().dom.setAttribute('tabIndex', -1);
22632 //this.deferFocus();
22635 if(this.resizable){
22636 this.setSize(this.wrap.getSize());
22639 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22642 // private (for BoxComponent)
22643 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22645 // private (for BoxComponent)
22646 getResizeEl : function(){
22650 // private (for BoxComponent)
22651 getPositionEl : function(){
22656 initEvents : function(){
22657 this.originalValue = this.getValue();
22661 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22664 // markInvalid : Roo.emptyFn,
22666 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22669 // clearInvalid : Roo.emptyFn,
22671 setValue : function(v){
22672 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22673 this.editorcore.pushValue();
22678 deferFocus : function(){
22679 this.focus.defer(10, this);
22683 focus : function(){
22684 this.editorcore.focus();
22690 onDestroy : function(){
22696 for (var i =0; i < this.toolbars.length;i++) {
22697 // fixme - ask toolbars for heights?
22698 this.toolbars[i].onDestroy();
22701 this.wrap.dom.innerHTML = '';
22702 this.wrap.remove();
22707 onFirstFocus : function(){
22708 //Roo.log("onFirstFocus");
22709 this.editorcore.onFirstFocus();
22710 for (var i =0; i < this.toolbars.length;i++) {
22711 this.toolbars[i].onFirstFocus();
22717 syncValue : function()
22719 this.editorcore.syncValue();
22722 pushValue : function()
22724 this.editorcore.pushValue();
22728 // hide stuff that is not compatible
22742 * @event specialkey
22746 * @cfg {String} fieldClass @hide
22749 * @cfg {String} focusClass @hide
22752 * @cfg {String} autoCreate @hide
22755 * @cfg {String} inputType @hide
22758 * @cfg {String} invalidClass @hide
22761 * @cfg {String} invalidText @hide
22764 * @cfg {String} msgFx @hide
22767 * @cfg {String} validateOnBlur @hide
22776 Roo.namespace('Roo.bootstrap.htmleditor');
22778 * @class Roo.bootstrap.HtmlEditorToolbar1
22783 new Roo.bootstrap.HtmlEditor({
22786 new Roo.bootstrap.HtmlEditorToolbar1({
22787 disable : { fonts: 1 , format: 1, ..., ... , ...],
22793 * @cfg {Object} disable List of elements to disable..
22794 * @cfg {Array} btns List of additional buttons.
22798 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22801 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22804 Roo.apply(this, config);
22806 // default disabled, based on 'good practice'..
22807 this.disable = this.disable || {};
22808 Roo.applyIf(this.disable, {
22811 specialElements : true
22813 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22815 this.editor = config.editor;
22816 this.editorcore = config.editor.editorcore;
22818 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22820 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22821 // dont call parent... till later.
22823 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22828 editorcore : false,
22833 "h1","h2","h3","h4","h5","h6",
22835 "abbr", "acronym", "address", "cite", "samp", "var",
22839 onRender : function(ct, position)
22841 // Roo.log("Call onRender: " + this.xtype);
22843 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22845 this.el.dom.style.marginBottom = '0';
22847 var editorcore = this.editorcore;
22848 var editor= this.editor;
22851 var btn = function(id,cmd , toggle, handler){
22853 var event = toggle ? 'toggle' : 'click';
22858 xns: Roo.bootstrap,
22861 enableToggle:toggle !== false,
22863 pressed : toggle ? false : null,
22866 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22867 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22876 xns: Roo.bootstrap,
22877 glyphicon : 'font',
22881 xns: Roo.bootstrap,
22885 Roo.each(this.formats, function(f) {
22886 style.menu.items.push({
22888 xns: Roo.bootstrap,
22889 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22894 editorcore.insertTag(this.tagname);
22901 children.push(style);
22904 btn('bold',false,true);
22905 btn('italic',false,true);
22906 btn('align-left', 'justifyleft',true);
22907 btn('align-center', 'justifycenter',true);
22908 btn('align-right' , 'justifyright',true);
22909 btn('link', false, false, function(btn) {
22910 //Roo.log("create link?");
22911 var url = prompt(this.createLinkText, this.defaultLinkValue);
22912 if(url && url != 'http:/'+'/'){
22913 this.editorcore.relayCmd('createlink', url);
22916 btn('list','insertunorderedlist',true);
22917 btn('pencil', false,true, function(btn){
22920 this.toggleSourceEdit(btn.pressed);
22926 xns: Roo.bootstrap,
22931 xns: Roo.bootstrap,
22936 cog.menu.items.push({
22938 xns: Roo.bootstrap,
22939 html : Clean styles,
22944 editorcore.insertTag(this.tagname);
22953 this.xtype = 'NavSimplebar';
22955 for(var i=0;i< children.length;i++) {
22957 this.buttons.add(this.addxtypeChild(children[i]));
22961 editor.on('editorevent', this.updateToolbar, this);
22963 onBtnClick : function(id)
22965 this.editorcore.relayCmd(id);
22966 this.editorcore.focus();
22970 * Protected method that will not generally be called directly. It triggers
22971 * a toolbar update by reading the markup state of the current selection in the editor.
22973 updateToolbar: function(){
22975 if(!this.editorcore.activated){
22976 this.editor.onFirstFocus(); // is this neeed?
22980 var btns = this.buttons;
22981 var doc = this.editorcore.doc;
22982 btns.get('bold').setActive(doc.queryCommandState('bold'));
22983 btns.get('italic').setActive(doc.queryCommandState('italic'));
22984 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22986 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22987 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22988 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22990 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22991 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22994 var ans = this.editorcore.getAllAncestors();
22995 if (this.formatCombo) {
22998 var store = this.formatCombo.store;
22999 this.formatCombo.setValue("");
23000 for (var i =0; i < ans.length;i++) {
23001 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23003 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23011 // hides menus... - so this cant be on a menu...
23012 Roo.bootstrap.MenuMgr.hideAll();
23014 Roo.bootstrap.MenuMgr.hideAll();
23015 //this.editorsyncValue();
23017 onFirstFocus: function() {
23018 this.buttons.each(function(item){
23022 toggleSourceEdit : function(sourceEditMode){
23025 if(sourceEditMode){
23026 Roo.log("disabling buttons");
23027 this.buttons.each( function(item){
23028 if(item.cmd != 'pencil'){
23034 Roo.log("enabling buttons");
23035 if(this.editorcore.initialized){
23036 this.buttons.each( function(item){
23042 Roo.log("calling toggole on editor");
23043 // tell the editor that it's been pressed..
23044 this.editor.toggleSourceEdit(sourceEditMode);
23054 * @class Roo.bootstrap.Table.AbstractSelectionModel
23055 * @extends Roo.util.Observable
23056 * Abstract base class for grid SelectionModels. It provides the interface that should be
23057 * implemented by descendant classes. This class should not be directly instantiated.
23060 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23061 this.locked = false;
23062 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23066 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23067 /** @ignore Called by the grid automatically. Do not call directly. */
23068 init : function(grid){
23074 * Locks the selections.
23077 this.locked = true;
23081 * Unlocks the selections.
23083 unlock : function(){
23084 this.locked = false;
23088 * Returns true if the selections are locked.
23089 * @return {Boolean}
23091 isLocked : function(){
23092 return this.locked;
23096 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23097 * @class Roo.bootstrap.Table.RowSelectionModel
23098 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23099 * It supports multiple selections and keyboard selection/navigation.
23101 * @param {Object} config
23104 Roo.bootstrap.Table.RowSelectionModel = function(config){
23105 Roo.apply(this, config);
23106 this.selections = new Roo.util.MixedCollection(false, function(o){
23111 this.lastActive = false;
23115 * @event selectionchange
23116 * Fires when the selection changes
23117 * @param {SelectionModel} this
23119 "selectionchange" : true,
23121 * @event afterselectionchange
23122 * Fires after the selection changes (eg. by key press or clicking)
23123 * @param {SelectionModel} this
23125 "afterselectionchange" : true,
23127 * @event beforerowselect
23128 * Fires when a row is selected being selected, return false to cancel.
23129 * @param {SelectionModel} this
23130 * @param {Number} rowIndex The selected index
23131 * @param {Boolean} keepExisting False if other selections will be cleared
23133 "beforerowselect" : true,
23136 * Fires when a row is selected.
23137 * @param {SelectionModel} this
23138 * @param {Number} rowIndex The selected index
23139 * @param {Roo.data.Record} r The record
23141 "rowselect" : true,
23143 * @event rowdeselect
23144 * Fires when a row is deselected.
23145 * @param {SelectionModel} this
23146 * @param {Number} rowIndex The selected index
23148 "rowdeselect" : true
23150 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23151 this.locked = false;
23154 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23156 * @cfg {Boolean} singleSelect
23157 * True to allow selection of only one row at a time (defaults to false)
23159 singleSelect : false,
23162 initEvents : function()
23165 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23166 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23167 //}else{ // allow click to work like normal
23168 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23170 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23171 this.grid.on("rowclick", this.handleMouseDown, this);
23173 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23174 "up" : function(e){
23176 this.selectPrevious(e.shiftKey);
23177 }else if(this.last !== false && this.lastActive !== false){
23178 var last = this.last;
23179 this.selectRange(this.last, this.lastActive-1);
23180 this.grid.getView().focusRow(this.lastActive);
23181 if(last !== false){
23185 this.selectFirstRow();
23187 this.fireEvent("afterselectionchange", this);
23189 "down" : function(e){
23191 this.selectNext(e.shiftKey);
23192 }else if(this.last !== false && this.lastActive !== false){
23193 var last = this.last;
23194 this.selectRange(this.last, this.lastActive+1);
23195 this.grid.getView().focusRow(this.lastActive);
23196 if(last !== false){
23200 this.selectFirstRow();
23202 this.fireEvent("afterselectionchange", this);
23206 this.grid.store.on('load', function(){
23207 this.selections.clear();
23210 var view = this.grid.view;
23211 view.on("refresh", this.onRefresh, this);
23212 view.on("rowupdated", this.onRowUpdated, this);
23213 view.on("rowremoved", this.onRemove, this);
23218 onRefresh : function()
23220 var ds = this.grid.store, i, v = this.grid.view;
23221 var s = this.selections;
23222 s.each(function(r){
23223 if((i = ds.indexOfId(r.id)) != -1){
23232 onRemove : function(v, index, r){
23233 this.selections.remove(r);
23237 onRowUpdated : function(v, index, r){
23238 if(this.isSelected(r)){
23239 v.onRowSelect(index);
23245 * @param {Array} records The records to select
23246 * @param {Boolean} keepExisting (optional) True to keep existing selections
23248 selectRecords : function(records, keepExisting)
23251 this.clearSelections();
23253 var ds = this.grid.store;
23254 for(var i = 0, len = records.length; i < len; i++){
23255 this.selectRow(ds.indexOf(records[i]), true);
23260 * Gets the number of selected rows.
23263 getCount : function(){
23264 return this.selections.length;
23268 * Selects the first row in the grid.
23270 selectFirstRow : function(){
23275 * Select the last row.
23276 * @param {Boolean} keepExisting (optional) True to keep existing selections
23278 selectLastRow : function(keepExisting){
23279 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23280 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23284 * Selects the row immediately following the last selected row.
23285 * @param {Boolean} keepExisting (optional) True to keep existing selections
23287 selectNext : function(keepExisting)
23289 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23290 this.selectRow(this.last+1, keepExisting);
23291 this.grid.getView().focusRow(this.last);
23296 * Selects the row that precedes the last selected row.
23297 * @param {Boolean} keepExisting (optional) True to keep existing selections
23299 selectPrevious : function(keepExisting){
23301 this.selectRow(this.last-1, keepExisting);
23302 this.grid.getView().focusRow(this.last);
23307 * Returns the selected records
23308 * @return {Array} Array of selected records
23310 getSelections : function(){
23311 return [].concat(this.selections.items);
23315 * Returns the first selected record.
23318 getSelected : function(){
23319 return this.selections.itemAt(0);
23324 * Clears all selections.
23326 clearSelections : function(fast)
23332 var ds = this.grid.store;
23333 var s = this.selections;
23334 s.each(function(r){
23335 this.deselectRow(ds.indexOfId(r.id));
23339 this.selections.clear();
23346 * Selects all rows.
23348 selectAll : function(){
23352 this.selections.clear();
23353 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23354 this.selectRow(i, true);
23359 * Returns True if there is a selection.
23360 * @return {Boolean}
23362 hasSelection : function(){
23363 return this.selections.length > 0;
23367 * Returns True if the specified row is selected.
23368 * @param {Number/Record} record The record or index of the record to check
23369 * @return {Boolean}
23371 isSelected : function(index){
23372 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23373 return (r && this.selections.key(r.id) ? true : false);
23377 * Returns True if the specified record id is selected.
23378 * @param {String} id The id of record to check
23379 * @return {Boolean}
23381 isIdSelected : function(id){
23382 return (this.selections.key(id) ? true : false);
23387 handleMouseDBClick : function(e, t){
23391 handleMouseDown : function(e, t)
23393 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23394 if(this.isLocked() || rowIndex < 0 ){
23397 if(e.shiftKey && this.last !== false){
23398 var last = this.last;
23399 this.selectRange(last, rowIndex, e.ctrlKey);
23400 this.last = last; // reset the last
23404 var isSelected = this.isSelected(rowIndex);
23405 //Roo.log("select row:" + rowIndex);
23407 this.deselectRow(rowIndex);
23409 this.selectRow(rowIndex, true);
23413 if(e.button !== 0 && isSelected){
23414 alert('rowIndex 2: ' + rowIndex);
23415 view.focusRow(rowIndex);
23416 }else if(e.ctrlKey && isSelected){
23417 this.deselectRow(rowIndex);
23418 }else if(!isSelected){
23419 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23420 view.focusRow(rowIndex);
23424 this.fireEvent("afterselectionchange", this);
23427 handleDragableRowClick : function(grid, rowIndex, e)
23429 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23430 this.selectRow(rowIndex, false);
23431 grid.view.focusRow(rowIndex);
23432 this.fireEvent("afterselectionchange", this);
23437 * Selects multiple rows.
23438 * @param {Array} rows Array of the indexes of the row to select
23439 * @param {Boolean} keepExisting (optional) True to keep existing selections
23441 selectRows : function(rows, keepExisting){
23443 this.clearSelections();
23445 for(var i = 0, len = rows.length; i < len; i++){
23446 this.selectRow(rows[i], true);
23451 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23452 * @param {Number} startRow The index of the first row in the range
23453 * @param {Number} endRow The index of the last row in the range
23454 * @param {Boolean} keepExisting (optional) True to retain existing selections
23456 selectRange : function(startRow, endRow, keepExisting){
23461 this.clearSelections();
23463 if(startRow <= endRow){
23464 for(var i = startRow; i <= endRow; i++){
23465 this.selectRow(i, true);
23468 for(var i = startRow; i >= endRow; i--){
23469 this.selectRow(i, true);
23475 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23476 * @param {Number} startRow The index of the first row in the range
23477 * @param {Number} endRow The index of the last row in the range
23479 deselectRange : function(startRow, endRow, preventViewNotify){
23483 for(var i = startRow; i <= endRow; i++){
23484 this.deselectRow(i, preventViewNotify);
23490 * @param {Number} row The index of the row to select
23491 * @param {Boolean} keepExisting (optional) True to keep existing selections
23493 selectRow : function(index, keepExisting, preventViewNotify)
23495 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23498 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23499 if(!keepExisting || this.singleSelect){
23500 this.clearSelections();
23503 var r = this.grid.store.getAt(index);
23504 //console.log('selectRow - record id :' + r.id);
23506 this.selections.add(r);
23507 this.last = this.lastActive = index;
23508 if(!preventViewNotify){
23509 var proxy = new Roo.Element(
23510 this.grid.getRowDom(index)
23512 proxy.addClass('bg-info info');
23514 this.fireEvent("rowselect", this, index, r);
23515 this.fireEvent("selectionchange", this);
23521 * @param {Number} row The index of the row to deselect
23523 deselectRow : function(index, preventViewNotify)
23528 if(this.last == index){
23531 if(this.lastActive == index){
23532 this.lastActive = false;
23535 var r = this.grid.store.getAt(index);
23540 this.selections.remove(r);
23541 //.console.log('deselectRow - record id :' + r.id);
23542 if(!preventViewNotify){
23544 var proxy = new Roo.Element(
23545 this.grid.getRowDom(index)
23547 proxy.removeClass('bg-info info');
23549 this.fireEvent("rowdeselect", this, index);
23550 this.fireEvent("selectionchange", this);
23554 restoreLast : function(){
23556 this.last = this._last;
23561 acceptsNav : function(row, col, cm){
23562 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23566 onEditorKey : function(field, e){
23567 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23572 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23574 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23576 }else if(k == e.ENTER && !e.ctrlKey){
23580 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23582 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23584 }else if(k == e.ESC){
23588 g.startEditing(newCell[0], newCell[1]);
23594 * Ext JS Library 1.1.1
23595 * Copyright(c) 2006-2007, Ext JS, LLC.
23597 * Originally Released Under LGPL - original licence link has changed is not relivant.
23600 * <script type="text/javascript">
23604 * @class Roo.bootstrap.PagingToolbar
23605 * @extends Roo.bootstrap.NavSimplebar
23606 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23608 * Create a new PagingToolbar
23609 * @param {Object} config The config object
23610 * @param {Roo.data.Store} store
23612 Roo.bootstrap.PagingToolbar = function(config)
23614 // old args format still supported... - xtype is prefered..
23615 // created from xtype...
23617 this.ds = config.dataSource;
23619 if (config.store && !this.ds) {
23620 this.store= Roo.factory(config.store, Roo.data);
23621 this.ds = this.store;
23622 this.ds.xmodule = this.xmodule || false;
23625 this.toolbarItems = [];
23626 if (config.items) {
23627 this.toolbarItems = config.items;
23630 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23635 this.bind(this.ds);
23638 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23642 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23644 * @cfg {Roo.data.Store} dataSource
23645 * The underlying data store providing the paged data
23648 * @cfg {String/HTMLElement/Element} container
23649 * container The id or element that will contain the toolbar
23652 * @cfg {Boolean} displayInfo
23653 * True to display the displayMsg (defaults to false)
23656 * @cfg {Number} pageSize
23657 * The number of records to display per page (defaults to 20)
23661 * @cfg {String} displayMsg
23662 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23664 displayMsg : 'Displaying {0} - {1} of {2}',
23666 * @cfg {String} emptyMsg
23667 * The message to display when no records are found (defaults to "No data to display")
23669 emptyMsg : 'No data to display',
23671 * Customizable piece of the default paging text (defaults to "Page")
23674 beforePageText : "Page",
23676 * Customizable piece of the default paging text (defaults to "of %0")
23679 afterPageText : "of {0}",
23681 * Customizable piece of the default paging text (defaults to "First Page")
23684 firstText : "First Page",
23686 * Customizable piece of the default paging text (defaults to "Previous Page")
23689 prevText : "Previous Page",
23691 * Customizable piece of the default paging text (defaults to "Next Page")
23694 nextText : "Next Page",
23696 * Customizable piece of the default paging text (defaults to "Last Page")
23699 lastText : "Last Page",
23701 * Customizable piece of the default paging text (defaults to "Refresh")
23704 refreshText : "Refresh",
23708 onRender : function(ct, position)
23710 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23711 this.navgroup.parentId = this.id;
23712 this.navgroup.onRender(this.el, null);
23713 // add the buttons to the navgroup
23715 if(this.displayInfo){
23716 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23717 this.displayEl = this.el.select('.x-paging-info', true).first();
23718 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23719 // this.displayEl = navel.el.select('span',true).first();
23725 Roo.each(_this.buttons, function(e){ // this might need to use render????
23726 Roo.factory(e).onRender(_this.el, null);
23730 Roo.each(_this.toolbarItems, function(e) {
23731 _this.navgroup.addItem(e);
23735 this.first = this.navgroup.addItem({
23736 tooltip: this.firstText,
23738 icon : 'fa fa-backward',
23740 preventDefault: true,
23741 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23744 this.prev = this.navgroup.addItem({
23745 tooltip: this.prevText,
23747 icon : 'fa fa-step-backward',
23749 preventDefault: true,
23750 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23752 //this.addSeparator();
23755 var field = this.navgroup.addItem( {
23757 cls : 'x-paging-position',
23759 html : this.beforePageText +
23760 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23761 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23764 this.field = field.el.select('input', true).first();
23765 this.field.on("keydown", this.onPagingKeydown, this);
23766 this.field.on("focus", function(){this.dom.select();});
23769 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23770 //this.field.setHeight(18);
23771 //this.addSeparator();
23772 this.next = this.navgroup.addItem({
23773 tooltip: this.nextText,
23775 html : ' <i class="fa fa-step-forward">',
23777 preventDefault: true,
23778 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23780 this.last = this.navgroup.addItem({
23781 tooltip: this.lastText,
23782 icon : 'fa fa-forward',
23785 preventDefault: true,
23786 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23788 //this.addSeparator();
23789 this.loading = this.navgroup.addItem({
23790 tooltip: this.refreshText,
23791 icon: 'fa fa-refresh',
23792 preventDefault: true,
23793 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23799 updateInfo : function(){
23800 if(this.displayEl){
23801 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23802 var msg = count == 0 ?
23806 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23808 this.displayEl.update(msg);
23813 onLoad : function(ds, r, o){
23814 this.cursor = o.params ? o.params.start : 0;
23815 var d = this.getPageData(),
23819 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23820 this.field.dom.value = ap;
23821 this.first.setDisabled(ap == 1);
23822 this.prev.setDisabled(ap == 1);
23823 this.next.setDisabled(ap == ps);
23824 this.last.setDisabled(ap == ps);
23825 this.loading.enable();
23830 getPageData : function(){
23831 var total = this.ds.getTotalCount();
23834 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23835 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23840 onLoadError : function(){
23841 this.loading.enable();
23845 onPagingKeydown : function(e){
23846 var k = e.getKey();
23847 var d = this.getPageData();
23849 var v = this.field.dom.value, pageNum;
23850 if(!v || isNaN(pageNum = parseInt(v, 10))){
23851 this.field.dom.value = d.activePage;
23854 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23855 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23858 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))
23860 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23861 this.field.dom.value = pageNum;
23862 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23865 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23867 var v = this.field.dom.value, pageNum;
23868 var increment = (e.shiftKey) ? 10 : 1;
23869 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23872 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23873 this.field.dom.value = d.activePage;
23876 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23878 this.field.dom.value = parseInt(v, 10) + increment;
23879 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23880 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23887 beforeLoad : function(){
23889 this.loading.disable();
23894 onClick : function(which){
23903 ds.load({params:{start: 0, limit: this.pageSize}});
23906 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23909 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23912 var total = ds.getTotalCount();
23913 var extra = total % this.pageSize;
23914 var lastStart = extra ? (total - extra) : total-this.pageSize;
23915 ds.load({params:{start: lastStart, limit: this.pageSize}});
23918 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23924 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23925 * @param {Roo.data.Store} store The data store to unbind
23927 unbind : function(ds){
23928 ds.un("beforeload", this.beforeLoad, this);
23929 ds.un("load", this.onLoad, this);
23930 ds.un("loadexception", this.onLoadError, this);
23931 ds.un("remove", this.updateInfo, this);
23932 ds.un("add", this.updateInfo, this);
23933 this.ds = undefined;
23937 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23938 * @param {Roo.data.Store} store The data store to bind
23940 bind : function(ds){
23941 ds.on("beforeload", this.beforeLoad, this);
23942 ds.on("load", this.onLoad, this);
23943 ds.on("loadexception", this.onLoadError, this);
23944 ds.on("remove", this.updateInfo, this);
23945 ds.on("add", this.updateInfo, this);
23956 * @class Roo.bootstrap.MessageBar
23957 * @extends Roo.bootstrap.Component
23958 * Bootstrap MessageBar class
23959 * @cfg {String} html contents of the MessageBar
23960 * @cfg {String} weight (info | success | warning | danger) default info
23961 * @cfg {String} beforeClass insert the bar before the given class
23962 * @cfg {Boolean} closable (true | false) default false
23963 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23966 * Create a new Element
23967 * @param {Object} config The config object
23970 Roo.bootstrap.MessageBar = function(config){
23971 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23974 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23980 beforeClass: 'bootstrap-sticky-wrap',
23982 getAutoCreate : function(){
23986 cls: 'alert alert-dismissable alert-' + this.weight,
23991 html: this.html || ''
23997 cfg.cls += ' alert-messages-fixed';
24011 onRender : function(ct, position)
24013 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24016 var cfg = Roo.apply({}, this.getAutoCreate());
24020 cfg.cls += ' ' + this.cls;
24023 cfg.style = this.style;
24025 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24027 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24030 this.el.select('>button.close').on('click', this.hide, this);
24036 if (!this.rendered) {
24042 this.fireEvent('show', this);
24048 if (!this.rendered) {
24054 this.fireEvent('hide', this);
24057 update : function()
24059 // var e = this.el.dom.firstChild;
24061 // if(this.closable){
24062 // e = e.nextSibling;
24065 // e.data = this.html || '';
24067 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24083 * @class Roo.bootstrap.Graph
24084 * @extends Roo.bootstrap.Component
24085 * Bootstrap Graph class
24089 @cfg {String} graphtype bar | vbar | pie
24090 @cfg {number} g_x coodinator | centre x (pie)
24091 @cfg {number} g_y coodinator | centre y (pie)
24092 @cfg {number} g_r radius (pie)
24093 @cfg {number} g_height height of the chart (respected by all elements in the set)
24094 @cfg {number} g_width width of the chart (respected by all elements in the set)
24095 @cfg {Object} title The title of the chart
24098 -opts (object) options for the chart
24100 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24101 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24103 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.
24104 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24106 o stretch (boolean)
24108 -opts (object) options for the pie
24111 o startAngle (number)
24112 o endAngle (number)
24116 * Create a new Input
24117 * @param {Object} config The config object
24120 Roo.bootstrap.Graph = function(config){
24121 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24127 * The img click event for the img.
24128 * @param {Roo.EventObject} e
24134 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24145 //g_colors: this.colors,
24152 getAutoCreate : function(){
24163 onRender : function(ct,position){
24166 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24168 if (typeof(Raphael) == 'undefined') {
24169 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24173 this.raphael = Raphael(this.el.dom);
24175 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24176 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24177 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24178 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24180 r.text(160, 10, "Single Series Chart").attr(txtattr);
24181 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24182 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24183 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24185 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24186 r.barchart(330, 10, 300, 220, data1);
24187 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24188 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24191 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24192 // r.barchart(30, 30, 560, 250, xdata, {
24193 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24194 // axis : "0 0 1 1",
24195 // axisxlabels : xdata
24196 // //yvalues : cols,
24199 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24201 // this.load(null,xdata,{
24202 // axis : "0 0 1 1",
24203 // axisxlabels : xdata
24208 load : function(graphtype,xdata,opts)
24210 this.raphael.clear();
24212 graphtype = this.graphtype;
24217 var r = this.raphael,
24218 fin = function () {
24219 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24221 fout = function () {
24222 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24224 pfin = function() {
24225 this.sector.stop();
24226 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24229 this.label[0].stop();
24230 this.label[0].attr({ r: 7.5 });
24231 this.label[1].attr({ "font-weight": 800 });
24234 pfout = function() {
24235 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24238 this.label[0].animate({ r: 5 }, 500, "bounce");
24239 this.label[1].attr({ "font-weight": 400 });
24245 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24248 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24251 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24252 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24254 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24261 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24266 setTitle: function(o)
24271 initEvents: function() {
24274 this.el.on('click', this.onClick, this);
24278 onClick : function(e)
24280 Roo.log('img onclick');
24281 this.fireEvent('click', this, e);
24293 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24296 * @class Roo.bootstrap.dash.NumberBox
24297 * @extends Roo.bootstrap.Component
24298 * Bootstrap NumberBox class
24299 * @cfg {String} headline Box headline
24300 * @cfg {String} content Box content
24301 * @cfg {String} icon Box icon
24302 * @cfg {String} footer Footer text
24303 * @cfg {String} fhref Footer href
24306 * Create a new NumberBox
24307 * @param {Object} config The config object
24311 Roo.bootstrap.dash.NumberBox = function(config){
24312 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24316 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24325 getAutoCreate : function(){
24329 cls : 'small-box ',
24337 cls : 'roo-headline',
24338 html : this.headline
24342 cls : 'roo-content',
24343 html : this.content
24357 cls : 'ion ' + this.icon
24366 cls : 'small-box-footer',
24367 href : this.fhref || '#',
24371 cfg.cn.push(footer);
24378 onRender : function(ct,position){
24379 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24386 setHeadline: function (value)
24388 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24391 setFooter: function (value, href)
24393 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24396 this.el.select('a.small-box-footer',true).first().attr('href', href);
24401 setContent: function (value)
24403 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24406 initEvents: function()
24420 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24423 * @class Roo.bootstrap.dash.TabBox
24424 * @extends Roo.bootstrap.Component
24425 * Bootstrap TabBox class
24426 * @cfg {String} title Title of the TabBox
24427 * @cfg {String} icon Icon of the TabBox
24428 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24429 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24432 * Create a new TabBox
24433 * @param {Object} config The config object
24437 Roo.bootstrap.dash.TabBox = function(config){
24438 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24443 * When a pane is added
24444 * @param {Roo.bootstrap.dash.TabPane} pane
24448 * @event activatepane
24449 * When a pane is activated
24450 * @param {Roo.bootstrap.dash.TabPane} pane
24452 "activatepane" : true
24460 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24465 tabScrollable : false,
24467 getChildContainer : function()
24469 return this.el.select('.tab-content', true).first();
24472 getAutoCreate : function(){
24476 cls: 'pull-left header',
24484 cls: 'fa ' + this.icon
24490 cls: 'nav nav-tabs pull-right',
24496 if(this.tabScrollable){
24503 cls: 'nav nav-tabs pull-right',
24514 cls: 'nav-tabs-custom',
24519 cls: 'tab-content no-padding',
24527 initEvents : function()
24529 //Roo.log('add add pane handler');
24530 this.on('addpane', this.onAddPane, this);
24533 * Updates the box title
24534 * @param {String} html to set the title to.
24536 setTitle : function(value)
24538 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24540 onAddPane : function(pane)
24542 this.panes.push(pane);
24543 //Roo.log('addpane');
24545 // tabs are rendere left to right..
24546 if(!this.showtabs){
24550 var ctr = this.el.select('.nav-tabs', true).first();
24553 var existing = ctr.select('.nav-tab',true);
24554 var qty = existing.getCount();;
24557 var tab = ctr.createChild({
24559 cls : 'nav-tab' + (qty ? '' : ' active'),
24567 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24570 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24572 pane.el.addClass('active');
24577 onTabClick : function(ev,un,ob,pane)
24579 //Roo.log('tab - prev default');
24580 ev.preventDefault();
24583 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24584 pane.tab.addClass('active');
24585 //Roo.log(pane.title);
24586 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24587 // technically we should have a deactivate event.. but maybe add later.
24588 // and it should not de-activate the selected tab...
24589 this.fireEvent('activatepane', pane);
24590 pane.el.addClass('active');
24591 pane.fireEvent('activate');
24596 getActivePane : function()
24599 Roo.each(this.panes, function(p) {
24600 if(p.el.hasClass('active')){
24621 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24623 * @class Roo.bootstrap.TabPane
24624 * @extends Roo.bootstrap.Component
24625 * Bootstrap TabPane class
24626 * @cfg {Boolean} active (false | true) Default false
24627 * @cfg {String} title title of panel
24631 * Create a new TabPane
24632 * @param {Object} config The config object
24635 Roo.bootstrap.dash.TabPane = function(config){
24636 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24642 * When a pane is activated
24643 * @param {Roo.bootstrap.dash.TabPane} pane
24650 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24655 // the tabBox that this is attached to.
24658 getAutoCreate : function()
24666 cfg.cls += ' active';
24671 initEvents : function()
24673 //Roo.log('trigger add pane handler');
24674 this.parent().fireEvent('addpane', this)
24678 * Updates the tab title
24679 * @param {String} html to set the title to.
24681 setTitle: function(str)
24687 this.tab.select('a', true).first().dom.innerHTML = str;
24704 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24707 * @class Roo.bootstrap.menu.Menu
24708 * @extends Roo.bootstrap.Component
24709 * Bootstrap Menu class - container for Menu
24710 * @cfg {String} html Text of the menu
24711 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24712 * @cfg {String} icon Font awesome icon
24713 * @cfg {String} pos Menu align to (top | bottom) default bottom
24717 * Create a new Menu
24718 * @param {Object} config The config object
24722 Roo.bootstrap.menu.Menu = function(config){
24723 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24727 * @event beforeshow
24728 * Fires before this menu is displayed
24729 * @param {Roo.bootstrap.menu.Menu} this
24733 * @event beforehide
24734 * Fires before this menu is hidden
24735 * @param {Roo.bootstrap.menu.Menu} this
24740 * Fires after this menu is displayed
24741 * @param {Roo.bootstrap.menu.Menu} this
24746 * Fires after this menu is hidden
24747 * @param {Roo.bootstrap.menu.Menu} this
24752 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24753 * @param {Roo.bootstrap.menu.Menu} this
24754 * @param {Roo.EventObject} e
24761 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24765 weight : 'default',
24770 getChildContainer : function() {
24771 if(this.isSubMenu){
24775 return this.el.select('ul.dropdown-menu', true).first();
24778 getAutoCreate : function()
24783 cls : 'roo-menu-text',
24791 cls : 'fa ' + this.icon
24802 cls : 'dropdown-button btn btn-' + this.weight,
24807 cls : 'dropdown-toggle btn btn-' + this.weight,
24817 cls : 'dropdown-menu'
24823 if(this.pos == 'top'){
24824 cfg.cls += ' dropup';
24827 if(this.isSubMenu){
24830 cls : 'dropdown-menu'
24837 onRender : function(ct, position)
24839 this.isSubMenu = ct.hasClass('dropdown-submenu');
24841 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24844 initEvents : function()
24846 if(this.isSubMenu){
24850 this.hidden = true;
24852 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24853 this.triggerEl.on('click', this.onTriggerPress, this);
24855 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24856 this.buttonEl.on('click', this.onClick, this);
24862 if(this.isSubMenu){
24866 return this.el.select('ul.dropdown-menu', true).first();
24869 onClick : function(e)
24871 this.fireEvent("click", this, e);
24874 onTriggerPress : function(e)
24876 if (this.isVisible()) {
24883 isVisible : function(){
24884 return !this.hidden;
24889 this.fireEvent("beforeshow", this);
24891 this.hidden = false;
24892 this.el.addClass('open');
24894 Roo.get(document).on("mouseup", this.onMouseUp, this);
24896 this.fireEvent("show", this);
24903 this.fireEvent("beforehide", this);
24905 this.hidden = true;
24906 this.el.removeClass('open');
24908 Roo.get(document).un("mouseup", this.onMouseUp);
24910 this.fireEvent("hide", this);
24913 onMouseUp : function()
24927 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24930 * @class Roo.bootstrap.menu.Item
24931 * @extends Roo.bootstrap.Component
24932 * Bootstrap MenuItem class
24933 * @cfg {Boolean} submenu (true | false) default false
24934 * @cfg {String} html text of the item
24935 * @cfg {String} href the link
24936 * @cfg {Boolean} disable (true | false) default false
24937 * @cfg {Boolean} preventDefault (true | false) default true
24938 * @cfg {String} icon Font awesome icon
24939 * @cfg {String} pos Submenu align to (left | right) default right
24943 * Create a new Item
24944 * @param {Object} config The config object
24948 Roo.bootstrap.menu.Item = function(config){
24949 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24953 * Fires when the mouse is hovering over this menu
24954 * @param {Roo.bootstrap.menu.Item} this
24955 * @param {Roo.EventObject} e
24960 * Fires when the mouse exits this menu
24961 * @param {Roo.bootstrap.menu.Item} this
24962 * @param {Roo.EventObject} e
24968 * The raw click event for the entire grid.
24969 * @param {Roo.EventObject} e
24975 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24980 preventDefault: true,
24985 getAutoCreate : function()
24990 cls : 'roo-menu-item-text',
24998 cls : 'fa ' + this.icon
25007 href : this.href || '#',
25014 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25018 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25020 if(this.pos == 'left'){
25021 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25028 initEvents : function()
25030 this.el.on('mouseover', this.onMouseOver, this);
25031 this.el.on('mouseout', this.onMouseOut, this);
25033 this.el.select('a', true).first().on('click', this.onClick, this);
25037 onClick : function(e)
25039 if(this.preventDefault){
25040 e.preventDefault();
25043 this.fireEvent("click", this, e);
25046 onMouseOver : function(e)
25048 if(this.submenu && this.pos == 'left'){
25049 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25052 this.fireEvent("mouseover", this, e);
25055 onMouseOut : function(e)
25057 this.fireEvent("mouseout", this, e);
25069 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25072 * @class Roo.bootstrap.menu.Separator
25073 * @extends Roo.bootstrap.Component
25074 * Bootstrap Separator class
25077 * Create a new Separator
25078 * @param {Object} config The config object
25082 Roo.bootstrap.menu.Separator = function(config){
25083 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25086 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25088 getAutoCreate : function(){
25109 * @class Roo.bootstrap.Tooltip
25110 * Bootstrap Tooltip class
25111 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25112 * to determine which dom element triggers the tooltip.
25114 * It needs to add support for additional attributes like tooltip-position
25117 * Create a new Toolti
25118 * @param {Object} config The config object
25121 Roo.bootstrap.Tooltip = function(config){
25122 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25124 this.alignment = Roo.bootstrap.Tooltip.alignment;
25126 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25127 this.alignment = config.alignment;
25132 Roo.apply(Roo.bootstrap.Tooltip, {
25134 * @function init initialize tooltip monitoring.
25138 currentTip : false,
25139 currentRegion : false,
25145 Roo.get(document).on('mouseover', this.enter ,this);
25146 Roo.get(document).on('mouseout', this.leave, this);
25149 this.currentTip = new Roo.bootstrap.Tooltip();
25152 enter : function(ev)
25154 var dom = ev.getTarget();
25156 //Roo.log(['enter',dom]);
25157 var el = Roo.fly(dom);
25158 if (this.currentEl) {
25160 //Roo.log(this.currentEl);
25161 //Roo.log(this.currentEl.contains(dom));
25162 if (this.currentEl == el) {
25165 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25171 if (this.currentTip.el) {
25172 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25176 if(!el || el.dom == document){
25182 // you can not look for children, as if el is the body.. then everythign is the child..
25183 if (!el.attr('tooltip')) { //
25184 if (!el.select("[tooltip]").elements.length) {
25187 // is the mouse over this child...?
25188 bindEl = el.select("[tooltip]").first();
25189 var xy = ev.getXY();
25190 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25191 //Roo.log("not in region.");
25194 //Roo.log("child element over..");
25197 this.currentEl = bindEl;
25198 this.currentTip.bind(bindEl);
25199 this.currentRegion = Roo.lib.Region.getRegion(dom);
25200 this.currentTip.enter();
25203 leave : function(ev)
25205 var dom = ev.getTarget();
25206 //Roo.log(['leave',dom]);
25207 if (!this.currentEl) {
25212 if (dom != this.currentEl.dom) {
25215 var xy = ev.getXY();
25216 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25219 // only activate leave if mouse cursor is outside... bounding box..
25224 if (this.currentTip) {
25225 this.currentTip.leave();
25227 //Roo.log('clear currentEl');
25228 this.currentEl = false;
25233 'left' : ['r-l', [-2,0], 'right'],
25234 'right' : ['l-r', [2,0], 'left'],
25235 'bottom' : ['t-b', [0,2], 'top'],
25236 'top' : [ 'b-t', [0,-2], 'bottom']
25242 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25247 delay : null, // can be { show : 300 , hide: 500}
25251 hoverState : null, //???
25253 placement : 'bottom',
25257 getAutoCreate : function(){
25264 cls : 'tooltip-arrow'
25267 cls : 'tooltip-inner'
25274 bind : function(el)
25280 enter : function () {
25282 if (this.timeout != null) {
25283 clearTimeout(this.timeout);
25286 this.hoverState = 'in';
25287 //Roo.log("enter - show");
25288 if (!this.delay || !this.delay.show) {
25293 this.timeout = setTimeout(function () {
25294 if (_t.hoverState == 'in') {
25297 }, this.delay.show);
25301 clearTimeout(this.timeout);
25303 this.hoverState = 'out';
25304 if (!this.delay || !this.delay.hide) {
25310 this.timeout = setTimeout(function () {
25311 //Roo.log("leave - timeout");
25313 if (_t.hoverState == 'out') {
25315 Roo.bootstrap.Tooltip.currentEl = false;
25320 show : function (msg)
25323 this.render(document.body);
25326 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25328 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25330 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25332 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25334 var placement = typeof this.placement == 'function' ?
25335 this.placement.call(this, this.el, on_el) :
25338 var autoToken = /\s?auto?\s?/i;
25339 var autoPlace = autoToken.test(placement);
25341 placement = placement.replace(autoToken, '') || 'top';
25345 //this.el.setXY([0,0]);
25347 //this.el.dom.style.display='block';
25349 //this.el.appendTo(on_el);
25351 var p = this.getPosition();
25352 var box = this.el.getBox();
25358 var align = this.alignment[placement];
25360 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25362 if(placement == 'top' || placement == 'bottom'){
25364 placement = 'right';
25367 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25368 placement = 'left';
25371 var scroll = Roo.select('body', true).first().getScroll();
25373 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25379 this.el.alignTo(this.bindEl, align[0],align[1]);
25380 //var arrow = this.el.select('.arrow',true).first();
25381 //arrow.set(align[2],
25383 this.el.addClass(placement);
25385 this.el.addClass('in fade');
25387 this.hoverState = null;
25389 if (this.el.hasClass('fade')) {
25400 //this.el.setXY([0,0]);
25401 this.el.removeClass('in');
25417 * @class Roo.bootstrap.LocationPicker
25418 * @extends Roo.bootstrap.Component
25419 * Bootstrap LocationPicker class
25420 * @cfg {Number} latitude Position when init default 0
25421 * @cfg {Number} longitude Position when init default 0
25422 * @cfg {Number} zoom default 15
25423 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25424 * @cfg {Boolean} mapTypeControl default false
25425 * @cfg {Boolean} disableDoubleClickZoom default false
25426 * @cfg {Boolean} scrollwheel default true
25427 * @cfg {Boolean} streetViewControl default false
25428 * @cfg {Number} radius default 0
25429 * @cfg {String} locationName
25430 * @cfg {Boolean} draggable default true
25431 * @cfg {Boolean} enableAutocomplete default false
25432 * @cfg {Boolean} enableReverseGeocode default true
25433 * @cfg {String} markerTitle
25436 * Create a new LocationPicker
25437 * @param {Object} config The config object
25441 Roo.bootstrap.LocationPicker = function(config){
25443 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25448 * Fires when the picker initialized.
25449 * @param {Roo.bootstrap.LocationPicker} this
25450 * @param {Google Location} location
25454 * @event positionchanged
25455 * Fires when the picker position changed.
25456 * @param {Roo.bootstrap.LocationPicker} this
25457 * @param {Google Location} location
25459 positionchanged : true,
25462 * Fires when the map resize.
25463 * @param {Roo.bootstrap.LocationPicker} this
25468 * Fires when the map show.
25469 * @param {Roo.bootstrap.LocationPicker} this
25474 * Fires when the map hide.
25475 * @param {Roo.bootstrap.LocationPicker} this
25480 * Fires when click the map.
25481 * @param {Roo.bootstrap.LocationPicker} this
25482 * @param {Map event} e
25486 * @event mapRightClick
25487 * Fires when right click the map.
25488 * @param {Roo.bootstrap.LocationPicker} this
25489 * @param {Map event} e
25491 mapRightClick : true,
25493 * @event markerClick
25494 * Fires when click the marker.
25495 * @param {Roo.bootstrap.LocationPicker} this
25496 * @param {Map event} e
25498 markerClick : true,
25500 * @event markerRightClick
25501 * Fires when right click the marker.
25502 * @param {Roo.bootstrap.LocationPicker} this
25503 * @param {Map event} e
25505 markerRightClick : true,
25507 * @event OverlayViewDraw
25508 * Fires when OverlayView Draw
25509 * @param {Roo.bootstrap.LocationPicker} this
25511 OverlayViewDraw : true,
25513 * @event OverlayViewOnAdd
25514 * Fires when OverlayView Draw
25515 * @param {Roo.bootstrap.LocationPicker} this
25517 OverlayViewOnAdd : true,
25519 * @event OverlayViewOnRemove
25520 * Fires when OverlayView Draw
25521 * @param {Roo.bootstrap.LocationPicker} this
25523 OverlayViewOnRemove : true,
25525 * @event OverlayViewShow
25526 * Fires when OverlayView Draw
25527 * @param {Roo.bootstrap.LocationPicker} this
25528 * @param {Pixel} cpx
25530 OverlayViewShow : true,
25532 * @event OverlayViewHide
25533 * Fires when OverlayView Draw
25534 * @param {Roo.bootstrap.LocationPicker} this
25536 OverlayViewHide : true,
25538 * @event loadexception
25539 * Fires when load google lib failed.
25540 * @param {Roo.bootstrap.LocationPicker} this
25542 loadexception : true
25547 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25549 gMapContext: false,
25555 mapTypeControl: false,
25556 disableDoubleClickZoom: false,
25558 streetViewControl: false,
25562 enableAutocomplete: false,
25563 enableReverseGeocode: true,
25566 getAutoCreate: function()
25571 cls: 'roo-location-picker'
25577 initEvents: function(ct, position)
25579 if(!this.el.getWidth() || this.isApplied()){
25583 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25588 initial: function()
25590 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25591 this.fireEvent('loadexception', this);
25595 if(!this.mapTypeId){
25596 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25599 this.gMapContext = this.GMapContext();
25601 this.initOverlayView();
25603 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25607 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25608 _this.setPosition(_this.gMapContext.marker.position);
25611 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25612 _this.fireEvent('mapClick', this, event);
25616 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25617 _this.fireEvent('mapRightClick', this, event);
25621 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25622 _this.fireEvent('markerClick', this, event);
25626 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25627 _this.fireEvent('markerRightClick', this, event);
25631 this.setPosition(this.gMapContext.location);
25633 this.fireEvent('initial', this, this.gMapContext.location);
25636 initOverlayView: function()
25640 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25644 _this.fireEvent('OverlayViewDraw', _this);
25649 _this.fireEvent('OverlayViewOnAdd', _this);
25652 onRemove: function()
25654 _this.fireEvent('OverlayViewOnRemove', _this);
25657 show: function(cpx)
25659 _this.fireEvent('OverlayViewShow', _this, cpx);
25664 _this.fireEvent('OverlayViewHide', _this);
25670 fromLatLngToContainerPixel: function(event)
25672 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25675 isApplied: function()
25677 return this.getGmapContext() == false ? false : true;
25680 getGmapContext: function()
25682 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25685 GMapContext: function()
25687 var position = new google.maps.LatLng(this.latitude, this.longitude);
25689 var _map = new google.maps.Map(this.el.dom, {
25692 mapTypeId: this.mapTypeId,
25693 mapTypeControl: this.mapTypeControl,
25694 disableDoubleClickZoom: this.disableDoubleClickZoom,
25695 scrollwheel: this.scrollwheel,
25696 streetViewControl: this.streetViewControl,
25697 locationName: this.locationName,
25698 draggable: this.draggable,
25699 enableAutocomplete: this.enableAutocomplete,
25700 enableReverseGeocode: this.enableReverseGeocode
25703 var _marker = new google.maps.Marker({
25704 position: position,
25706 title: this.markerTitle,
25707 draggable: this.draggable
25714 location: position,
25715 radius: this.radius,
25716 locationName: this.locationName,
25717 addressComponents: {
25718 formatted_address: null,
25719 addressLine1: null,
25720 addressLine2: null,
25722 streetNumber: null,
25726 stateOrProvince: null
25729 domContainer: this.el.dom,
25730 geodecoder: new google.maps.Geocoder()
25734 drawCircle: function(center, radius, options)
25736 if (this.gMapContext.circle != null) {
25737 this.gMapContext.circle.setMap(null);
25741 options = Roo.apply({}, options, {
25742 strokeColor: "#0000FF",
25743 strokeOpacity: .35,
25745 fillColor: "#0000FF",
25749 options.map = this.gMapContext.map;
25750 options.radius = radius;
25751 options.center = center;
25752 this.gMapContext.circle = new google.maps.Circle(options);
25753 return this.gMapContext.circle;
25759 setPosition: function(location)
25761 this.gMapContext.location = location;
25762 this.gMapContext.marker.setPosition(location);
25763 this.gMapContext.map.panTo(location);
25764 this.drawCircle(location, this.gMapContext.radius, {});
25768 if (this.gMapContext.settings.enableReverseGeocode) {
25769 this.gMapContext.geodecoder.geocode({
25770 latLng: this.gMapContext.location
25771 }, function(results, status) {
25773 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25774 _this.gMapContext.locationName = results[0].formatted_address;
25775 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25777 _this.fireEvent('positionchanged', this, location);
25784 this.fireEvent('positionchanged', this, location);
25789 google.maps.event.trigger(this.gMapContext.map, "resize");
25791 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25793 this.fireEvent('resize', this);
25796 setPositionByLatLng: function(latitude, longitude)
25798 this.setPosition(new google.maps.LatLng(latitude, longitude));
25801 getCurrentPosition: function()
25804 latitude: this.gMapContext.location.lat(),
25805 longitude: this.gMapContext.location.lng()
25809 getAddressName: function()
25811 return this.gMapContext.locationName;
25814 getAddressComponents: function()
25816 return this.gMapContext.addressComponents;
25819 address_component_from_google_geocode: function(address_components)
25823 for (var i = 0; i < address_components.length; i++) {
25824 var component = address_components[i];
25825 if (component.types.indexOf("postal_code") >= 0) {
25826 result.postalCode = component.short_name;
25827 } else if (component.types.indexOf("street_number") >= 0) {
25828 result.streetNumber = component.short_name;
25829 } else if (component.types.indexOf("route") >= 0) {
25830 result.streetName = component.short_name;
25831 } else if (component.types.indexOf("neighborhood") >= 0) {
25832 result.city = component.short_name;
25833 } else if (component.types.indexOf("locality") >= 0) {
25834 result.city = component.short_name;
25835 } else if (component.types.indexOf("sublocality") >= 0) {
25836 result.district = component.short_name;
25837 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25838 result.stateOrProvince = component.short_name;
25839 } else if (component.types.indexOf("country") >= 0) {
25840 result.country = component.short_name;
25844 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25845 result.addressLine2 = "";
25849 setZoomLevel: function(zoom)
25851 this.gMapContext.map.setZoom(zoom);
25864 this.fireEvent('show', this);
25875 this.fireEvent('hide', this);
25880 Roo.apply(Roo.bootstrap.LocationPicker, {
25882 OverlayView : function(map, options)
25884 options = options || {};
25898 * @class Roo.bootstrap.Alert
25899 * @extends Roo.bootstrap.Component
25900 * Bootstrap Alert class
25901 * @cfg {String} title The title of alert
25902 * @cfg {String} html The content of alert
25903 * @cfg {String} weight ( success | info | warning | danger )
25904 * @cfg {String} faicon font-awesomeicon
25907 * Create a new alert
25908 * @param {Object} config The config object
25912 Roo.bootstrap.Alert = function(config){
25913 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25917 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25924 getAutoCreate : function()
25933 cls : 'roo-alert-icon'
25938 cls : 'roo-alert-title',
25943 cls : 'roo-alert-text',
25950 cfg.cn[0].cls += ' fa ' + this.faicon;
25954 cfg.cls += ' alert-' + this.weight;
25960 initEvents: function()
25962 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25965 setTitle : function(str)
25967 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25970 setText : function(str)
25972 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25975 setWeight : function(weight)
25978 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25981 this.weight = weight;
25983 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25986 setIcon : function(icon)
25989 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25992 this.faicon = icon;
25994 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26015 * @class Roo.bootstrap.UploadCropbox
26016 * @extends Roo.bootstrap.Component
26017 * Bootstrap UploadCropbox class
26018 * @cfg {String} emptyText show when image has been loaded
26019 * @cfg {String} rotateNotify show when image too small to rotate
26020 * @cfg {Number} errorTimeout default 3000
26021 * @cfg {Number} minWidth default 300
26022 * @cfg {Number} minHeight default 300
26023 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26024 * @cfg {Boolean} isDocument (true|false) default false
26025 * @cfg {String} url action url
26026 * @cfg {String} paramName default 'imageUpload'
26027 * @cfg {String} method default POST
26028 * @cfg {Boolean} loadMask (true|false) default true
26029 * @cfg {Boolean} loadingText default 'Loading...'
26032 * Create a new UploadCropbox
26033 * @param {Object} config The config object
26036 Roo.bootstrap.UploadCropbox = function(config){
26037 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26041 * @event beforeselectfile
26042 * Fire before select file
26043 * @param {Roo.bootstrap.UploadCropbox} this
26045 "beforeselectfile" : true,
26048 * Fire after initEvent
26049 * @param {Roo.bootstrap.UploadCropbox} this
26054 * Fire after initEvent
26055 * @param {Roo.bootstrap.UploadCropbox} this
26056 * @param {String} data
26061 * Fire when preparing the file data
26062 * @param {Roo.bootstrap.UploadCropbox} this
26063 * @param {Object} file
26068 * Fire when get exception
26069 * @param {Roo.bootstrap.UploadCropbox} this
26070 * @param {XMLHttpRequest} xhr
26072 "exception" : true,
26074 * @event beforeloadcanvas
26075 * Fire before load the canvas
26076 * @param {Roo.bootstrap.UploadCropbox} this
26077 * @param {String} src
26079 "beforeloadcanvas" : true,
26082 * Fire when trash image
26083 * @param {Roo.bootstrap.UploadCropbox} this
26088 * Fire when download the image
26089 * @param {Roo.bootstrap.UploadCropbox} this
26093 * @event footerbuttonclick
26094 * Fire when footerbuttonclick
26095 * @param {Roo.bootstrap.UploadCropbox} this
26096 * @param {String} type
26098 "footerbuttonclick" : true,
26102 * @param {Roo.bootstrap.UploadCropbox} this
26107 * Fire when rotate the image
26108 * @param {Roo.bootstrap.UploadCropbox} this
26109 * @param {String} pos
26114 * Fire when inspect the file
26115 * @param {Roo.bootstrap.UploadCropbox} this
26116 * @param {Object} file
26121 * Fire when xhr upload the file
26122 * @param {Roo.bootstrap.UploadCropbox} this
26123 * @param {Object} data
26128 * Fire when arrange the file data
26129 * @param {Roo.bootstrap.UploadCropbox} this
26130 * @param {Object} formData
26135 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26138 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26140 emptyText : 'Click to upload image',
26141 rotateNotify : 'Image is too small to rotate',
26142 errorTimeout : 3000,
26156 cropType : 'image/jpeg',
26158 canvasLoaded : false,
26159 isDocument : false,
26161 paramName : 'imageUpload',
26163 loadingText : 'Loading...',
26166 getAutoCreate : function()
26170 cls : 'roo-upload-cropbox',
26174 cls : 'roo-upload-cropbox-selector',
26179 cls : 'roo-upload-cropbox-body',
26180 style : 'cursor:pointer',
26184 cls : 'roo-upload-cropbox-preview'
26188 cls : 'roo-upload-cropbox-thumb'
26192 cls : 'roo-upload-cropbox-empty-notify',
26193 html : this.emptyText
26197 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26198 html : this.rotateNotify
26204 cls : 'roo-upload-cropbox-footer',
26207 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26217 onRender : function(ct, position)
26219 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26221 if (this.buttons.length) {
26223 Roo.each(this.buttons, function(bb) {
26225 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26227 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26233 this.maskEl = this.el;
26237 initEvents : function()
26239 this.urlAPI = (window.createObjectURL && window) ||
26240 (window.URL && URL.revokeObjectURL && URL) ||
26241 (window.webkitURL && webkitURL);
26243 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26244 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26246 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26247 this.selectorEl.hide();
26249 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26250 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26252 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26253 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26254 this.thumbEl.hide();
26256 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26257 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26259 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26260 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26261 this.errorEl.hide();
26263 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26264 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26265 this.footerEl.hide();
26267 this.setThumbBoxSize();
26273 this.fireEvent('initial', this);
26280 window.addEventListener("resize", function() { _this.resize(); } );
26282 this.bodyEl.on('click', this.beforeSelectFile, this);
26285 this.bodyEl.on('touchstart', this.onTouchStart, this);
26286 this.bodyEl.on('touchmove', this.onTouchMove, this);
26287 this.bodyEl.on('touchend', this.onTouchEnd, this);
26291 this.bodyEl.on('mousedown', this.onMouseDown, this);
26292 this.bodyEl.on('mousemove', this.onMouseMove, this);
26293 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26294 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26295 Roo.get(document).on('mouseup', this.onMouseUp, this);
26298 this.selectorEl.on('change', this.onFileSelected, this);
26304 this.baseScale = 1;
26306 this.baseRotate = 1;
26307 this.dragable = false;
26308 this.pinching = false;
26311 this.cropData = false;
26312 this.notifyEl.dom.innerHTML = this.emptyText;
26314 this.selectorEl.dom.value = '';
26318 resize : function()
26320 if(this.fireEvent('resize', this) != false){
26321 this.setThumbBoxPosition();
26322 this.setCanvasPosition();
26326 onFooterButtonClick : function(e, el, o, type)
26329 case 'rotate-left' :
26330 this.onRotateLeft(e);
26332 case 'rotate-right' :
26333 this.onRotateRight(e);
26336 this.beforeSelectFile(e);
26351 this.fireEvent('footerbuttonclick', this, type);
26354 beforeSelectFile : function(e)
26356 e.preventDefault();
26358 if(this.fireEvent('beforeselectfile', this) != false){
26359 this.selectorEl.dom.click();
26363 onFileSelected : function(e)
26365 e.preventDefault();
26367 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26371 var file = this.selectorEl.dom.files[0];
26373 if(this.fireEvent('inspect', this, file) != false){
26374 this.prepare(file);
26379 trash : function(e)
26381 this.fireEvent('trash', this);
26384 download : function(e)
26386 this.fireEvent('download', this);
26389 loadCanvas : function(src)
26391 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26395 this.imageEl = document.createElement('img');
26399 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26401 this.imageEl.src = src;
26405 onLoadCanvas : function()
26407 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26408 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26410 this.bodyEl.un('click', this.beforeSelectFile, this);
26412 this.notifyEl.hide();
26413 this.thumbEl.show();
26414 this.footerEl.show();
26416 this.baseRotateLevel();
26418 if(this.isDocument){
26419 this.setThumbBoxSize();
26422 this.setThumbBoxPosition();
26424 this.baseScaleLevel();
26430 this.canvasLoaded = true;
26433 this.maskEl.unmask();
26438 setCanvasPosition : function()
26440 if(!this.canvasEl){
26444 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26445 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26447 this.previewEl.setLeft(pw);
26448 this.previewEl.setTop(ph);
26452 onMouseDown : function(e)
26456 this.dragable = true;
26457 this.pinching = false;
26459 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26460 this.dragable = false;
26464 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26465 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26469 onMouseMove : function(e)
26473 if(!this.canvasLoaded){
26477 if (!this.dragable){
26481 var minX = Math.ceil(this.thumbEl.getLeft(true));
26482 var minY = Math.ceil(this.thumbEl.getTop(true));
26484 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26485 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26487 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26488 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26490 x = x - this.mouseX;
26491 y = y - this.mouseY;
26493 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26494 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26496 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26497 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26499 this.previewEl.setLeft(bgX);
26500 this.previewEl.setTop(bgY);
26502 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26503 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26506 onMouseUp : function(e)
26510 this.dragable = false;
26513 onMouseWheel : function(e)
26517 this.startScale = this.scale;
26519 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26521 if(!this.zoomable()){
26522 this.scale = this.startScale;
26531 zoomable : function()
26533 var minScale = this.thumbEl.getWidth() / this.minWidth;
26535 if(this.minWidth < this.minHeight){
26536 minScale = this.thumbEl.getHeight() / this.minHeight;
26539 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26540 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26544 (this.rotate == 0 || this.rotate == 180) &&
26546 width > this.imageEl.OriginWidth ||
26547 height > this.imageEl.OriginHeight ||
26548 (width < this.minWidth && height < this.minHeight)
26556 (this.rotate == 90 || this.rotate == 270) &&
26558 width > this.imageEl.OriginWidth ||
26559 height > this.imageEl.OriginHeight ||
26560 (width < this.minHeight && height < this.minWidth)
26567 !this.isDocument &&
26568 (this.rotate == 0 || this.rotate == 180) &&
26570 width < this.minWidth ||
26571 width > this.imageEl.OriginWidth ||
26572 height < this.minHeight ||
26573 height > this.imageEl.OriginHeight
26580 !this.isDocument &&
26581 (this.rotate == 90 || this.rotate == 270) &&
26583 width < this.minHeight ||
26584 width > this.imageEl.OriginWidth ||
26585 height < this.minWidth ||
26586 height > this.imageEl.OriginHeight
26596 onRotateLeft : function(e)
26598 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26600 var minScale = this.thumbEl.getWidth() / this.minWidth;
26602 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26603 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26605 this.startScale = this.scale;
26607 while (this.getScaleLevel() < minScale){
26609 this.scale = this.scale + 1;
26611 if(!this.zoomable()){
26616 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26617 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26622 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26629 this.scale = this.startScale;
26631 this.onRotateFail();
26636 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26638 if(this.isDocument){
26639 this.setThumbBoxSize();
26640 this.setThumbBoxPosition();
26641 this.setCanvasPosition();
26646 this.fireEvent('rotate', this, 'left');
26650 onRotateRight : function(e)
26652 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26654 var minScale = this.thumbEl.getWidth() / this.minWidth;
26656 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26657 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26659 this.startScale = this.scale;
26661 while (this.getScaleLevel() < minScale){
26663 this.scale = this.scale + 1;
26665 if(!this.zoomable()){
26670 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26671 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26676 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26683 this.scale = this.startScale;
26685 this.onRotateFail();
26690 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26692 if(this.isDocument){
26693 this.setThumbBoxSize();
26694 this.setThumbBoxPosition();
26695 this.setCanvasPosition();
26700 this.fireEvent('rotate', this, 'right');
26703 onRotateFail : function()
26705 this.errorEl.show(true);
26709 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26714 this.previewEl.dom.innerHTML = '';
26716 var canvasEl = document.createElement("canvas");
26718 var contextEl = canvasEl.getContext("2d");
26720 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26721 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26722 var center = this.imageEl.OriginWidth / 2;
26724 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26725 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26726 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26727 center = this.imageEl.OriginHeight / 2;
26730 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26732 contextEl.translate(center, center);
26733 contextEl.rotate(this.rotate * Math.PI / 180);
26735 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26737 this.canvasEl = document.createElement("canvas");
26739 this.contextEl = this.canvasEl.getContext("2d");
26741 switch (this.rotate) {
26744 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26745 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26747 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26752 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26753 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26755 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26756 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);
26760 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26765 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26766 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26768 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26769 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);
26773 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);
26778 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26779 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26781 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26782 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26786 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);
26793 this.previewEl.appendChild(this.canvasEl);
26795 this.setCanvasPosition();
26800 if(!this.canvasLoaded){
26804 var imageCanvas = document.createElement("canvas");
26806 var imageContext = imageCanvas.getContext("2d");
26808 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26809 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26811 var center = imageCanvas.width / 2;
26813 imageContext.translate(center, center);
26815 imageContext.rotate(this.rotate * Math.PI / 180);
26817 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26819 var canvas = document.createElement("canvas");
26821 var context = canvas.getContext("2d");
26823 canvas.width = this.minWidth;
26824 canvas.height = this.minHeight;
26826 switch (this.rotate) {
26829 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26830 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26832 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26833 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26835 var targetWidth = this.minWidth - 2 * x;
26836 var targetHeight = this.minHeight - 2 * y;
26840 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26841 scale = targetWidth / width;
26844 if(x > 0 && y == 0){
26845 scale = targetHeight / height;
26848 if(x > 0 && y > 0){
26849 scale = targetWidth / width;
26851 if(width < height){
26852 scale = targetHeight / height;
26856 context.scale(scale, scale);
26858 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26859 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26861 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26862 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26864 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26869 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26870 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26872 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26873 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26875 var targetWidth = this.minWidth - 2 * x;
26876 var targetHeight = this.minHeight - 2 * y;
26880 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26881 scale = targetWidth / width;
26884 if(x > 0 && y == 0){
26885 scale = targetHeight / height;
26888 if(x > 0 && y > 0){
26889 scale = targetWidth / width;
26891 if(width < height){
26892 scale = targetHeight / height;
26896 context.scale(scale, scale);
26898 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26899 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26901 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26902 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26904 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26906 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26911 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26912 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26914 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26915 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26917 var targetWidth = this.minWidth - 2 * x;
26918 var targetHeight = this.minHeight - 2 * y;
26922 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26923 scale = targetWidth / width;
26926 if(x > 0 && y == 0){
26927 scale = targetHeight / height;
26930 if(x > 0 && y > 0){
26931 scale = targetWidth / width;
26933 if(width < height){
26934 scale = targetHeight / height;
26938 context.scale(scale, scale);
26940 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26941 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26943 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26944 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26946 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26947 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26949 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26954 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26955 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26957 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26958 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26960 var targetWidth = this.minWidth - 2 * x;
26961 var targetHeight = this.minHeight - 2 * y;
26965 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26966 scale = targetWidth / width;
26969 if(x > 0 && y == 0){
26970 scale = targetHeight / height;
26973 if(x > 0 && y > 0){
26974 scale = targetWidth / width;
26976 if(width < height){
26977 scale = targetHeight / height;
26981 context.scale(scale, scale);
26983 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26984 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26986 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26987 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26989 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26991 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26998 this.cropData = canvas.toDataURL(this.cropType);
27000 if(this.fireEvent('crop', this, this.cropData) !== false){
27001 this.process(this.file, this.cropData);
27008 setThumbBoxSize : function()
27012 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27013 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27014 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27016 this.minWidth = width;
27017 this.minHeight = height;
27019 if(this.rotate == 90 || this.rotate == 270){
27020 this.minWidth = height;
27021 this.minHeight = width;
27026 width = Math.ceil(this.minWidth * height / this.minHeight);
27028 if(this.minWidth > this.minHeight){
27030 height = Math.ceil(this.minHeight * width / this.minWidth);
27033 this.thumbEl.setStyle({
27034 width : width + 'px',
27035 height : height + 'px'
27042 setThumbBoxPosition : function()
27044 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27045 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27047 this.thumbEl.setLeft(x);
27048 this.thumbEl.setTop(y);
27052 baseRotateLevel : function()
27054 this.baseRotate = 1;
27057 typeof(this.exif) != 'undefined' &&
27058 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27059 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27061 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27064 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27068 baseScaleLevel : function()
27072 if(this.isDocument){
27074 if(this.baseRotate == 6 || this.baseRotate == 8){
27076 height = this.thumbEl.getHeight();
27077 this.baseScale = height / this.imageEl.OriginWidth;
27079 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27080 width = this.thumbEl.getWidth();
27081 this.baseScale = width / this.imageEl.OriginHeight;
27087 height = this.thumbEl.getHeight();
27088 this.baseScale = height / this.imageEl.OriginHeight;
27090 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27091 width = this.thumbEl.getWidth();
27092 this.baseScale = width / this.imageEl.OriginWidth;
27098 if(this.baseRotate == 6 || this.baseRotate == 8){
27100 width = this.thumbEl.getHeight();
27101 this.baseScale = width / this.imageEl.OriginHeight;
27103 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27104 height = this.thumbEl.getWidth();
27105 this.baseScale = height / this.imageEl.OriginHeight;
27108 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27109 height = this.thumbEl.getWidth();
27110 this.baseScale = height / this.imageEl.OriginHeight;
27112 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27113 width = this.thumbEl.getHeight();
27114 this.baseScale = width / this.imageEl.OriginWidth;
27121 width = this.thumbEl.getWidth();
27122 this.baseScale = width / this.imageEl.OriginWidth;
27124 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27125 height = this.thumbEl.getHeight();
27126 this.baseScale = height / this.imageEl.OriginHeight;
27129 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27131 height = this.thumbEl.getHeight();
27132 this.baseScale = height / this.imageEl.OriginHeight;
27134 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27135 width = this.thumbEl.getWidth();
27136 this.baseScale = width / this.imageEl.OriginWidth;
27144 getScaleLevel : function()
27146 return this.baseScale * Math.pow(1.1, this.scale);
27149 onTouchStart : function(e)
27151 if(!this.canvasLoaded){
27152 this.beforeSelectFile(e);
27156 var touches = e.browserEvent.touches;
27162 if(touches.length == 1){
27163 this.onMouseDown(e);
27167 if(touches.length != 2){
27173 for(var i = 0, finger; finger = touches[i]; i++){
27174 coords.push(finger.pageX, finger.pageY);
27177 var x = Math.pow(coords[0] - coords[2], 2);
27178 var y = Math.pow(coords[1] - coords[3], 2);
27180 this.startDistance = Math.sqrt(x + y);
27182 this.startScale = this.scale;
27184 this.pinching = true;
27185 this.dragable = false;
27189 onTouchMove : function(e)
27191 if(!this.pinching && !this.dragable){
27195 var touches = e.browserEvent.touches;
27202 this.onMouseMove(e);
27208 for(var i = 0, finger; finger = touches[i]; i++){
27209 coords.push(finger.pageX, finger.pageY);
27212 var x = Math.pow(coords[0] - coords[2], 2);
27213 var y = Math.pow(coords[1] - coords[3], 2);
27215 this.endDistance = Math.sqrt(x + y);
27217 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27219 if(!this.zoomable()){
27220 this.scale = this.startScale;
27228 onTouchEnd : function(e)
27230 this.pinching = false;
27231 this.dragable = false;
27235 process : function(file, crop)
27238 this.maskEl.mask(this.loadingText);
27241 this.xhr = new XMLHttpRequest();
27243 file.xhr = this.xhr;
27245 this.xhr.open(this.method, this.url, true);
27248 "Accept": "application/json",
27249 "Cache-Control": "no-cache",
27250 "X-Requested-With": "XMLHttpRequest"
27253 for (var headerName in headers) {
27254 var headerValue = headers[headerName];
27256 this.xhr.setRequestHeader(headerName, headerValue);
27262 this.xhr.onload = function()
27264 _this.xhrOnLoad(_this.xhr);
27267 this.xhr.onerror = function()
27269 _this.xhrOnError(_this.xhr);
27272 var formData = new FormData();
27274 formData.append('returnHTML', 'NO');
27277 formData.append('crop', crop);
27280 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27281 formData.append(this.paramName, file, file.name);
27284 if(typeof(file.filename) != 'undefined'){
27285 formData.append('filename', file.filename);
27288 if(typeof(file.mimetype) != 'undefined'){
27289 formData.append('mimetype', file.mimetype);
27292 if(this.fireEvent('arrange', this, formData) != false){
27293 this.xhr.send(formData);
27297 xhrOnLoad : function(xhr)
27300 this.maskEl.unmask();
27303 if (xhr.readyState !== 4) {
27304 this.fireEvent('exception', this, xhr);
27308 var response = Roo.decode(xhr.responseText);
27310 if(!response.success){
27311 this.fireEvent('exception', this, xhr);
27315 var response = Roo.decode(xhr.responseText);
27317 this.fireEvent('upload', this, response);
27321 xhrOnError : function()
27324 this.maskEl.unmask();
27327 Roo.log('xhr on error');
27329 var response = Roo.decode(xhr.responseText);
27335 prepare : function(file)
27338 this.maskEl.mask(this.loadingText);
27344 if(typeof(file) === 'string'){
27345 this.loadCanvas(file);
27349 if(!file || !this.urlAPI){
27354 this.cropType = file.type;
27358 if(this.fireEvent('prepare', this, this.file) != false){
27360 var reader = new FileReader();
27362 reader.onload = function (e) {
27363 if (e.target.error) {
27364 Roo.log(e.target.error);
27368 var buffer = e.target.result,
27369 dataView = new DataView(buffer),
27371 maxOffset = dataView.byteLength - 4,
27375 if (dataView.getUint16(0) === 0xffd8) {
27376 while (offset < maxOffset) {
27377 markerBytes = dataView.getUint16(offset);
27379 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27380 markerLength = dataView.getUint16(offset + 2) + 2;
27381 if (offset + markerLength > dataView.byteLength) {
27382 Roo.log('Invalid meta data: Invalid segment size.');
27386 if(markerBytes == 0xffe1){
27387 _this.parseExifData(
27394 offset += markerLength;
27404 var url = _this.urlAPI.createObjectURL(_this.file);
27406 _this.loadCanvas(url);
27411 reader.readAsArrayBuffer(this.file);
27417 parseExifData : function(dataView, offset, length)
27419 var tiffOffset = offset + 10,
27423 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27424 // No Exif data, might be XMP data instead
27428 // Check for the ASCII code for "Exif" (0x45786966):
27429 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27430 // No Exif data, might be XMP data instead
27433 if (tiffOffset + 8 > dataView.byteLength) {
27434 Roo.log('Invalid Exif data: Invalid segment size.');
27437 // Check for the two null bytes:
27438 if (dataView.getUint16(offset + 8) !== 0x0000) {
27439 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27442 // Check the byte alignment:
27443 switch (dataView.getUint16(tiffOffset)) {
27445 littleEndian = true;
27448 littleEndian = false;
27451 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27454 // Check for the TIFF tag marker (0x002A):
27455 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27456 Roo.log('Invalid Exif data: Missing TIFF marker.');
27459 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27460 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27462 this.parseExifTags(
27465 tiffOffset + dirOffset,
27470 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27475 if (dirOffset + 6 > dataView.byteLength) {
27476 Roo.log('Invalid Exif data: Invalid directory offset.');
27479 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27480 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27481 if (dirEndOffset + 4 > dataView.byteLength) {
27482 Roo.log('Invalid Exif data: Invalid directory size.');
27485 for (i = 0; i < tagsNumber; i += 1) {
27489 dirOffset + 2 + 12 * i, // tag offset
27493 // Return the offset to the next directory:
27494 return dataView.getUint32(dirEndOffset, littleEndian);
27497 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27499 var tag = dataView.getUint16(offset, littleEndian);
27501 this.exif[tag] = this.getExifValue(
27505 dataView.getUint16(offset + 2, littleEndian), // tag type
27506 dataView.getUint32(offset + 4, littleEndian), // tag length
27511 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27513 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27522 Roo.log('Invalid Exif data: Invalid tag type.');
27526 tagSize = tagType.size * length;
27527 // Determine if the value is contained in the dataOffset bytes,
27528 // or if the value at the dataOffset is a pointer to the actual data:
27529 dataOffset = tagSize > 4 ?
27530 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27531 if (dataOffset + tagSize > dataView.byteLength) {
27532 Roo.log('Invalid Exif data: Invalid data offset.');
27535 if (length === 1) {
27536 return tagType.getValue(dataView, dataOffset, littleEndian);
27539 for (i = 0; i < length; i += 1) {
27540 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27543 if (tagType.ascii) {
27545 // Concatenate the chars:
27546 for (i = 0; i < values.length; i += 1) {
27548 // Ignore the terminating NULL byte(s):
27549 if (c === '\u0000') {
27561 Roo.apply(Roo.bootstrap.UploadCropbox, {
27563 'Orientation': 0x0112
27567 1: 0, //'top-left',
27569 3: 180, //'bottom-right',
27570 // 4: 'bottom-left',
27572 6: 90, //'right-top',
27573 // 7: 'right-bottom',
27574 8: 270 //'left-bottom'
27578 // byte, 8-bit unsigned int:
27580 getValue: function (dataView, dataOffset) {
27581 return dataView.getUint8(dataOffset);
27585 // ascii, 8-bit byte:
27587 getValue: function (dataView, dataOffset) {
27588 return String.fromCharCode(dataView.getUint8(dataOffset));
27593 // short, 16 bit int:
27595 getValue: function (dataView, dataOffset, littleEndian) {
27596 return dataView.getUint16(dataOffset, littleEndian);
27600 // long, 32 bit int:
27602 getValue: function (dataView, dataOffset, littleEndian) {
27603 return dataView.getUint32(dataOffset, littleEndian);
27607 // rational = two long values, first is numerator, second is denominator:
27609 getValue: function (dataView, dataOffset, littleEndian) {
27610 return dataView.getUint32(dataOffset, littleEndian) /
27611 dataView.getUint32(dataOffset + 4, littleEndian);
27615 // slong, 32 bit signed int:
27617 getValue: function (dataView, dataOffset, littleEndian) {
27618 return dataView.getInt32(dataOffset, littleEndian);
27622 // srational, two slongs, first is numerator, second is denominator:
27624 getValue: function (dataView, dataOffset, littleEndian) {
27625 return dataView.getInt32(dataOffset, littleEndian) /
27626 dataView.getInt32(dataOffset + 4, littleEndian);
27636 cls : 'btn-group roo-upload-cropbox-rotate-left',
27637 action : 'rotate-left',
27641 cls : 'btn btn-default',
27642 html : '<i class="fa fa-undo"></i>'
27648 cls : 'btn-group roo-upload-cropbox-picture',
27649 action : 'picture',
27653 cls : 'btn btn-default',
27654 html : '<i class="fa fa-picture-o"></i>'
27660 cls : 'btn-group roo-upload-cropbox-rotate-right',
27661 action : 'rotate-right',
27665 cls : 'btn btn-default',
27666 html : '<i class="fa fa-repeat"></i>'
27674 cls : 'btn-group roo-upload-cropbox-rotate-left',
27675 action : 'rotate-left',
27679 cls : 'btn btn-default',
27680 html : '<i class="fa fa-undo"></i>'
27686 cls : 'btn-group roo-upload-cropbox-download',
27687 action : 'download',
27691 cls : 'btn btn-default',
27692 html : '<i class="fa fa-download"></i>'
27698 cls : 'btn-group roo-upload-cropbox-crop',
27703 cls : 'btn btn-default',
27704 html : '<i class="fa fa-crop"></i>'
27710 cls : 'btn-group roo-upload-cropbox-trash',
27715 cls : 'btn btn-default',
27716 html : '<i class="fa fa-trash"></i>'
27722 cls : 'btn-group roo-upload-cropbox-rotate-right',
27723 action : 'rotate-right',
27727 cls : 'btn btn-default',
27728 html : '<i class="fa fa-repeat"></i>'
27736 cls : 'btn-group roo-upload-cropbox-rotate-left',
27737 action : 'rotate-left',
27741 cls : 'btn btn-default',
27742 html : '<i class="fa fa-undo"></i>'
27748 cls : 'btn-group roo-upload-cropbox-rotate-right',
27749 action : 'rotate-right',
27753 cls : 'btn btn-default',
27754 html : '<i class="fa fa-repeat"></i>'
27767 * @class Roo.bootstrap.DocumentManager
27768 * @extends Roo.bootstrap.Component
27769 * Bootstrap DocumentManager class
27770 * @cfg {String} paramName default 'imageUpload'
27771 * @cfg {String} toolTipName default 'filename'
27772 * @cfg {String} method default POST
27773 * @cfg {String} url action url
27774 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27775 * @cfg {Boolean} multiple multiple upload default true
27776 * @cfg {Number} thumbSize default 300
27777 * @cfg {String} fieldLabel
27778 * @cfg {Number} labelWidth default 4
27779 * @cfg {String} labelAlign (left|top) default left
27780 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27781 * @cfg {Number} labellg set the width of label (1-12)
27782 * @cfg {Number} labelmd set the width of label (1-12)
27783 * @cfg {Number} labelsm set the width of label (1-12)
27784 * @cfg {Number} labelxs set the width of label (1-12)
27787 * Create a new DocumentManager
27788 * @param {Object} config The config object
27791 Roo.bootstrap.DocumentManager = function(config){
27792 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27795 this.delegates = [];
27800 * Fire when initial the DocumentManager
27801 * @param {Roo.bootstrap.DocumentManager} this
27806 * inspect selected file
27807 * @param {Roo.bootstrap.DocumentManager} this
27808 * @param {File} file
27813 * Fire when xhr load exception
27814 * @param {Roo.bootstrap.DocumentManager} this
27815 * @param {XMLHttpRequest} xhr
27817 "exception" : true,
27819 * @event afterupload
27820 * Fire when xhr load exception
27821 * @param {Roo.bootstrap.DocumentManager} this
27822 * @param {XMLHttpRequest} xhr
27824 "afterupload" : true,
27827 * prepare the form data
27828 * @param {Roo.bootstrap.DocumentManager} this
27829 * @param {Object} formData
27834 * Fire when remove the file
27835 * @param {Roo.bootstrap.DocumentManager} this
27836 * @param {Object} file
27841 * Fire after refresh the file
27842 * @param {Roo.bootstrap.DocumentManager} this
27847 * Fire after click the image
27848 * @param {Roo.bootstrap.DocumentManager} this
27849 * @param {Object} file
27854 * Fire when upload a image and editable set to true
27855 * @param {Roo.bootstrap.DocumentManager} this
27856 * @param {Object} file
27860 * @event beforeselectfile
27861 * Fire before select file
27862 * @param {Roo.bootstrap.DocumentManager} this
27864 "beforeselectfile" : true,
27867 * Fire before process file
27868 * @param {Roo.bootstrap.DocumentManager} this
27869 * @param {Object} file
27876 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27885 paramName : 'imageUpload',
27886 toolTipName : 'filename',
27889 labelAlign : 'left',
27899 getAutoCreate : function()
27901 var managerWidget = {
27903 cls : 'roo-document-manager',
27907 cls : 'roo-document-manager-selector',
27912 cls : 'roo-document-manager-uploader',
27916 cls : 'roo-document-manager-upload-btn',
27917 html : '<i class="fa fa-plus"></i>'
27928 cls : 'column col-md-12',
27933 if(this.fieldLabel.length){
27938 cls : 'column col-md-12',
27939 html : this.fieldLabel
27943 cls : 'column col-md-12',
27948 if(this.labelAlign == 'left'){
27953 html : this.fieldLabel
27962 if(this.labelWidth > 12){
27963 content[0].style = "width: " + this.labelWidth + 'px';
27966 if(this.labelWidth < 13 && this.labelmd == 0){
27967 this.labelmd = this.labelWidth;
27970 if(this.labellg > 0){
27971 content[0].cls += ' col-lg-' + this.labellg;
27972 content[1].cls += ' col-lg-' + (12 - this.labellg);
27975 if(this.labelmd > 0){
27976 content[0].cls += ' col-md-' + this.labelmd;
27977 content[1].cls += ' col-md-' + (12 - this.labelmd);
27980 if(this.labelsm > 0){
27981 content[0].cls += ' col-sm-' + this.labelsm;
27982 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27985 if(this.labelxs > 0){
27986 content[0].cls += ' col-xs-' + this.labelxs;
27987 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27995 cls : 'row clearfix',
28003 initEvents : function()
28005 this.managerEl = this.el.select('.roo-document-manager', true).first();
28006 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28008 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28009 this.selectorEl.hide();
28012 this.selectorEl.attr('multiple', 'multiple');
28015 this.selectorEl.on('change', this.onFileSelected, this);
28017 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28018 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28020 this.uploader.on('click', this.onUploaderClick, this);
28022 this.renderProgressDialog();
28026 window.addEventListener("resize", function() { _this.refresh(); } );
28028 this.fireEvent('initial', this);
28031 renderProgressDialog : function()
28035 this.progressDialog = new Roo.bootstrap.Modal({
28036 cls : 'roo-document-manager-progress-dialog',
28037 allow_close : false,
28047 btnclick : function() {
28048 _this.uploadCancel();
28054 this.progressDialog.render(Roo.get(document.body));
28056 this.progress = new Roo.bootstrap.Progress({
28057 cls : 'roo-document-manager-progress',
28062 this.progress.render(this.progressDialog.getChildContainer());
28064 this.progressBar = new Roo.bootstrap.ProgressBar({
28065 cls : 'roo-document-manager-progress-bar',
28068 aria_valuemax : 12,
28072 this.progressBar.render(this.progress.getChildContainer());
28075 onUploaderClick : function(e)
28077 e.preventDefault();
28079 if(this.fireEvent('beforeselectfile', this) != false){
28080 this.selectorEl.dom.click();
28085 onFileSelected : function(e)
28087 e.preventDefault();
28089 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28093 Roo.each(this.selectorEl.dom.files, function(file){
28094 if(this.fireEvent('inspect', this, file) != false){
28095 this.files.push(file);
28105 this.selectorEl.dom.value = '';
28107 if(!this.files.length){
28111 if(this.boxes > 0 && this.files.length > this.boxes){
28112 this.files = this.files.slice(0, this.boxes);
28115 this.uploader.show();
28117 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28118 this.uploader.hide();
28127 Roo.each(this.files, function(file){
28129 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28130 var f = this.renderPreview(file);
28135 if(file.type.indexOf('image') != -1){
28136 this.delegates.push(
28138 _this.process(file);
28139 }).createDelegate(this)
28147 _this.process(file);
28148 }).createDelegate(this)
28153 this.files = files;
28155 this.delegates = this.delegates.concat(docs);
28157 if(!this.delegates.length){
28162 this.progressBar.aria_valuemax = this.delegates.length;
28169 arrange : function()
28171 if(!this.delegates.length){
28172 this.progressDialog.hide();
28177 var delegate = this.delegates.shift();
28179 this.progressDialog.show();
28181 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28183 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28188 refresh : function()
28190 this.uploader.show();
28192 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28193 this.uploader.hide();
28196 Roo.isTouch ? this.closable(false) : this.closable(true);
28198 this.fireEvent('refresh', this);
28201 onRemove : function(e, el, o)
28203 e.preventDefault();
28205 this.fireEvent('remove', this, o);
28209 remove : function(o)
28213 Roo.each(this.files, function(file){
28214 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28223 this.files = files;
28230 Roo.each(this.files, function(file){
28235 file.target.remove();
28244 onClick : function(e, el, o)
28246 e.preventDefault();
28248 this.fireEvent('click', this, o);
28252 closable : function(closable)
28254 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28256 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28268 xhrOnLoad : function(xhr)
28270 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28274 if (xhr.readyState !== 4) {
28276 this.fireEvent('exception', this, xhr);
28280 var response = Roo.decode(xhr.responseText);
28282 if(!response.success){
28284 this.fireEvent('exception', this, xhr);
28288 var file = this.renderPreview(response.data);
28290 this.files.push(file);
28294 this.fireEvent('afterupload', this, xhr);
28298 xhrOnError : function(xhr)
28300 Roo.log('xhr on error');
28302 var response = Roo.decode(xhr.responseText);
28309 process : function(file)
28311 if(this.fireEvent('process', this, file) !== false){
28312 if(this.editable && file.type.indexOf('image') != -1){
28313 this.fireEvent('edit', this, file);
28317 this.uploadStart(file, false);
28324 uploadStart : function(file, crop)
28326 this.xhr = new XMLHttpRequest();
28328 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28333 file.xhr = this.xhr;
28335 this.managerEl.createChild({
28337 cls : 'roo-document-manager-loading',
28341 tooltip : file.name,
28342 cls : 'roo-document-manager-thumb',
28343 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28349 this.xhr.open(this.method, this.url, true);
28352 "Accept": "application/json",
28353 "Cache-Control": "no-cache",
28354 "X-Requested-With": "XMLHttpRequest"
28357 for (var headerName in headers) {
28358 var headerValue = headers[headerName];
28360 this.xhr.setRequestHeader(headerName, headerValue);
28366 this.xhr.onload = function()
28368 _this.xhrOnLoad(_this.xhr);
28371 this.xhr.onerror = function()
28373 _this.xhrOnError(_this.xhr);
28376 var formData = new FormData();
28378 formData.append('returnHTML', 'NO');
28381 formData.append('crop', crop);
28384 formData.append(this.paramName, file, file.name);
28391 if(this.fireEvent('prepare', this, formData, options) != false){
28393 if(options.manually){
28397 this.xhr.send(formData);
28401 this.uploadCancel();
28404 uploadCancel : function()
28410 this.delegates = [];
28412 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28419 renderPreview : function(file)
28421 if(typeof(file.target) != 'undefined' && file.target){
28425 var previewEl = this.managerEl.createChild({
28427 cls : 'roo-document-manager-preview',
28431 tooltip : file[this.toolTipName],
28432 cls : 'roo-document-manager-thumb',
28433 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28438 html : '<i class="fa fa-times-circle"></i>'
28443 var close = previewEl.select('button.close', true).first();
28445 close.on('click', this.onRemove, this, file);
28447 file.target = previewEl;
28449 var image = previewEl.select('img', true).first();
28453 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28455 image.on('click', this.onClick, this, file);
28461 onPreviewLoad : function(file, image)
28463 if(typeof(file.target) == 'undefined' || !file.target){
28467 var width = image.dom.naturalWidth || image.dom.width;
28468 var height = image.dom.naturalHeight || image.dom.height;
28470 if(width > height){
28471 file.target.addClass('wide');
28475 file.target.addClass('tall');
28480 uploadFromSource : function(file, crop)
28482 this.xhr = new XMLHttpRequest();
28484 this.managerEl.createChild({
28486 cls : 'roo-document-manager-loading',
28490 tooltip : file.name,
28491 cls : 'roo-document-manager-thumb',
28492 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28498 this.xhr.open(this.method, this.url, true);
28501 "Accept": "application/json",
28502 "Cache-Control": "no-cache",
28503 "X-Requested-With": "XMLHttpRequest"
28506 for (var headerName in headers) {
28507 var headerValue = headers[headerName];
28509 this.xhr.setRequestHeader(headerName, headerValue);
28515 this.xhr.onload = function()
28517 _this.xhrOnLoad(_this.xhr);
28520 this.xhr.onerror = function()
28522 _this.xhrOnError(_this.xhr);
28525 var formData = new FormData();
28527 formData.append('returnHTML', 'NO');
28529 formData.append('crop', crop);
28531 if(typeof(file.filename) != 'undefined'){
28532 formData.append('filename', file.filename);
28535 if(typeof(file.mimetype) != 'undefined'){
28536 formData.append('mimetype', file.mimetype);
28541 if(this.fireEvent('prepare', this, formData) != false){
28542 this.xhr.send(formData);
28552 * @class Roo.bootstrap.DocumentViewer
28553 * @extends Roo.bootstrap.Component
28554 * Bootstrap DocumentViewer class
28555 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28556 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28559 * Create a new DocumentViewer
28560 * @param {Object} config The config object
28563 Roo.bootstrap.DocumentViewer = function(config){
28564 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28569 * Fire after initEvent
28570 * @param {Roo.bootstrap.DocumentViewer} this
28576 * @param {Roo.bootstrap.DocumentViewer} this
28581 * Fire after download button
28582 * @param {Roo.bootstrap.DocumentViewer} this
28587 * Fire after trash button
28588 * @param {Roo.bootstrap.DocumentViewer} this
28595 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28597 showDownload : true,
28601 getAutoCreate : function()
28605 cls : 'roo-document-viewer',
28609 cls : 'roo-document-viewer-body',
28613 cls : 'roo-document-viewer-thumb',
28617 cls : 'roo-document-viewer-image'
28625 cls : 'roo-document-viewer-footer',
28628 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28632 cls : 'btn-group roo-document-viewer-download',
28636 cls : 'btn btn-default',
28637 html : '<i class="fa fa-download"></i>'
28643 cls : 'btn-group roo-document-viewer-trash',
28647 cls : 'btn btn-default',
28648 html : '<i class="fa fa-trash"></i>'
28661 initEvents : function()
28663 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28664 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28666 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28667 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28669 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28670 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28672 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28673 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28675 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28676 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28678 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28679 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28681 this.bodyEl.on('click', this.onClick, this);
28682 this.downloadBtn.on('click', this.onDownload, this);
28683 this.trashBtn.on('click', this.onTrash, this);
28685 this.downloadBtn.hide();
28686 this.trashBtn.hide();
28688 if(this.showDownload){
28689 this.downloadBtn.show();
28692 if(this.showTrash){
28693 this.trashBtn.show();
28696 if(!this.showDownload && !this.showTrash) {
28697 this.footerEl.hide();
28702 initial : function()
28704 this.fireEvent('initial', this);
28708 onClick : function(e)
28710 e.preventDefault();
28712 this.fireEvent('click', this);
28715 onDownload : function(e)
28717 e.preventDefault();
28719 this.fireEvent('download', this);
28722 onTrash : function(e)
28724 e.preventDefault();
28726 this.fireEvent('trash', this);
28738 * @class Roo.bootstrap.NavProgressBar
28739 * @extends Roo.bootstrap.Component
28740 * Bootstrap NavProgressBar class
28743 * Create a new nav progress bar
28744 * @param {Object} config The config object
28747 Roo.bootstrap.NavProgressBar = function(config){
28748 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28750 this.bullets = this.bullets || [];
28752 // Roo.bootstrap.NavProgressBar.register(this);
28756 * Fires when the active item changes
28757 * @param {Roo.bootstrap.NavProgressBar} this
28758 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28759 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28766 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28771 getAutoCreate : function()
28773 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28777 cls : 'roo-navigation-bar-group',
28781 cls : 'roo-navigation-top-bar'
28785 cls : 'roo-navigation-bullets-bar',
28789 cls : 'roo-navigation-bar'
28796 cls : 'roo-navigation-bottom-bar'
28806 initEvents: function()
28811 onRender : function(ct, position)
28813 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28815 if(this.bullets.length){
28816 Roo.each(this.bullets, function(b){
28825 addItem : function(cfg)
28827 var item = new Roo.bootstrap.NavProgressItem(cfg);
28829 item.parentId = this.id;
28830 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28833 var top = new Roo.bootstrap.Element({
28835 cls : 'roo-navigation-bar-text'
28838 var bottom = new Roo.bootstrap.Element({
28840 cls : 'roo-navigation-bar-text'
28843 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28844 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28846 var topText = new Roo.bootstrap.Element({
28848 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28851 var bottomText = new Roo.bootstrap.Element({
28853 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28856 topText.onRender(top.el, null);
28857 bottomText.onRender(bottom.el, null);
28860 item.bottomEl = bottom;
28863 this.barItems.push(item);
28868 getActive : function()
28870 var active = false;
28872 Roo.each(this.barItems, function(v){
28874 if (!v.isActive()) {
28886 setActiveItem : function(item)
28890 Roo.each(this.barItems, function(v){
28891 if (v.rid == item.rid) {
28895 if (v.isActive()) {
28896 v.setActive(false);
28901 item.setActive(true);
28903 this.fireEvent('changed', this, item, prev);
28906 getBarItem: function(rid)
28910 Roo.each(this.barItems, function(e) {
28911 if (e.rid != rid) {
28922 indexOfItem : function(item)
28926 Roo.each(this.barItems, function(v, i){
28928 if (v.rid != item.rid) {
28939 setActiveNext : function()
28941 var i = this.indexOfItem(this.getActive());
28943 if (i > this.barItems.length) {
28947 this.setActiveItem(this.barItems[i+1]);
28950 setActivePrev : function()
28952 var i = this.indexOfItem(this.getActive());
28958 this.setActiveItem(this.barItems[i-1]);
28961 format : function()
28963 if(!this.barItems.length){
28967 var width = 100 / this.barItems.length;
28969 Roo.each(this.barItems, function(i){
28970 i.el.setStyle('width', width + '%');
28971 i.topEl.el.setStyle('width', width + '%');
28972 i.bottomEl.el.setStyle('width', width + '%');
28981 * Nav Progress Item
28986 * @class Roo.bootstrap.NavProgressItem
28987 * @extends Roo.bootstrap.Component
28988 * Bootstrap NavProgressItem class
28989 * @cfg {String} rid the reference id
28990 * @cfg {Boolean} active (true|false) Is item active default false
28991 * @cfg {Boolean} disabled (true|false) Is item active default false
28992 * @cfg {String} html
28993 * @cfg {String} position (top|bottom) text position default bottom
28994 * @cfg {String} icon show icon instead of number
28997 * Create a new NavProgressItem
28998 * @param {Object} config The config object
29000 Roo.bootstrap.NavProgressItem = function(config){
29001 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29006 * The raw click event for the entire grid.
29007 * @param {Roo.bootstrap.NavProgressItem} this
29008 * @param {Roo.EventObject} e
29015 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29021 position : 'bottom',
29024 getAutoCreate : function()
29026 var iconCls = 'roo-navigation-bar-item-icon';
29028 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29032 cls: 'roo-navigation-bar-item',
29042 cfg.cls += ' active';
29045 cfg.cls += ' disabled';
29051 disable : function()
29053 this.setDisabled(true);
29056 enable : function()
29058 this.setDisabled(false);
29061 initEvents: function()
29063 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29065 this.iconEl.on('click', this.onClick, this);
29068 onClick : function(e)
29070 e.preventDefault();
29076 if(this.fireEvent('click', this, e) === false){
29080 this.parent().setActiveItem(this);
29083 isActive: function ()
29085 return this.active;
29088 setActive : function(state)
29090 if(this.active == state){
29094 this.active = state;
29097 this.el.addClass('active');
29101 this.el.removeClass('active');
29106 setDisabled : function(state)
29108 if(this.disabled == state){
29112 this.disabled = state;
29115 this.el.addClass('disabled');
29119 this.el.removeClass('disabled');
29122 tooltipEl : function()
29124 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29137 * @class Roo.bootstrap.FieldLabel
29138 * @extends Roo.bootstrap.Component
29139 * Bootstrap FieldLabel class
29140 * @cfg {String} html contents of the element
29141 * @cfg {String} tag tag of the element default label
29142 * @cfg {String} cls class of the element
29143 * @cfg {String} target label target
29144 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29145 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29146 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29147 * @cfg {String} iconTooltip default "This field is required"
29150 * Create a new FieldLabel
29151 * @param {Object} config The config object
29154 Roo.bootstrap.FieldLabel = function(config){
29155 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29160 * Fires after the field has been marked as invalid.
29161 * @param {Roo.form.FieldLabel} this
29162 * @param {String} msg The validation message
29167 * Fires after the field has been validated with no errors.
29168 * @param {Roo.form.FieldLabel} this
29174 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29181 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29182 validClass : 'text-success fa fa-lg fa-check',
29183 iconTooltip : 'This field is required',
29185 getAutoCreate : function(){
29189 cls : 'roo-bootstrap-field-label ' + this.cls,
29195 tooltip : this.iconTooltip
29207 initEvents: function()
29209 Roo.bootstrap.Element.superclass.initEvents.call(this);
29211 this.iconEl = this.el.select('i', true).first();
29213 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29215 Roo.bootstrap.FieldLabel.register(this);
29219 * Mark this field as valid
29221 markValid : function()
29223 this.iconEl.show();
29225 this.iconEl.removeClass(this.invalidClass);
29227 this.iconEl.addClass(this.validClass);
29229 this.fireEvent('valid', this);
29233 * Mark this field as invalid
29234 * @param {String} msg The validation message
29236 markInvalid : function(msg)
29238 this.iconEl.show();
29240 this.iconEl.removeClass(this.validClass);
29242 this.iconEl.addClass(this.invalidClass);
29244 this.fireEvent('invalid', this, msg);
29250 Roo.apply(Roo.bootstrap.FieldLabel, {
29255 * register a FieldLabel Group
29256 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29258 register : function(label)
29260 if(this.groups.hasOwnProperty(label.target)){
29264 this.groups[label.target] = label;
29268 * fetch a FieldLabel Group based on the target
29269 * @param {string} target
29270 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29272 get: function(target) {
29273 if (typeof(this.groups[target]) == 'undefined') {
29277 return this.groups[target] ;
29286 * page DateSplitField.
29292 * @class Roo.bootstrap.DateSplitField
29293 * @extends Roo.bootstrap.Component
29294 * Bootstrap DateSplitField class
29295 * @cfg {string} fieldLabel - the label associated
29296 * @cfg {Number} labelWidth set the width of label (0-12)
29297 * @cfg {String} labelAlign (top|left)
29298 * @cfg {Boolean} dayAllowBlank (true|false) default false
29299 * @cfg {Boolean} monthAllowBlank (true|false) default false
29300 * @cfg {Boolean} yearAllowBlank (true|false) default false
29301 * @cfg {string} dayPlaceholder
29302 * @cfg {string} monthPlaceholder
29303 * @cfg {string} yearPlaceholder
29304 * @cfg {string} dayFormat default 'd'
29305 * @cfg {string} monthFormat default 'm'
29306 * @cfg {string} yearFormat default 'Y'
29307 * @cfg {Number} labellg set the width of label (1-12)
29308 * @cfg {Number} labelmd set the width of label (1-12)
29309 * @cfg {Number} labelsm set the width of label (1-12)
29310 * @cfg {Number} labelxs set the width of label (1-12)
29314 * Create a new DateSplitField
29315 * @param {Object} config The config object
29318 Roo.bootstrap.DateSplitField = function(config){
29319 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29325 * getting the data of years
29326 * @param {Roo.bootstrap.DateSplitField} this
29327 * @param {Object} years
29332 * getting the data of days
29333 * @param {Roo.bootstrap.DateSplitField} this
29334 * @param {Object} days
29339 * Fires after the field has been marked as invalid.
29340 * @param {Roo.form.Field} this
29341 * @param {String} msg The validation message
29346 * Fires after the field has been validated with no errors.
29347 * @param {Roo.form.Field} this
29353 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29356 labelAlign : 'top',
29358 dayAllowBlank : false,
29359 monthAllowBlank : false,
29360 yearAllowBlank : false,
29361 dayPlaceholder : '',
29362 monthPlaceholder : '',
29363 yearPlaceholder : '',
29367 isFormField : true,
29373 getAutoCreate : function()
29377 cls : 'row roo-date-split-field-group',
29382 cls : 'form-hidden-field roo-date-split-field-group-value',
29388 var labelCls = 'col-md-12';
29389 var contentCls = 'col-md-4';
29391 if(this.fieldLabel){
29395 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29399 html : this.fieldLabel
29404 if(this.labelAlign == 'left'){
29406 if(this.labelWidth > 12){
29407 label.style = "width: " + this.labelWidth + 'px';
29410 if(this.labelWidth < 13 && this.labelmd == 0){
29411 this.labelmd = this.labelWidth;
29414 if(this.labellg > 0){
29415 labelCls = ' col-lg-' + this.labellg;
29416 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29419 if(this.labelmd > 0){
29420 labelCls = ' col-md-' + this.labelmd;
29421 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29424 if(this.labelsm > 0){
29425 labelCls = ' col-sm-' + this.labelsm;
29426 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29429 if(this.labelxs > 0){
29430 labelCls = ' col-xs-' + this.labelxs;
29431 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29435 label.cls += ' ' + labelCls;
29437 cfg.cn.push(label);
29440 Roo.each(['day', 'month', 'year'], function(t){
29443 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29450 inputEl: function ()
29452 return this.el.select('.roo-date-split-field-group-value', true).first();
29455 onRender : function(ct, position)
29459 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29461 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29463 this.dayField = new Roo.bootstrap.ComboBox({
29464 allowBlank : this.dayAllowBlank,
29465 alwaysQuery : true,
29466 displayField : 'value',
29469 forceSelection : true,
29471 placeholder : this.dayPlaceholder,
29472 selectOnFocus : true,
29473 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29474 triggerAction : 'all',
29476 valueField : 'value',
29477 store : new Roo.data.SimpleStore({
29478 data : (function() {
29480 _this.fireEvent('days', _this, days);
29483 fields : [ 'value' ]
29486 select : function (_self, record, index)
29488 _this.setValue(_this.getValue());
29493 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29495 this.monthField = new Roo.bootstrap.MonthField({
29496 after : '<i class=\"fa fa-calendar\"></i>',
29497 allowBlank : this.monthAllowBlank,
29498 placeholder : this.monthPlaceholder,
29501 render : function (_self)
29503 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29504 e.preventDefault();
29508 select : function (_self, oldvalue, newvalue)
29510 _this.setValue(_this.getValue());
29515 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29517 this.yearField = new Roo.bootstrap.ComboBox({
29518 allowBlank : this.yearAllowBlank,
29519 alwaysQuery : true,
29520 displayField : 'value',
29523 forceSelection : true,
29525 placeholder : this.yearPlaceholder,
29526 selectOnFocus : true,
29527 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29528 triggerAction : 'all',
29530 valueField : 'value',
29531 store : new Roo.data.SimpleStore({
29532 data : (function() {
29534 _this.fireEvent('years', _this, years);
29537 fields : [ 'value' ]
29540 select : function (_self, record, index)
29542 _this.setValue(_this.getValue());
29547 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29550 setValue : function(v, format)
29552 this.inputEl.dom.value = v;
29554 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29556 var d = Date.parseDate(v, f);
29563 this.setDay(d.format(this.dayFormat));
29564 this.setMonth(d.format(this.monthFormat));
29565 this.setYear(d.format(this.yearFormat));
29572 setDay : function(v)
29574 this.dayField.setValue(v);
29575 this.inputEl.dom.value = this.getValue();
29580 setMonth : function(v)
29582 this.monthField.setValue(v, true);
29583 this.inputEl.dom.value = this.getValue();
29588 setYear : function(v)
29590 this.yearField.setValue(v);
29591 this.inputEl.dom.value = this.getValue();
29596 getDay : function()
29598 return this.dayField.getValue();
29601 getMonth : function()
29603 return this.monthField.getValue();
29606 getYear : function()
29608 return this.yearField.getValue();
29611 getValue : function()
29613 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29615 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29625 this.inputEl.dom.value = '';
29630 validate : function()
29632 var d = this.dayField.validate();
29633 var m = this.monthField.validate();
29634 var y = this.yearField.validate();
29639 (!this.dayAllowBlank && !d) ||
29640 (!this.monthAllowBlank && !m) ||
29641 (!this.yearAllowBlank && !y)
29646 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29655 this.markInvalid();
29660 markValid : function()
29663 var label = this.el.select('label', true).first();
29664 var icon = this.el.select('i.fa-star', true).first();
29670 this.fireEvent('valid', this);
29674 * Mark this field as invalid
29675 * @param {String} msg The validation message
29677 markInvalid : function(msg)
29680 var label = this.el.select('label', true).first();
29681 var icon = this.el.select('i.fa-star', true).first();
29683 if(label && !icon){
29684 this.el.select('.roo-date-split-field-label', true).createChild({
29686 cls : 'text-danger fa fa-lg fa-star',
29687 tooltip : 'This field is required',
29688 style : 'margin-right:5px;'
29692 this.fireEvent('invalid', this, msg);
29695 clearInvalid : function()
29697 var label = this.el.select('label', true).first();
29698 var icon = this.el.select('i.fa-star', true).first();
29704 this.fireEvent('valid', this);
29707 getName: function()
29717 * http://masonry.desandro.com
29719 * The idea is to render all the bricks based on vertical width...
29721 * The original code extends 'outlayer' - we might need to use that....
29727 * @class Roo.bootstrap.LayoutMasonry
29728 * @extends Roo.bootstrap.Component
29729 * Bootstrap Layout Masonry class
29732 * Create a new Element
29733 * @param {Object} config The config object
29736 Roo.bootstrap.LayoutMasonry = function(config){
29737 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29745 * Fire after layout the items
29746 * @param {Roo.bootstrap.LayoutMasonry} this
29747 * @param {Roo.EventObject} e
29754 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29757 * @cfg {Boolean} isLayoutInstant = no animation?
29759 isLayoutInstant : false, // needed?
29762 * @cfg {Number} boxWidth width of the columns
29767 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29772 * @cfg {Number} padWidth padding below box..
29777 * @cfg {Number} gutter gutter width..
29782 * @cfg {Number} maxCols maximum number of columns
29788 * @cfg {Boolean} isAutoInitial defalut true
29790 isAutoInitial : true,
29795 * @cfg {Boolean} isHorizontal defalut false
29797 isHorizontal : false,
29799 currentSize : null,
29805 bricks: null, //CompositeElement
29809 _isLayoutInited : false,
29811 // isAlternative : false, // only use for vertical layout...
29814 * @cfg {Number} alternativePadWidth padding below box..
29816 alternativePadWidth : 50,
29818 getAutoCreate : function(){
29822 cls: 'blog-masonary-wrapper ' + this.cls,
29824 cls : 'mas-boxes masonary'
29831 getChildContainer: function( )
29833 if (this.boxesEl) {
29834 return this.boxesEl;
29837 this.boxesEl = this.el.select('.mas-boxes').first();
29839 return this.boxesEl;
29843 initEvents : function()
29847 if(this.isAutoInitial){
29848 Roo.log('hook children rendered');
29849 this.on('childrenrendered', function() {
29850 Roo.log('children rendered');
29856 initial : function()
29858 this.currentSize = this.el.getBox(true);
29860 Roo.EventManager.onWindowResize(this.resize, this);
29862 if(!this.isAutoInitial){
29870 //this.layout.defer(500,this);
29874 resize : function()
29876 var cs = this.el.getBox(true);
29879 this.currentSize.width == cs.width &&
29880 this.currentSize.x == cs.x &&
29881 this.currentSize.height == cs.height &&
29882 this.currentSize.y == cs.y
29884 Roo.log("no change in with or X or Y");
29888 this.currentSize = cs;
29894 layout : function()
29896 this._resetLayout();
29898 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29900 this.layoutItems( isInstant );
29902 this._isLayoutInited = true;
29904 this.fireEvent('layout', this);
29908 _resetLayout : function()
29910 if(this.isHorizontal){
29911 this.horizontalMeasureColumns();
29915 this.verticalMeasureColumns();
29919 verticalMeasureColumns : function()
29921 this.getContainerWidth();
29923 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29924 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29928 var boxWidth = this.boxWidth + this.padWidth;
29930 if(this.containerWidth < this.boxWidth){
29931 boxWidth = this.containerWidth
29934 var containerWidth = this.containerWidth;
29936 var cols = Math.floor(containerWidth / boxWidth);
29938 this.cols = Math.max( cols, 1 );
29940 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29942 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29944 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29946 this.colWidth = boxWidth + avail - this.padWidth;
29948 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29949 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29952 horizontalMeasureColumns : function()
29954 this.getContainerWidth();
29956 var boxWidth = this.boxWidth;
29958 if(this.containerWidth < boxWidth){
29959 boxWidth = this.containerWidth;
29962 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29964 this.el.setHeight(boxWidth);
29968 getContainerWidth : function()
29970 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29973 layoutItems : function( isInstant )
29975 var items = Roo.apply([], this.bricks);
29977 if(this.isHorizontal){
29978 this._horizontalLayoutItems( items , isInstant );
29982 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29983 // this._verticalAlternativeLayoutItems( items , isInstant );
29987 this._verticalLayoutItems( items , isInstant );
29991 _verticalLayoutItems : function ( items , isInstant)
29993 if ( !items || !items.length ) {
29998 ['xs', 'xs', 'xs', 'tall'],
29999 ['xs', 'xs', 'tall'],
30000 ['xs', 'xs', 'sm'],
30001 ['xs', 'xs', 'xs'],
30007 ['sm', 'xs', 'xs'],
30011 ['tall', 'xs', 'xs', 'xs'],
30012 ['tall', 'xs', 'xs'],
30024 Roo.each(items, function(item, k){
30026 switch (item.size) {
30027 // these layouts take up a full box,
30038 boxes.push([item]);
30061 var filterPattern = function(box, length)
30069 var pattern = box.slice(0, length);
30073 Roo.each(pattern, function(i){
30074 format.push(i.size);
30077 Roo.each(standard, function(s){
30079 if(String(s) != String(format)){
30088 if(!match && length == 1){
30093 filterPattern(box, length - 1);
30097 queue.push(pattern);
30099 box = box.slice(length, box.length);
30101 filterPattern(box, 4);
30107 Roo.each(boxes, function(box, k){
30113 if(box.length == 1){
30118 filterPattern(box, 4);
30122 this._processVerticalLayoutQueue( queue, isInstant );
30126 // _verticalAlternativeLayoutItems : function( items , isInstant )
30128 // if ( !items || !items.length ) {
30132 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30136 _horizontalLayoutItems : function ( items , isInstant)
30138 if ( !items || !items.length || items.length < 3) {
30144 var eItems = items.slice(0, 3);
30146 items = items.slice(3, items.length);
30149 ['xs', 'xs', 'xs', 'wide'],
30150 ['xs', 'xs', 'wide'],
30151 ['xs', 'xs', 'sm'],
30152 ['xs', 'xs', 'xs'],
30158 ['sm', 'xs', 'xs'],
30162 ['wide', 'xs', 'xs', 'xs'],
30163 ['wide', 'xs', 'xs'],
30176 Roo.each(items, function(item, k){
30178 switch (item.size) {
30189 boxes.push([item]);
30213 var filterPattern = function(box, length)
30221 var pattern = box.slice(0, length);
30225 Roo.each(pattern, function(i){
30226 format.push(i.size);
30229 Roo.each(standard, function(s){
30231 if(String(s) != String(format)){
30240 if(!match && length == 1){
30245 filterPattern(box, length - 1);
30249 queue.push(pattern);
30251 box = box.slice(length, box.length);
30253 filterPattern(box, 4);
30259 Roo.each(boxes, function(box, k){
30265 if(box.length == 1){
30270 filterPattern(box, 4);
30277 var pos = this.el.getBox(true);
30281 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30283 var hit_end = false;
30285 Roo.each(queue, function(box){
30289 Roo.each(box, function(b){
30291 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30301 Roo.each(box, function(b){
30303 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30306 mx = Math.max(mx, b.x);
30310 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30314 Roo.each(box, function(b){
30316 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30330 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30333 /** Sets position of item in DOM
30334 * @param {Element} item
30335 * @param {Number} x - horizontal position
30336 * @param {Number} y - vertical position
30337 * @param {Boolean} isInstant - disables transitions
30339 _processVerticalLayoutQueue : function( queue, isInstant )
30341 var pos = this.el.getBox(true);
30346 for (var i = 0; i < this.cols; i++){
30350 Roo.each(queue, function(box, k){
30352 var col = k % this.cols;
30354 Roo.each(box, function(b,kk){
30356 b.el.position('absolute');
30358 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30359 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30361 if(b.size == 'md-left' || b.size == 'md-right'){
30362 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30363 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30366 b.el.setWidth(width);
30367 b.el.setHeight(height);
30369 b.el.select('iframe',true).setSize(width,height);
30373 for (var i = 0; i < this.cols; i++){
30375 if(maxY[i] < maxY[col]){
30380 col = Math.min(col, i);
30384 x = pos.x + col * (this.colWidth + this.padWidth);
30388 var positions = [];
30390 switch (box.length){
30392 positions = this.getVerticalOneBoxColPositions(x, y, box);
30395 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30398 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30401 positions = this.getVerticalFourBoxColPositions(x, y, box);
30407 Roo.each(box, function(b,kk){
30409 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30411 var sz = b.el.getSize();
30413 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30421 for (var i = 0; i < this.cols; i++){
30422 mY = Math.max(mY, maxY[i]);
30425 this.el.setHeight(mY - pos.y);
30429 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30431 // var pos = this.el.getBox(true);
30434 // var maxX = pos.right;
30436 // var maxHeight = 0;
30438 // Roo.each(items, function(item, k){
30442 // item.el.position('absolute');
30444 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30446 // item.el.setWidth(width);
30448 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30450 // item.el.setHeight(height);
30453 // item.el.setXY([x, y], isInstant ? false : true);
30455 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30458 // y = y + height + this.alternativePadWidth;
30460 // maxHeight = maxHeight + height + this.alternativePadWidth;
30464 // this.el.setHeight(maxHeight);
30468 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30470 var pos = this.el.getBox(true);
30475 var maxX = pos.right;
30477 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30479 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30481 Roo.each(queue, function(box, k){
30483 Roo.each(box, function(b, kk){
30485 b.el.position('absolute');
30487 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30488 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30490 if(b.size == 'md-left' || b.size == 'md-right'){
30491 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30492 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30495 b.el.setWidth(width);
30496 b.el.setHeight(height);
30504 var positions = [];
30506 switch (box.length){
30508 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30511 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30514 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30517 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30523 Roo.each(box, function(b,kk){
30525 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30527 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30535 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30537 Roo.each(eItems, function(b,k){
30539 b.size = (k == 0) ? 'sm' : 'xs';
30540 b.x = (k == 0) ? 2 : 1;
30541 b.y = (k == 0) ? 2 : 1;
30543 b.el.position('absolute');
30545 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30547 b.el.setWidth(width);
30549 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30551 b.el.setHeight(height);
30555 var positions = [];
30558 x : maxX - this.unitWidth * 2 - this.gutter,
30563 x : maxX - this.unitWidth,
30564 y : minY + (this.unitWidth + this.gutter) * 2
30568 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30572 Roo.each(eItems, function(b,k){
30574 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30580 getVerticalOneBoxColPositions : function(x, y, box)
30584 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30586 if(box[0].size == 'md-left'){
30590 if(box[0].size == 'md-right'){
30595 x : x + (this.unitWidth + this.gutter) * rand,
30602 getVerticalTwoBoxColPositions : function(x, y, box)
30606 if(box[0].size == 'xs'){
30610 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30614 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30628 x : x + (this.unitWidth + this.gutter) * 2,
30629 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30636 getVerticalThreeBoxColPositions : function(x, y, box)
30640 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30648 x : x + (this.unitWidth + this.gutter) * 1,
30653 x : x + (this.unitWidth + this.gutter) * 2,
30661 if(box[0].size == 'xs' && box[1].size == 'xs'){
30670 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30674 x : x + (this.unitWidth + this.gutter) * 1,
30688 x : x + (this.unitWidth + this.gutter) * 2,
30693 x : x + (this.unitWidth + this.gutter) * 2,
30694 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30701 getVerticalFourBoxColPositions : function(x, y, box)
30705 if(box[0].size == 'xs'){
30714 y : y + (this.unitHeight + this.gutter) * 1
30719 y : y + (this.unitHeight + this.gutter) * 2
30723 x : x + (this.unitWidth + this.gutter) * 1,
30737 x : x + (this.unitWidth + this.gutter) * 2,
30742 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30743 y : y + (this.unitHeight + this.gutter) * 1
30747 x : x + (this.unitWidth + this.gutter) * 2,
30748 y : y + (this.unitWidth + this.gutter) * 2
30755 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30759 if(box[0].size == 'md-left'){
30761 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30768 if(box[0].size == 'md-right'){
30770 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30771 y : minY + (this.unitWidth + this.gutter) * 1
30777 var rand = Math.floor(Math.random() * (4 - box[0].y));
30780 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30781 y : minY + (this.unitWidth + this.gutter) * rand
30788 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30792 if(box[0].size == 'xs'){
30795 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30800 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30801 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30809 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30814 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30815 y : minY + (this.unitWidth + this.gutter) * 2
30822 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30826 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30829 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30834 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30835 y : minY + (this.unitWidth + this.gutter) * 1
30839 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30840 y : minY + (this.unitWidth + this.gutter) * 2
30847 if(box[0].size == 'xs' && box[1].size == 'xs'){
30850 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30855 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30860 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30861 y : minY + (this.unitWidth + this.gutter) * 1
30869 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30874 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30875 y : minY + (this.unitWidth + this.gutter) * 2
30879 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30880 y : minY + (this.unitWidth + this.gutter) * 2
30887 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30891 if(box[0].size == 'xs'){
30894 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30899 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30904 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),
30909 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30910 y : minY + (this.unitWidth + this.gutter) * 1
30918 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30923 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30924 y : minY + (this.unitWidth + this.gutter) * 2
30928 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30929 y : minY + (this.unitWidth + this.gutter) * 2
30933 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),
30934 y : minY + (this.unitWidth + this.gutter) * 2
30948 * http://masonry.desandro.com
30950 * The idea is to render all the bricks based on vertical width...
30952 * The original code extends 'outlayer' - we might need to use that....
30958 * @class Roo.bootstrap.LayoutMasonryAuto
30959 * @extends Roo.bootstrap.Component
30960 * Bootstrap Layout Masonry class
30963 * Create a new Element
30964 * @param {Object} config The config object
30967 Roo.bootstrap.LayoutMasonryAuto = function(config){
30968 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30971 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30974 * @cfg {Boolean} isFitWidth - resize the width..
30976 isFitWidth : false, // options..
30978 * @cfg {Boolean} isOriginLeft = left align?
30980 isOriginLeft : true,
30982 * @cfg {Boolean} isOriginTop = top align?
30984 isOriginTop : false,
30986 * @cfg {Boolean} isLayoutInstant = no animation?
30988 isLayoutInstant : false, // needed?
30990 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30992 isResizingContainer : true,
30994 * @cfg {Number} columnWidth width of the columns
31000 * @cfg {Number} maxCols maximum number of columns
31005 * @cfg {Number} padHeight padding below box..
31011 * @cfg {Boolean} isAutoInitial defalut true
31014 isAutoInitial : true,
31020 initialColumnWidth : 0,
31021 currentSize : null,
31023 colYs : null, // array.
31030 bricks: null, //CompositeElement
31031 cols : 0, // array?
31032 // element : null, // wrapped now this.el
31033 _isLayoutInited : null,
31036 getAutoCreate : function(){
31040 cls: 'blog-masonary-wrapper ' + this.cls,
31042 cls : 'mas-boxes masonary'
31049 getChildContainer: function( )
31051 if (this.boxesEl) {
31052 return this.boxesEl;
31055 this.boxesEl = this.el.select('.mas-boxes').first();
31057 return this.boxesEl;
31061 initEvents : function()
31065 if(this.isAutoInitial){
31066 Roo.log('hook children rendered');
31067 this.on('childrenrendered', function() {
31068 Roo.log('children rendered');
31075 initial : function()
31077 this.reloadItems();
31079 this.currentSize = this.el.getBox(true);
31081 /// was window resize... - let's see if this works..
31082 Roo.EventManager.onWindowResize(this.resize, this);
31084 if(!this.isAutoInitial){
31089 this.layout.defer(500,this);
31092 reloadItems: function()
31094 this.bricks = this.el.select('.masonry-brick', true);
31096 this.bricks.each(function(b) {
31097 //Roo.log(b.getSize());
31098 if (!b.attr('originalwidth')) {
31099 b.attr('originalwidth', b.getSize().width);
31104 Roo.log(this.bricks.elements.length);
31107 resize : function()
31110 var cs = this.el.getBox(true);
31112 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31113 Roo.log("no change in with or X");
31116 this.currentSize = cs;
31120 layout : function()
31123 this._resetLayout();
31124 //this._manageStamps();
31126 // don't animate first layout
31127 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31128 this.layoutItems( isInstant );
31130 // flag for initalized
31131 this._isLayoutInited = true;
31134 layoutItems : function( isInstant )
31136 //var items = this._getItemsForLayout( this.items );
31137 // original code supports filtering layout items.. we just ignore it..
31139 this._layoutItems( this.bricks , isInstant );
31141 this._postLayout();
31143 _layoutItems : function ( items , isInstant)
31145 //this.fireEvent( 'layout', this, items );
31148 if ( !items || !items.elements.length ) {
31149 // no items, emit event with empty array
31154 items.each(function(item) {
31155 Roo.log("layout item");
31157 // get x/y object from method
31158 var position = this._getItemLayoutPosition( item );
31160 position.item = item;
31161 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31162 queue.push( position );
31165 this._processLayoutQueue( queue );
31167 /** Sets position of item in DOM
31168 * @param {Element} item
31169 * @param {Number} x - horizontal position
31170 * @param {Number} y - vertical position
31171 * @param {Boolean} isInstant - disables transitions
31173 _processLayoutQueue : function( queue )
31175 for ( var i=0, len = queue.length; i < len; i++ ) {
31176 var obj = queue[i];
31177 obj.item.position('absolute');
31178 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31184 * Any logic you want to do after each layout,
31185 * i.e. size the container
31187 _postLayout : function()
31189 this.resizeContainer();
31192 resizeContainer : function()
31194 if ( !this.isResizingContainer ) {
31197 var size = this._getContainerSize();
31199 this.el.setSize(size.width,size.height);
31200 this.boxesEl.setSize(size.width,size.height);
31206 _resetLayout : function()
31208 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31209 this.colWidth = this.el.getWidth();
31210 //this.gutter = this.el.getWidth();
31212 this.measureColumns();
31218 this.colYs.push( 0 );
31224 measureColumns : function()
31226 this.getContainerWidth();
31227 // if columnWidth is 0, default to outerWidth of first item
31228 if ( !this.columnWidth ) {
31229 var firstItem = this.bricks.first();
31230 Roo.log(firstItem);
31231 this.columnWidth = this.containerWidth;
31232 if (firstItem && firstItem.attr('originalwidth') ) {
31233 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31235 // columnWidth fall back to item of first element
31236 Roo.log("set column width?");
31237 this.initialColumnWidth = this.columnWidth ;
31239 // if first elem has no width, default to size of container
31244 if (this.initialColumnWidth) {
31245 this.columnWidth = this.initialColumnWidth;
31250 // column width is fixed at the top - however if container width get's smaller we should
31253 // this bit calcs how man columns..
31255 var columnWidth = this.columnWidth += this.gutter;
31257 // calculate columns
31258 var containerWidth = this.containerWidth + this.gutter;
31260 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31261 // fix rounding errors, typically with gutters
31262 var excess = columnWidth - containerWidth % columnWidth;
31265 // if overshoot is less than a pixel, round up, otherwise floor it
31266 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31267 cols = Math[ mathMethod ]( cols );
31268 this.cols = Math.max( cols, 1 );
31269 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31271 // padding positioning..
31272 var totalColWidth = this.cols * this.columnWidth;
31273 var padavail = this.containerWidth - totalColWidth;
31274 // so for 2 columns - we need 3 'pads'
31276 var padNeeded = (1+this.cols) * this.padWidth;
31278 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31280 this.columnWidth += padExtra
31281 //this.padWidth = Math.floor(padavail / ( this.cols));
31283 // adjust colum width so that padding is fixed??
31285 // we have 3 columns ... total = width * 3
31286 // we have X left over... that should be used by
31288 //if (this.expandC) {
31296 getContainerWidth : function()
31298 /* // container is parent if fit width
31299 var container = this.isFitWidth ? this.element.parentNode : this.element;
31300 // check that this.size and size are there
31301 // IE8 triggers resize on body size change, so they might not be
31303 var size = getSize( container ); //FIXME
31304 this.containerWidth = size && size.innerWidth; //FIXME
31307 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31311 _getItemLayoutPosition : function( item ) // what is item?
31313 // we resize the item to our columnWidth..
31315 item.setWidth(this.columnWidth);
31316 item.autoBoxAdjust = false;
31318 var sz = item.getSize();
31320 // how many columns does this brick span
31321 var remainder = this.containerWidth % this.columnWidth;
31323 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31324 // round if off by 1 pixel, otherwise use ceil
31325 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31326 colSpan = Math.min( colSpan, this.cols );
31328 // normally this should be '1' as we dont' currently allow multi width columns..
31330 var colGroup = this._getColGroup( colSpan );
31331 // get the minimum Y value from the columns
31332 var minimumY = Math.min.apply( Math, colGroup );
31333 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31335 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31337 // position the brick
31339 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31340 y: this.currentSize.y + minimumY + this.padHeight
31344 // apply setHeight to necessary columns
31345 var setHeight = minimumY + sz.height + this.padHeight;
31346 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31348 var setSpan = this.cols + 1 - colGroup.length;
31349 for ( var i = 0; i < setSpan; i++ ) {
31350 this.colYs[ shortColIndex + i ] = setHeight ;
31357 * @param {Number} colSpan - number of columns the element spans
31358 * @returns {Array} colGroup
31360 _getColGroup : function( colSpan )
31362 if ( colSpan < 2 ) {
31363 // if brick spans only one column, use all the column Ys
31368 // how many different places could this brick fit horizontally
31369 var groupCount = this.cols + 1 - colSpan;
31370 // for each group potential horizontal position
31371 for ( var i = 0; i < groupCount; i++ ) {
31372 // make an array of colY values for that one group
31373 var groupColYs = this.colYs.slice( i, i + colSpan );
31374 // and get the max value of the array
31375 colGroup[i] = Math.max.apply( Math, groupColYs );
31380 _manageStamp : function( stamp )
31382 var stampSize = stamp.getSize();
31383 var offset = stamp.getBox();
31384 // get the columns that this stamp affects
31385 var firstX = this.isOriginLeft ? offset.x : offset.right;
31386 var lastX = firstX + stampSize.width;
31387 var firstCol = Math.floor( firstX / this.columnWidth );
31388 firstCol = Math.max( 0, firstCol );
31390 var lastCol = Math.floor( lastX / this.columnWidth );
31391 // lastCol should not go over if multiple of columnWidth #425
31392 lastCol -= lastX % this.columnWidth ? 0 : 1;
31393 lastCol = Math.min( this.cols - 1, lastCol );
31395 // set colYs to bottom of the stamp
31396 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31399 for ( var i = firstCol; i <= lastCol; i++ ) {
31400 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31405 _getContainerSize : function()
31407 this.maxY = Math.max.apply( Math, this.colYs );
31412 if ( this.isFitWidth ) {
31413 size.width = this._getContainerFitWidth();
31419 _getContainerFitWidth : function()
31421 var unusedCols = 0;
31422 // count unused columns
31425 if ( this.colYs[i] !== 0 ) {
31430 // fit container to columns that have been used
31431 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31434 needsResizeLayout : function()
31436 var previousWidth = this.containerWidth;
31437 this.getContainerWidth();
31438 return previousWidth !== this.containerWidth;
31453 * @class Roo.bootstrap.MasonryBrick
31454 * @extends Roo.bootstrap.Component
31455 * Bootstrap MasonryBrick class
31458 * Create a new MasonryBrick
31459 * @param {Object} config The config object
31462 Roo.bootstrap.MasonryBrick = function(config){
31463 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31469 * When a MasonryBrick is clcik
31470 * @param {Roo.bootstrap.MasonryBrick} this
31471 * @param {Roo.EventObject} e
31477 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31480 * @cfg {String} title
31484 * @cfg {String} html
31488 * @cfg {String} bgimage
31492 * @cfg {String} videourl
31496 * @cfg {String} cls
31500 * @cfg {String} href
31504 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31509 * @cfg {String} placetitle (center|bottom)
31514 * @cfg {Boolean} isFitContainer defalut true
31516 isFitContainer : true,
31519 * @cfg {Boolean} preventDefault defalut false
31521 preventDefault : false,
31524 * @cfg {Boolean} inverse defalut false
31526 maskInverse : false,
31528 getAutoCreate : function()
31530 if(!this.isFitContainer){
31531 return this.getSplitAutoCreate();
31534 var cls = 'masonry-brick masonry-brick-full';
31536 if(this.href.length){
31537 cls += ' masonry-brick-link';
31540 if(this.bgimage.length){
31541 cls += ' masonry-brick-image';
31544 if(this.maskInverse){
31545 cls += ' mask-inverse';
31548 if(!this.html.length && !this.maskInverse){
31549 cls += ' enable-mask';
31553 cls += ' masonry-' + this.size + '-brick';
31556 if(this.placetitle.length){
31558 switch (this.placetitle) {
31560 cls += ' masonry-center-title';
31563 cls += ' masonry-bottom-title';
31570 if(!this.html.length && !this.bgimage.length){
31571 cls += ' masonry-center-title';
31574 if(!this.html.length && this.bgimage.length){
31575 cls += ' masonry-bottom-title';
31580 cls += ' ' + this.cls;
31584 tag: (this.href.length) ? 'a' : 'div',
31589 cls: 'masonry-brick-paragraph',
31595 if(this.href.length){
31596 cfg.href = this.href;
31599 var cn = cfg.cn[0].cn;
31601 if(this.title.length){
31604 cls: 'masonry-brick-title',
31609 if(this.html.length){
31612 cls: 'masonry-brick-text',
31616 if (!this.title.length && !this.html.length) {
31617 cfg.cn[0].cls += ' hide';
31620 if(this.bgimage.length){
31623 cls: 'masonry-brick-image-view',
31628 if(this.videourl.length){
31629 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31630 // youtube support only?
31633 cls: 'masonry-brick-image-view',
31636 allowfullscreen : true
31644 cls: 'masonry-brick-mask'
31651 getSplitAutoCreate : function()
31653 var cls = 'masonry-brick masonry-brick-split';
31655 if(this.href.length){
31656 cls += ' masonry-brick-link';
31659 if(this.bgimage.length){
31660 cls += ' masonry-brick-image';
31664 cls += ' masonry-' + this.size + '-brick';
31667 switch (this.placetitle) {
31669 cls += ' masonry-center-title';
31672 cls += ' masonry-bottom-title';
31675 if(!this.bgimage.length){
31676 cls += ' masonry-center-title';
31679 if(this.bgimage.length){
31680 cls += ' masonry-bottom-title';
31686 cls += ' ' + this.cls;
31690 tag: (this.href.length) ? 'a' : 'div',
31695 cls: 'masonry-brick-split-head',
31699 cls: 'masonry-brick-paragraph',
31706 cls: 'masonry-brick-split-body',
31712 if(this.href.length){
31713 cfg.href = this.href;
31716 if(this.title.length){
31717 cfg.cn[0].cn[0].cn.push({
31719 cls: 'masonry-brick-title',
31724 if(this.html.length){
31725 cfg.cn[1].cn.push({
31727 cls: 'masonry-brick-text',
31732 if(this.bgimage.length){
31733 cfg.cn[0].cn.push({
31735 cls: 'masonry-brick-image-view',
31740 if(this.videourl.length){
31741 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31742 // youtube support only?
31743 cfg.cn[0].cn.cn.push({
31745 cls: 'masonry-brick-image-view',
31748 allowfullscreen : true
31755 initEvents: function()
31757 switch (this.size) {
31790 this.el.on('touchstart', this.onTouchStart, this);
31791 this.el.on('touchmove', this.onTouchMove, this);
31792 this.el.on('touchend', this.onTouchEnd, this);
31793 this.el.on('contextmenu', this.onContextMenu, this);
31795 this.el.on('mouseenter' ,this.enter, this);
31796 this.el.on('mouseleave', this.leave, this);
31797 this.el.on('click', this.onClick, this);
31800 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31801 this.parent().bricks.push(this);
31806 onClick: function(e, el)
31808 var time = this.endTimer - this.startTimer;
31812 e.preventDefault();
31817 if(!this.preventDefault){
31821 e.preventDefault();
31822 this.fireEvent('click', this);
31825 enter: function(e, el)
31827 e.preventDefault();
31829 if(!this.isFitContainer || this.maskInverse){
31833 if(this.bgimage.length && this.html.length){
31834 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31838 leave: function(e, el)
31840 e.preventDefault();
31842 if(!this.isFitContainer || this.maskInverse){
31846 if(this.bgimage.length && this.html.length){
31847 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31851 onTouchStart: function(e, el)
31853 // e.preventDefault();
31855 this.touchmoved = false;
31857 if(!this.isFitContainer){
31861 if(!this.bgimage.length || !this.html.length){
31865 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31867 this.timer = new Date().getTime();
31871 onTouchMove: function(e, el)
31873 this.touchmoved = true;
31876 onContextMenu : function(e,el)
31878 e.preventDefault();
31879 e.stopPropagation();
31883 onTouchEnd: function(e, el)
31885 // e.preventDefault();
31887 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31894 if(!this.bgimage.length || !this.html.length){
31896 if(this.href.length){
31897 window.location.href = this.href;
31903 if(!this.isFitContainer){
31907 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31909 window.location.href = this.href;
31924 * @class Roo.bootstrap.Brick
31925 * @extends Roo.bootstrap.Component
31926 * Bootstrap Brick class
31929 * Create a new Brick
31930 * @param {Object} config The config object
31933 Roo.bootstrap.Brick = function(config){
31934 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31940 * When a Brick is click
31941 * @param {Roo.bootstrap.Brick} this
31942 * @param {Roo.EventObject} e
31948 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31951 * @cfg {String} title
31955 * @cfg {String} html
31959 * @cfg {String} bgimage
31963 * @cfg {String} cls
31967 * @cfg {String} href
31971 * @cfg {String} video
31975 * @cfg {Boolean} square
31979 getAutoCreate : function()
31981 var cls = 'roo-brick';
31983 if(this.href.length){
31984 cls += ' roo-brick-link';
31987 if(this.bgimage.length){
31988 cls += ' roo-brick-image';
31991 if(!this.html.length && !this.bgimage.length){
31992 cls += ' roo-brick-center-title';
31995 if(!this.html.length && this.bgimage.length){
31996 cls += ' roo-brick-bottom-title';
32000 cls += ' ' + this.cls;
32004 tag: (this.href.length) ? 'a' : 'div',
32009 cls: 'roo-brick-paragraph',
32015 if(this.href.length){
32016 cfg.href = this.href;
32019 var cn = cfg.cn[0].cn;
32021 if(this.title.length){
32024 cls: 'roo-brick-title',
32029 if(this.html.length){
32032 cls: 'roo-brick-text',
32039 if(this.bgimage.length){
32042 cls: 'roo-brick-image-view',
32050 initEvents: function()
32052 if(this.title.length || this.html.length){
32053 this.el.on('mouseenter' ,this.enter, this);
32054 this.el.on('mouseleave', this.leave, this);
32058 Roo.EventManager.onWindowResize(this.resize, this);
32063 resize : function()
32065 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32067 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32069 if(this.bgimage.length){
32070 var image = this.el.select('.roo-brick-image-view', true).first();
32071 image.setWidth(paragraph.getWidth());
32072 image.setHeight(paragraph.getWidth());
32074 this.el.setHeight(paragraph.getWidth());
32080 enter: function(e, el)
32082 e.preventDefault();
32084 if(this.bgimage.length){
32085 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32086 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32090 leave: function(e, el)
32092 e.preventDefault();
32094 if(this.bgimage.length){
32095 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32096 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32112 * @class Roo.bootstrap.NumberField
32113 * @extends Roo.bootstrap.Input
32114 * Bootstrap NumberField class
32120 * Create a new NumberField
32121 * @param {Object} config The config object
32124 Roo.bootstrap.NumberField = function(config){
32125 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32128 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32131 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32133 allowDecimals : true,
32135 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32137 decimalSeparator : ".",
32139 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32141 decimalPrecision : 2,
32143 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32145 allowNegative : true,
32147 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32149 minValue : Number.NEGATIVE_INFINITY,
32151 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32153 maxValue : Number.MAX_VALUE,
32155 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32157 minText : "The minimum value for this field is {0}",
32159 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32161 maxText : "The maximum value for this field is {0}",
32163 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32164 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32166 nanText : "{0} is not a valid number",
32168 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32173 initEvents : function()
32175 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32177 var allowed = "0123456789";
32179 if(this.allowDecimals){
32180 allowed += this.decimalSeparator;
32183 if(this.allowNegative){
32187 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32189 var keyPress = function(e){
32191 var k = e.getKey();
32193 var c = e.getCharCode();
32196 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32197 allowed.indexOf(String.fromCharCode(c)) === -1
32203 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32207 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32212 this.el.on("keypress", keyPress, this);
32215 validateValue : function(value)
32218 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32222 var num = this.parseValue(value);
32225 this.markInvalid(String.format(this.nanText, value));
32229 if(num < this.minValue){
32230 this.markInvalid(String.format(this.minText, this.minValue));
32234 if(num > this.maxValue){
32235 this.markInvalid(String.format(this.maxText, this.maxValue));
32242 getValue : function()
32244 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32247 parseValue : function(value)
32249 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32250 return isNaN(value) ? '' : value;
32253 fixPrecision : function(value)
32255 var nan = isNaN(value);
32257 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32258 return nan ? '' : value;
32260 return parseFloat(value).toFixed(this.decimalPrecision);
32263 setValue : function(v)
32265 v = this.fixPrecision(v);
32266 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32269 decimalPrecisionFcn : function(v)
32271 return Math.floor(v);
32274 beforeBlur : function()
32280 var v = this.parseValue(this.getRawValue());
32295 * @class Roo.bootstrap.DocumentSlider
32296 * @extends Roo.bootstrap.Component
32297 * Bootstrap DocumentSlider class
32300 * Create a new DocumentViewer
32301 * @param {Object} config The config object
32304 Roo.bootstrap.DocumentSlider = function(config){
32305 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32312 * Fire after initEvent
32313 * @param {Roo.bootstrap.DocumentSlider} this
32318 * Fire after update
32319 * @param {Roo.bootstrap.DocumentSlider} this
32325 * @param {Roo.bootstrap.DocumentSlider} this
32331 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32337 getAutoCreate : function()
32341 cls : 'roo-document-slider',
32345 cls : 'roo-document-slider-header',
32349 cls : 'roo-document-slider-header-title'
32355 cls : 'roo-document-slider-body',
32359 cls : 'roo-document-slider-prev',
32363 cls : 'fa fa-chevron-left'
32369 cls : 'roo-document-slider-thumb',
32373 cls : 'roo-document-slider-image'
32379 cls : 'roo-document-slider-next',
32383 cls : 'fa fa-chevron-right'
32395 initEvents : function()
32397 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32398 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32400 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32401 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32403 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32404 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32406 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32407 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32409 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32410 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32412 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32413 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32415 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32416 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32418 this.thumbEl.on('click', this.onClick, this);
32420 this.prevIndicator.on('click', this.prev, this);
32422 this.nextIndicator.on('click', this.next, this);
32426 initial : function()
32428 if(this.files.length){
32429 this.indicator = 1;
32433 this.fireEvent('initial', this);
32436 update : function()
32438 this.imageEl.attr('src', this.files[this.indicator - 1]);
32440 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32442 this.prevIndicator.show();
32444 if(this.indicator == 1){
32445 this.prevIndicator.hide();
32448 this.nextIndicator.show();
32450 if(this.indicator == this.files.length){
32451 this.nextIndicator.hide();
32454 this.thumbEl.scrollTo('top');
32456 this.fireEvent('update', this);
32459 onClick : function(e)
32461 e.preventDefault();
32463 this.fireEvent('click', this);
32468 e.preventDefault();
32470 this.indicator = Math.max(1, this.indicator - 1);
32477 e.preventDefault();
32479 this.indicator = Math.min(this.files.length, this.indicator + 1);
32493 * @class Roo.bootstrap.RadioSet
32494 * @extends Roo.bootstrap.Input
32495 * Bootstrap RadioSet class
32496 * @cfg {String} indicatorpos (left|right) default left
32497 * @cfg {Boolean} inline (true|false) inline the element (default true)
32498 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32500 * Create a new RadioSet
32501 * @param {Object} config The config object
32504 Roo.bootstrap.RadioSet = function(config){
32506 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32510 Roo.bootstrap.RadioSet.register(this);
32515 * Fires when the element is checked or unchecked.
32516 * @param {Roo.bootstrap.RadioSet} this This radio
32517 * @param {Roo.bootstrap.Radio} item The checked item
32524 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32532 indicatorpos : 'left',
32534 getAutoCreate : function()
32538 cls : 'roo-radio-set-label',
32542 html : this.fieldLabel
32547 if(this.indicatorpos == 'left'){
32550 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32551 tooltip : 'This field is required'
32556 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32557 tooltip : 'This field is required'
32563 cls : 'roo-radio-set-items'
32566 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32568 if (align === 'left' && this.fieldLabel.length) {
32571 cls : "roo-radio-set-right",
32577 if(this.labelWidth > 12){
32578 label.style = "width: " + this.labelWidth + 'px';
32581 if(this.labelWidth < 13 && this.labelmd == 0){
32582 this.labelmd = this.labelWidth;
32585 if(this.labellg > 0){
32586 label.cls += ' col-lg-' + this.labellg;
32587 items.cls += ' col-lg-' + (12 - this.labellg);
32590 if(this.labelmd > 0){
32591 label.cls += ' col-md-' + this.labelmd;
32592 items.cls += ' col-md-' + (12 - this.labelmd);
32595 if(this.labelsm > 0){
32596 label.cls += ' col-sm-' + this.labelsm;
32597 items.cls += ' col-sm-' + (12 - this.labelsm);
32600 if(this.labelxs > 0){
32601 label.cls += ' col-xs-' + this.labelxs;
32602 items.cls += ' col-xs-' + (12 - this.labelxs);
32608 cls : 'roo-radio-set',
32612 cls : 'roo-radio-set-input',
32615 value : this.value ? this.value : ''
32622 if(this.weight.length){
32623 cfg.cls += ' roo-radio-' + this.weight;
32627 cfg.cls += ' roo-radio-set-inline';
32634 initEvents : function()
32636 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32637 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32639 if(!this.fieldLabel.length){
32640 this.labelEl.hide();
32643 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32644 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32646 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32647 this.indicatorEl().hide();
32649 this.originalValue = this.getValue();
32653 inputEl: function ()
32655 return this.el.select('.roo-radio-set-input', true).first();
32658 getChildContainer : function()
32660 return this.itemsEl;
32663 register : function(item)
32665 this.radioes.push(item);
32669 validate : function()
32673 Roo.each(this.radioes, function(i){
32682 if(this.allowBlank) {
32686 if(this.disabled || valid){
32691 this.markInvalid();
32696 markValid : function()
32698 if(this.labelEl.isVisible(true)){
32699 this.indicatorEl().hide();
32702 this.el.removeClass([this.invalidClass, this.validClass]);
32703 this.el.addClass(this.validClass);
32705 this.fireEvent('valid', this);
32708 markInvalid : function(msg)
32710 if(this.allowBlank || this.disabled){
32714 if(this.labelEl.isVisible(true)){
32715 this.indicatorEl().show();
32718 this.el.removeClass([this.invalidClass, this.validClass]);
32719 this.el.addClass(this.invalidClass);
32721 this.fireEvent('invalid', this, msg);
32725 setValue : function(v, suppressEvent)
32727 Roo.each(this.radioes, function(i){
32730 i.el.removeClass('checked');
32732 if(i.value === v || i.value.toString() === v.toString()){
32734 i.el.addClass('checked');
32736 if(suppressEvent !== true){
32737 this.fireEvent('check', this, i);
32743 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32747 clearInvalid : function(){
32749 if(!this.el || this.preventMark){
32753 if(this.labelEl.isVisible(true)){
32754 this.indicatorEl().hide();
32757 this.el.removeClass([this.invalidClass]);
32759 this.fireEvent('valid', this);
32764 Roo.apply(Roo.bootstrap.RadioSet, {
32768 register : function(set)
32770 this.groups[set.name] = set;
32773 get: function(name)
32775 if (typeof(this.groups[name]) == 'undefined') {
32779 return this.groups[name] ;
32785 * Ext JS Library 1.1.1
32786 * Copyright(c) 2006-2007, Ext JS, LLC.
32788 * Originally Released Under LGPL - original licence link has changed is not relivant.
32791 * <script type="text/javascript">
32796 * @class Roo.bootstrap.SplitBar
32797 * @extends Roo.util.Observable
32798 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32802 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32803 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32804 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32805 split.minSize = 100;
32806 split.maxSize = 600;
32807 split.animate = true;
32808 split.on('moved', splitterMoved);
32811 * Create a new SplitBar
32812 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32813 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32814 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32815 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32816 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32817 position of the SplitBar).
32819 Roo.bootstrap.SplitBar = function(cfg){
32824 // dragElement : elm
32825 // resizingElement: el,
32827 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32828 // placement : Roo.bootstrap.SplitBar.LEFT ,
32829 // existingProxy ???
32832 this.el = Roo.get(cfg.dragElement, true);
32833 this.el.dom.unselectable = "on";
32835 this.resizingEl = Roo.get(cfg.resizingElement, true);
32839 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32840 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32843 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32846 * The minimum size of the resizing element. (Defaults to 0)
32852 * The maximum size of the resizing element. (Defaults to 2000)
32855 this.maxSize = 2000;
32858 * Whether to animate the transition to the new size
32861 this.animate = false;
32864 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32867 this.useShim = false;
32872 if(!cfg.existingProxy){
32874 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32876 this.proxy = Roo.get(cfg.existingProxy).dom;
32879 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32882 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32885 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32888 this.dragSpecs = {};
32891 * @private The adapter to use to positon and resize elements
32893 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32894 this.adapter.init(this);
32896 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32898 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32899 this.el.addClass("roo-splitbar-h");
32902 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32903 this.el.addClass("roo-splitbar-v");
32909 * Fires when the splitter is moved (alias for {@link #event-moved})
32910 * @param {Roo.bootstrap.SplitBar} this
32911 * @param {Number} newSize the new width or height
32916 * Fires when the splitter is moved
32917 * @param {Roo.bootstrap.SplitBar} this
32918 * @param {Number} newSize the new width or height
32922 * @event beforeresize
32923 * Fires before the splitter is dragged
32924 * @param {Roo.bootstrap.SplitBar} this
32926 "beforeresize" : true,
32928 "beforeapply" : true
32931 Roo.util.Observable.call(this);
32934 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32935 onStartProxyDrag : function(x, y){
32936 this.fireEvent("beforeresize", this);
32938 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32940 o.enableDisplayMode("block");
32941 // all splitbars share the same overlay
32942 Roo.bootstrap.SplitBar.prototype.overlay = o;
32944 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32945 this.overlay.show();
32946 Roo.get(this.proxy).setDisplayed("block");
32947 var size = this.adapter.getElementSize(this);
32948 this.activeMinSize = this.getMinimumSize();;
32949 this.activeMaxSize = this.getMaximumSize();;
32950 var c1 = size - this.activeMinSize;
32951 var c2 = Math.max(this.activeMaxSize - size, 0);
32952 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32953 this.dd.resetConstraints();
32954 this.dd.setXConstraint(
32955 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32956 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32958 this.dd.setYConstraint(0, 0);
32960 this.dd.resetConstraints();
32961 this.dd.setXConstraint(0, 0);
32962 this.dd.setYConstraint(
32963 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32964 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32967 this.dragSpecs.startSize = size;
32968 this.dragSpecs.startPoint = [x, y];
32969 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32973 * @private Called after the drag operation by the DDProxy
32975 onEndProxyDrag : function(e){
32976 Roo.get(this.proxy).setDisplayed(false);
32977 var endPoint = Roo.lib.Event.getXY(e);
32979 this.overlay.hide();
32982 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32983 newSize = this.dragSpecs.startSize +
32984 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32985 endPoint[0] - this.dragSpecs.startPoint[0] :
32986 this.dragSpecs.startPoint[0] - endPoint[0]
32989 newSize = this.dragSpecs.startSize +
32990 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32991 endPoint[1] - this.dragSpecs.startPoint[1] :
32992 this.dragSpecs.startPoint[1] - endPoint[1]
32995 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32996 if(newSize != this.dragSpecs.startSize){
32997 if(this.fireEvent('beforeapply', this, newSize) !== false){
32998 this.adapter.setElementSize(this, newSize);
32999 this.fireEvent("moved", this, newSize);
33000 this.fireEvent("resize", this, newSize);
33006 * Get the adapter this SplitBar uses
33007 * @return The adapter object
33009 getAdapter : function(){
33010 return this.adapter;
33014 * Set the adapter this SplitBar uses
33015 * @param {Object} adapter A SplitBar adapter object
33017 setAdapter : function(adapter){
33018 this.adapter = adapter;
33019 this.adapter.init(this);
33023 * Gets the minimum size for the resizing element
33024 * @return {Number} The minimum size
33026 getMinimumSize : function(){
33027 return this.minSize;
33031 * Sets the minimum size for the resizing element
33032 * @param {Number} minSize The minimum size
33034 setMinimumSize : function(minSize){
33035 this.minSize = minSize;
33039 * Gets the maximum size for the resizing element
33040 * @return {Number} The maximum size
33042 getMaximumSize : function(){
33043 return this.maxSize;
33047 * Sets the maximum size for the resizing element
33048 * @param {Number} maxSize The maximum size
33050 setMaximumSize : function(maxSize){
33051 this.maxSize = maxSize;
33055 * Sets the initialize size for the resizing element
33056 * @param {Number} size The initial size
33058 setCurrentSize : function(size){
33059 var oldAnimate = this.animate;
33060 this.animate = false;
33061 this.adapter.setElementSize(this, size);
33062 this.animate = oldAnimate;
33066 * Destroy this splitbar.
33067 * @param {Boolean} removeEl True to remove the element
33069 destroy : function(removeEl){
33071 this.shim.remove();
33074 this.proxy.parentNode.removeChild(this.proxy);
33082 * @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.
33084 Roo.bootstrap.SplitBar.createProxy = function(dir){
33085 var proxy = new Roo.Element(document.createElement("div"));
33086 proxy.unselectable();
33087 var cls = 'roo-splitbar-proxy';
33088 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33089 document.body.appendChild(proxy.dom);
33094 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33095 * Default Adapter. It assumes the splitter and resizing element are not positioned
33096 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33098 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33101 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33102 // do nothing for now
33103 init : function(s){
33107 * Called before drag operations to get the current size of the resizing element.
33108 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33110 getElementSize : function(s){
33111 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33112 return s.resizingEl.getWidth();
33114 return s.resizingEl.getHeight();
33119 * Called after drag operations to set the size of the resizing element.
33120 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33121 * @param {Number} newSize The new size to set
33122 * @param {Function} onComplete A function to be invoked when resizing is complete
33124 setElementSize : function(s, newSize, onComplete){
33125 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33127 s.resizingEl.setWidth(newSize);
33129 onComplete(s, newSize);
33132 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33137 s.resizingEl.setHeight(newSize);
33139 onComplete(s, newSize);
33142 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33149 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33150 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33151 * Adapter that moves the splitter element to align with the resized sizing element.
33152 * Used with an absolute positioned SplitBar.
33153 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33154 * document.body, make sure you assign an id to the body element.
33156 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33157 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33158 this.container = Roo.get(container);
33161 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33162 init : function(s){
33163 this.basic.init(s);
33166 getElementSize : function(s){
33167 return this.basic.getElementSize(s);
33170 setElementSize : function(s, newSize, onComplete){
33171 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33174 moveSplitter : function(s){
33175 var yes = Roo.bootstrap.SplitBar;
33176 switch(s.placement){
33178 s.el.setX(s.resizingEl.getRight());
33181 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33184 s.el.setY(s.resizingEl.getBottom());
33187 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33194 * Orientation constant - Create a vertical SplitBar
33198 Roo.bootstrap.SplitBar.VERTICAL = 1;
33201 * Orientation constant - Create a horizontal SplitBar
33205 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33208 * Placement constant - The resizing element is to the left of the splitter element
33212 Roo.bootstrap.SplitBar.LEFT = 1;
33215 * Placement constant - The resizing element is to the right of the splitter element
33219 Roo.bootstrap.SplitBar.RIGHT = 2;
33222 * Placement constant - The resizing element is positioned above the splitter element
33226 Roo.bootstrap.SplitBar.TOP = 3;
33229 * Placement constant - The resizing element is positioned under splitter element
33233 Roo.bootstrap.SplitBar.BOTTOM = 4;
33234 Roo.namespace("Roo.bootstrap.layout");/*
33236 * Ext JS Library 1.1.1
33237 * Copyright(c) 2006-2007, Ext JS, LLC.
33239 * Originally Released Under LGPL - original licence link has changed is not relivant.
33242 * <script type="text/javascript">
33246 * @class Roo.bootstrap.layout.Manager
33247 * @extends Roo.bootstrap.Component
33248 * Base class for layout managers.
33250 Roo.bootstrap.layout.Manager = function(config)
33252 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33258 /** false to disable window resize monitoring @type Boolean */
33259 this.monitorWindowResize = true;
33264 * Fires when a layout is performed.
33265 * @param {Roo.LayoutManager} this
33269 * @event regionresized
33270 * Fires when the user resizes a region.
33271 * @param {Roo.LayoutRegion} region The resized region
33272 * @param {Number} newSize The new size (width for east/west, height for north/south)
33274 "regionresized" : true,
33276 * @event regioncollapsed
33277 * Fires when a region is collapsed.
33278 * @param {Roo.LayoutRegion} region The collapsed region
33280 "regioncollapsed" : true,
33282 * @event regionexpanded
33283 * Fires when a region is expanded.
33284 * @param {Roo.LayoutRegion} region The expanded region
33286 "regionexpanded" : true
33288 this.updating = false;
33291 this.el = Roo.get(config.el);
33297 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33302 monitorWindowResize : true,
33308 onRender : function(ct, position)
33311 this.el = Roo.get(ct);
33314 //this.fireEvent('render',this);
33318 initEvents: function()
33322 // ie scrollbar fix
33323 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33324 document.body.scroll = "no";
33325 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33326 this.el.position('relative');
33328 this.id = this.el.id;
33329 this.el.addClass("roo-layout-container");
33330 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33331 if(this.el.dom != document.body ) {
33332 this.el.on('resize', this.layout,this);
33333 this.el.on('show', this.layout,this);
33339 * Returns true if this layout is currently being updated
33340 * @return {Boolean}
33342 isUpdating : function(){
33343 return this.updating;
33347 * Suspend the LayoutManager from doing auto-layouts while
33348 * making multiple add or remove calls
33350 beginUpdate : function(){
33351 this.updating = true;
33355 * Restore auto-layouts and optionally disable the manager from performing a layout
33356 * @param {Boolean} noLayout true to disable a layout update
33358 endUpdate : function(noLayout){
33359 this.updating = false;
33365 layout: function(){
33369 onRegionResized : function(region, newSize){
33370 this.fireEvent("regionresized", region, newSize);
33374 onRegionCollapsed : function(region){
33375 this.fireEvent("regioncollapsed", region);
33378 onRegionExpanded : function(region){
33379 this.fireEvent("regionexpanded", region);
33383 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33384 * performs box-model adjustments.
33385 * @return {Object} The size as an object {width: (the width), height: (the height)}
33387 getViewSize : function()
33390 if(this.el.dom != document.body){
33391 size = this.el.getSize();
33393 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33395 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33396 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33401 * Returns the Element this layout is bound to.
33402 * @return {Roo.Element}
33404 getEl : function(){
33409 * Returns the specified region.
33410 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33411 * @return {Roo.LayoutRegion}
33413 getRegion : function(target){
33414 return this.regions[target.toLowerCase()];
33417 onWindowResize : function(){
33418 if(this.monitorWindowResize){
33425 * Ext JS Library 1.1.1
33426 * Copyright(c) 2006-2007, Ext JS, LLC.
33428 * Originally Released Under LGPL - original licence link has changed is not relivant.
33431 * <script type="text/javascript">
33434 * @class Roo.bootstrap.layout.Border
33435 * @extends Roo.bootstrap.layout.Manager
33436 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33437 * please see: examples/bootstrap/nested.html<br><br>
33439 <b>The container the layout is rendered into can be either the body element or any other element.
33440 If it is not the body element, the container needs to either be an absolute positioned element,
33441 or you will need to add "position:relative" to the css of the container. You will also need to specify
33442 the container size if it is not the body element.</b>
33445 * Create a new Border
33446 * @param {Object} config Configuration options
33448 Roo.bootstrap.layout.Border = function(config){
33449 config = config || {};
33450 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33454 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33455 if(config[region]){
33456 config[region].region = region;
33457 this.addRegion(config[region]);
33463 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33465 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33467 * Creates and adds a new region if it doesn't already exist.
33468 * @param {String} target The target region key (north, south, east, west or center).
33469 * @param {Object} config The regions config object
33470 * @return {BorderLayoutRegion} The new region
33472 addRegion : function(config)
33474 if(!this.regions[config.region]){
33475 var r = this.factory(config);
33476 this.bindRegion(r);
33478 return this.regions[config.region];
33482 bindRegion : function(r){
33483 this.regions[r.config.region] = r;
33485 r.on("visibilitychange", this.layout, this);
33486 r.on("paneladded", this.layout, this);
33487 r.on("panelremoved", this.layout, this);
33488 r.on("invalidated", this.layout, this);
33489 r.on("resized", this.onRegionResized, this);
33490 r.on("collapsed", this.onRegionCollapsed, this);
33491 r.on("expanded", this.onRegionExpanded, this);
33495 * Performs a layout update.
33497 layout : function()
33499 if(this.updating) {
33503 // render all the rebions if they have not been done alreayd?
33504 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33505 if(this.regions[region] && !this.regions[region].bodyEl){
33506 this.regions[region].onRender(this.el)
33510 var size = this.getViewSize();
33511 var w = size.width;
33512 var h = size.height;
33517 //var x = 0, y = 0;
33519 var rs = this.regions;
33520 var north = rs["north"];
33521 var south = rs["south"];
33522 var west = rs["west"];
33523 var east = rs["east"];
33524 var center = rs["center"];
33525 //if(this.hideOnLayout){ // not supported anymore
33526 //c.el.setStyle("display", "none");
33528 if(north && north.isVisible()){
33529 var b = north.getBox();
33530 var m = north.getMargins();
33531 b.width = w - (m.left+m.right);
33534 centerY = b.height + b.y + m.bottom;
33535 centerH -= centerY;
33536 north.updateBox(this.safeBox(b));
33538 if(south && south.isVisible()){
33539 var b = south.getBox();
33540 var m = south.getMargins();
33541 b.width = w - (m.left+m.right);
33543 var totalHeight = (b.height + m.top + m.bottom);
33544 b.y = h - totalHeight + m.top;
33545 centerH -= totalHeight;
33546 south.updateBox(this.safeBox(b));
33548 if(west && west.isVisible()){
33549 var b = west.getBox();
33550 var m = west.getMargins();
33551 b.height = centerH - (m.top+m.bottom);
33553 b.y = centerY + m.top;
33554 var totalWidth = (b.width + m.left + m.right);
33555 centerX += totalWidth;
33556 centerW -= totalWidth;
33557 west.updateBox(this.safeBox(b));
33559 if(east && east.isVisible()){
33560 var b = east.getBox();
33561 var m = east.getMargins();
33562 b.height = centerH - (m.top+m.bottom);
33563 var totalWidth = (b.width + m.left + m.right);
33564 b.x = w - totalWidth + m.left;
33565 b.y = centerY + m.top;
33566 centerW -= totalWidth;
33567 east.updateBox(this.safeBox(b));
33570 var m = center.getMargins();
33572 x: centerX + m.left,
33573 y: centerY + m.top,
33574 width: centerW - (m.left+m.right),
33575 height: centerH - (m.top+m.bottom)
33577 //if(this.hideOnLayout){
33578 //center.el.setStyle("display", "block");
33580 center.updateBox(this.safeBox(centerBox));
33583 this.fireEvent("layout", this);
33587 safeBox : function(box){
33588 box.width = Math.max(0, box.width);
33589 box.height = Math.max(0, box.height);
33594 * Adds a ContentPanel (or subclass) to this layout.
33595 * @param {String} target The target region key (north, south, east, west or center).
33596 * @param {Roo.ContentPanel} panel The panel to add
33597 * @return {Roo.ContentPanel} The added panel
33599 add : function(target, panel){
33601 target = target.toLowerCase();
33602 return this.regions[target].add(panel);
33606 * Remove a ContentPanel (or subclass) to this layout.
33607 * @param {String} target The target region key (north, south, east, west or center).
33608 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33609 * @return {Roo.ContentPanel} The removed panel
33611 remove : function(target, panel){
33612 target = target.toLowerCase();
33613 return this.regions[target].remove(panel);
33617 * Searches all regions for a panel with the specified id
33618 * @param {String} panelId
33619 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33621 findPanel : function(panelId){
33622 var rs = this.regions;
33623 for(var target in rs){
33624 if(typeof rs[target] != "function"){
33625 var p = rs[target].getPanel(panelId);
33635 * Searches all regions for a panel with the specified id and activates (shows) it.
33636 * @param {String/ContentPanel} panelId The panels id or the panel itself
33637 * @return {Roo.ContentPanel} The shown panel or null
33639 showPanel : function(panelId) {
33640 var rs = this.regions;
33641 for(var target in rs){
33642 var r = rs[target];
33643 if(typeof r != "function"){
33644 if(r.hasPanel(panelId)){
33645 return r.showPanel(panelId);
33653 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33654 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33657 restoreState : function(provider){
33659 provider = Roo.state.Manager;
33661 var sm = new Roo.LayoutStateManager();
33662 sm.init(this, provider);
33668 * Adds a xtype elements to the layout.
33672 xtype : 'ContentPanel',
33679 xtype : 'NestedLayoutPanel',
33685 items : [ ... list of content panels or nested layout panels.. ]
33689 * @param {Object} cfg Xtype definition of item to add.
33691 addxtype : function(cfg)
33693 // basically accepts a pannel...
33694 // can accept a layout region..!?!?
33695 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33698 // theory? children can only be panels??
33700 //if (!cfg.xtype.match(/Panel$/)) {
33705 if (typeof(cfg.region) == 'undefined') {
33706 Roo.log("Failed to add Panel, region was not set");
33710 var region = cfg.region;
33716 xitems = cfg.items;
33723 case 'Content': // ContentPanel (el, cfg)
33724 case 'Scroll': // ContentPanel (el, cfg)
33726 cfg.autoCreate = true;
33727 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33729 // var el = this.el.createChild();
33730 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33733 this.add(region, ret);
33737 case 'TreePanel': // our new panel!
33738 cfg.el = this.el.createChild();
33739 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33740 this.add(region, ret);
33745 // create a new Layout (which is a Border Layout...
33747 var clayout = cfg.layout;
33748 clayout.el = this.el.createChild();
33749 clayout.items = clayout.items || [];
33753 // replace this exitems with the clayout ones..
33754 xitems = clayout.items;
33756 // force background off if it's in center...
33757 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33758 cfg.background = false;
33760 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33763 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33764 //console.log('adding nested layout panel ' + cfg.toSource());
33765 this.add(region, ret);
33766 nb = {}; /// find first...
33771 // needs grid and region
33773 //var el = this.getRegion(region).el.createChild();
33775 *var el = this.el.createChild();
33776 // create the grid first...
33777 cfg.grid.container = el;
33778 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33781 if (region == 'center' && this.active ) {
33782 cfg.background = false;
33785 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33787 this.add(region, ret);
33789 if (cfg.background) {
33790 // render grid on panel activation (if panel background)
33791 ret.on('activate', function(gp) {
33792 if (!gp.grid.rendered) {
33793 // gp.grid.render(el);
33797 // cfg.grid.render(el);
33803 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33804 // it was the old xcomponent building that caused this before.
33805 // espeically if border is the top element in the tree.
33815 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33817 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33818 this.add(region, ret);
33822 throw "Can not add '" + cfg.xtype + "' to Border";
33828 this.beginUpdate();
33832 Roo.each(xitems, function(i) {
33833 region = nb && i.region ? i.region : false;
33835 var add = ret.addxtype(i);
33838 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33839 if (!i.background) {
33840 abn[region] = nb[region] ;
33847 // make the last non-background panel active..
33848 //if (nb) { Roo.log(abn); }
33851 for(var r in abn) {
33852 region = this.getRegion(r);
33854 // tried using nb[r], but it does not work..
33856 region.showPanel(abn[r]);
33867 factory : function(cfg)
33870 var validRegions = Roo.bootstrap.layout.Border.regions;
33872 var target = cfg.region;
33875 var r = Roo.bootstrap.layout;
33879 return new r.North(cfg);
33881 return new r.South(cfg);
33883 return new r.East(cfg);
33885 return new r.West(cfg);
33887 return new r.Center(cfg);
33889 throw 'Layout region "'+target+'" not supported.';
33896 * Ext JS Library 1.1.1
33897 * Copyright(c) 2006-2007, Ext JS, LLC.
33899 * Originally Released Under LGPL - original licence link has changed is not relivant.
33902 * <script type="text/javascript">
33906 * @class Roo.bootstrap.layout.Basic
33907 * @extends Roo.util.Observable
33908 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33909 * and does not have a titlebar, tabs or any other features. All it does is size and position
33910 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33911 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33912 * @cfg {string} region the region that it inhabits..
33913 * @cfg {bool} skipConfig skip config?
33917 Roo.bootstrap.layout.Basic = function(config){
33919 this.mgr = config.mgr;
33921 this.position = config.region;
33923 var skipConfig = config.skipConfig;
33927 * @scope Roo.BasicLayoutRegion
33931 * @event beforeremove
33932 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33933 * @param {Roo.LayoutRegion} this
33934 * @param {Roo.ContentPanel} panel The panel
33935 * @param {Object} e The cancel event object
33937 "beforeremove" : true,
33939 * @event invalidated
33940 * Fires when the layout for this region is changed.
33941 * @param {Roo.LayoutRegion} this
33943 "invalidated" : true,
33945 * @event visibilitychange
33946 * Fires when this region is shown or hidden
33947 * @param {Roo.LayoutRegion} this
33948 * @param {Boolean} visibility true or false
33950 "visibilitychange" : true,
33952 * @event paneladded
33953 * Fires when a panel is added.
33954 * @param {Roo.LayoutRegion} this
33955 * @param {Roo.ContentPanel} panel The panel
33957 "paneladded" : true,
33959 * @event panelremoved
33960 * Fires when a panel is removed.
33961 * @param {Roo.LayoutRegion} this
33962 * @param {Roo.ContentPanel} panel The panel
33964 "panelremoved" : true,
33966 * @event beforecollapse
33967 * Fires when this region before collapse.
33968 * @param {Roo.LayoutRegion} this
33970 "beforecollapse" : true,
33973 * Fires when this region is collapsed.
33974 * @param {Roo.LayoutRegion} this
33976 "collapsed" : true,
33979 * Fires when this region is expanded.
33980 * @param {Roo.LayoutRegion} this
33985 * Fires when this region is slid into view.
33986 * @param {Roo.LayoutRegion} this
33988 "slideshow" : true,
33991 * Fires when this region slides out of view.
33992 * @param {Roo.LayoutRegion} this
33994 "slidehide" : true,
33996 * @event panelactivated
33997 * Fires when a panel is activated.
33998 * @param {Roo.LayoutRegion} this
33999 * @param {Roo.ContentPanel} panel The activated panel
34001 "panelactivated" : true,
34004 * Fires when the user resizes this region.
34005 * @param {Roo.LayoutRegion} this
34006 * @param {Number} newSize The new size (width for east/west, height for north/south)
34010 /** A collection of panels in this region. @type Roo.util.MixedCollection */
34011 this.panels = new Roo.util.MixedCollection();
34012 this.panels.getKey = this.getPanelId.createDelegate(this);
34014 this.activePanel = null;
34015 // ensure listeners are added...
34017 if (config.listeners || config.events) {
34018 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
34019 listeners : config.listeners || {},
34020 events : config.events || {}
34024 if(skipConfig !== true){
34025 this.applyConfig(config);
34029 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
34031 getPanelId : function(p){
34035 applyConfig : function(config){
34036 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34037 this.config = config;
34042 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
34043 * the width, for horizontal (north, south) the height.
34044 * @param {Number} newSize The new width or height
34046 resizeTo : function(newSize){
34047 var el = this.el ? this.el :
34048 (this.activePanel ? this.activePanel.getEl() : null);
34050 switch(this.position){
34053 el.setWidth(newSize);
34054 this.fireEvent("resized", this, newSize);
34058 el.setHeight(newSize);
34059 this.fireEvent("resized", this, newSize);
34065 getBox : function(){
34066 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34069 getMargins : function(){
34070 return this.margins;
34073 updateBox : function(box){
34075 var el = this.activePanel.getEl();
34076 el.dom.style.left = box.x + "px";
34077 el.dom.style.top = box.y + "px";
34078 this.activePanel.setSize(box.width, box.height);
34082 * Returns the container element for this region.
34083 * @return {Roo.Element}
34085 getEl : function(){
34086 return this.activePanel;
34090 * Returns true if this region is currently visible.
34091 * @return {Boolean}
34093 isVisible : function(){
34094 return this.activePanel ? true : false;
34097 setActivePanel : function(panel){
34098 panel = this.getPanel(panel);
34099 if(this.activePanel && this.activePanel != panel){
34100 this.activePanel.setActiveState(false);
34101 this.activePanel.getEl().setLeftTop(-10000,-10000);
34103 this.activePanel = panel;
34104 panel.setActiveState(true);
34106 panel.setSize(this.box.width, this.box.height);
34108 this.fireEvent("panelactivated", this, panel);
34109 this.fireEvent("invalidated");
34113 * Show the specified panel.
34114 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34115 * @return {Roo.ContentPanel} The shown panel or null
34117 showPanel : function(panel){
34118 panel = this.getPanel(panel);
34120 this.setActivePanel(panel);
34126 * Get the active panel for this region.
34127 * @return {Roo.ContentPanel} The active panel or null
34129 getActivePanel : function(){
34130 return this.activePanel;
34134 * Add the passed ContentPanel(s)
34135 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34136 * @return {Roo.ContentPanel} The panel added (if only one was added)
34138 add : function(panel){
34139 if(arguments.length > 1){
34140 for(var i = 0, len = arguments.length; i < len; i++) {
34141 this.add(arguments[i]);
34145 if(this.hasPanel(panel)){
34146 this.showPanel(panel);
34149 var el = panel.getEl();
34150 if(el.dom.parentNode != this.mgr.el.dom){
34151 this.mgr.el.dom.appendChild(el.dom);
34153 if(panel.setRegion){
34154 panel.setRegion(this);
34156 this.panels.add(panel);
34157 el.setStyle("position", "absolute");
34158 if(!panel.background){
34159 this.setActivePanel(panel);
34160 if(this.config.initialSize && this.panels.getCount()==1){
34161 this.resizeTo(this.config.initialSize);
34164 this.fireEvent("paneladded", this, panel);
34169 * Returns true if the panel is in this region.
34170 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34171 * @return {Boolean}
34173 hasPanel : function(panel){
34174 if(typeof panel == "object"){ // must be panel obj
34175 panel = panel.getId();
34177 return this.getPanel(panel) ? true : false;
34181 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34182 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34183 * @param {Boolean} preservePanel Overrides the config preservePanel option
34184 * @return {Roo.ContentPanel} The panel that was removed
34186 remove : function(panel, preservePanel){
34187 panel = this.getPanel(panel);
34192 this.fireEvent("beforeremove", this, panel, e);
34193 if(e.cancel === true){
34196 var panelId = panel.getId();
34197 this.panels.removeKey(panelId);
34202 * Returns the panel specified or null if it's not in this region.
34203 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34204 * @return {Roo.ContentPanel}
34206 getPanel : function(id){
34207 if(typeof id == "object"){ // must be panel obj
34210 return this.panels.get(id);
34214 * Returns this regions position (north/south/east/west/center).
34217 getPosition: function(){
34218 return this.position;
34222 * Ext JS Library 1.1.1
34223 * Copyright(c) 2006-2007, Ext JS, LLC.
34225 * Originally Released Under LGPL - original licence link has changed is not relivant.
34228 * <script type="text/javascript">
34232 * @class Roo.bootstrap.layout.Region
34233 * @extends Roo.bootstrap.layout.Basic
34234 * This class represents a region in a layout manager.
34236 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34237 * @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})
34238 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34239 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34240 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34241 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34242 * @cfg {String} title The title for the region (overrides panel titles)
34243 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34244 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34245 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34246 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34247 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34248 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34249 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34250 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34251 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34252 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34254 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34255 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34256 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34257 * @cfg {Number} width For East/West panels
34258 * @cfg {Number} height For North/South panels
34259 * @cfg {Boolean} split To show the splitter
34260 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34262 * @cfg {string} cls Extra CSS classes to add to region
34264 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34265 * @cfg {string} region the region that it inhabits..
34268 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34269 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34271 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34272 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34273 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34275 Roo.bootstrap.layout.Region = function(config)
34277 this.applyConfig(config);
34279 var mgr = config.mgr;
34280 var pos = config.region;
34281 config.skipConfig = true;
34282 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34285 this.onRender(mgr.el);
34288 this.visible = true;
34289 this.collapsed = false;
34290 this.unrendered_panels = [];
34293 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34295 position: '', // set by wrapper (eg. north/south etc..)
34296 unrendered_panels : null, // unrendered panels.
34297 createBody : function(){
34298 /** This region's body element
34299 * @type Roo.Element */
34300 this.bodyEl = this.el.createChild({
34302 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34306 onRender: function(ctr, pos)
34308 var dh = Roo.DomHelper;
34309 /** This region's container element
34310 * @type Roo.Element */
34311 this.el = dh.append(ctr.dom, {
34313 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34315 /** This region's title element
34316 * @type Roo.Element */
34318 this.titleEl = dh.append(this.el.dom,
34321 unselectable: "on",
34322 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34324 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34325 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34328 this.titleEl.enableDisplayMode();
34329 /** This region's title text element
34330 * @type HTMLElement */
34331 this.titleTextEl = this.titleEl.dom.firstChild;
34332 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34334 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34335 this.closeBtn.enableDisplayMode();
34336 this.closeBtn.on("click", this.closeClicked, this);
34337 this.closeBtn.hide();
34339 this.createBody(this.config);
34340 if(this.config.hideWhenEmpty){
34342 this.on("paneladded", this.validateVisibility, this);
34343 this.on("panelremoved", this.validateVisibility, this);
34345 if(this.autoScroll){
34346 this.bodyEl.setStyle("overflow", "auto");
34348 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34350 //if(c.titlebar !== false){
34351 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34352 this.titleEl.hide();
34354 this.titleEl.show();
34355 if(this.config.title){
34356 this.titleTextEl.innerHTML = this.config.title;
34360 if(this.config.collapsed){
34361 this.collapse(true);
34363 if(this.config.hidden){
34367 if (this.unrendered_panels && this.unrendered_panels.length) {
34368 for (var i =0;i< this.unrendered_panels.length; i++) {
34369 this.add(this.unrendered_panels[i]);
34371 this.unrendered_panels = null;
34377 applyConfig : function(c)
34380 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34381 var dh = Roo.DomHelper;
34382 if(c.titlebar !== false){
34383 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34384 this.collapseBtn.on("click", this.collapse, this);
34385 this.collapseBtn.enableDisplayMode();
34387 if(c.showPin === true || this.showPin){
34388 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34389 this.stickBtn.enableDisplayMode();
34390 this.stickBtn.on("click", this.expand, this);
34391 this.stickBtn.hide();
34396 /** This region's collapsed element
34397 * @type Roo.Element */
34400 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34401 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34404 if(c.floatable !== false){
34405 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34406 this.collapsedEl.on("click", this.collapseClick, this);
34409 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34410 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34411 id: "message", unselectable: "on", style:{"float":"left"}});
34412 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34414 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34415 this.expandBtn.on("click", this.expand, this);
34419 if(this.collapseBtn){
34420 this.collapseBtn.setVisible(c.collapsible == true);
34423 this.cmargins = c.cmargins || this.cmargins ||
34424 (this.position == "west" || this.position == "east" ?
34425 {top: 0, left: 2, right:2, bottom: 0} :
34426 {top: 2, left: 0, right:0, bottom: 2});
34428 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34431 this.bottomTabs = c.tabPosition != "top";
34433 this.autoScroll = c.autoScroll || false;
34438 this.duration = c.duration || .30;
34439 this.slideDuration = c.slideDuration || .45;
34444 * Returns true if this region is currently visible.
34445 * @return {Boolean}
34447 isVisible : function(){
34448 return this.visible;
34452 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34453 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34455 //setCollapsedTitle : function(title){
34456 // title = title || " ";
34457 // if(this.collapsedTitleTextEl){
34458 // this.collapsedTitleTextEl.innerHTML = title;
34462 getBox : function(){
34464 // if(!this.collapsed){
34465 b = this.el.getBox(false, true);
34467 // b = this.collapsedEl.getBox(false, true);
34472 getMargins : function(){
34473 return this.margins;
34474 //return this.collapsed ? this.cmargins : this.margins;
34477 highlight : function(){
34478 this.el.addClass("x-layout-panel-dragover");
34481 unhighlight : function(){
34482 this.el.removeClass("x-layout-panel-dragover");
34485 updateBox : function(box)
34487 if (!this.bodyEl) {
34488 return; // not rendered yet..
34492 if(!this.collapsed){
34493 this.el.dom.style.left = box.x + "px";
34494 this.el.dom.style.top = box.y + "px";
34495 this.updateBody(box.width, box.height);
34497 this.collapsedEl.dom.style.left = box.x + "px";
34498 this.collapsedEl.dom.style.top = box.y + "px";
34499 this.collapsedEl.setSize(box.width, box.height);
34502 this.tabs.autoSizeTabs();
34506 updateBody : function(w, h)
34509 this.el.setWidth(w);
34510 w -= this.el.getBorderWidth("rl");
34511 if(this.config.adjustments){
34512 w += this.config.adjustments[0];
34515 if(h !== null && h > 0){
34516 this.el.setHeight(h);
34517 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34518 h -= this.el.getBorderWidth("tb");
34519 if(this.config.adjustments){
34520 h += this.config.adjustments[1];
34522 this.bodyEl.setHeight(h);
34524 h = this.tabs.syncHeight(h);
34527 if(this.panelSize){
34528 w = w !== null ? w : this.panelSize.width;
34529 h = h !== null ? h : this.panelSize.height;
34531 if(this.activePanel){
34532 var el = this.activePanel.getEl();
34533 w = w !== null ? w : el.getWidth();
34534 h = h !== null ? h : el.getHeight();
34535 this.panelSize = {width: w, height: h};
34536 this.activePanel.setSize(w, h);
34538 if(Roo.isIE && this.tabs){
34539 this.tabs.el.repaint();
34544 * Returns the container element for this region.
34545 * @return {Roo.Element}
34547 getEl : function(){
34552 * Hides this region.
34555 //if(!this.collapsed){
34556 this.el.dom.style.left = "-2000px";
34559 // this.collapsedEl.dom.style.left = "-2000px";
34560 // this.collapsedEl.hide();
34562 this.visible = false;
34563 this.fireEvent("visibilitychange", this, false);
34567 * Shows this region if it was previously hidden.
34570 //if(!this.collapsed){
34573 // this.collapsedEl.show();
34575 this.visible = true;
34576 this.fireEvent("visibilitychange", this, true);
34579 closeClicked : function(){
34580 if(this.activePanel){
34581 this.remove(this.activePanel);
34585 collapseClick : function(e){
34587 e.stopPropagation();
34590 e.stopPropagation();
34596 * Collapses this region.
34597 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34600 collapse : function(skipAnim, skipCheck = false){
34601 if(this.collapsed) {
34605 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34607 this.collapsed = true;
34609 this.split.el.hide();
34611 if(this.config.animate && skipAnim !== true){
34612 this.fireEvent("invalidated", this);
34613 this.animateCollapse();
34615 this.el.setLocation(-20000,-20000);
34617 this.collapsedEl.show();
34618 this.fireEvent("collapsed", this);
34619 this.fireEvent("invalidated", this);
34625 animateCollapse : function(){
34630 * Expands this region if it was previously collapsed.
34631 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34632 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34635 expand : function(e, skipAnim){
34637 e.stopPropagation();
34639 if(!this.collapsed || this.el.hasActiveFx()) {
34643 this.afterSlideIn();
34646 this.collapsed = false;
34647 if(this.config.animate && skipAnim !== true){
34648 this.animateExpand();
34652 this.split.el.show();
34654 this.collapsedEl.setLocation(-2000,-2000);
34655 this.collapsedEl.hide();
34656 this.fireEvent("invalidated", this);
34657 this.fireEvent("expanded", this);
34661 animateExpand : function(){
34665 initTabs : function()
34667 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34669 var ts = new Roo.bootstrap.panel.Tabs({
34670 el: this.bodyEl.dom,
34671 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34672 disableTooltips: this.config.disableTabTips,
34673 toolbar : this.config.toolbar
34676 if(this.config.hideTabs){
34677 ts.stripWrap.setDisplayed(false);
34680 ts.resizeTabs = this.config.resizeTabs === true;
34681 ts.minTabWidth = this.config.minTabWidth || 40;
34682 ts.maxTabWidth = this.config.maxTabWidth || 250;
34683 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34684 ts.monitorResize = false;
34685 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34686 ts.bodyEl.addClass('roo-layout-tabs-body');
34687 this.panels.each(this.initPanelAsTab, this);
34690 initPanelAsTab : function(panel){
34691 var ti = this.tabs.addTab(
34695 this.config.closeOnTab && panel.isClosable(),
34698 if(panel.tabTip !== undefined){
34699 ti.setTooltip(panel.tabTip);
34701 ti.on("activate", function(){
34702 this.setActivePanel(panel);
34705 if(this.config.closeOnTab){
34706 ti.on("beforeclose", function(t, e){
34708 this.remove(panel);
34712 panel.tabItem = ti;
34717 updatePanelTitle : function(panel, title)
34719 if(this.activePanel == panel){
34720 this.updateTitle(title);
34723 var ti = this.tabs.getTab(panel.getEl().id);
34725 if(panel.tabTip !== undefined){
34726 ti.setTooltip(panel.tabTip);
34731 updateTitle : function(title){
34732 if(this.titleTextEl && !this.config.title){
34733 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34737 setActivePanel : function(panel)
34739 panel = this.getPanel(panel);
34740 if(this.activePanel && this.activePanel != panel){
34741 this.activePanel.setActiveState(false);
34743 this.activePanel = panel;
34744 panel.setActiveState(true);
34745 if(this.panelSize){
34746 panel.setSize(this.panelSize.width, this.panelSize.height);
34749 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34751 this.updateTitle(panel.getTitle());
34753 this.fireEvent("invalidated", this);
34755 this.fireEvent("panelactivated", this, panel);
34759 * Shows the specified panel.
34760 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34761 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34763 showPanel : function(panel)
34765 panel = this.getPanel(panel);
34768 var tab = this.tabs.getTab(panel.getEl().id);
34769 if(tab.isHidden()){
34770 this.tabs.unhideTab(tab.id);
34774 this.setActivePanel(panel);
34781 * Get the active panel for this region.
34782 * @return {Roo.ContentPanel} The active panel or null
34784 getActivePanel : function(){
34785 return this.activePanel;
34788 validateVisibility : function(){
34789 if(this.panels.getCount() < 1){
34790 this.updateTitle(" ");
34791 this.closeBtn.hide();
34794 if(!this.isVisible()){
34801 * Adds the passed ContentPanel(s) to this region.
34802 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34803 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34805 add : function(panel)
34807 if(arguments.length > 1){
34808 for(var i = 0, len = arguments.length; i < len; i++) {
34809 this.add(arguments[i]);
34814 // if we have not been rendered yet, then we can not really do much of this..
34815 if (!this.bodyEl) {
34816 this.unrendered_panels.push(panel);
34823 if(this.hasPanel(panel)){
34824 this.showPanel(panel);
34827 panel.setRegion(this);
34828 this.panels.add(panel);
34829 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34830 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34831 // and hide them... ???
34832 this.bodyEl.dom.appendChild(panel.getEl().dom);
34833 if(panel.background !== true){
34834 this.setActivePanel(panel);
34836 this.fireEvent("paneladded", this, panel);
34843 this.initPanelAsTab(panel);
34847 if(panel.background !== true){
34848 this.tabs.activate(panel.getEl().id);
34850 this.fireEvent("paneladded", this, panel);
34855 * Hides the tab for the specified panel.
34856 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34858 hidePanel : function(panel){
34859 if(this.tabs && (panel = this.getPanel(panel))){
34860 this.tabs.hideTab(panel.getEl().id);
34865 * Unhides the tab for a previously hidden panel.
34866 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34868 unhidePanel : function(panel){
34869 if(this.tabs && (panel = this.getPanel(panel))){
34870 this.tabs.unhideTab(panel.getEl().id);
34874 clearPanels : function(){
34875 while(this.panels.getCount() > 0){
34876 this.remove(this.panels.first());
34881 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34882 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34883 * @param {Boolean} preservePanel Overrides the config preservePanel option
34884 * @return {Roo.ContentPanel} The panel that was removed
34886 remove : function(panel, preservePanel)
34888 panel = this.getPanel(panel);
34893 this.fireEvent("beforeremove", this, panel, e);
34894 if(e.cancel === true){
34897 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34898 var panelId = panel.getId();
34899 this.panels.removeKey(panelId);
34901 document.body.appendChild(panel.getEl().dom);
34904 this.tabs.removeTab(panel.getEl().id);
34905 }else if (!preservePanel){
34906 this.bodyEl.dom.removeChild(panel.getEl().dom);
34908 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34909 var p = this.panels.first();
34910 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34911 tempEl.appendChild(p.getEl().dom);
34912 this.bodyEl.update("");
34913 this.bodyEl.dom.appendChild(p.getEl().dom);
34915 this.updateTitle(p.getTitle());
34917 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34918 this.setActivePanel(p);
34920 panel.setRegion(null);
34921 if(this.activePanel == panel){
34922 this.activePanel = null;
34924 if(this.config.autoDestroy !== false && preservePanel !== true){
34925 try{panel.destroy();}catch(e){}
34927 this.fireEvent("panelremoved", this, panel);
34932 * Returns the TabPanel component used by this region
34933 * @return {Roo.TabPanel}
34935 getTabs : function(){
34939 createTool : function(parentEl, className){
34940 var btn = Roo.DomHelper.append(parentEl, {
34942 cls: "x-layout-tools-button",
34945 cls: "roo-layout-tools-button-inner " + className,
34949 btn.addClassOnOver("roo-layout-tools-button-over");
34954 * Ext JS Library 1.1.1
34955 * Copyright(c) 2006-2007, Ext JS, LLC.
34957 * Originally Released Under LGPL - original licence link has changed is not relivant.
34960 * <script type="text/javascript">
34966 * @class Roo.SplitLayoutRegion
34967 * @extends Roo.LayoutRegion
34968 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34970 Roo.bootstrap.layout.Split = function(config){
34971 this.cursor = config.cursor;
34972 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34975 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34977 splitTip : "Drag to resize.",
34978 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34979 useSplitTips : false,
34981 applyConfig : function(config){
34982 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34985 onRender : function(ctr,pos) {
34987 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34988 if(!this.config.split){
34993 var splitEl = Roo.DomHelper.append(ctr.dom, {
34995 id: this.el.id + "-split",
34996 cls: "roo-layout-split roo-layout-split-"+this.position,
34999 /** The SplitBar for this region
35000 * @type Roo.SplitBar */
35001 // does not exist yet...
35002 Roo.log([this.position, this.orientation]);
35004 this.split = new Roo.bootstrap.SplitBar({
35005 dragElement : splitEl,
35006 resizingElement: this.el,
35007 orientation : this.orientation
35010 this.split.on("moved", this.onSplitMove, this);
35011 this.split.useShim = this.config.useShim === true;
35012 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
35013 if(this.useSplitTips){
35014 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
35016 //if(config.collapsible){
35017 // this.split.el.on("dblclick", this.collapse, this);
35020 if(typeof this.config.minSize != "undefined"){
35021 this.split.minSize = this.config.minSize;
35023 if(typeof this.config.maxSize != "undefined"){
35024 this.split.maxSize = this.config.maxSize;
35026 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
35027 this.hideSplitter();
35032 getHMaxSize : function(){
35033 var cmax = this.config.maxSize || 10000;
35034 var center = this.mgr.getRegion("center");
35035 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
35038 getVMaxSize : function(){
35039 var cmax = this.config.maxSize || 10000;
35040 var center = this.mgr.getRegion("center");
35041 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
35044 onSplitMove : function(split, newSize){
35045 this.fireEvent("resized", this, newSize);
35049 * Returns the {@link Roo.SplitBar} for this region.
35050 * @return {Roo.SplitBar}
35052 getSplitBar : function(){
35057 this.hideSplitter();
35058 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35061 hideSplitter : function(){
35063 this.split.el.setLocation(-2000,-2000);
35064 this.split.el.hide();
35070 this.split.el.show();
35072 Roo.bootstrap.layout.Split.superclass.show.call(this);
35075 beforeSlide: function(){
35076 if(Roo.isGecko){// firefox overflow auto bug workaround
35077 this.bodyEl.clip();
35079 this.tabs.bodyEl.clip();
35081 if(this.activePanel){
35082 this.activePanel.getEl().clip();
35084 if(this.activePanel.beforeSlide){
35085 this.activePanel.beforeSlide();
35091 afterSlide : function(){
35092 if(Roo.isGecko){// firefox overflow auto bug workaround
35093 this.bodyEl.unclip();
35095 this.tabs.bodyEl.unclip();
35097 if(this.activePanel){
35098 this.activePanel.getEl().unclip();
35099 if(this.activePanel.afterSlide){
35100 this.activePanel.afterSlide();
35106 initAutoHide : function(){
35107 if(this.autoHide !== false){
35108 if(!this.autoHideHd){
35109 var st = new Roo.util.DelayedTask(this.slideIn, this);
35110 this.autoHideHd = {
35111 "mouseout": function(e){
35112 if(!e.within(this.el, true)){
35116 "mouseover" : function(e){
35122 this.el.on(this.autoHideHd);
35126 clearAutoHide : function(){
35127 if(this.autoHide !== false){
35128 this.el.un("mouseout", this.autoHideHd.mouseout);
35129 this.el.un("mouseover", this.autoHideHd.mouseover);
35133 clearMonitor : function(){
35134 Roo.get(document).un("click", this.slideInIf, this);
35137 // these names are backwards but not changed for compat
35138 slideOut : function(){
35139 if(this.isSlid || this.el.hasActiveFx()){
35142 this.isSlid = true;
35143 if(this.collapseBtn){
35144 this.collapseBtn.hide();
35146 this.closeBtnState = this.closeBtn.getStyle('display');
35147 this.closeBtn.hide();
35149 this.stickBtn.show();
35152 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35153 this.beforeSlide();
35154 this.el.setStyle("z-index", 10001);
35155 this.el.slideIn(this.getSlideAnchor(), {
35156 callback: function(){
35158 this.initAutoHide();
35159 Roo.get(document).on("click", this.slideInIf, this);
35160 this.fireEvent("slideshow", this);
35167 afterSlideIn : function(){
35168 this.clearAutoHide();
35169 this.isSlid = false;
35170 this.clearMonitor();
35171 this.el.setStyle("z-index", "");
35172 if(this.collapseBtn){
35173 this.collapseBtn.show();
35175 this.closeBtn.setStyle('display', this.closeBtnState);
35177 this.stickBtn.hide();
35179 this.fireEvent("slidehide", this);
35182 slideIn : function(cb){
35183 if(!this.isSlid || this.el.hasActiveFx()){
35187 this.isSlid = false;
35188 this.beforeSlide();
35189 this.el.slideOut(this.getSlideAnchor(), {
35190 callback: function(){
35191 this.el.setLeftTop(-10000, -10000);
35193 this.afterSlideIn();
35201 slideInIf : function(e){
35202 if(!e.within(this.el)){
35207 animateCollapse : function(){
35208 this.beforeSlide();
35209 this.el.setStyle("z-index", 20000);
35210 var anchor = this.getSlideAnchor();
35211 this.el.slideOut(anchor, {
35212 callback : function(){
35213 this.el.setStyle("z-index", "");
35214 this.collapsedEl.slideIn(anchor, {duration:.3});
35216 this.el.setLocation(-10000,-10000);
35218 this.fireEvent("collapsed", this);
35225 animateExpand : function(){
35226 this.beforeSlide();
35227 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35228 this.el.setStyle("z-index", 20000);
35229 this.collapsedEl.hide({
35232 this.el.slideIn(this.getSlideAnchor(), {
35233 callback : function(){
35234 this.el.setStyle("z-index", "");
35237 this.split.el.show();
35239 this.fireEvent("invalidated", this);
35240 this.fireEvent("expanded", this);
35268 getAnchor : function(){
35269 return this.anchors[this.position];
35272 getCollapseAnchor : function(){
35273 return this.canchors[this.position];
35276 getSlideAnchor : function(){
35277 return this.sanchors[this.position];
35280 getAlignAdj : function(){
35281 var cm = this.cmargins;
35282 switch(this.position){
35298 getExpandAdj : function(){
35299 var c = this.collapsedEl, cm = this.cmargins;
35300 switch(this.position){
35302 return [-(cm.right+c.getWidth()+cm.left), 0];
35305 return [cm.right+c.getWidth()+cm.left, 0];
35308 return [0, -(cm.top+cm.bottom+c.getHeight())];
35311 return [0, cm.top+cm.bottom+c.getHeight()];
35317 * Ext JS Library 1.1.1
35318 * Copyright(c) 2006-2007, Ext JS, LLC.
35320 * Originally Released Under LGPL - original licence link has changed is not relivant.
35323 * <script type="text/javascript">
35326 * These classes are private internal classes
35328 Roo.bootstrap.layout.Center = function(config){
35329 config.region = "center";
35330 Roo.bootstrap.layout.Region.call(this, config);
35331 this.visible = true;
35332 this.minWidth = config.minWidth || 20;
35333 this.minHeight = config.minHeight || 20;
35336 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35338 // center panel can't be hidden
35342 // center panel can't be hidden
35345 getMinWidth: function(){
35346 return this.minWidth;
35349 getMinHeight: function(){
35350 return this.minHeight;
35363 Roo.bootstrap.layout.North = function(config)
35365 config.region = 'north';
35366 config.cursor = 'n-resize';
35368 Roo.bootstrap.layout.Split.call(this, config);
35372 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35373 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35374 this.split.el.addClass("roo-layout-split-v");
35376 var size = config.initialSize || config.height;
35377 if(typeof size != "undefined"){
35378 this.el.setHeight(size);
35381 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35383 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35387 getBox : function(){
35388 if(this.collapsed){
35389 return this.collapsedEl.getBox();
35391 var box = this.el.getBox();
35393 box.height += this.split.el.getHeight();
35398 updateBox : function(box){
35399 if(this.split && !this.collapsed){
35400 box.height -= this.split.el.getHeight();
35401 this.split.el.setLeft(box.x);
35402 this.split.el.setTop(box.y+box.height);
35403 this.split.el.setWidth(box.width);
35405 if(this.collapsed){
35406 this.updateBody(box.width, null);
35408 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35416 Roo.bootstrap.layout.South = function(config){
35417 config.region = 'south';
35418 config.cursor = 's-resize';
35419 Roo.bootstrap.layout.Split.call(this, config);
35421 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35422 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35423 this.split.el.addClass("roo-layout-split-v");
35425 var size = config.initialSize || config.height;
35426 if(typeof size != "undefined"){
35427 this.el.setHeight(size);
35431 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35432 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35433 getBox : function(){
35434 if(this.collapsed){
35435 return this.collapsedEl.getBox();
35437 var box = this.el.getBox();
35439 var sh = this.split.el.getHeight();
35446 updateBox : function(box){
35447 if(this.split && !this.collapsed){
35448 var sh = this.split.el.getHeight();
35451 this.split.el.setLeft(box.x);
35452 this.split.el.setTop(box.y-sh);
35453 this.split.el.setWidth(box.width);
35455 if(this.collapsed){
35456 this.updateBody(box.width, null);
35458 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35462 Roo.bootstrap.layout.East = function(config){
35463 config.region = "east";
35464 config.cursor = "e-resize";
35465 Roo.bootstrap.layout.Split.call(this, config);
35467 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35468 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35469 this.split.el.addClass("roo-layout-split-h");
35471 var size = config.initialSize || config.width;
35472 if(typeof size != "undefined"){
35473 this.el.setWidth(size);
35476 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35477 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35478 getBox : function(){
35479 if(this.collapsed){
35480 return this.collapsedEl.getBox();
35482 var box = this.el.getBox();
35484 var sw = this.split.el.getWidth();
35491 updateBox : function(box){
35492 if(this.split && !this.collapsed){
35493 var sw = this.split.el.getWidth();
35495 this.split.el.setLeft(box.x);
35496 this.split.el.setTop(box.y);
35497 this.split.el.setHeight(box.height);
35500 if(this.collapsed){
35501 this.updateBody(null, box.height);
35503 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35507 Roo.bootstrap.layout.West = function(config){
35508 config.region = "west";
35509 config.cursor = "w-resize";
35511 Roo.bootstrap.layout.Split.call(this, config);
35513 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35514 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35515 this.split.el.addClass("roo-layout-split-h");
35519 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35520 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35522 onRender: function(ctr, pos)
35524 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35525 var size = this.config.initialSize || this.config.width;
35526 if(typeof size != "undefined"){
35527 this.el.setWidth(size);
35531 getBox : function(){
35532 if(this.collapsed){
35533 return this.collapsedEl.getBox();
35535 var box = this.el.getBox();
35537 box.width += this.split.el.getWidth();
35542 updateBox : function(box){
35543 if(this.split && !this.collapsed){
35544 var sw = this.split.el.getWidth();
35546 this.split.el.setLeft(box.x+box.width);
35547 this.split.el.setTop(box.y);
35548 this.split.el.setHeight(box.height);
35550 if(this.collapsed){
35551 this.updateBody(null, box.height);
35553 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35556 Roo.namespace("Roo.bootstrap.panel");/*
35558 * Ext JS Library 1.1.1
35559 * Copyright(c) 2006-2007, Ext JS, LLC.
35561 * Originally Released Under LGPL - original licence link has changed is not relivant.
35564 * <script type="text/javascript">
35567 * @class Roo.ContentPanel
35568 * @extends Roo.util.Observable
35569 * A basic ContentPanel element.
35570 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35571 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35572 * @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
35573 * @cfg {Boolean} closable True if the panel can be closed/removed
35574 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35575 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35576 * @cfg {Toolbar} toolbar A toolbar for this panel
35577 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35578 * @cfg {String} title The title for this panel
35579 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35580 * @cfg {String} url Calls {@link #setUrl} with this value
35581 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35582 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35583 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35584 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35585 * @cfg {Boolean} badges render the badges
35588 * Create a new ContentPanel.
35589 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35590 * @param {String/Object} config A string to set only the title or a config object
35591 * @param {String} content (optional) Set the HTML content for this panel
35592 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35594 Roo.bootstrap.panel.Content = function( config){
35596 this.tpl = config.tpl || false;
35598 var el = config.el;
35599 var content = config.content;
35601 if(config.autoCreate){ // xtype is available if this is called from factory
35604 this.el = Roo.get(el);
35605 if(!this.el && config && config.autoCreate){
35606 if(typeof config.autoCreate == "object"){
35607 if(!config.autoCreate.id){
35608 config.autoCreate.id = config.id||el;
35610 this.el = Roo.DomHelper.append(document.body,
35611 config.autoCreate, true);
35613 var elcfg = { tag: "div",
35614 cls: "roo-layout-inactive-content",
35618 elcfg.html = config.html;
35622 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35625 this.closable = false;
35626 this.loaded = false;
35627 this.active = false;
35630 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35632 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35634 this.wrapEl = this.el; //this.el.wrap();
35636 if (config.toolbar.items) {
35637 ti = config.toolbar.items ;
35638 delete config.toolbar.items ;
35642 this.toolbar.render(this.wrapEl, 'before');
35643 for(var i =0;i < ti.length;i++) {
35644 // Roo.log(['add child', items[i]]);
35645 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35647 this.toolbar.items = nitems;
35648 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35649 delete config.toolbar;
35653 // xtype created footer. - not sure if will work as we normally have to render first..
35654 if (this.footer && !this.footer.el && this.footer.xtype) {
35655 if (!this.wrapEl) {
35656 this.wrapEl = this.el.wrap();
35659 this.footer.container = this.wrapEl.createChild();
35661 this.footer = Roo.factory(this.footer, Roo);
35666 if(typeof config == "string"){
35667 this.title = config;
35669 Roo.apply(this, config);
35673 this.resizeEl = Roo.get(this.resizeEl, true);
35675 this.resizeEl = this.el;
35677 // handle view.xtype
35685 * Fires when this panel is activated.
35686 * @param {Roo.ContentPanel} this
35690 * @event deactivate
35691 * Fires when this panel is activated.
35692 * @param {Roo.ContentPanel} this
35694 "deactivate" : true,
35698 * Fires when this panel is resized if fitToFrame is true.
35699 * @param {Roo.ContentPanel} this
35700 * @param {Number} width The width after any component adjustments
35701 * @param {Number} height The height after any component adjustments
35707 * Fires when this tab is created
35708 * @param {Roo.ContentPanel} this
35719 if(this.autoScroll){
35720 this.resizeEl.setStyle("overflow", "auto");
35722 // fix randome scrolling
35723 //this.el.on('scroll', function() {
35724 // Roo.log('fix random scolling');
35725 // this.scrollTo('top',0);
35728 content = content || this.content;
35730 this.setContent(content);
35732 if(config && config.url){
35733 this.setUrl(this.url, this.params, this.loadOnce);
35738 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35740 if (this.view && typeof(this.view.xtype) != 'undefined') {
35741 this.view.el = this.el.appendChild(document.createElement("div"));
35742 this.view = Roo.factory(this.view);
35743 this.view.render && this.view.render(false, '');
35747 this.fireEvent('render', this);
35750 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35754 setRegion : function(region){
35755 this.region = region;
35756 this.setActiveClass(region && !this.background);
35760 setActiveClass: function(state)
35763 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35764 this.el.setStyle('position','relative');
35766 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35767 this.el.setStyle('position', 'absolute');
35772 * Returns the toolbar for this Panel if one was configured.
35773 * @return {Roo.Toolbar}
35775 getToolbar : function(){
35776 return this.toolbar;
35779 setActiveState : function(active)
35781 this.active = active;
35782 this.setActiveClass(active);
35784 this.fireEvent("deactivate", this);
35786 this.fireEvent("activate", this);
35790 * Updates this panel's element
35791 * @param {String} content The new content
35792 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35794 setContent : function(content, loadScripts){
35795 this.el.update(content, loadScripts);
35798 ignoreResize : function(w, h){
35799 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35802 this.lastSize = {width: w, height: h};
35807 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35808 * @return {Roo.UpdateManager} The UpdateManager
35810 getUpdateManager : function(){
35811 return this.el.getUpdateManager();
35814 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35815 * @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:
35818 url: "your-url.php",
35819 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35820 callback: yourFunction,
35821 scope: yourObject, //(optional scope)
35824 text: "Loading...",
35829 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35830 * 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.
35831 * @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}
35832 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35833 * @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.
35834 * @return {Roo.ContentPanel} this
35837 var um = this.el.getUpdateManager();
35838 um.update.apply(um, arguments);
35844 * 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.
35845 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35846 * @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)
35847 * @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)
35848 * @return {Roo.UpdateManager} The UpdateManager
35850 setUrl : function(url, params, loadOnce){
35851 if(this.refreshDelegate){
35852 this.removeListener("activate", this.refreshDelegate);
35854 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35855 this.on("activate", this.refreshDelegate);
35856 return this.el.getUpdateManager();
35859 _handleRefresh : function(url, params, loadOnce){
35860 if(!loadOnce || !this.loaded){
35861 var updater = this.el.getUpdateManager();
35862 updater.update(url, params, this._setLoaded.createDelegate(this));
35866 _setLoaded : function(){
35867 this.loaded = true;
35871 * Returns this panel's id
35874 getId : function(){
35879 * Returns this panel's element - used by regiosn to add.
35880 * @return {Roo.Element}
35882 getEl : function(){
35883 return this.wrapEl || this.el;
35888 adjustForComponents : function(width, height)
35890 //Roo.log('adjustForComponents ');
35891 if(this.resizeEl != this.el){
35892 width -= this.el.getFrameWidth('lr');
35893 height -= this.el.getFrameWidth('tb');
35896 var te = this.toolbar.getEl();
35897 te.setWidth(width);
35898 height -= te.getHeight();
35901 var te = this.footer.getEl();
35902 te.setWidth(width);
35903 height -= te.getHeight();
35907 if(this.adjustments){
35908 width += this.adjustments[0];
35909 height += this.adjustments[1];
35911 return {"width": width, "height": height};
35914 setSize : function(width, height){
35915 if(this.fitToFrame && !this.ignoreResize(width, height)){
35916 if(this.fitContainer && this.resizeEl != this.el){
35917 this.el.setSize(width, height);
35919 var size = this.adjustForComponents(width, height);
35920 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35921 this.fireEvent('resize', this, size.width, size.height);
35926 * Returns this panel's title
35929 getTitle : function(){
35931 if (typeof(this.title) != 'object') {
35936 for (var k in this.title) {
35937 if (!this.title.hasOwnProperty(k)) {
35941 if (k.indexOf('-') >= 0) {
35942 var s = k.split('-');
35943 for (var i = 0; i<s.length; i++) {
35944 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
35947 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
35954 * Set this panel's title
35955 * @param {String} title
35957 setTitle : function(title){
35958 this.title = title;
35960 this.region.updatePanelTitle(this, title);
35965 * Returns true is this panel was configured to be closable
35966 * @return {Boolean}
35968 isClosable : function(){
35969 return this.closable;
35972 beforeSlide : function(){
35974 this.resizeEl.clip();
35977 afterSlide : function(){
35979 this.resizeEl.unclip();
35983 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35984 * Will fail silently if the {@link #setUrl} method has not been called.
35985 * This does not activate the panel, just updates its content.
35987 refresh : function(){
35988 if(this.refreshDelegate){
35989 this.loaded = false;
35990 this.refreshDelegate();
35995 * Destroys this panel
35997 destroy : function(){
35998 this.el.removeAllListeners();
35999 var tempEl = document.createElement("span");
36000 tempEl.appendChild(this.el.dom);
36001 tempEl.innerHTML = "";
36007 * form - if the content panel contains a form - this is a reference to it.
36008 * @type {Roo.form.Form}
36012 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
36013 * This contains a reference to it.
36019 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
36029 * @param {Object} cfg Xtype definition of item to add.
36033 getChildContainer: function () {
36034 return this.getEl();
36039 var ret = new Roo.factory(cfg);
36044 if (cfg.xtype.match(/^Form$/)) {
36047 //if (this.footer) {
36048 // el = this.footer.container.insertSibling(false, 'before');
36050 el = this.el.createChild();
36053 this.form = new Roo.form.Form(cfg);
36056 if ( this.form.allItems.length) {
36057 this.form.render(el.dom);
36061 // should only have one of theses..
36062 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36063 // views.. should not be just added - used named prop 'view''
36065 cfg.el = this.el.appendChild(document.createElement("div"));
36068 var ret = new Roo.factory(cfg);
36070 ret.render && ret.render(false, ''); // render blank..
36080 * @class Roo.bootstrap.panel.Grid
36081 * @extends Roo.bootstrap.panel.Content
36083 * Create a new GridPanel.
36084 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36085 * @param {Object} config A the config object
36091 Roo.bootstrap.panel.Grid = function(config)
36095 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36096 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36098 config.el = this.wrapper;
36099 //this.el = this.wrapper;
36101 if (config.container) {
36102 // ctor'ed from a Border/panel.grid
36105 this.wrapper.setStyle("overflow", "hidden");
36106 this.wrapper.addClass('roo-grid-container');
36111 if(config.toolbar){
36112 var tool_el = this.wrapper.createChild();
36113 this.toolbar = Roo.factory(config.toolbar);
36115 if (config.toolbar.items) {
36116 ti = config.toolbar.items ;
36117 delete config.toolbar.items ;
36121 this.toolbar.render(tool_el);
36122 for(var i =0;i < ti.length;i++) {
36123 // Roo.log(['add child', items[i]]);
36124 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36126 this.toolbar.items = nitems;
36128 delete config.toolbar;
36131 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36132 config.grid.scrollBody = true;;
36133 config.grid.monitorWindowResize = false; // turn off autosizing
36134 config.grid.autoHeight = false;
36135 config.grid.autoWidth = false;
36137 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36139 if (config.background) {
36140 // render grid on panel activation (if panel background)
36141 this.on('activate', function(gp) {
36142 if (!gp.grid.rendered) {
36143 gp.grid.render(this.wrapper);
36144 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36149 this.grid.render(this.wrapper);
36150 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36153 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36154 // ??? needed ??? config.el = this.wrapper;
36159 // xtype created footer. - not sure if will work as we normally have to render first..
36160 if (this.footer && !this.footer.el && this.footer.xtype) {
36162 var ctr = this.grid.getView().getFooterPanel(true);
36163 this.footer.dataSource = this.grid.dataSource;
36164 this.footer = Roo.factory(this.footer, Roo);
36165 this.footer.render(ctr);
36175 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36176 getId : function(){
36177 return this.grid.id;
36181 * Returns the grid for this panel
36182 * @return {Roo.bootstrap.Table}
36184 getGrid : function(){
36188 setSize : function(width, height){
36189 if(!this.ignoreResize(width, height)){
36190 var grid = this.grid;
36191 var size = this.adjustForComponents(width, height);
36192 var gridel = grid.getGridEl();
36193 gridel.setSize(size.width, size.height);
36195 var thd = grid.getGridEl().select('thead',true).first();
36196 var tbd = grid.getGridEl().select('tbody', true).first();
36198 tbd.setSize(width, height - thd.getHeight());
36207 beforeSlide : function(){
36208 this.grid.getView().scroller.clip();
36211 afterSlide : function(){
36212 this.grid.getView().scroller.unclip();
36215 destroy : function(){
36216 this.grid.destroy();
36218 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36223 * @class Roo.bootstrap.panel.Nest
36224 * @extends Roo.bootstrap.panel.Content
36226 * Create a new Panel, that can contain a layout.Border.
36229 * @param {Roo.BorderLayout} layout The layout for this panel
36230 * @param {String/Object} config A string to set only the title or a config object
36232 Roo.bootstrap.panel.Nest = function(config)
36234 // construct with only one argument..
36235 /* FIXME - implement nicer consturctors
36236 if (layout.layout) {
36238 layout = config.layout;
36239 delete config.layout;
36241 if (layout.xtype && !layout.getEl) {
36242 // then layout needs constructing..
36243 layout = Roo.factory(layout, Roo);
36247 config.el = config.layout.getEl();
36249 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36251 config.layout.monitorWindowResize = false; // turn off autosizing
36252 this.layout = config.layout;
36253 this.layout.getEl().addClass("roo-layout-nested-layout");
36260 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36262 setSize : function(width, height){
36263 if(!this.ignoreResize(width, height)){
36264 var size = this.adjustForComponents(width, height);
36265 var el = this.layout.getEl();
36266 if (size.height < 1) {
36267 el.setWidth(size.width);
36269 el.setSize(size.width, size.height);
36271 var touch = el.dom.offsetWidth;
36272 this.layout.layout();
36273 // ie requires a double layout on the first pass
36274 if(Roo.isIE && !this.initialized){
36275 this.initialized = true;
36276 this.layout.layout();
36281 // activate all subpanels if not currently active..
36283 setActiveState : function(active){
36284 this.active = active;
36285 this.setActiveClass(active);
36288 this.fireEvent("deactivate", this);
36292 this.fireEvent("activate", this);
36293 // not sure if this should happen before or after..
36294 if (!this.layout) {
36295 return; // should not happen..
36298 for (var r in this.layout.regions) {
36299 reg = this.layout.getRegion(r);
36300 if (reg.getActivePanel()) {
36301 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36302 reg.setActivePanel(reg.getActivePanel());
36305 if (!reg.panels.length) {
36308 reg.showPanel(reg.getPanel(0));
36317 * Returns the nested BorderLayout for this panel
36318 * @return {Roo.BorderLayout}
36320 getLayout : function(){
36321 return this.layout;
36325 * Adds a xtype elements to the layout of the nested panel
36329 xtype : 'ContentPanel',
36336 xtype : 'NestedLayoutPanel',
36342 items : [ ... list of content panels or nested layout panels.. ]
36346 * @param {Object} cfg Xtype definition of item to add.
36348 addxtype : function(cfg) {
36349 return this.layout.addxtype(cfg);
36354 * Ext JS Library 1.1.1
36355 * Copyright(c) 2006-2007, Ext JS, LLC.
36357 * Originally Released Under LGPL - original licence link has changed is not relivant.
36360 * <script type="text/javascript">
36363 * @class Roo.TabPanel
36364 * @extends Roo.util.Observable
36365 * A lightweight tab container.
36369 // basic tabs 1, built from existing content
36370 var tabs = new Roo.TabPanel("tabs1");
36371 tabs.addTab("script", "View Script");
36372 tabs.addTab("markup", "View Markup");
36373 tabs.activate("script");
36375 // more advanced tabs, built from javascript
36376 var jtabs = new Roo.TabPanel("jtabs");
36377 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36379 // set up the UpdateManager
36380 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36381 var updater = tab2.getUpdateManager();
36382 updater.setDefaultUrl("ajax1.htm");
36383 tab2.on('activate', updater.refresh, updater, true);
36385 // Use setUrl for Ajax loading
36386 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36387 tab3.setUrl("ajax2.htm", null, true);
36390 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36393 jtabs.activate("jtabs-1");
36396 * Create a new TabPanel.
36397 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36398 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36400 Roo.bootstrap.panel.Tabs = function(config){
36402 * The container element for this TabPanel.
36403 * @type Roo.Element
36405 this.el = Roo.get(config.el);
36408 if(typeof config == "boolean"){
36409 this.tabPosition = config ? "bottom" : "top";
36411 Roo.apply(this, config);
36415 if(this.tabPosition == "bottom"){
36416 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36417 this.el.addClass("roo-tabs-bottom");
36419 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36420 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36421 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36423 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36425 if(this.tabPosition != "bottom"){
36426 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36427 * @type Roo.Element
36429 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36430 this.el.addClass("roo-tabs-top");
36434 this.bodyEl.setStyle("position", "relative");
36436 this.active = null;
36437 this.activateDelegate = this.activate.createDelegate(this);
36442 * Fires when the active tab changes
36443 * @param {Roo.TabPanel} this
36444 * @param {Roo.TabPanelItem} activePanel The new active tab
36448 * @event beforetabchange
36449 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36450 * @param {Roo.TabPanel} this
36451 * @param {Object} e Set cancel to true on this object to cancel the tab change
36452 * @param {Roo.TabPanelItem} tab The tab being changed to
36454 "beforetabchange" : true
36457 Roo.EventManager.onWindowResize(this.onResize, this);
36458 this.cpad = this.el.getPadding("lr");
36459 this.hiddenCount = 0;
36462 // toolbar on the tabbar support...
36463 if (this.toolbar) {
36464 alert("no toolbar support yet");
36465 this.toolbar = false;
36467 var tcfg = this.toolbar;
36468 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36469 this.toolbar = new Roo.Toolbar(tcfg);
36470 if (Roo.isSafari) {
36471 var tbl = tcfg.container.child('table', true);
36472 tbl.setAttribute('width', '100%');
36480 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36483 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36485 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36487 tabPosition : "top",
36489 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36491 currentTabWidth : 0,
36493 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36497 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36501 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36503 preferredTabWidth : 175,
36505 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36507 resizeTabs : false,
36509 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36511 monitorResize : true,
36513 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36518 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36519 * @param {String} id The id of the div to use <b>or create</b>
36520 * @param {String} text The text for the tab
36521 * @param {String} content (optional) Content to put in the TabPanelItem body
36522 * @param {Boolean} closable (optional) True to create a close icon on the tab
36523 * @return {Roo.TabPanelItem} The created TabPanelItem
36525 addTab : function(id, text, content, closable, tpl)
36527 var item = new Roo.bootstrap.panel.TabItem({
36531 closable : closable,
36534 this.addTabItem(item);
36536 item.setContent(content);
36542 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36543 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36544 * @return {Roo.TabPanelItem}
36546 getTab : function(id){
36547 return this.items[id];
36551 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36552 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36554 hideTab : function(id){
36555 var t = this.items[id];
36558 this.hiddenCount++;
36559 this.autoSizeTabs();
36564 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36565 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36567 unhideTab : function(id){
36568 var t = this.items[id];
36570 t.setHidden(false);
36571 this.hiddenCount--;
36572 this.autoSizeTabs();
36577 * Adds an existing {@link Roo.TabPanelItem}.
36578 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36580 addTabItem : function(item){
36581 this.items[item.id] = item;
36582 this.items.push(item);
36583 // if(this.resizeTabs){
36584 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36585 // this.autoSizeTabs();
36587 // item.autoSize();
36592 * Removes a {@link Roo.TabPanelItem}.
36593 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36595 removeTab : function(id){
36596 var items = this.items;
36597 var tab = items[id];
36598 if(!tab) { return; }
36599 var index = items.indexOf(tab);
36600 if(this.active == tab && items.length > 1){
36601 var newTab = this.getNextAvailable(index);
36606 this.stripEl.dom.removeChild(tab.pnode.dom);
36607 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36608 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36610 items.splice(index, 1);
36611 delete this.items[tab.id];
36612 tab.fireEvent("close", tab);
36613 tab.purgeListeners();
36614 this.autoSizeTabs();
36617 getNextAvailable : function(start){
36618 var items = this.items;
36620 // look for a next tab that will slide over to
36621 // replace the one being removed
36622 while(index < items.length){
36623 var item = items[++index];
36624 if(item && !item.isHidden()){
36628 // if one isn't found select the previous tab (on the left)
36631 var item = items[--index];
36632 if(item && !item.isHidden()){
36640 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36641 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36643 disableTab : function(id){
36644 var tab = this.items[id];
36645 if(tab && this.active != tab){
36651 * Enables a {@link Roo.TabPanelItem} that is disabled.
36652 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36654 enableTab : function(id){
36655 var tab = this.items[id];
36660 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36661 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36662 * @return {Roo.TabPanelItem} The TabPanelItem.
36664 activate : function(id){
36665 var tab = this.items[id];
36669 if(tab == this.active || tab.disabled){
36673 this.fireEvent("beforetabchange", this, e, tab);
36674 if(e.cancel !== true && !tab.disabled){
36676 this.active.hide();
36678 this.active = this.items[id];
36679 this.active.show();
36680 this.fireEvent("tabchange", this, this.active);
36686 * Gets the active {@link Roo.TabPanelItem}.
36687 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36689 getActiveTab : function(){
36690 return this.active;
36694 * Updates the tab body element to fit the height of the container element
36695 * for overflow scrolling
36696 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36698 syncHeight : function(targetHeight){
36699 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36700 var bm = this.bodyEl.getMargins();
36701 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36702 this.bodyEl.setHeight(newHeight);
36706 onResize : function(){
36707 if(this.monitorResize){
36708 this.autoSizeTabs();
36713 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36715 beginUpdate : function(){
36716 this.updating = true;
36720 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36722 endUpdate : function(){
36723 this.updating = false;
36724 this.autoSizeTabs();
36728 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36730 autoSizeTabs : function(){
36731 var count = this.items.length;
36732 var vcount = count - this.hiddenCount;
36733 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36736 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36737 var availWidth = Math.floor(w / vcount);
36738 var b = this.stripBody;
36739 if(b.getWidth() > w){
36740 var tabs = this.items;
36741 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36742 if(availWidth < this.minTabWidth){
36743 /*if(!this.sleft){ // incomplete scrolling code
36744 this.createScrollButtons();
36747 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36750 if(this.currentTabWidth < this.preferredTabWidth){
36751 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36757 * Returns the number of tabs in this TabPanel.
36760 getCount : function(){
36761 return this.items.length;
36765 * Resizes all the tabs to the passed width
36766 * @param {Number} The new width
36768 setTabWidth : function(width){
36769 this.currentTabWidth = width;
36770 for(var i = 0, len = this.items.length; i < len; i++) {
36771 if(!this.items[i].isHidden()) {
36772 this.items[i].setWidth(width);
36778 * Destroys this TabPanel
36779 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36781 destroy : function(removeEl){
36782 Roo.EventManager.removeResizeListener(this.onResize, this);
36783 for(var i = 0, len = this.items.length; i < len; i++){
36784 this.items[i].purgeListeners();
36786 if(removeEl === true){
36787 this.el.update("");
36792 createStrip : function(container)
36794 var strip = document.createElement("nav");
36795 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36796 container.appendChild(strip);
36800 createStripList : function(strip)
36802 // div wrapper for retard IE
36803 // returns the "tr" element.
36804 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36805 //'<div class="x-tabs-strip-wrap">'+
36806 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36807 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36808 return strip.firstChild; //.firstChild.firstChild.firstChild;
36810 createBody : function(container)
36812 var body = document.createElement("div");
36813 Roo.id(body, "tab-body");
36814 //Roo.fly(body).addClass("x-tabs-body");
36815 Roo.fly(body).addClass("tab-content");
36816 container.appendChild(body);
36819 createItemBody :function(bodyEl, id){
36820 var body = Roo.getDom(id);
36822 body = document.createElement("div");
36825 //Roo.fly(body).addClass("x-tabs-item-body");
36826 Roo.fly(body).addClass("tab-pane");
36827 bodyEl.insertBefore(body, bodyEl.firstChild);
36831 createStripElements : function(stripEl, text, closable, tpl)
36833 var td = document.createElement("li"); // was td..
36836 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36839 stripEl.appendChild(td);
36841 td.className = "x-tabs-closable";
36842 if(!this.closeTpl){
36843 this.closeTpl = new Roo.Template(
36844 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36845 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36846 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36849 var el = this.closeTpl.overwrite(td, {"text": text});
36850 var close = el.getElementsByTagName("div")[0];
36851 var inner = el.getElementsByTagName("em")[0];
36852 return {"el": el, "close": close, "inner": inner};
36855 // not sure what this is..
36856 // if(!this.tabTpl){
36857 //this.tabTpl = new Roo.Template(
36858 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36859 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36861 // this.tabTpl = new Roo.Template(
36862 // '<a href="#">' +
36863 // '<span unselectable="on"' +
36864 // (this.disableTooltips ? '' : ' title="{text}"') +
36865 // ' >{text}</span></a>'
36871 var template = tpl || this.tabTpl || false;
36875 template = new Roo.Template(
36877 '<span unselectable="on"' +
36878 (this.disableTooltips ? '' : ' title="{text}"') +
36879 ' >{text}</span></a>'
36883 switch (typeof(template)) {
36887 template = new Roo.Template(template);
36893 var el = template.overwrite(td, {"text": text});
36895 var inner = el.getElementsByTagName("span")[0];
36897 return {"el": el, "inner": inner};
36905 * @class Roo.TabPanelItem
36906 * @extends Roo.util.Observable
36907 * Represents an individual item (tab plus body) in a TabPanel.
36908 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36909 * @param {String} id The id of this TabPanelItem
36910 * @param {String} text The text for the tab of this TabPanelItem
36911 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36913 Roo.bootstrap.panel.TabItem = function(config){
36915 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36916 * @type Roo.TabPanel
36918 this.tabPanel = config.panel;
36920 * The id for this TabPanelItem
36923 this.id = config.id;
36925 this.disabled = false;
36927 this.text = config.text;
36929 this.loaded = false;
36930 this.closable = config.closable;
36933 * The body element for this TabPanelItem.
36934 * @type Roo.Element
36936 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36937 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36938 this.bodyEl.setStyle("display", "block");
36939 this.bodyEl.setStyle("zoom", "1");
36940 //this.hideAction();
36942 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36944 this.el = Roo.get(els.el);
36945 this.inner = Roo.get(els.inner, true);
36946 this.textEl = Roo.get(this.el.dom.firstChild, true);
36947 this.pnode = Roo.get(els.el.parentNode, true);
36948 this.el.on("mousedown", this.onTabMouseDown, this);
36949 this.el.on("click", this.onTabClick, this);
36951 if(config.closable){
36952 var c = Roo.get(els.close, true);
36953 c.dom.title = this.closeText;
36954 c.addClassOnOver("close-over");
36955 c.on("click", this.closeClick, this);
36961 * Fires when this tab becomes the active tab.
36962 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36963 * @param {Roo.TabPanelItem} this
36967 * @event beforeclose
36968 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36969 * @param {Roo.TabPanelItem} this
36970 * @param {Object} e Set cancel to true on this object to cancel the close.
36972 "beforeclose": true,
36975 * Fires when this tab is closed.
36976 * @param {Roo.TabPanelItem} this
36980 * @event deactivate
36981 * Fires when this tab is no longer the active tab.
36982 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36983 * @param {Roo.TabPanelItem} this
36985 "deactivate" : true
36987 this.hidden = false;
36989 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36992 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36994 purgeListeners : function(){
36995 Roo.util.Observable.prototype.purgeListeners.call(this);
36996 this.el.removeAllListeners();
36999 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
37002 this.pnode.addClass("active");
37005 this.tabPanel.stripWrap.repaint();
37007 this.fireEvent("activate", this.tabPanel, this);
37011 * Returns true if this tab is the active tab.
37012 * @return {Boolean}
37014 isActive : function(){
37015 return this.tabPanel.getActiveTab() == this;
37019 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
37022 this.pnode.removeClass("active");
37024 this.fireEvent("deactivate", this.tabPanel, this);
37027 hideAction : function(){
37028 this.bodyEl.hide();
37029 this.bodyEl.setStyle("position", "absolute");
37030 this.bodyEl.setLeft("-20000px");
37031 this.bodyEl.setTop("-20000px");
37034 showAction : function(){
37035 this.bodyEl.setStyle("position", "relative");
37036 this.bodyEl.setTop("");
37037 this.bodyEl.setLeft("");
37038 this.bodyEl.show();
37042 * Set the tooltip for the tab.
37043 * @param {String} tooltip The tab's tooltip
37045 setTooltip : function(text){
37046 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
37047 this.textEl.dom.qtip = text;
37048 this.textEl.dom.removeAttribute('title');
37050 this.textEl.dom.title = text;
37054 onTabClick : function(e){
37055 e.preventDefault();
37056 this.tabPanel.activate(this.id);
37059 onTabMouseDown : function(e){
37060 e.preventDefault();
37061 this.tabPanel.activate(this.id);
37064 getWidth : function(){
37065 return this.inner.getWidth();
37068 setWidth : function(width){
37069 var iwidth = width - this.pnode.getPadding("lr");
37070 this.inner.setWidth(iwidth);
37071 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37072 this.pnode.setWidth(width);
37076 * Show or hide the tab
37077 * @param {Boolean} hidden True to hide or false to show.
37079 setHidden : function(hidden){
37080 this.hidden = hidden;
37081 this.pnode.setStyle("display", hidden ? "none" : "");
37085 * Returns true if this tab is "hidden"
37086 * @return {Boolean}
37088 isHidden : function(){
37089 return this.hidden;
37093 * Returns the text for this tab
37096 getText : function(){
37100 autoSize : function(){
37101 //this.el.beginMeasure();
37102 this.textEl.setWidth(1);
37104 * #2804 [new] Tabs in Roojs
37105 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37107 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37108 //this.el.endMeasure();
37112 * Sets the text for the tab (Note: this also sets the tooltip text)
37113 * @param {String} text The tab's text and tooltip
37115 setText : function(text){
37117 this.textEl.update(text);
37118 this.setTooltip(text);
37119 //if(!this.tabPanel.resizeTabs){
37120 // this.autoSize();
37124 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37126 activate : function(){
37127 this.tabPanel.activate(this.id);
37131 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37133 disable : function(){
37134 if(this.tabPanel.active != this){
37135 this.disabled = true;
37136 this.pnode.addClass("disabled");
37141 * Enables this TabPanelItem if it was previously disabled.
37143 enable : function(){
37144 this.disabled = false;
37145 this.pnode.removeClass("disabled");
37149 * Sets the content for this TabPanelItem.
37150 * @param {String} content The content
37151 * @param {Boolean} loadScripts true to look for and load scripts
37153 setContent : function(content, loadScripts){
37154 this.bodyEl.update(content, loadScripts);
37158 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37159 * @return {Roo.UpdateManager} The UpdateManager
37161 getUpdateManager : function(){
37162 return this.bodyEl.getUpdateManager();
37166 * Set a URL to be used to load the content for this TabPanelItem.
37167 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37168 * @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)
37169 * @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)
37170 * @return {Roo.UpdateManager} The UpdateManager
37172 setUrl : function(url, params, loadOnce){
37173 if(this.refreshDelegate){
37174 this.un('activate', this.refreshDelegate);
37176 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37177 this.on("activate", this.refreshDelegate);
37178 return this.bodyEl.getUpdateManager();
37182 _handleRefresh : function(url, params, loadOnce){
37183 if(!loadOnce || !this.loaded){
37184 var updater = this.bodyEl.getUpdateManager();
37185 updater.update(url, params, this._setLoaded.createDelegate(this));
37190 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37191 * Will fail silently if the setUrl method has not been called.
37192 * This does not activate the panel, just updates its content.
37194 refresh : function(){
37195 if(this.refreshDelegate){
37196 this.loaded = false;
37197 this.refreshDelegate();
37202 _setLoaded : function(){
37203 this.loaded = true;
37207 closeClick : function(e){
37210 this.fireEvent("beforeclose", this, o);
37211 if(o.cancel !== true){
37212 this.tabPanel.removeTab(this.id);
37216 * The text displayed in the tooltip for the close icon.
37219 closeText : "Close this tab"