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()
1296 titleEl : function()
1298 if(!this.el || !this.panel.length || !this.header.length){
1302 return this.el.select('.panel-title',true).first();
1305 setTitle : function(v)
1307 var titleEl = this.titleEl();
1313 titleEl.dom.innerHTML = v;
1316 getTitle : function()
1319 var titleEl = this.titleEl();
1325 return titleEl.dom.innerHTML;
1328 setRightTitle : function(v)
1330 var t = this.el.select('.panel-header-right',true).first();
1336 t.dom.innerHTML = v;
1339 onClick : function(e)
1343 this.fireEvent('click', this, e);
1357 * @class Roo.bootstrap.Img
1358 * @extends Roo.bootstrap.Component
1359 * Bootstrap Img class
1360 * @cfg {Boolean} imgResponsive false | true
1361 * @cfg {String} border rounded | circle | thumbnail
1362 * @cfg {String} src image source
1363 * @cfg {String} alt image alternative text
1364 * @cfg {String} href a tag href
1365 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1366 * @cfg {String} xsUrl xs image source
1367 * @cfg {String} smUrl sm image source
1368 * @cfg {String} mdUrl md image source
1369 * @cfg {String} lgUrl lg image source
1372 * Create a new Input
1373 * @param {Object} config The config object
1376 Roo.bootstrap.Img = function(config){
1377 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1383 * The img click event for the img.
1384 * @param {Roo.EventObject} e
1390 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1392 imgResponsive: true,
1402 getAutoCreate : function()
1404 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1405 return this.createSingleImg();
1410 cls: 'roo-image-responsive-group',
1415 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1417 if(!_this[size + 'Url']){
1423 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1424 html: _this.html || cfg.html,
1425 src: _this[size + 'Url']
1428 img.cls += ' roo-image-responsive-' + size;
1430 var s = ['xs', 'sm', 'md', 'lg'];
1432 s.splice(s.indexOf(size), 1);
1434 Roo.each(s, function(ss){
1435 img.cls += ' hidden-' + ss;
1438 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1439 cfg.cls += ' img-' + _this.border;
1443 cfg.alt = _this.alt;
1456 a.target = _this.target;
1460 cfg.cn.push((_this.href) ? a : img);
1467 createSingleImg : function()
1471 cls: (this.imgResponsive) ? 'img-responsive' : '',
1473 src : 'about:blank' // just incase src get's set to undefined?!?
1476 cfg.html = this.html || cfg.html;
1478 cfg.src = this.src || cfg.src;
1480 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1481 cfg.cls += ' img-' + this.border;
1498 a.target = this.target;
1503 return (this.href) ? a : cfg;
1506 initEvents: function()
1509 this.el.on('click', this.onClick, this);
1514 onClick : function(e)
1516 Roo.log('img onclick');
1517 this.fireEvent('click', this, e);
1520 * Sets the url of the image - used to update it
1521 * @param {String} url the url of the image
1524 setSrc : function(url)
1528 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1529 this.el.dom.src = url;
1533 this.el.select('img', true).first().dom.src = url;
1549 * @class Roo.bootstrap.Link
1550 * @extends Roo.bootstrap.Component
1551 * Bootstrap Link Class
1552 * @cfg {String} alt image alternative text
1553 * @cfg {String} href a tag href
1554 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1555 * @cfg {String} html the content of the link.
1556 * @cfg {String} anchor name for the anchor link
1557 * @cfg {String} fa - favicon
1559 * @cfg {Boolean} preventDefault (true | false) default false
1563 * Create a new Input
1564 * @param {Object} config The config object
1567 Roo.bootstrap.Link = function(config){
1568 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1574 * The img click event for the img.
1575 * @param {Roo.EventObject} e
1581 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1585 preventDefault: false,
1591 getAutoCreate : function()
1593 var html = this.html || '';
1595 if (this.fa !== false) {
1596 html = '<i class="fa fa-' + this.fa + '"></i>';
1601 // anchor's do not require html/href...
1602 if (this.anchor === false) {
1604 cfg.href = this.href || '#';
1606 cfg.name = this.anchor;
1607 if (this.html !== false || this.fa !== false) {
1610 if (this.href !== false) {
1611 cfg.href = this.href;
1615 if(this.alt !== false){
1620 if(this.target !== false) {
1621 cfg.target = this.target;
1627 initEvents: function() {
1629 if(!this.href || this.preventDefault){
1630 this.el.on('click', this.onClick, this);
1634 onClick : function(e)
1636 if(this.preventDefault){
1639 //Roo.log('img onclick');
1640 this.fireEvent('click', this, e);
1653 * @class Roo.bootstrap.Header
1654 * @extends Roo.bootstrap.Component
1655 * Bootstrap Header class
1656 * @cfg {String} html content of header
1657 * @cfg {Number} level (1|2|3|4|5|6) default 1
1660 * Create a new Header
1661 * @param {Object} config The config object
1665 Roo.bootstrap.Header = function(config){
1666 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1669 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1677 getAutoCreate : function(){
1682 tag: 'h' + (1 *this.level),
1683 html: this.html || ''
1695 * Ext JS Library 1.1.1
1696 * Copyright(c) 2006-2007, Ext JS, LLC.
1698 * Originally Released Under LGPL - original licence link has changed is not relivant.
1701 * <script type="text/javascript">
1705 * @class Roo.bootstrap.MenuMgr
1706 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1709 Roo.bootstrap.MenuMgr = function(){
1710 var menus, active, groups = {}, attached = false, lastShow = new Date();
1712 // private - called when first menu is created
1715 active = new Roo.util.MixedCollection();
1716 Roo.get(document).addKeyListener(27, function(){
1717 if(active.length > 0){
1725 if(active && active.length > 0){
1726 var c = active.clone();
1736 if(active.length < 1){
1737 Roo.get(document).un("mouseup", onMouseDown);
1745 var last = active.last();
1746 lastShow = new Date();
1749 Roo.get(document).on("mouseup", onMouseDown);
1754 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1755 m.parentMenu.activeChild = m;
1756 }else if(last && last.isVisible()){
1757 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1762 function onBeforeHide(m){
1764 m.activeChild.hide();
1766 if(m.autoHideTimer){
1767 clearTimeout(m.autoHideTimer);
1768 delete m.autoHideTimer;
1773 function onBeforeShow(m){
1774 var pm = m.parentMenu;
1775 if(!pm && !m.allowOtherMenus){
1777 }else if(pm && pm.activeChild && active != m){
1778 pm.activeChild.hide();
1782 // private this should really trigger on mouseup..
1783 function onMouseDown(e){
1784 Roo.log("on Mouse Up");
1786 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1787 Roo.log("MenuManager hideAll");
1796 function onBeforeCheck(mi, state){
1798 var g = groups[mi.group];
1799 for(var i = 0, l = g.length; i < l; i++){
1801 g[i].setChecked(false);
1810 * Hides all menus that are currently visible
1812 hideAll : function(){
1817 register : function(menu){
1821 menus[menu.id] = menu;
1822 menu.on("beforehide", onBeforeHide);
1823 menu.on("hide", onHide);
1824 menu.on("beforeshow", onBeforeShow);
1825 menu.on("show", onShow);
1827 if(g && menu.events["checkchange"]){
1831 groups[g].push(menu);
1832 menu.on("checkchange", onCheck);
1837 * Returns a {@link Roo.menu.Menu} object
1838 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1839 * be used to generate and return a new Menu instance.
1841 get : function(menu){
1842 if(typeof menu == "string"){ // menu id
1844 }else if(menu.events){ // menu instance
1847 /*else if(typeof menu.length == 'number'){ // array of menu items?
1848 return new Roo.bootstrap.Menu({items:menu});
1849 }else{ // otherwise, must be a config
1850 return new Roo.bootstrap.Menu(menu);
1857 unregister : function(menu){
1858 delete menus[menu.id];
1859 menu.un("beforehide", onBeforeHide);
1860 menu.un("hide", onHide);
1861 menu.un("beforeshow", onBeforeShow);
1862 menu.un("show", onShow);
1864 if(g && menu.events["checkchange"]){
1865 groups[g].remove(menu);
1866 menu.un("checkchange", onCheck);
1871 registerCheckable : function(menuItem){
1872 var g = menuItem.group;
1877 groups[g].push(menuItem);
1878 menuItem.on("beforecheckchange", onBeforeCheck);
1883 unregisterCheckable : function(menuItem){
1884 var g = menuItem.group;
1886 groups[g].remove(menuItem);
1887 menuItem.un("beforecheckchange", onBeforeCheck);
1899 * @class Roo.bootstrap.Menu
1900 * @extends Roo.bootstrap.Component
1901 * Bootstrap Menu class - container for MenuItems
1902 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1903 * @cfg {bool} hidden if the menu should be hidden when rendered.
1904 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1905 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1909 * @param {Object} config The config object
1913 Roo.bootstrap.Menu = function(config){
1914 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1915 if (this.registerMenu && this.type != 'treeview') {
1916 Roo.bootstrap.MenuMgr.register(this);
1921 * Fires before this menu is displayed
1922 * @param {Roo.menu.Menu} this
1927 * Fires before this menu is hidden
1928 * @param {Roo.menu.Menu} this
1933 * Fires after this menu is displayed
1934 * @param {Roo.menu.Menu} this
1939 * Fires after this menu is hidden
1940 * @param {Roo.menu.Menu} this
1945 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1946 * @param {Roo.menu.Menu} this
1947 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1948 * @param {Roo.EventObject} e
1953 * Fires when the mouse is hovering over this menu
1954 * @param {Roo.menu.Menu} this
1955 * @param {Roo.EventObject} e
1956 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1961 * Fires when the mouse exits this menu
1962 * @param {Roo.menu.Menu} this
1963 * @param {Roo.EventObject} e
1964 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1969 * Fires when a menu item contained in this menu is clicked
1970 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1971 * @param {Roo.EventObject} e
1975 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1978 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1982 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1985 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1987 registerMenu : true,
1989 menuItems :false, // stores the menu items..
1999 getChildContainer : function() {
2003 getAutoCreate : function(){
2005 //if (['right'].indexOf(this.align)!==-1) {
2006 // cfg.cn[1].cls += ' pull-right'
2012 cls : 'dropdown-menu' ,
2013 style : 'z-index:1000'
2017 if (this.type === 'submenu') {
2018 cfg.cls = 'submenu active';
2020 if (this.type === 'treeview') {
2021 cfg.cls = 'treeview-menu';
2026 initEvents : function() {
2028 // Roo.log("ADD event");
2029 // Roo.log(this.triggerEl.dom);
2031 this.triggerEl.on('click', this.onTriggerClick, this);
2033 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2035 this.triggerEl.addClass('dropdown-toggle');
2038 this.el.on('touchstart' , this.onTouch, this);
2040 this.el.on('click' , this.onClick, this);
2042 this.el.on("mouseover", this.onMouseOver, this);
2043 this.el.on("mouseout", this.onMouseOut, this);
2047 findTargetItem : function(e)
2049 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2053 //Roo.log(t); Roo.log(t.id);
2055 //Roo.log(this.menuitems);
2056 return this.menuitems.get(t.id);
2058 //return this.items.get(t.menuItemId);
2064 onTouch : function(e)
2066 Roo.log("menu.onTouch");
2067 //e.stopEvent(); this make the user popdown broken
2071 onClick : function(e)
2073 Roo.log("menu.onClick");
2075 var t = this.findTargetItem(e);
2076 if(!t || t.isContainer){
2081 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2082 if(t == this.activeItem && t.shouldDeactivate(e)){
2083 this.activeItem.deactivate();
2084 delete this.activeItem;
2088 this.setActiveItem(t, true);
2096 Roo.log('pass click event');
2100 this.fireEvent("click", this, t, e);
2104 (function() { _this.hide(); }).defer(100);
2107 onMouseOver : function(e){
2108 var t = this.findTargetItem(e);
2111 // if(t.canActivate && !t.disabled){
2112 // this.setActiveItem(t, true);
2116 this.fireEvent("mouseover", this, e, t);
2118 isVisible : function(){
2119 return !this.hidden;
2121 onMouseOut : function(e){
2122 var t = this.findTargetItem(e);
2125 // if(t == this.activeItem && t.shouldDeactivate(e)){
2126 // this.activeItem.deactivate();
2127 // delete this.activeItem;
2130 this.fireEvent("mouseout", this, e, t);
2135 * Displays this menu relative to another element
2136 * @param {String/HTMLElement/Roo.Element} element The element to align to
2137 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2138 * the element (defaults to this.defaultAlign)
2139 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2141 show : function(el, pos, parentMenu){
2142 this.parentMenu = parentMenu;
2146 this.fireEvent("beforeshow", this);
2147 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2150 * Displays this menu at a specific xy position
2151 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2152 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2154 showAt : function(xy, parentMenu, /* private: */_e){
2155 this.parentMenu = parentMenu;
2160 this.fireEvent("beforeshow", this);
2161 //xy = this.el.adjustForConstraints(xy);
2165 this.hideMenuItems();
2166 this.hidden = false;
2167 this.triggerEl.addClass('open');
2169 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2170 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2173 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2178 this.fireEvent("show", this);
2184 this.doFocus.defer(50, this);
2188 doFocus : function(){
2190 this.focusEl.focus();
2195 * Hides this menu and optionally all parent menus
2196 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2198 hide : function(deep)
2201 this.hideMenuItems();
2202 if(this.el && this.isVisible()){
2203 this.fireEvent("beforehide", this);
2204 if(this.activeItem){
2205 this.activeItem.deactivate();
2206 this.activeItem = null;
2208 this.triggerEl.removeClass('open');;
2210 this.fireEvent("hide", this);
2212 if(deep === true && this.parentMenu){
2213 this.parentMenu.hide(true);
2217 onTriggerClick : function(e)
2219 Roo.log('trigger click');
2221 var target = e.getTarget();
2223 Roo.log(target.nodeName.toLowerCase());
2225 if(target.nodeName.toLowerCase() === 'i'){
2231 onTriggerPress : function(e)
2233 Roo.log('trigger press');
2234 //Roo.log(e.getTarget());
2235 // Roo.log(this.triggerEl.dom);
2237 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2238 var pel = Roo.get(e.getTarget());
2239 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2240 Roo.log('is treeview or dropdown?');
2244 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2248 if (this.isVisible()) {
2253 this.show(this.triggerEl, false, false);
2256 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2263 hideMenuItems : function()
2265 Roo.log("hide Menu Items");
2269 //$(backdrop).remove()
2270 this.el.select('.open',true).each(function(aa) {
2272 aa.removeClass('open');
2273 //var parent = getParent($(this))
2274 //var relatedTarget = { relatedTarget: this }
2276 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2277 //if (e.isDefaultPrevented()) return
2278 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2281 addxtypeChild : function (tree, cntr) {
2282 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2284 this.menuitems.add(comp);
2305 * @class Roo.bootstrap.MenuItem
2306 * @extends Roo.bootstrap.Component
2307 * Bootstrap MenuItem class
2308 * @cfg {String} html the menu label
2309 * @cfg {String} href the link
2310 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2311 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2312 * @cfg {Boolean} active used on sidebars to highlight active itesm
2313 * @cfg {String} fa favicon to show on left of menu item.
2314 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2318 * Create a new MenuItem
2319 * @param {Object} config The config object
2323 Roo.bootstrap.MenuItem = function(config){
2324 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2329 * The raw click event for the entire grid.
2330 * @param {Roo.bootstrap.MenuItem} this
2331 * @param {Roo.EventObject} e
2337 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2341 preventDefault: false,
2342 isContainer : false,
2346 getAutoCreate : function(){
2348 if(this.isContainer){
2351 cls: 'dropdown-menu-item'
2365 if (this.fa !== false) {
2368 cls : 'fa fa-' + this.fa
2377 cls: 'dropdown-menu-item',
2380 if (this.parent().type == 'treeview') {
2381 cfg.cls = 'treeview-menu';
2384 cfg.cls += ' active';
2389 anc.href = this.href || cfg.cn[0].href ;
2390 ctag.html = this.html || cfg.cn[0].html ;
2394 initEvents: function()
2396 if (this.parent().type == 'treeview') {
2397 this.el.select('a').on('click', this.onClick, this);
2400 this.menu.parentType = this.xtype;
2401 this.menu.triggerEl = this.el;
2402 this.menu = this.addxtype(Roo.apply({}, this.menu));
2406 onClick : function(e)
2408 Roo.log('item on click ');
2410 if(this.preventDefault){
2413 //this.parent().hideMenuItems();
2415 this.fireEvent('click', this, e);
2434 * @class Roo.bootstrap.MenuSeparator
2435 * @extends Roo.bootstrap.Component
2436 * Bootstrap MenuSeparator class
2439 * Create a new MenuItem
2440 * @param {Object} config The config object
2444 Roo.bootstrap.MenuSeparator = function(config){
2445 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2448 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2450 getAutoCreate : function(){
2469 * @class Roo.bootstrap.Modal
2470 * @extends Roo.bootstrap.Component
2471 * Bootstrap Modal class
2472 * @cfg {String} title Title of dialog
2473 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2474 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2475 * @cfg {Boolean} specificTitle default false
2476 * @cfg {Array} buttons Array of buttons or standard button set..
2477 * @cfg {String} buttonPosition (left|right|center) default right
2478 * @cfg {Boolean} animate default true
2479 * @cfg {Boolean} allow_close default true
2480 * @cfg {Boolean} fitwindow default false
2481 * @cfg {String} size (sm|lg) default empty
2485 * Create a new Modal Dialog
2486 * @param {Object} config The config object
2489 Roo.bootstrap.Modal = function(config){
2490 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2495 * The raw btnclick event for the button
2496 * @param {Roo.EventObject} e
2500 this.buttons = this.buttons || [];
2503 this.tmpl = Roo.factory(this.tmpl);
2508 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2510 title : 'test dialog',
2520 specificTitle: false,
2522 buttonPosition: 'right',
2541 onRender : function(ct, position)
2543 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2546 var cfg = Roo.apply({}, this.getAutoCreate());
2549 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2551 //if (!cfg.name.length) {
2555 cfg.cls += ' ' + this.cls;
2558 cfg.style = this.style;
2560 this.el = Roo.get(document.body).createChild(cfg, position);
2562 //var type = this.el.dom.type;
2565 if(this.tabIndex !== undefined){
2566 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2569 this.dialogEl = this.el.select('.modal-dialog',true).first();
2570 this.bodyEl = this.el.select('.modal-body',true).first();
2571 this.closeEl = this.el.select('.modal-header .close', true).first();
2572 this.headerEl = this.el.select('.modal-header',true).first();
2573 this.titleEl = this.el.select('.modal-title',true).first();
2574 this.footerEl = this.el.select('.modal-footer',true).first();
2576 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2577 this.maskEl.enableDisplayMode("block");
2579 //this.el.addClass("x-dlg-modal");
2581 if (this.buttons.length) {
2582 Roo.each(this.buttons, function(bb) {
2583 var b = Roo.apply({}, bb);
2584 b.xns = b.xns || Roo.bootstrap;
2585 b.xtype = b.xtype || 'Button';
2586 if (typeof(b.listeners) == 'undefined') {
2587 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2590 var btn = Roo.factory(b);
2592 btn.render(this.el.select('.modal-footer div').first());
2596 // render the children.
2599 if(typeof(this.items) != 'undefined'){
2600 var items = this.items;
2603 for(var i =0;i < items.length;i++) {
2604 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2608 this.items = nitems;
2610 // where are these used - they used to be body/close/footer
2614 //this.el.addClass([this.fieldClass, this.cls]);
2618 getAutoCreate : function(){
2623 html : this.html || ''
2628 cls : 'modal-title',
2632 if(this.specificTitle){
2638 if (this.allow_close) {
2650 if(this.size.length){
2651 size = 'modal-' + this.size;
2656 style : 'display: none',
2659 cls: "modal-dialog " + size,
2662 cls : "modal-content",
2665 cls : 'modal-header',
2670 cls : 'modal-footer',
2674 cls: 'btn-' + this.buttonPosition
2691 modal.cls += ' fade';
2697 getChildContainer : function() {
2702 getButtonContainer : function() {
2703 return this.el.select('.modal-footer div',true).first();
2706 initEvents : function()
2708 if (this.allow_close) {
2709 this.closeEl.on('click', this.hide, this);
2711 Roo.EventManager.onWindowResize(this.resize, this, true);
2718 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2719 if (this.fitwindow) {
2720 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2721 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2726 setSize : function(w,h)
2736 if (!this.rendered) {
2740 this.el.setStyle('display', 'block');
2742 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2745 this.el.addClass('in');
2748 this.el.addClass('in');
2752 // not sure how we can show data in here..
2754 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2757 Roo.get(document.body).addClass("x-body-masked");
2759 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2760 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2765 this.fireEvent('show', this);
2767 // set zindex here - otherwise it appears to be ignored...
2768 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2771 this.items.forEach( function(e) {
2772 e.layout ? e.layout() : false;
2780 if(this.fireEvent("beforehide", this) !== false){
2782 Roo.get(document.body).removeClass("x-body-masked");
2783 this.el.removeClass('in');
2784 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2786 if(this.animate){ // why
2788 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2790 this.el.setStyle('display', 'none');
2792 this.fireEvent('hide', this);
2796 addButton : function(str, cb)
2800 var b = Roo.apply({}, { html : str } );
2801 b.xns = b.xns || Roo.bootstrap;
2802 b.xtype = b.xtype || 'Button';
2803 if (typeof(b.listeners) == 'undefined') {
2804 b.listeners = { click : cb.createDelegate(this) };
2807 var btn = Roo.factory(b);
2809 btn.render(this.el.select('.modal-footer div').first());
2815 setDefaultButton : function(btn)
2817 //this.el.select('.modal-footer').()
2821 resizeTo: function(w,h)
2825 this.dialogEl.setWidth(w);
2826 if (this.diff === false) {
2827 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2830 this.bodyEl.setHeight(h-this.diff);
2834 setContentSize : function(w, h)
2838 onButtonClick: function(btn,e)
2841 this.fireEvent('btnclick', btn.name, e);
2844 * Set the title of the Dialog
2845 * @param {String} str new Title
2847 setTitle: function(str) {
2848 this.titleEl.dom.innerHTML = str;
2851 * Set the body of the Dialog
2852 * @param {String} str new Title
2854 setBody: function(str) {
2855 this.bodyEl.dom.innerHTML = str;
2858 * Set the body of the Dialog using the template
2859 * @param {Obj} data - apply this data to the template and replace the body contents.
2861 applyBody: function(obj)
2864 Roo.log("Error - using apply Body without a template");
2867 this.tmpl.overwrite(this.bodyEl, obj);
2873 Roo.apply(Roo.bootstrap.Modal, {
2875 * Button config that displays a single OK button
2884 * Button config that displays Yes and No buttons
2900 * Button config that displays OK and Cancel buttons
2915 * Button config that displays Yes, No and Cancel buttons
2939 * messagebox - can be used as a replace
2943 * @class Roo.MessageBox
2944 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2948 Roo.Msg.alert('Status', 'Changes saved successfully.');
2950 // Prompt for user data:
2951 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2953 // process text value...
2957 // Show a dialog using config options:
2959 title:'Save Changes?',
2960 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2961 buttons: Roo.Msg.YESNOCANCEL,
2968 Roo.bootstrap.MessageBox = function(){
2969 var dlg, opt, mask, waitTimer;
2970 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2971 var buttons, activeTextEl, bwidth;
2975 var handleButton = function(button){
2977 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2981 var handleHide = function(){
2983 dlg.el.removeClass(opt.cls);
2986 // Roo.TaskMgr.stop(waitTimer);
2987 // waitTimer = null;
2992 var updateButtons = function(b){
2995 buttons["ok"].hide();
2996 buttons["cancel"].hide();
2997 buttons["yes"].hide();
2998 buttons["no"].hide();
2999 //dlg.footer.dom.style.display = 'none';
3002 dlg.footerEl.dom.style.display = '';
3003 for(var k in buttons){
3004 if(typeof buttons[k] != "function"){
3007 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3008 width += buttons[k].el.getWidth()+15;
3018 var handleEsc = function(d, k, e){
3019 if(opt && opt.closable !== false){
3029 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3030 * @return {Roo.BasicDialog} The BasicDialog element
3032 getDialog : function(){
3034 dlg = new Roo.bootstrap.Modal( {
3037 //constraintoviewport:false,
3039 //collapsible : false,
3044 //buttonAlign:"center",
3045 closeClick : function(){
3046 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3049 handleButton("cancel");
3054 dlg.on("hide", handleHide);
3056 //dlg.addKeyListener(27, handleEsc);
3058 this.buttons = buttons;
3059 var bt = this.buttonText;
3060 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3061 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3062 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3063 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3065 bodyEl = dlg.bodyEl.createChild({
3067 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3068 '<textarea class="roo-mb-textarea"></textarea>' +
3069 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3071 msgEl = bodyEl.dom.firstChild;
3072 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3073 textboxEl.enableDisplayMode();
3074 textboxEl.addKeyListener([10,13], function(){
3075 if(dlg.isVisible() && opt && opt.buttons){
3078 }else if(opt.buttons.yes){
3079 handleButton("yes");
3083 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3084 textareaEl.enableDisplayMode();
3085 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3086 progressEl.enableDisplayMode();
3088 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3089 //var pf = progressEl.dom.firstChild;
3091 //pp = Roo.get(pf.firstChild);
3092 //pp.setHeight(pf.offsetHeight);
3100 * Updates the message box body text
3101 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3102 * the XHTML-compliant non-breaking space character '&#160;')
3103 * @return {Roo.MessageBox} This message box
3105 updateText : function(text)
3107 if(!dlg.isVisible() && !opt.width){
3108 dlg.dialogEl.setWidth(this.maxWidth);
3109 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3111 msgEl.innerHTML = text || ' ';
3113 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3114 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3116 Math.min(opt.width || cw , this.maxWidth),
3117 Math.max(opt.minWidth || this.minWidth, bwidth)
3120 activeTextEl.setWidth(w);
3122 if(dlg.isVisible()){
3123 dlg.fixedcenter = false;
3125 // to big, make it scroll. = But as usual stupid IE does not support
3128 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3129 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3130 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3132 bodyEl.dom.style.height = '';
3133 bodyEl.dom.style.overflowY = '';
3136 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3138 bodyEl.dom.style.overflowX = '';
3141 dlg.setContentSize(w, bodyEl.getHeight());
3142 if(dlg.isVisible()){
3143 dlg.fixedcenter = true;
3149 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3150 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3151 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3152 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3153 * @return {Roo.MessageBox} This message box
3155 updateProgress : function(value, text){
3157 this.updateText(text);
3159 if (pp) { // weird bug on my firefox - for some reason this is not defined
3160 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3166 * Returns true if the message box is currently displayed
3167 * @return {Boolean} True if the message box is visible, else false
3169 isVisible : function(){
3170 return dlg && dlg.isVisible();
3174 * Hides the message box if it is displayed
3177 if(this.isVisible()){
3183 * Displays a new message box, or reinitializes an existing message box, based on the config options
3184 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3185 * The following config object properties are supported:
3187 Property Type Description
3188 ---------- --------------- ------------------------------------------------------------------------------------
3189 animEl String/Element An id or Element from which the message box should animate as it opens and
3190 closes (defaults to undefined)
3191 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3192 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3193 closable Boolean False to hide the top-right close button (defaults to true). Note that
3194 progress and wait dialogs will ignore this property and always hide the
3195 close button as they can only be closed programmatically.
3196 cls String A custom CSS class to apply to the message box element
3197 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3198 displayed (defaults to 75)
3199 fn Function A callback function to execute after closing the dialog. The arguments to the
3200 function will be btn (the name of the button that was clicked, if applicable,
3201 e.g. "ok"), and text (the value of the active text field, if applicable).
3202 Progress and wait dialogs will ignore this option since they do not respond to
3203 user actions and can only be closed programmatically, so any required function
3204 should be called by the same code after it closes the dialog.
3205 icon String A CSS class that provides a background image to be used as an icon for
3206 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3207 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3208 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3209 modal Boolean False to allow user interaction with the page while the message box is
3210 displayed (defaults to true)
3211 msg String A string that will replace the existing message box body text (defaults
3212 to the XHTML-compliant non-breaking space character ' ')
3213 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3214 progress Boolean True to display a progress bar (defaults to false)
3215 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3216 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3217 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3218 title String The title text
3219 value String The string value to set into the active textbox element if displayed
3220 wait Boolean True to display a progress bar (defaults to false)
3221 width Number The width of the dialog in pixels
3228 msg: 'Please enter your address:',
3230 buttons: Roo.MessageBox.OKCANCEL,
3233 animEl: 'addAddressBtn'
3236 * @param {Object} config Configuration options
3237 * @return {Roo.MessageBox} This message box
3239 show : function(options)
3242 // this causes nightmares if you show one dialog after another
3243 // especially on callbacks..
3245 if(this.isVisible()){
3248 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3249 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3250 Roo.log("New Dialog Message:" + options.msg )
3251 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3252 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3255 var d = this.getDialog();
3257 d.setTitle(opt.title || " ");
3258 d.closeEl.setDisplayed(opt.closable !== false);
3259 activeTextEl = textboxEl;
3260 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3265 textareaEl.setHeight(typeof opt.multiline == "number" ?
3266 opt.multiline : this.defaultTextHeight);
3267 activeTextEl = textareaEl;
3276 progressEl.setDisplayed(opt.progress === true);
3277 this.updateProgress(0);
3278 activeTextEl.dom.value = opt.value || "";
3280 dlg.setDefaultButton(activeTextEl);
3282 var bs = opt.buttons;
3286 }else if(bs && bs.yes){
3287 db = buttons["yes"];
3289 dlg.setDefaultButton(db);
3291 bwidth = updateButtons(opt.buttons);
3292 this.updateText(opt.msg);
3294 d.el.addClass(opt.cls);
3296 d.proxyDrag = opt.proxyDrag === true;
3297 d.modal = opt.modal !== false;
3298 d.mask = opt.modal !== false ? mask : false;
3300 // force it to the end of the z-index stack so it gets a cursor in FF
3301 document.body.appendChild(dlg.el.dom);
3302 d.animateTarget = null;
3303 d.show(options.animEl);
3309 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3310 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3311 * and closing the message box when the process is complete.
3312 * @param {String} title The title bar text
3313 * @param {String} msg The message box body text
3314 * @return {Roo.MessageBox} This message box
3316 progress : function(title, msg){
3323 minWidth: this.minProgressWidth,
3330 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3331 * If a callback function is passed it will be called after the user clicks the button, and the
3332 * id of the button that was clicked will be passed as the only parameter to the callback
3333 * (could also be the top-right close button).
3334 * @param {String} title The title bar text
3335 * @param {String} msg The message box body text
3336 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3337 * @param {Object} scope (optional) The scope of the callback function
3338 * @return {Roo.MessageBox} This message box
3340 alert : function(title, msg, fn, scope)
3355 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3356 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3357 * You are responsible for closing the message box when the process is complete.
3358 * @param {String} msg The message box body text
3359 * @param {String} title (optional) The title bar text
3360 * @return {Roo.MessageBox} This message box
3362 wait : function(msg, title){
3373 waitTimer = Roo.TaskMgr.start({
3375 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3383 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3384 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3385 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3386 * @param {String} title The title bar text
3387 * @param {String} msg The message box body text
3388 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3389 * @param {Object} scope (optional) The scope of the callback function
3390 * @return {Roo.MessageBox} This message box
3392 confirm : function(title, msg, fn, scope){
3396 buttons: this.YESNO,
3405 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3406 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3407 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3408 * (could also be the top-right close button) and the text that was entered will be passed as the two
3409 * parameters to the callback.
3410 * @param {String} title The title bar text
3411 * @param {String} msg The message box body text
3412 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3413 * @param {Object} scope (optional) The scope of the callback function
3414 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3415 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3416 * @return {Roo.MessageBox} This message box
3418 prompt : function(title, msg, fn, scope, multiline){
3422 buttons: this.OKCANCEL,
3427 multiline: multiline,
3434 * Button config that displays a single OK button
3439 * Button config that displays Yes and No buttons
3442 YESNO : {yes:true, no:true},
3444 * Button config that displays OK and Cancel buttons
3447 OKCANCEL : {ok:true, cancel:true},
3449 * Button config that displays Yes, No and Cancel buttons
3452 YESNOCANCEL : {yes:true, no:true, cancel:true},
3455 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3458 defaultTextHeight : 75,
3460 * The maximum width in pixels of the message box (defaults to 600)
3465 * The minimum width in pixels of the message box (defaults to 100)
3470 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3471 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3474 minProgressWidth : 250,
3476 * An object containing the default button text strings that can be overriden for localized language support.
3477 * Supported properties are: ok, cancel, yes and no.
3478 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3491 * Shorthand for {@link Roo.MessageBox}
3493 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3494 Roo.Msg = Roo.Msg || Roo.MessageBox;
3503 * @class Roo.bootstrap.Navbar
3504 * @extends Roo.bootstrap.Component
3505 * Bootstrap Navbar class
3508 * Create a new Navbar
3509 * @param {Object} config The config object
3513 Roo.bootstrap.Navbar = function(config){
3514 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3518 * @event beforetoggle
3519 * Fire before toggle the menu
3520 * @param {Roo.EventObject} e
3522 "beforetoggle" : true
3526 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3535 getAutoCreate : function(){
3538 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3542 initEvents :function ()
3544 //Roo.log(this.el.select('.navbar-toggle',true));
3545 this.el.select('.navbar-toggle',true).on('click', function() {
3546 if(this.fireEvent('beforetoggle', this) !== false){
3547 this.el.select('.navbar-collapse',true).toggleClass('in');
3557 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3559 var size = this.el.getSize();
3560 this.maskEl.setSize(size.width, size.height);
3561 this.maskEl.enableDisplayMode("block");
3570 getChildContainer : function()
3572 if (this.el.select('.collapse').getCount()) {
3573 return this.el.select('.collapse',true).first();
3606 * @class Roo.bootstrap.NavSimplebar
3607 * @extends Roo.bootstrap.Navbar
3608 * Bootstrap Sidebar class
3610 * @cfg {Boolean} inverse is inverted color
3612 * @cfg {String} type (nav | pills | tabs)
3613 * @cfg {Boolean} arrangement stacked | justified
3614 * @cfg {String} align (left | right) alignment
3616 * @cfg {Boolean} main (true|false) main nav bar? default false
3617 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3619 * @cfg {String} tag (header|footer|nav|div) default is nav
3625 * Create a new Sidebar
3626 * @param {Object} config The config object
3630 Roo.bootstrap.NavSimplebar = function(config){
3631 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3634 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3650 getAutoCreate : function(){
3654 tag : this.tag || 'div',
3667 this.type = this.type || 'nav';
3668 if (['tabs','pills'].indexOf(this.type)!==-1) {
3669 cfg.cn[0].cls += ' nav-' + this.type
3673 if (this.type!=='nav') {
3674 Roo.log('nav type must be nav/tabs/pills')
3676 cfg.cn[0].cls += ' navbar-nav'
3682 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3683 cfg.cn[0].cls += ' nav-' + this.arrangement;
3687 if (this.align === 'right') {
3688 cfg.cn[0].cls += ' navbar-right';
3692 cfg.cls += ' navbar-inverse';
3719 * @class Roo.bootstrap.NavHeaderbar
3720 * @extends Roo.bootstrap.NavSimplebar
3721 * Bootstrap Sidebar class
3723 * @cfg {String} brand what is brand
3724 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3725 * @cfg {String} brand_href href of the brand
3726 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3727 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3728 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3729 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3732 * Create a new Sidebar
3733 * @param {Object} config The config object
3737 Roo.bootstrap.NavHeaderbar = function(config){
3738 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3742 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3749 desktopCenter : false,
3752 getAutoCreate : function(){
3755 tag: this.nav || 'nav',
3762 if (this.desktopCenter) {
3763 cn.push({cls : 'container', cn : []});
3770 cls: 'navbar-header',
3775 cls: 'navbar-toggle',
3776 'data-toggle': 'collapse',
3781 html: 'Toggle navigation'
3803 cls: 'collapse navbar-collapse',
3807 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3809 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3810 cfg.cls += ' navbar-' + this.position;
3812 // tag can override this..
3814 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3817 if (this.brand !== '') {
3820 href: this.brand_href ? this.brand_href : '#',
3821 cls: 'navbar-brand',
3829 cfg.cls += ' main-nav';
3837 getHeaderChildContainer : function()
3839 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3840 return this.el.select('.navbar-header',true).first();
3843 return this.getChildContainer();
3847 initEvents : function()
3849 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3851 if (this.autohide) {
3856 Roo.get(document).on('scroll',function(e) {
3857 var ns = Roo.get(document).getScroll().top;
3858 var os = prevScroll;
3862 ft.removeClass('slideDown');
3863 ft.addClass('slideUp');
3866 ft.removeClass('slideUp');
3867 ft.addClass('slideDown');
3888 * @class Roo.bootstrap.NavSidebar
3889 * @extends Roo.bootstrap.Navbar
3890 * Bootstrap Sidebar class
3893 * Create a new Sidebar
3894 * @param {Object} config The config object
3898 Roo.bootstrap.NavSidebar = function(config){
3899 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3902 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3904 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3906 getAutoCreate : function(){
3911 cls: 'sidebar sidebar-nav'
3933 * @class Roo.bootstrap.NavGroup
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap NavGroup class
3936 * @cfg {String} align (left|right)
3937 * @cfg {Boolean} inverse
3938 * @cfg {String} type (nav|pills|tab) default nav
3939 * @cfg {String} navId - reference Id for navbar.
3943 * Create a new nav group
3944 * @param {Object} config The config object
3947 Roo.bootstrap.NavGroup = function(config){
3948 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3951 Roo.bootstrap.NavGroup.register(this);
3955 * Fires when the active item changes
3956 * @param {Roo.bootstrap.NavGroup} this
3957 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3958 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3965 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3976 getAutoCreate : function()
3978 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3985 if (['tabs','pills'].indexOf(this.type)!==-1) {
3986 cfg.cls += ' nav-' + this.type
3988 if (this.type!=='nav') {
3989 Roo.log('nav type must be nav/tabs/pills')
3991 cfg.cls += ' navbar-nav'
3994 if (this.parent().sidebar) {
3997 cls: 'dashboard-menu sidebar-menu'
4003 if (this.form === true) {
4009 if (this.align === 'right') {
4010 cfg.cls += ' navbar-right';
4012 cfg.cls += ' navbar-left';
4016 if (this.align === 'right') {
4017 cfg.cls += ' navbar-right';
4021 cfg.cls += ' navbar-inverse';
4029 * sets the active Navigation item
4030 * @param {Roo.bootstrap.NavItem} the new current navitem
4032 setActiveItem : function(item)
4035 Roo.each(this.navItems, function(v){
4040 v.setActive(false, true);
4047 item.setActive(true, true);
4048 this.fireEvent('changed', this, item, prev);
4053 * gets the active Navigation item
4054 * @return {Roo.bootstrap.NavItem} the current navitem
4056 getActive : function()
4060 Roo.each(this.navItems, function(v){
4071 indexOfNav : function()
4075 Roo.each(this.navItems, function(v,i){
4086 * adds a Navigation item
4087 * @param {Roo.bootstrap.NavItem} the navitem to add
4089 addItem : function(cfg)
4091 var cn = new Roo.bootstrap.NavItem(cfg);
4093 cn.parentId = this.id;
4094 cn.onRender(this.el, null);
4098 * register a Navigation item
4099 * @param {Roo.bootstrap.NavItem} the navitem to add
4101 register : function(item)
4103 this.navItems.push( item);
4104 item.navId = this.navId;
4109 * clear all the Navigation item
4112 clearAll : function()
4115 this.el.dom.innerHTML = '';
4118 getNavItem: function(tabId)
4121 Roo.each(this.navItems, function(e) {
4122 if (e.tabId == tabId) {
4132 setActiveNext : function()
4134 var i = this.indexOfNav(this.getActive());
4135 if (i > this.navItems.length) {
4138 this.setActiveItem(this.navItems[i+1]);
4140 setActivePrev : function()
4142 var i = this.indexOfNav(this.getActive());
4146 this.setActiveItem(this.navItems[i-1]);
4148 clearWasActive : function(except) {
4149 Roo.each(this.navItems, function(e) {
4150 if (e.tabId != except.tabId && e.was_active) {
4151 e.was_active = false;
4158 getWasActive : function ()
4161 Roo.each(this.navItems, function(e) {
4176 Roo.apply(Roo.bootstrap.NavGroup, {
4180 * register a Navigation Group
4181 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4183 register : function(navgrp)
4185 this.groups[navgrp.navId] = navgrp;
4189 * fetch a Navigation Group based on the navigation ID
4190 * @param {string} the navgroup to add
4191 * @returns {Roo.bootstrap.NavGroup} the navgroup
4193 get: function(navId) {
4194 if (typeof(this.groups[navId]) == 'undefined') {
4196 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4198 return this.groups[navId] ;
4213 * @class Roo.bootstrap.NavItem
4214 * @extends Roo.bootstrap.Component
4215 * Bootstrap Navbar.NavItem class
4216 * @cfg {String} href link to
4217 * @cfg {String} html content of button
4218 * @cfg {String} badge text inside badge
4219 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4220 * @cfg {String} glyphicon name of glyphicon
4221 * @cfg {String} icon name of font awesome icon
4222 * @cfg {Boolean} active Is item active
4223 * @cfg {Boolean} disabled Is item disabled
4225 * @cfg {Boolean} preventDefault (true | false) default false
4226 * @cfg {String} tabId the tab that this item activates.
4227 * @cfg {String} tagtype (a|span) render as a href or span?
4228 * @cfg {Boolean} animateRef (true|false) link to element default false
4231 * Create a new Navbar Item
4232 * @param {Object} config The config object
4234 Roo.bootstrap.NavItem = function(config){
4235 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4240 * The raw click event for the entire grid.
4241 * @param {Roo.EventObject} e
4246 * Fires when the active item active state changes
4247 * @param {Roo.bootstrap.NavItem} this
4248 * @param {boolean} state the new state
4254 * Fires when scroll to element
4255 * @param {Roo.bootstrap.NavItem} this
4256 * @param {Object} options
4257 * @param {Roo.EventObject} e
4265 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4273 preventDefault : false,
4280 getAutoCreate : function(){
4289 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4291 if (this.disabled) {
4292 cfg.cls += ' disabled';
4295 if (this.href || this.html || this.glyphicon || this.icon) {
4299 href : this.href || "#",
4300 html: this.html || ''
4305 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4308 if(this.glyphicon) {
4309 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4314 cfg.cn[0].html += " <span class='caret'></span>";
4318 if (this.badge !== '') {
4320 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4328 initEvents: function()
4330 if (typeof (this.menu) != 'undefined') {
4331 this.menu.parentType = this.xtype;
4332 this.menu.triggerEl = this.el;
4333 this.menu = this.addxtype(Roo.apply({}, this.menu));
4336 this.el.select('a',true).on('click', this.onClick, this);
4338 if(this.tagtype == 'span'){
4339 this.el.select('span',true).on('click', this.onClick, this);
4342 // at this point parent should be available..
4343 this.parent().register(this);
4346 onClick : function(e)
4348 if (e.getTarget('.dropdown-menu-item')) {
4349 // did you click on a menu itemm.... - then don't trigger onclick..
4354 this.preventDefault ||
4357 Roo.log("NavItem - prevent Default?");
4361 if (this.disabled) {
4365 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4366 if (tg && tg.transition) {
4367 Roo.log("waiting for the transitionend");
4373 //Roo.log("fire event clicked");
4374 if(this.fireEvent('click', this, e) === false){
4378 if(this.tagtype == 'span'){
4382 //Roo.log(this.href);
4383 var ael = this.el.select('a',true).first();
4386 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4387 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4388 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4389 return; // ignore... - it's a 'hash' to another page.
4391 Roo.log("NavItem - prevent Default?");
4393 this.scrollToElement(e);
4397 var p = this.parent();
4399 if (['tabs','pills'].indexOf(p.type)!==-1) {
4400 if (typeof(p.setActiveItem) !== 'undefined') {
4401 p.setActiveItem(this);
4405 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4406 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4407 // remove the collapsed menu expand...
4408 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4412 isActive: function () {
4415 setActive : function(state, fire, is_was_active)
4417 if (this.active && !state && this.navId) {
4418 this.was_active = true;
4419 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4421 nv.clearWasActive(this);
4425 this.active = state;
4428 this.el.removeClass('active');
4429 } else if (!this.el.hasClass('active')) {
4430 this.el.addClass('active');
4433 this.fireEvent('changed', this, state);
4436 // show a panel if it's registered and related..
4438 if (!this.navId || !this.tabId || !state || is_was_active) {
4442 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4446 var pan = tg.getPanelByName(this.tabId);
4450 // if we can not flip to new panel - go back to old nav highlight..
4451 if (false == tg.showPanel(pan)) {
4452 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4454 var onav = nv.getWasActive();
4456 onav.setActive(true, false, true);
4465 // this should not be here...
4466 setDisabled : function(state)
4468 this.disabled = state;
4470 this.el.removeClass('disabled');
4471 } else if (!this.el.hasClass('disabled')) {
4472 this.el.addClass('disabled');
4478 * Fetch the element to display the tooltip on.
4479 * @return {Roo.Element} defaults to this.el
4481 tooltipEl : function()
4483 return this.el.select('' + this.tagtype + '', true).first();
4486 scrollToElement : function(e)
4488 var c = document.body;
4491 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4493 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4494 c = document.documentElement;
4497 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4503 var o = target.calcOffsetsTo(c);
4510 this.fireEvent('scrollto', this, options, e);
4512 Roo.get(c).scrollTo('top', options.value, true);
4525 * <span> icon </span>
4526 * <span> text </span>
4527 * <span>badge </span>
4531 * @class Roo.bootstrap.NavSidebarItem
4532 * @extends Roo.bootstrap.NavItem
4533 * Bootstrap Navbar.NavSidebarItem class
4534 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4535 * {bool} open is the menu open
4537 * Create a new Navbar Button
4538 * @param {Object} config The config object
4540 Roo.bootstrap.NavSidebarItem = function(config){
4541 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4546 * The raw click event for the entire grid.
4547 * @param {Roo.EventObject} e
4552 * Fires when the active item active state changes
4553 * @param {Roo.bootstrap.NavSidebarItem} this
4554 * @param {boolean} state the new state
4562 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4564 badgeWeight : 'default',
4568 getAutoCreate : function(){
4573 href : this.href || '#',
4585 html : this.html || ''
4590 cfg.cls += ' active';
4593 if (this.disabled) {
4594 cfg.cls += ' disabled';
4597 cfg.cls += ' open x-open';
4600 if (this.glyphicon || this.icon) {
4601 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4602 a.cn.push({ tag : 'i', cls : c }) ;
4607 if (this.badge !== '') {
4609 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4613 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4614 a.cls += 'dropdown-toggle treeview' ;
4622 initEvents : function()
4624 if (typeof (this.menu) != 'undefined') {
4625 this.menu.parentType = this.xtype;
4626 this.menu.triggerEl = this.el;
4627 this.menu = this.addxtype(Roo.apply({}, this.menu));
4630 this.el.on('click', this.onClick, this);
4633 if(this.badge !== ''){
4635 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4640 onClick : function(e)
4647 if(this.preventDefault){
4651 this.fireEvent('click', this);
4654 disable : function()
4656 this.setDisabled(true);
4661 this.setDisabled(false);
4664 setDisabled : function(state)
4666 if(this.disabled == state){
4670 this.disabled = state;
4673 this.el.addClass('disabled');
4677 this.el.removeClass('disabled');
4682 setActive : function(state)
4684 if(this.active == state){
4688 this.active = state;
4691 this.el.addClass('active');
4695 this.el.removeClass('active');
4700 isActive: function ()
4705 setBadge : function(str)
4711 this.badgeEl.dom.innerHTML = str;
4728 * @class Roo.bootstrap.Row
4729 * @extends Roo.bootstrap.Component
4730 * Bootstrap Row class (contains columns...)
4734 * @param {Object} config The config object
4737 Roo.bootstrap.Row = function(config){
4738 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4741 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4743 getAutoCreate : function(){
4762 * @class Roo.bootstrap.Element
4763 * @extends Roo.bootstrap.Component
4764 * Bootstrap Element class
4765 * @cfg {String} html contents of the element
4766 * @cfg {String} tag tag of the element
4767 * @cfg {String} cls class of the element
4768 * @cfg {Boolean} preventDefault (true|false) default false
4769 * @cfg {Boolean} clickable (true|false) default false
4772 * Create a new Element
4773 * @param {Object} config The config object
4776 Roo.bootstrap.Element = function(config){
4777 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4783 * When a element is chick
4784 * @param {Roo.bootstrap.Element} this
4785 * @param {Roo.EventObject} e
4791 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4796 preventDefault: false,
4799 getAutoCreate : function(){
4810 initEvents: function()
4812 Roo.bootstrap.Element.superclass.initEvents.call(this);
4815 this.el.on('click', this.onClick, this);
4820 onClick : function(e)
4822 if(this.preventDefault){
4826 this.fireEvent('click', this, e);
4829 getValue : function()
4831 return this.el.dom.innerHTML;
4834 setValue : function(value)
4836 this.el.dom.innerHTML = value;
4851 * @class Roo.bootstrap.Pagination
4852 * @extends Roo.bootstrap.Component
4853 * Bootstrap Pagination class
4854 * @cfg {String} size xs | sm | md | lg
4855 * @cfg {Boolean} inverse false | true
4858 * Create a new Pagination
4859 * @param {Object} config The config object
4862 Roo.bootstrap.Pagination = function(config){
4863 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4866 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4872 getAutoCreate : function(){
4878 cfg.cls += ' inverse';
4884 cfg.cls += " " + this.cls;
4902 * @class Roo.bootstrap.PaginationItem
4903 * @extends Roo.bootstrap.Component
4904 * Bootstrap PaginationItem class
4905 * @cfg {String} html text
4906 * @cfg {String} href the link
4907 * @cfg {Boolean} preventDefault (true | false) default true
4908 * @cfg {Boolean} active (true | false) default false
4909 * @cfg {Boolean} disabled default false
4913 * Create a new PaginationItem
4914 * @param {Object} config The config object
4918 Roo.bootstrap.PaginationItem = function(config){
4919 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4924 * The raw click event for the entire grid.
4925 * @param {Roo.EventObject} e
4931 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4935 preventDefault: true,
4940 getAutoCreate : function(){
4946 href : this.href ? this.href : '#',
4947 html : this.html ? this.html : ''
4957 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4961 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4967 initEvents: function() {
4969 this.el.on('click', this.onClick, this);
4972 onClick : function(e)
4974 Roo.log('PaginationItem on click ');
4975 if(this.preventDefault){
4983 this.fireEvent('click', this, e);
4999 * @class Roo.bootstrap.Slider
5000 * @extends Roo.bootstrap.Component
5001 * Bootstrap Slider class
5004 * Create a new Slider
5005 * @param {Object} config The config object
5008 Roo.bootstrap.Slider = function(config){
5009 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5012 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5014 getAutoCreate : function(){
5018 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5022 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5034 * Ext JS Library 1.1.1
5035 * Copyright(c) 2006-2007, Ext JS, LLC.
5037 * Originally Released Under LGPL - original licence link has changed is not relivant.
5040 * <script type="text/javascript">
5045 * @class Roo.grid.ColumnModel
5046 * @extends Roo.util.Observable
5047 * This is the default implementation of a ColumnModel used by the Grid. It defines
5048 * the columns in the grid.
5051 var colModel = new Roo.grid.ColumnModel([
5052 {header: "Ticker", width: 60, sortable: true, locked: true},
5053 {header: "Company Name", width: 150, sortable: true},
5054 {header: "Market Cap.", width: 100, sortable: true},
5055 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5056 {header: "Employees", width: 100, sortable: true, resizable: false}
5061 * The config options listed for this class are options which may appear in each
5062 * individual column definition.
5063 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5065 * @param {Object} config An Array of column config objects. See this class's
5066 * config objects for details.
5068 Roo.grid.ColumnModel = function(config){
5070 * The config passed into the constructor
5072 this.config = config;
5075 // if no id, create one
5076 // if the column does not have a dataIndex mapping,
5077 // map it to the order it is in the config
5078 for(var i = 0, len = config.length; i < len; i++){
5080 if(typeof c.dataIndex == "undefined"){
5083 if(typeof c.renderer == "string"){
5084 c.renderer = Roo.util.Format[c.renderer];
5086 if(typeof c.id == "undefined"){
5089 if(c.editor && c.editor.xtype){
5090 c.editor = Roo.factory(c.editor, Roo.grid);
5092 if(c.editor && c.editor.isFormField){
5093 c.editor = new Roo.grid.GridEditor(c.editor);
5095 this.lookup[c.id] = c;
5099 * The width of columns which have no width specified (defaults to 100)
5102 this.defaultWidth = 100;
5105 * Default sortable of columns which have no sortable specified (defaults to false)
5108 this.defaultSortable = false;
5112 * @event widthchange
5113 * Fires when the width of a column changes.
5114 * @param {ColumnModel} this
5115 * @param {Number} columnIndex The column index
5116 * @param {Number} newWidth The new width
5118 "widthchange": true,
5120 * @event headerchange
5121 * Fires when the text of a header changes.
5122 * @param {ColumnModel} this
5123 * @param {Number} columnIndex The column index
5124 * @param {Number} newText The new header text
5126 "headerchange": true,
5128 * @event hiddenchange
5129 * Fires when a column is hidden or "unhidden".
5130 * @param {ColumnModel} this
5131 * @param {Number} columnIndex The column index
5132 * @param {Boolean} hidden true if hidden, false otherwise
5134 "hiddenchange": true,
5136 * @event columnmoved
5137 * Fires when a column is moved.
5138 * @param {ColumnModel} this
5139 * @param {Number} oldIndex
5140 * @param {Number} newIndex
5142 "columnmoved" : true,
5144 * @event columlockchange
5145 * Fires when a column's locked state is changed
5146 * @param {ColumnModel} this
5147 * @param {Number} colIndex
5148 * @param {Boolean} locked true if locked
5150 "columnlockchange" : true
5152 Roo.grid.ColumnModel.superclass.constructor.call(this);
5154 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5156 * @cfg {String} header The header text to display in the Grid view.
5159 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5160 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5161 * specified, the column's index is used as an index into the Record's data Array.
5164 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5165 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5168 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5169 * Defaults to the value of the {@link #defaultSortable} property.
5170 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5173 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5176 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5179 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5182 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5185 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5186 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5187 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5188 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5191 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5194 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5197 * @cfg {String} cursor (Optional)
5200 * @cfg {String} tooltip (Optional)
5203 * @cfg {Number} xs (Optional)
5206 * @cfg {Number} sm (Optional)
5209 * @cfg {Number} md (Optional)
5212 * @cfg {Number} lg (Optional)
5215 * Returns the id of the column at the specified index.
5216 * @param {Number} index The column index
5217 * @return {String} the id
5219 getColumnId : function(index){
5220 return this.config[index].id;
5224 * Returns the column for a specified id.
5225 * @param {String} id The column id
5226 * @return {Object} the column
5228 getColumnById : function(id){
5229 return this.lookup[id];
5234 * Returns the column for a specified dataIndex.
5235 * @param {String} dataIndex The column dataIndex
5236 * @return {Object|Boolean} the column or false if not found
5238 getColumnByDataIndex: function(dataIndex){
5239 var index = this.findColumnIndex(dataIndex);
5240 return index > -1 ? this.config[index] : false;
5244 * Returns the index for a specified column id.
5245 * @param {String} id The column id
5246 * @return {Number} the index, or -1 if not found
5248 getIndexById : function(id){
5249 for(var i = 0, len = this.config.length; i < len; i++){
5250 if(this.config[i].id == id){
5258 * Returns the index for a specified column dataIndex.
5259 * @param {String} dataIndex The column dataIndex
5260 * @return {Number} the index, or -1 if not found
5263 findColumnIndex : function(dataIndex){
5264 for(var i = 0, len = this.config.length; i < len; i++){
5265 if(this.config[i].dataIndex == dataIndex){
5273 moveColumn : function(oldIndex, newIndex){
5274 var c = this.config[oldIndex];
5275 this.config.splice(oldIndex, 1);
5276 this.config.splice(newIndex, 0, c);
5277 this.dataMap = null;
5278 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5281 isLocked : function(colIndex){
5282 return this.config[colIndex].locked === true;
5285 setLocked : function(colIndex, value, suppressEvent){
5286 if(this.isLocked(colIndex) == value){
5289 this.config[colIndex].locked = value;
5291 this.fireEvent("columnlockchange", this, colIndex, value);
5295 getTotalLockedWidth : function(){
5297 for(var i = 0; i < this.config.length; i++){
5298 if(this.isLocked(i) && !this.isHidden(i)){
5299 this.totalWidth += this.getColumnWidth(i);
5305 getLockedCount : function(){
5306 for(var i = 0, len = this.config.length; i < len; i++){
5307 if(!this.isLocked(i)){
5312 return this.config.length;
5316 * Returns the number of columns.
5319 getColumnCount : function(visibleOnly){
5320 if(visibleOnly === true){
5322 for(var i = 0, len = this.config.length; i < len; i++){
5323 if(!this.isHidden(i)){
5329 return this.config.length;
5333 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5334 * @param {Function} fn
5335 * @param {Object} scope (optional)
5336 * @return {Array} result
5338 getColumnsBy : function(fn, scope){
5340 for(var i = 0, len = this.config.length; i < len; i++){
5341 var c = this.config[i];
5342 if(fn.call(scope||this, c, i) === true){
5350 * Returns true if the specified column is sortable.
5351 * @param {Number} col The column index
5354 isSortable : function(col){
5355 if(typeof this.config[col].sortable == "undefined"){
5356 return this.defaultSortable;
5358 return this.config[col].sortable;
5362 * Returns the rendering (formatting) function defined for the column.
5363 * @param {Number} col The column index.
5364 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5366 getRenderer : function(col){
5367 if(!this.config[col].renderer){
5368 return Roo.grid.ColumnModel.defaultRenderer;
5370 return this.config[col].renderer;
5374 * Sets the rendering (formatting) function for a column.
5375 * @param {Number} col The column index
5376 * @param {Function} fn The function to use to process the cell's raw data
5377 * to return HTML markup for the grid view. The render function is called with
5378 * the following parameters:<ul>
5379 * <li>Data value.</li>
5380 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5381 * <li>css A CSS style string to apply to the table cell.</li>
5382 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5383 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5384 * <li>Row index</li>
5385 * <li>Column index</li>
5386 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5388 setRenderer : function(col, fn){
5389 this.config[col].renderer = fn;
5393 * Returns the width for the specified column.
5394 * @param {Number} col The column index
5397 getColumnWidth : function(col){
5398 return this.config[col].width * 1 || this.defaultWidth;
5402 * Sets the width for a column.
5403 * @param {Number} col The column index
5404 * @param {Number} width The new width
5406 setColumnWidth : function(col, width, suppressEvent){
5407 this.config[col].width = width;
5408 this.totalWidth = null;
5410 this.fireEvent("widthchange", this, col, width);
5415 * Returns the total width of all columns.
5416 * @param {Boolean} includeHidden True to include hidden column widths
5419 getTotalWidth : function(includeHidden){
5420 if(!this.totalWidth){
5421 this.totalWidth = 0;
5422 for(var i = 0, len = this.config.length; i < len; i++){
5423 if(includeHidden || !this.isHidden(i)){
5424 this.totalWidth += this.getColumnWidth(i);
5428 return this.totalWidth;
5432 * Returns the header for the specified column.
5433 * @param {Number} col The column index
5436 getColumnHeader : function(col){
5437 return this.config[col].header;
5441 * Sets the header for a column.
5442 * @param {Number} col The column index
5443 * @param {String} header The new header
5445 setColumnHeader : function(col, header){
5446 this.config[col].header = header;
5447 this.fireEvent("headerchange", this, col, header);
5451 * Returns the tooltip for the specified column.
5452 * @param {Number} col The column index
5455 getColumnTooltip : function(col){
5456 return this.config[col].tooltip;
5459 * Sets the tooltip for a column.
5460 * @param {Number} col The column index
5461 * @param {String} tooltip The new tooltip
5463 setColumnTooltip : function(col, tooltip){
5464 this.config[col].tooltip = tooltip;
5468 * Returns the dataIndex for the specified column.
5469 * @param {Number} col The column index
5472 getDataIndex : function(col){
5473 return this.config[col].dataIndex;
5477 * Sets the dataIndex for a column.
5478 * @param {Number} col The column index
5479 * @param {Number} dataIndex The new dataIndex
5481 setDataIndex : function(col, dataIndex){
5482 this.config[col].dataIndex = dataIndex;
5488 * Returns true if the cell is editable.
5489 * @param {Number} colIndex The column index
5490 * @param {Number} rowIndex The row index - this is nto actually used..?
5493 isCellEditable : function(colIndex, rowIndex){
5494 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5498 * Returns the editor defined for the cell/column.
5499 * return false or null to disable editing.
5500 * @param {Number} colIndex The column index
5501 * @param {Number} rowIndex The row index
5504 getCellEditor : function(colIndex, rowIndex){
5505 return this.config[colIndex].editor;
5509 * Sets if a column is editable.
5510 * @param {Number} col The column index
5511 * @param {Boolean} editable True if the column is editable
5513 setEditable : function(col, editable){
5514 this.config[col].editable = editable;
5519 * Returns true if the column is hidden.
5520 * @param {Number} colIndex The column index
5523 isHidden : function(colIndex){
5524 return this.config[colIndex].hidden;
5529 * Returns true if the column width cannot be changed
5531 isFixed : function(colIndex){
5532 return this.config[colIndex].fixed;
5536 * Returns true if the column can be resized
5539 isResizable : function(colIndex){
5540 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5543 * Sets if a column is hidden.
5544 * @param {Number} colIndex The column index
5545 * @param {Boolean} hidden True if the column is hidden
5547 setHidden : function(colIndex, hidden){
5548 this.config[colIndex].hidden = hidden;
5549 this.totalWidth = null;
5550 this.fireEvent("hiddenchange", this, colIndex, hidden);
5554 * Sets the editor for a column.
5555 * @param {Number} col The column index
5556 * @param {Object} editor The editor object
5558 setEditor : function(col, editor){
5559 this.config[col].editor = editor;
5563 Roo.grid.ColumnModel.defaultRenderer = function(value)
5565 if(typeof value == "object") {
5568 if(typeof value == "string" && value.length < 1){
5572 return String.format("{0}", value);
5575 // Alias for backwards compatibility
5576 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.LoadMask
5590 * A simple utility class for generically masking elements while loading data. If the element being masked has
5591 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5592 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5593 * element's UpdateManager load indicator and will be destroyed after the initial load.
5595 * Create a new LoadMask
5596 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5597 * @param {Object} config The config object
5599 Roo.LoadMask = function(el, config){
5600 this.el = Roo.get(el);
5601 Roo.apply(this, config);
5603 this.store.on('beforeload', this.onBeforeLoad, this);
5604 this.store.on('load', this.onLoad, this);
5605 this.store.on('loadexception', this.onLoadException, this);
5606 this.removeMask = false;
5608 var um = this.el.getUpdateManager();
5609 um.showLoadIndicator = false; // disable the default indicator
5610 um.on('beforeupdate', this.onBeforeLoad, this);
5611 um.on('update', this.onLoad, this);
5612 um.on('failure', this.onLoad, this);
5613 this.removeMask = true;
5617 Roo.LoadMask.prototype = {
5619 * @cfg {Boolean} removeMask
5620 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5621 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5625 * The text to display in a centered loading message box (defaults to 'Loading...')
5629 * @cfg {String} msgCls
5630 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5632 msgCls : 'x-mask-loading',
5635 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5641 * Disables the mask to prevent it from being displayed
5643 disable : function(){
5644 this.disabled = true;
5648 * Enables the mask so that it can be displayed
5650 enable : function(){
5651 this.disabled = false;
5654 onLoadException : function()
5658 if (typeof(arguments[3]) != 'undefined') {
5659 Roo.MessageBox.alert("Error loading",arguments[3]);
5663 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5664 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5673 this.el.unmask(this.removeMask);
5678 this.el.unmask(this.removeMask);
5682 onBeforeLoad : function(){
5684 (function() { this.el.mask(this.msg, this.msgCls) }).defer(50, this);
5689 destroy : function(){
5691 this.store.un('beforeload', this.onBeforeLoad, this);
5692 this.store.un('load', this.onLoad, this);
5693 this.store.un('loadexception', this.onLoadException, this);
5695 var um = this.el.getUpdateManager();
5696 um.un('beforeupdate', this.onBeforeLoad, this);
5697 um.un('update', this.onLoad, this);
5698 um.un('failure', this.onLoad, this);
5709 * @class Roo.bootstrap.Table
5710 * @extends Roo.bootstrap.Component
5711 * Bootstrap Table class
5712 * @cfg {String} cls table class
5713 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5714 * @cfg {String} bgcolor Specifies the background color for a table
5715 * @cfg {Number} border Specifies whether the table cells should have borders or not
5716 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5717 * @cfg {Number} cellspacing Specifies the space between cells
5718 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5719 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5720 * @cfg {String} sortable Specifies that the table should be sortable
5721 * @cfg {String} summary Specifies a summary of the content of a table
5722 * @cfg {Number} width Specifies the width of a table
5723 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5725 * @cfg {boolean} striped Should the rows be alternative striped
5726 * @cfg {boolean} bordered Add borders to the table
5727 * @cfg {boolean} hover Add hover highlighting
5728 * @cfg {boolean} condensed Format condensed
5729 * @cfg {boolean} responsive Format condensed
5730 * @cfg {Boolean} loadMask (true|false) default false
5731 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5732 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5733 * @cfg {Boolean} rowSelection (true|false) default false
5734 * @cfg {Boolean} cellSelection (true|false) default false
5735 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5736 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5740 * Create a new Table
5741 * @param {Object} config The config object
5744 Roo.bootstrap.Table = function(config){
5745 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5750 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5751 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5752 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5753 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5755 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5757 this.sm.grid = this;
5758 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5759 this.sm = this.selModel;
5760 this.sm.xmodule = this.xmodule || false;
5763 if (this.cm && typeof(this.cm.config) == 'undefined') {
5764 this.colModel = new Roo.grid.ColumnModel(this.cm);
5765 this.cm = this.colModel;
5766 this.cm.xmodule = this.xmodule || false;
5769 this.store= Roo.factory(this.store, Roo.data);
5770 this.ds = this.store;
5771 this.ds.xmodule = this.xmodule || false;
5774 if (this.footer && this.store) {
5775 this.footer.dataSource = this.ds;
5776 this.footer = Roo.factory(this.footer);
5783 * Fires when a cell is clicked
5784 * @param {Roo.bootstrap.Table} this
5785 * @param {Roo.Element} el
5786 * @param {Number} rowIndex
5787 * @param {Number} columnIndex
5788 * @param {Roo.EventObject} e
5792 * @event celldblclick
5793 * Fires when a cell is double clicked
5794 * @param {Roo.bootstrap.Table} this
5795 * @param {Roo.Element} el
5796 * @param {Number} rowIndex
5797 * @param {Number} columnIndex
5798 * @param {Roo.EventObject} e
5800 "celldblclick" : true,
5803 * Fires when a row is clicked
5804 * @param {Roo.bootstrap.Table} this
5805 * @param {Roo.Element} el
5806 * @param {Number} rowIndex
5807 * @param {Roo.EventObject} e
5811 * @event rowdblclick
5812 * Fires when a row is double clicked
5813 * @param {Roo.bootstrap.Table} this
5814 * @param {Roo.Element} el
5815 * @param {Number} rowIndex
5816 * @param {Roo.EventObject} e
5818 "rowdblclick" : true,
5821 * Fires when a mouseover occur
5822 * @param {Roo.bootstrap.Table} this
5823 * @param {Roo.Element} el
5824 * @param {Number} rowIndex
5825 * @param {Number} columnIndex
5826 * @param {Roo.EventObject} e
5831 * Fires when a mouseout occur
5832 * @param {Roo.bootstrap.Table} this
5833 * @param {Roo.Element} el
5834 * @param {Number} rowIndex
5835 * @param {Number} columnIndex
5836 * @param {Roo.EventObject} e
5841 * Fires when a row is rendered, so you can change add a style to it.
5842 * @param {Roo.bootstrap.Table} this
5843 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5847 * @event rowsrendered
5848 * Fires when all the rows have been rendered
5849 * @param {Roo.bootstrap.Table} this
5851 'rowsrendered' : true,
5853 * @event contextmenu
5854 * The raw contextmenu event for the entire grid.
5855 * @param {Roo.EventObject} e
5857 "contextmenu" : true,
5859 * @event rowcontextmenu
5860 * Fires when a row is right clicked
5861 * @param {Roo.bootstrap.Table} this
5862 * @param {Number} rowIndex
5863 * @param {Roo.EventObject} e
5865 "rowcontextmenu" : true,
5867 * @event cellcontextmenu
5868 * Fires when a cell is right clicked
5869 * @param {Roo.bootstrap.Table} this
5870 * @param {Number} rowIndex
5871 * @param {Number} cellIndex
5872 * @param {Roo.EventObject} e
5874 "cellcontextmenu" : true,
5876 * @event headercontextmenu
5877 * Fires when a header is right clicked
5878 * @param {Roo.bootstrap.Table} this
5879 * @param {Number} columnIndex
5880 * @param {Roo.EventObject} e
5882 "headercontextmenu" : true
5886 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5912 rowSelection : false,
5913 cellSelection : false,
5916 // Roo.Element - the tbody
5918 // Roo.Element - thead element
5921 container: false, // used by gridpanel...
5923 getAutoCreate : function()
5925 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5932 if (this.scrollBody) {
5933 cfg.cls += ' table-body-fixed';
5936 cfg.cls += ' table-striped';
5940 cfg.cls += ' table-hover';
5942 if (this.bordered) {
5943 cfg.cls += ' table-bordered';
5945 if (this.condensed) {
5946 cfg.cls += ' table-condensed';
5948 if (this.responsive) {
5949 cfg.cls += ' table-responsive';
5953 cfg.cls+= ' ' +this.cls;
5956 // this lot should be simplifed...
5959 cfg.align=this.align;
5962 cfg.bgcolor=this.bgcolor;
5965 cfg.border=this.border;
5967 if (this.cellpadding) {
5968 cfg.cellpadding=this.cellpadding;
5970 if (this.cellspacing) {
5971 cfg.cellspacing=this.cellspacing;
5974 cfg.frame=this.frame;
5977 cfg.rules=this.rules;
5979 if (this.sortable) {
5980 cfg.sortable=this.sortable;
5983 cfg.summary=this.summary;
5986 cfg.width=this.width;
5989 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5992 if(this.store || this.cm){
5993 if(this.headerShow){
5994 cfg.cn.push(this.renderHeader());
5997 cfg.cn.push(this.renderBody());
5999 if(this.footerShow){
6000 cfg.cn.push(this.renderFooter());
6002 // where does this come from?
6003 //cfg.cls+= ' TableGrid';
6006 return { cn : [ cfg ] };
6009 initEvents : function()
6011 if(!this.store || !this.cm){
6014 if (this.selModel) {
6015 this.selModel.initEvents();
6019 //Roo.log('initEvents with ds!!!!');
6021 this.mainBody = this.el.select('tbody', true).first();
6022 this.mainHead = this.el.select('thead', true).first();
6029 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6030 e.on('click', _this.sort, _this);
6033 this.mainBody.on("click", this.onClick, this);
6034 this.mainBody.on("dblclick", this.onDblClick, this);
6036 // why is this done????? = it breaks dialogs??
6037 //this.parent().el.setStyle('position', 'relative');
6041 this.footer.parentId = this.id;
6042 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6045 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6047 this.store.on('load', this.onLoad, this);
6048 this.store.on('beforeload', this.onBeforeLoad, this);
6049 this.store.on('update', this.onUpdate, this);
6050 this.store.on('add', this.onAdd, this);
6051 this.store.on("clear", this.clear, this);
6053 this.el.on("contextmenu", this.onContextMenu, this);
6055 this.mainBody.on('scroll', this.onBodyScroll, this);
6060 onContextMenu : function(e, t)
6062 this.processEvent("contextmenu", e);
6065 processEvent : function(name, e)
6067 if (name != 'touchstart' ) {
6068 this.fireEvent(name, e);
6071 var t = e.getTarget();
6073 var cell = Roo.get(t);
6079 if(cell.findParent('tfoot', false, true)){
6083 if(cell.findParent('thead', false, true)){
6085 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6086 cell = Roo.get(t).findParent('th', false, true);
6088 Roo.log("failed to find th in thead?");
6089 Roo.log(e.getTarget());
6094 var cellIndex = cell.dom.cellIndex;
6096 var ename = name == 'touchstart' ? 'click' : name;
6097 this.fireEvent("header" + ename, this, cellIndex, e);
6102 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6103 cell = Roo.get(t).findParent('td', false, true);
6105 Roo.log("failed to find th in tbody?");
6106 Roo.log(e.getTarget());
6111 var row = cell.findParent('tr', false, true);
6112 var cellIndex = cell.dom.cellIndex;
6113 var rowIndex = row.dom.rowIndex - 1;
6117 this.fireEvent("row" + name, this, rowIndex, e);
6121 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6127 onMouseover : function(e, el)
6129 var cell = Roo.get(el);
6135 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6136 cell = cell.findParent('td', false, true);
6139 var row = cell.findParent('tr', false, true);
6140 var cellIndex = cell.dom.cellIndex;
6141 var rowIndex = row.dom.rowIndex - 1; // start from 0
6143 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6147 onMouseout : function(e, el)
6149 var cell = Roo.get(el);
6155 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6156 cell = cell.findParent('td', false, true);
6159 var row = cell.findParent('tr', false, true);
6160 var cellIndex = cell.dom.cellIndex;
6161 var rowIndex = row.dom.rowIndex - 1; // start from 0
6163 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6167 onClick : function(e, el)
6169 var cell = Roo.get(el);
6171 if(!cell || (!this.cellSelection && !this.rowSelection)){
6175 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6176 cell = cell.findParent('td', false, true);
6179 if(!cell || typeof(cell) == 'undefined'){
6183 var row = cell.findParent('tr', false, true);
6185 if(!row || typeof(row) == 'undefined'){
6189 var cellIndex = cell.dom.cellIndex;
6190 var rowIndex = this.getRowIndex(row);
6192 // why??? - should these not be based on SelectionModel?
6193 if(this.cellSelection){
6194 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6197 if(this.rowSelection){
6198 this.fireEvent('rowclick', this, row, rowIndex, e);
6204 onDblClick : function(e,el)
6206 var cell = Roo.get(el);
6208 if(!cell || (!this.cellSelection && !this.rowSelection)){
6212 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6213 cell = cell.findParent('td', false, true);
6216 if(!cell || typeof(cell) == 'undefined'){
6220 var row = cell.findParent('tr', false, true);
6222 if(!row || typeof(row) == 'undefined'){
6226 var cellIndex = cell.dom.cellIndex;
6227 var rowIndex = this.getRowIndex(row);
6229 if(this.cellSelection){
6230 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6233 if(this.rowSelection){
6234 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6238 sort : function(e,el)
6240 var col = Roo.get(el);
6242 if(!col.hasClass('sortable')){
6246 var sort = col.attr('sort');
6249 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6253 this.store.sortInfo = {field : sort, direction : dir};
6256 Roo.log("calling footer first");
6257 this.footer.onClick('first');
6260 this.store.load({ params : { start : 0 } });
6264 renderHeader : function()
6272 this.totalWidth = 0;
6274 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6276 var config = cm.config[i];
6281 html: cm.getColumnHeader(i)
6286 if(typeof(config.sortable) != 'undefined' && config.sortable){
6288 c.html = '<i class="glyphicon"></i>' + c.html;
6291 if(typeof(config.lgHeader) != 'undefined'){
6292 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6295 if(typeof(config.mdHeader) != 'undefined'){
6296 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6299 if(typeof(config.smHeader) != 'undefined'){
6300 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6303 if(typeof(config.xsHeader) != 'undefined'){
6304 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6311 if(typeof(config.tooltip) != 'undefined'){
6312 c.tooltip = config.tooltip;
6315 if(typeof(config.colspan) != 'undefined'){
6316 c.colspan = config.colspan;
6319 if(typeof(config.hidden) != 'undefined' && config.hidden){
6320 c.style += ' display:none;';
6323 if(typeof(config.dataIndex) != 'undefined'){
6324 c.sort = config.dataIndex;
6329 if(typeof(config.align) != 'undefined' && config.align.length){
6330 c.style += ' text-align:' + config.align + ';';
6333 if(typeof(config.width) != 'undefined'){
6334 c.style += ' width:' + config.width + 'px;';
6335 this.totalWidth += config.width;
6337 this.totalWidth += 100; // assume minimum of 100 per column?
6340 if(typeof(config.cls) != 'undefined'){
6341 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6344 ['xs','sm','md','lg'].map(function(size){
6346 if(typeof(config[size]) == 'undefined'){
6350 if (!config[size]) { // 0 = hidden
6351 c.cls += ' hidden-' + size;
6355 c.cls += ' col-' + size + '-' + config[size];
6365 renderBody : function()
6375 colspan : this.cm.getColumnCount()
6385 renderFooter : function()
6395 colspan : this.cm.getColumnCount()
6409 // Roo.log('ds onload');
6414 var ds = this.store;
6416 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6417 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6418 if (_this.store.sortInfo) {
6420 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6421 e.select('i', true).addClass(['glyphicon-arrow-up']);
6424 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6425 e.select('i', true).addClass(['glyphicon-arrow-down']);
6430 var tbody = this.mainBody;
6432 if(ds.getCount() > 0){
6433 ds.data.each(function(d,rowIndex){
6434 var row = this.renderRow(cm, ds, rowIndex);
6436 tbody.createChild(row);
6440 if(row.cellObjects.length){
6441 Roo.each(row.cellObjects, function(r){
6442 _this.renderCellObject(r);
6449 Roo.each(this.el.select('tbody td', true).elements, function(e){
6450 e.on('mouseover', _this.onMouseover, _this);
6453 Roo.each(this.el.select('tbody td', true).elements, function(e){
6454 e.on('mouseout', _this.onMouseout, _this);
6456 this.fireEvent('rowsrendered', this);
6457 //if(this.loadMask){
6458 // this.maskEl.hide();
6465 onUpdate : function(ds,record)
6467 this.refreshRow(record);
6471 onRemove : function(ds, record, index, isUpdate){
6472 if(isUpdate !== true){
6473 this.fireEvent("beforerowremoved", this, index, record);
6475 var bt = this.mainBody.dom;
6477 var rows = this.el.select('tbody > tr', true).elements;
6479 if(typeof(rows[index]) != 'undefined'){
6480 bt.removeChild(rows[index].dom);
6483 // if(bt.rows[index]){
6484 // bt.removeChild(bt.rows[index]);
6487 if(isUpdate !== true){
6488 //this.stripeRows(index);
6489 //this.syncRowHeights(index, index);
6491 this.fireEvent("rowremoved", this, index, record);
6495 onAdd : function(ds, records, rowIndex)
6497 //Roo.log('on Add called');
6498 // - note this does not handle multiple adding very well..
6499 var bt = this.mainBody.dom;
6500 for (var i =0 ; i < records.length;i++) {
6501 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6502 //Roo.log(records[i]);
6503 //Roo.log(this.store.getAt(rowIndex+i));
6504 this.insertRow(this.store, rowIndex + i, false);
6511 refreshRow : function(record){
6512 var ds = this.store, index;
6513 if(typeof record == 'number'){
6515 record = ds.getAt(index);
6517 index = ds.indexOf(record);
6519 this.insertRow(ds, index, true);
6521 this.onRemove(ds, record, index+1, true);
6523 //this.syncRowHeights(index, index);
6525 this.fireEvent("rowupdated", this, index, record);
6528 insertRow : function(dm, rowIndex, isUpdate){
6531 this.fireEvent("beforerowsinserted", this, rowIndex);
6533 //var s = this.getScrollState();
6534 var row = this.renderRow(this.cm, this.store, rowIndex);
6535 // insert before rowIndex..
6536 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6540 if(row.cellObjects.length){
6541 Roo.each(row.cellObjects, function(r){
6542 _this.renderCellObject(r);
6547 this.fireEvent("rowsinserted", this, rowIndex);
6548 //this.syncRowHeights(firstRow, lastRow);
6549 //this.stripeRows(firstRow);
6556 getRowDom : function(rowIndex)
6558 var rows = this.el.select('tbody > tr', true).elements;
6560 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6563 // returns the object tree for a tr..
6566 renderRow : function(cm, ds, rowIndex)
6569 var d = ds.getAt(rowIndex);
6576 var cellObjects = [];
6578 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6579 var config = cm.config[i];
6581 var renderer = cm.getRenderer(i);
6585 if(typeof(renderer) !== 'undefined'){
6586 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6588 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6589 // and are rendered into the cells after the row is rendered - using the id for the element.
6591 if(typeof(value) === 'object'){
6601 rowIndex : rowIndex,
6606 this.fireEvent('rowclass', this, rowcfg);
6610 cls : rowcfg.rowClass,
6612 html: (typeof(value) === 'object') ? '' : value
6619 if(typeof(config.colspan) != 'undefined'){
6620 td.colspan = config.colspan;
6623 if(typeof(config.hidden) != 'undefined' && config.hidden){
6624 td.style += ' display:none;';
6627 if(typeof(config.align) != 'undefined' && config.align.length){
6628 td.style += ' text-align:' + config.align + ';';
6631 if(typeof(config.width) != 'undefined'){
6632 td.style += ' width:' + config.width + 'px;';
6635 if(typeof(config.cursor) != 'undefined'){
6636 td.style += ' cursor:' + config.cursor + ';';
6639 if(typeof(config.cls) != 'undefined'){
6640 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6643 ['xs','sm','md','lg'].map(function(size){
6645 if(typeof(config[size]) == 'undefined'){
6649 if (!config[size]) { // 0 = hidden
6650 td.cls += ' hidden-' + size;
6654 td.cls += ' col-' + size + '-' + config[size];
6662 row.cellObjects = cellObjects;
6670 onBeforeLoad : function()
6672 //Roo.log('ds onBeforeLoad');
6676 //if(this.loadMask){
6677 // this.maskEl.show();
6685 this.el.select('tbody', true).first().dom.innerHTML = '';
6688 * Show or hide a row.
6689 * @param {Number} rowIndex to show or hide
6690 * @param {Boolean} state hide
6692 setRowVisibility : function(rowIndex, state)
6694 var bt = this.mainBody.dom;
6696 var rows = this.el.select('tbody > tr', true).elements;
6698 if(typeof(rows[rowIndex]) == 'undefined'){
6701 rows[rowIndex].dom.style.display = state ? '' : 'none';
6705 getSelectionModel : function(){
6707 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6709 return this.selModel;
6712 * Render the Roo.bootstrap object from renderder
6714 renderCellObject : function(r)
6718 var t = r.cfg.render(r.container);
6721 Roo.each(r.cfg.cn, function(c){
6723 container: t.getChildContainer(),
6726 _this.renderCellObject(child);
6731 getRowIndex : function(row)
6735 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6746 * Returns the grid's underlying element = used by panel.Grid
6747 * @return {Element} The element
6749 getGridEl : function(){
6753 * Forces a resize - used by panel.Grid
6754 * @return {Element} The element
6756 autoSize : function()
6758 //var ctr = Roo.get(this.container.dom.parentElement);
6759 var ctr = Roo.get(this.el.dom);
6761 var thd = this.getGridEl().select('thead',true).first();
6762 var tbd = this.getGridEl().select('tbody', true).first();
6763 var tfd = this.getGridEl().select('tfoot', true).first();
6765 var cw = ctr.getWidth();
6769 tbd.setSize(ctr.getWidth(),
6770 ctr.getHeight() - (thd.getHeight() + (tfd ? tfd.getHeight() : 0))
6772 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6775 cw = Math.max(cw, this.totalWidth);
6776 this.getGridEl().select('tr',true).setWidth(cw);
6777 // resize 'expandable coloumn?
6779 return; // we doe not have a view in this design..
6782 onBodyScroll: function()
6785 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6786 this.mainHead.setStyle({
6787 'position' : 'relative',
6788 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6805 * @class Roo.bootstrap.TableCell
6806 * @extends Roo.bootstrap.Component
6807 * Bootstrap TableCell class
6808 * @cfg {String} html cell contain text
6809 * @cfg {String} cls cell class
6810 * @cfg {String} tag cell tag (td|th) default td
6811 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6812 * @cfg {String} align Aligns the content in a cell
6813 * @cfg {String} axis Categorizes cells
6814 * @cfg {String} bgcolor Specifies the background color of a cell
6815 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6816 * @cfg {Number} colspan Specifies the number of columns a cell should span
6817 * @cfg {String} headers Specifies one or more header cells a cell is related to
6818 * @cfg {Number} height Sets the height of a cell
6819 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6820 * @cfg {Number} rowspan Sets the number of rows a cell should span
6821 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6822 * @cfg {String} valign Vertical aligns the content in a cell
6823 * @cfg {Number} width Specifies the width of a cell
6826 * Create a new TableCell
6827 * @param {Object} config The config object
6830 Roo.bootstrap.TableCell = function(config){
6831 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6834 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6854 getAutoCreate : function(){
6855 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6875 cfg.align=this.align
6881 cfg.bgcolor=this.bgcolor
6884 cfg.charoff=this.charoff
6887 cfg.colspan=this.colspan
6890 cfg.headers=this.headers
6893 cfg.height=this.height
6896 cfg.nowrap=this.nowrap
6899 cfg.rowspan=this.rowspan
6902 cfg.scope=this.scope
6905 cfg.valign=this.valign
6908 cfg.width=this.width
6927 * @class Roo.bootstrap.TableRow
6928 * @extends Roo.bootstrap.Component
6929 * Bootstrap TableRow class
6930 * @cfg {String} cls row class
6931 * @cfg {String} align Aligns the content in a table row
6932 * @cfg {String} bgcolor Specifies a background color for a table row
6933 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6934 * @cfg {String} valign Vertical aligns the content in a table row
6937 * Create a new TableRow
6938 * @param {Object} config The config object
6941 Roo.bootstrap.TableRow = function(config){
6942 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6945 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6953 getAutoCreate : function(){
6954 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6964 cfg.align = this.align;
6967 cfg.bgcolor = this.bgcolor;
6970 cfg.charoff = this.charoff;
6973 cfg.valign = this.valign;
6991 * @class Roo.bootstrap.TableBody
6992 * @extends Roo.bootstrap.Component
6993 * Bootstrap TableBody class
6994 * @cfg {String} cls element class
6995 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6996 * @cfg {String} align Aligns the content inside the element
6997 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6998 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7001 * Create a new TableBody
7002 * @param {Object} config The config object
7005 Roo.bootstrap.TableBody = function(config){
7006 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7009 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7017 getAutoCreate : function(){
7018 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7032 cfg.align = this.align;
7035 cfg.charoff = this.charoff;
7038 cfg.valign = this.valign;
7045 // initEvents : function()
7052 // this.store = Roo.factory(this.store, Roo.data);
7053 // this.store.on('load', this.onLoad, this);
7055 // this.store.load();
7059 // onLoad: function ()
7061 // this.fireEvent('load', this);
7071 * Ext JS Library 1.1.1
7072 * Copyright(c) 2006-2007, Ext JS, LLC.
7074 * Originally Released Under LGPL - original licence link has changed is not relivant.
7077 * <script type="text/javascript">
7080 // as we use this in bootstrap.
7081 Roo.namespace('Roo.form');
7083 * @class Roo.form.Action
7084 * Internal Class used to handle form actions
7086 * @param {Roo.form.BasicForm} el The form element or its id
7087 * @param {Object} config Configuration options
7092 // define the action interface
7093 Roo.form.Action = function(form, options){
7095 this.options = options || {};
7098 * Client Validation Failed
7101 Roo.form.Action.CLIENT_INVALID = 'client';
7103 * Server Validation Failed
7106 Roo.form.Action.SERVER_INVALID = 'server';
7108 * Connect to Server Failed
7111 Roo.form.Action.CONNECT_FAILURE = 'connect';
7113 * Reading Data from Server Failed
7116 Roo.form.Action.LOAD_FAILURE = 'load';
7118 Roo.form.Action.prototype = {
7120 failureType : undefined,
7121 response : undefined,
7125 run : function(options){
7130 success : function(response){
7135 handleResponse : function(response){
7139 // default connection failure
7140 failure : function(response){
7142 this.response = response;
7143 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7144 this.form.afterAction(this, false);
7147 processResponse : function(response){
7148 this.response = response;
7149 if(!response.responseText){
7152 this.result = this.handleResponse(response);
7156 // utility functions used internally
7157 getUrl : function(appendParams){
7158 var url = this.options.url || this.form.url || this.form.el.dom.action;
7160 var p = this.getParams();
7162 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7168 getMethod : function(){
7169 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7172 getParams : function(){
7173 var bp = this.form.baseParams;
7174 var p = this.options.params;
7176 if(typeof p == "object"){
7177 p = Roo.urlEncode(Roo.applyIf(p, bp));
7178 }else if(typeof p == 'string' && bp){
7179 p += '&' + Roo.urlEncode(bp);
7182 p = Roo.urlEncode(bp);
7187 createCallback : function(){
7189 success: this.success,
7190 failure: this.failure,
7192 timeout: (this.form.timeout*1000),
7193 upload: this.form.fileUpload ? this.success : undefined
7198 Roo.form.Action.Submit = function(form, options){
7199 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7202 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7205 haveProgress : false,
7206 uploadComplete : false,
7208 // uploadProgress indicator.
7209 uploadProgress : function()
7211 if (!this.form.progressUrl) {
7215 if (!this.haveProgress) {
7216 Roo.MessageBox.progress("Uploading", "Uploading");
7218 if (this.uploadComplete) {
7219 Roo.MessageBox.hide();
7223 this.haveProgress = true;
7225 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7227 var c = new Roo.data.Connection();
7229 url : this.form.progressUrl,
7234 success : function(req){
7235 //console.log(data);
7239 rdata = Roo.decode(req.responseText)
7241 Roo.log("Invalid data from server..");
7245 if (!rdata || !rdata.success) {
7247 Roo.MessageBox.alert(Roo.encode(rdata));
7250 var data = rdata.data;
7252 if (this.uploadComplete) {
7253 Roo.MessageBox.hide();
7258 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7259 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7262 this.uploadProgress.defer(2000,this);
7265 failure: function(data) {
7266 Roo.log('progress url failed ');
7277 // run get Values on the form, so it syncs any secondary forms.
7278 this.form.getValues();
7280 var o = this.options;
7281 var method = this.getMethod();
7282 var isPost = method == 'POST';
7283 if(o.clientValidation === false || this.form.isValid()){
7285 if (this.form.progressUrl) {
7286 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7287 (new Date() * 1) + '' + Math.random());
7292 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7293 form:this.form.el.dom,
7294 url:this.getUrl(!isPost),
7296 params:isPost ? this.getParams() : null,
7297 isUpload: this.form.fileUpload
7300 this.uploadProgress();
7302 }else if (o.clientValidation !== false){ // client validation failed
7303 this.failureType = Roo.form.Action.CLIENT_INVALID;
7304 this.form.afterAction(this, false);
7308 success : function(response)
7310 this.uploadComplete= true;
7311 if (this.haveProgress) {
7312 Roo.MessageBox.hide();
7316 var result = this.processResponse(response);
7317 if(result === true || result.success){
7318 this.form.afterAction(this, true);
7322 this.form.markInvalid(result.errors);
7323 this.failureType = Roo.form.Action.SERVER_INVALID;
7325 this.form.afterAction(this, false);
7327 failure : function(response)
7329 this.uploadComplete= true;
7330 if (this.haveProgress) {
7331 Roo.MessageBox.hide();
7334 this.response = response;
7335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7336 this.form.afterAction(this, false);
7339 handleResponse : function(response){
7340 if(this.form.errorReader){
7341 var rs = this.form.errorReader.read(response);
7344 for(var i = 0, len = rs.records.length; i < len; i++) {
7345 var r = rs.records[i];
7349 if(errors.length < 1){
7353 success : rs.success,
7359 ret = Roo.decode(response.responseText);
7363 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7373 Roo.form.Action.Load = function(form, options){
7374 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7375 this.reader = this.form.reader;
7378 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7383 Roo.Ajax.request(Roo.apply(
7384 this.createCallback(), {
7385 method:this.getMethod(),
7386 url:this.getUrl(false),
7387 params:this.getParams()
7391 success : function(response){
7393 var result = this.processResponse(response);
7394 if(result === true || !result.success || !result.data){
7395 this.failureType = Roo.form.Action.LOAD_FAILURE;
7396 this.form.afterAction(this, false);
7399 this.form.clearInvalid();
7400 this.form.setValues(result.data);
7401 this.form.afterAction(this, true);
7404 handleResponse : function(response){
7405 if(this.form.reader){
7406 var rs = this.form.reader.read(response);
7407 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7409 success : rs.success,
7413 return Roo.decode(response.responseText);
7417 Roo.form.Action.ACTION_TYPES = {
7418 'load' : Roo.form.Action.Load,
7419 'submit' : Roo.form.Action.Submit
7428 * @class Roo.bootstrap.Form
7429 * @extends Roo.bootstrap.Component
7430 * Bootstrap Form class
7431 * @cfg {String} method GET | POST (default POST)
7432 * @cfg {String} labelAlign top | left (default top)
7433 * @cfg {String} align left | right - for navbars
7434 * @cfg {Boolean} loadMask load mask when submit (default true)
7439 * @param {Object} config The config object
7443 Roo.bootstrap.Form = function(config){
7444 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7446 Roo.bootstrap.Form.popover.apply();
7450 * @event clientvalidation
7451 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7452 * @param {Form} this
7453 * @param {Boolean} valid true if the form has passed client-side validation
7455 clientvalidation: true,
7457 * @event beforeaction
7458 * Fires before any action is performed. Return false to cancel the action.
7459 * @param {Form} this
7460 * @param {Action} action The action to be performed
7464 * @event actionfailed
7465 * Fires when an action fails.
7466 * @param {Form} this
7467 * @param {Action} action The action that failed
7469 actionfailed : true,
7471 * @event actioncomplete
7472 * Fires when an action is completed.
7473 * @param {Form} this
7474 * @param {Action} action The action that completed
7476 actioncomplete : true
7481 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7484 * @cfg {String} method
7485 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7490 * The URL to use for form actions if one isn't supplied in the action options.
7493 * @cfg {Boolean} fileUpload
7494 * Set to true if this form is a file upload.
7498 * @cfg {Object} baseParams
7499 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7503 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7507 * @cfg {Sting} align (left|right) for navbar forms
7512 activeAction : null,
7515 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7516 * element by passing it or its id or mask the form itself by passing in true.
7519 waitMsgTarget : false,
7524 * @cfg {Boolean} errorMask (true|false) default false
7528 getAutoCreate : function(){
7532 method : this.method || 'POST',
7533 id : this.id || Roo.id(),
7536 if (this.parent().xtype.match(/^Nav/)) {
7537 cfg.cls = 'navbar-form navbar-' + this.align;
7541 if (this.labelAlign == 'left' ) {
7542 cfg.cls += ' form-horizontal';
7548 initEvents : function()
7550 this.el.on('submit', this.onSubmit, this);
7551 // this was added as random key presses on the form where triggering form submit.
7552 this.el.on('keypress', function(e) {
7553 if (e.getCharCode() != 13) {
7556 // we might need to allow it for textareas.. and some other items.
7557 // check e.getTarget().
7559 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7563 Roo.log("keypress blocked");
7571 onSubmit : function(e){
7576 * Returns true if client-side validation on the form is successful.
7579 isValid : function(){
7580 var items = this.getItems();
7584 items.each(function(f){
7591 if(!target && f.el.isVisible(true)){
7597 if(this.errorMask && !valid){
7598 Roo.bootstrap.Form.popover.mask(this, target);
7605 * Returns true if any fields in this form have changed since their original load.
7608 isDirty : function(){
7610 var items = this.getItems();
7611 items.each(function(f){
7621 * Performs a predefined action (submit or load) or custom actions you define on this form.
7622 * @param {String} actionName The name of the action type
7623 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7624 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7625 * accept other config options):
7627 Property Type Description
7628 ---------------- --------------- ----------------------------------------------------------------------------------
7629 url String The url for the action (defaults to the form's url)
7630 method String The form method to use (defaults to the form's method, or POST if not defined)
7631 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7632 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7633 validate the form on the client (defaults to false)
7635 * @return {BasicForm} this
7637 doAction : function(action, options){
7638 if(typeof action == 'string'){
7639 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7641 if(this.fireEvent('beforeaction', this, action) !== false){
7642 this.beforeAction(action);
7643 action.run.defer(100, action);
7649 beforeAction : function(action){
7650 var o = action.options;
7653 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7655 // not really supported yet.. ??
7657 //if(this.waitMsgTarget === true){
7658 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7659 //}else if(this.waitMsgTarget){
7660 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7661 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7663 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7669 afterAction : function(action, success){
7670 this.activeAction = null;
7671 var o = action.options;
7673 //if(this.waitMsgTarget === true){
7675 //}else if(this.waitMsgTarget){
7676 // this.waitMsgTarget.unmask();
7678 // Roo.MessageBox.updateProgress(1);
7679 // Roo.MessageBox.hide();
7686 Roo.callback(o.success, o.scope, [this, action]);
7687 this.fireEvent('actioncomplete', this, action);
7691 // failure condition..
7692 // we have a scenario where updates need confirming.
7693 // eg. if a locking scenario exists..
7694 // we look for { errors : { needs_confirm : true }} in the response.
7696 (typeof(action.result) != 'undefined') &&
7697 (typeof(action.result.errors) != 'undefined') &&
7698 (typeof(action.result.errors.needs_confirm) != 'undefined')
7701 Roo.log("not supported yet");
7704 Roo.MessageBox.confirm(
7705 "Change requires confirmation",
7706 action.result.errorMsg,
7711 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7721 Roo.callback(o.failure, o.scope, [this, action]);
7722 // show an error message if no failed handler is set..
7723 if (!this.hasListener('actionfailed')) {
7724 Roo.log("need to add dialog support");
7726 Roo.MessageBox.alert("Error",
7727 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7728 action.result.errorMsg :
7729 "Saving Failed, please check your entries or try again"
7734 this.fireEvent('actionfailed', this, action);
7739 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7740 * @param {String} id The value to search for
7743 findField : function(id){
7744 var items = this.getItems();
7745 var field = items.get(id);
7747 items.each(function(f){
7748 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7755 return field || null;
7758 * Mark fields in this form invalid in bulk.
7759 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7760 * @return {BasicForm} this
7762 markInvalid : function(errors){
7763 if(errors instanceof Array){
7764 for(var i = 0, len = errors.length; i < len; i++){
7765 var fieldError = errors[i];
7766 var f = this.findField(fieldError.id);
7768 f.markInvalid(fieldError.msg);
7774 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7775 field.markInvalid(errors[id]);
7779 //Roo.each(this.childForms || [], function (f) {
7780 // f.markInvalid(errors);
7787 * Set values for fields in this form in bulk.
7788 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7789 * @return {BasicForm} this
7791 setValues : function(values){
7792 if(values instanceof Array){ // array of objects
7793 for(var i = 0, len = values.length; i < len; i++){
7795 var f = this.findField(v.id);
7797 f.setValue(v.value);
7798 if(this.trackResetOnLoad){
7799 f.originalValue = f.getValue();
7803 }else{ // object hash
7806 if(typeof values[id] != 'function' && (field = this.findField(id))){
7808 if (field.setFromData &&
7810 field.displayField &&
7811 // combos' with local stores can
7812 // be queried via setValue()
7813 // to set their value..
7814 (field.store && !field.store.isLocal)
7818 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7819 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7820 field.setFromData(sd);
7823 field.setValue(values[id]);
7827 if(this.trackResetOnLoad){
7828 field.originalValue = field.getValue();
7834 //Roo.each(this.childForms || [], function (f) {
7835 // f.setValues(values);
7842 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7843 * they are returned as an array.
7844 * @param {Boolean} asString
7847 getValues : function(asString){
7848 //if (this.childForms) {
7849 // copy values from the child forms
7850 // Roo.each(this.childForms, function (f) {
7851 // this.setValues(f.getValues());
7857 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7858 if(asString === true){
7861 return Roo.urlDecode(fs);
7865 * Returns the fields in this form as an object with key/value pairs.
7866 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7869 getFieldValues : function(with_hidden)
7871 var items = this.getItems();
7873 items.each(function(f){
7877 var v = f.getValue();
7878 if (f.inputType =='radio') {
7879 if (typeof(ret[f.getName()]) == 'undefined') {
7880 ret[f.getName()] = ''; // empty..
7883 if (!f.el.dom.checked) {
7891 // not sure if this supported any more..
7892 if ((typeof(v) == 'object') && f.getRawValue) {
7893 v = f.getRawValue() ; // dates..
7895 // combo boxes where name != hiddenName...
7896 if (f.name !== false && f.name != '' && f.name != f.getName()) {
7897 ret[f.name] = f.getRawValue();
7899 ret[f.getName()] = v;
7906 * Clears all invalid messages in this form.
7907 * @return {BasicForm} this
7909 clearInvalid : function(){
7910 var items = this.getItems();
7912 items.each(function(f){
7923 * @return {BasicForm} this
7926 var items = this.getItems();
7927 items.each(function(f){
7931 Roo.each(this.childForms || [], function (f) {
7938 getItems : function()
7940 var r=new Roo.util.MixedCollection(false, function(o){
7941 return o.id || (o.id = Roo.id());
7943 var iter = function(el) {
7950 Roo.each(el.items,function(e) {
7967 Roo.apply(Roo.bootstrap.Form, {
7994 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
7995 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
7996 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
7997 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8000 this.maskEl.top.enableDisplayMode("block");
8001 this.maskEl.left.enableDisplayMode("block");
8002 this.maskEl.bottom.enableDisplayMode("block");
8003 this.maskEl.right.enableDisplayMode("block");
8005 this.toolTip = new Roo.bootstrap.Tooltip({
8006 cls : 'roo-form-error-popover',
8008 'left' : ['r-l', [-2,0], 'right'],
8009 'right' : ['l-r', [2,0], 'left'],
8010 'bottom' : ['tl-bl', [0,2], 'top'],
8011 'top' : [ 'bl-tl', [0,-2], 'bottom']
8015 this.toolTip.render(Roo.get(document.body));
8017 this.toolTip.el.enableDisplayMode("block");
8019 Roo.get(document.body).on('click', function(){
8023 this.isApplied = true
8026 mask : function(form, target)
8030 this.target = target;
8032 if(!this.form.errorMask || !target.el){
8036 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8038 var scrolled = scrollable.getScroll();
8040 var ot = this.target.el.calcOffsetsTo(scrollable);
8042 scrollTo = ot[1] - 100;
8044 scrollable.scrollTo('top', scrollTo);
8046 var box = this.target.el.getBox();
8048 var zIndex = Roo.bootstrap.Modal.zIndex++;
8050 this.maskEl.top.setStyle('position', 'fixed');
8051 this.maskEl.top.setStyle('z-index', zIndex);
8052 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8053 this.maskEl.top.setXY([0, 0]);
8054 this.maskEl.top.show();
8056 this.maskEl.left.setStyle('position', 'fixed');
8057 this.maskEl.left.setStyle('z-index', zIndex);
8058 this.maskEl.left.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8059 this.maskEl.left.setXY([box.right + this.padding, box.y - this.padding]);
8060 this.maskEl.left.show();
8062 this.maskEl.bottom.setStyle('position', 'fixed');
8063 this.maskEl.bottom.setStyle('z-index', zIndex);
8064 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8065 this.maskEl.bottom.setXY([0, box.bottom + this.padding]);
8066 this.maskEl.bottom.show();
8068 this.maskEl.right.setStyle('position', 'fixed');
8069 this.maskEl.right.setStyle('z-index', zIndex);
8070 this.maskEl.right.setSize(box.x - this.padding, box.height + this.padding * 2);
8071 this.maskEl.right.setXY([0, box.y - this.padding]);
8072 this.maskEl.right.show();
8075 this.toolTip.bindEl = this.target.el;
8077 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8079 var tip = this.target.blankText;
8081 if(this.target.getValue() !== '' && this.target.regexText.length){
8082 tip = this.target.regexText;
8085 this.toolTip.show(tip);
8087 this.intervalID = window.setInterval(function() {
8088 Roo.bootstrap.Form.popover.unmask();
8091 window.onwheel = function(){ return false;};
8093 (function(){ this.isMasked = true; }).defer(500, this);
8101 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8105 this.maskEl.top.setStyle('position', 'absolute');
8106 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8107 this.maskEl.top.hide();
8109 this.maskEl.left.setStyle('position', 'absolute');
8110 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8111 this.maskEl.left.hide();
8113 this.maskEl.bottom.setStyle('position', 'absolute');
8114 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8115 this.maskEl.bottom.hide();
8117 this.maskEl.right.setStyle('position', 'absolute');
8118 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8119 this.maskEl.right.hide();
8121 this.toolTip.hide();
8123 this.toolTip.el.hide();
8125 window.onwheel = function(){ return true;};
8127 if(this.intervalID){
8128 window.clearInterval(this.intervalID);
8129 this.intervalID = false;
8132 this.isMasked = false;
8142 * Ext JS Library 1.1.1
8143 * Copyright(c) 2006-2007, Ext JS, LLC.
8145 * Originally Released Under LGPL - original licence link has changed is not relivant.
8148 * <script type="text/javascript">
8151 * @class Roo.form.VTypes
8152 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8155 Roo.form.VTypes = function(){
8156 // closure these in so they are only created once.
8157 var alpha = /^[a-zA-Z_]+$/;
8158 var alphanum = /^[a-zA-Z0-9_]+$/;
8159 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8160 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8162 // All these messages and functions are configurable
8165 * The function used to validate email addresses
8166 * @param {String} value The email address
8168 'email' : function(v){
8169 return email.test(v);
8172 * The error text to display when the email validation function returns false
8175 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8177 * The keystroke filter mask to be applied on email input
8180 'emailMask' : /[a-z0-9_\.\-@]/i,
8183 * The function used to validate URLs
8184 * @param {String} value The URL
8186 'url' : function(v){
8190 * The error text to display when the url validation function returns false
8193 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8196 * The function used to validate alpha values
8197 * @param {String} value The value
8199 'alpha' : function(v){
8200 return alpha.test(v);
8203 * The error text to display when the alpha validation function returns false
8206 'alphaText' : 'This field should only contain letters and _',
8208 * The keystroke filter mask to be applied on alpha input
8211 'alphaMask' : /[a-z_]/i,
8214 * The function used to validate alphanumeric values
8215 * @param {String} value The value
8217 'alphanum' : function(v){
8218 return alphanum.test(v);
8221 * The error text to display when the alphanumeric validation function returns false
8224 'alphanumText' : 'This field should only contain letters, numbers and _',
8226 * The keystroke filter mask to be applied on alphanumeric input
8229 'alphanumMask' : /[a-z0-9_]/i
8239 * @class Roo.bootstrap.Input
8240 * @extends Roo.bootstrap.Component
8241 * Bootstrap Input class
8242 * @cfg {Boolean} disabled is it disabled
8243 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8244 * @cfg {String} name name of the input
8245 * @cfg {string} fieldLabel - the label associated
8246 * @cfg {string} placeholder - placeholder to put in text.
8247 * @cfg {string} before - input group add on before
8248 * @cfg {string} after - input group add on after
8249 * @cfg {string} size - (lg|sm) or leave empty..
8250 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8251 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8252 * @cfg {Number} md colspan out of 12 for computer-sized screens
8253 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8254 * @cfg {string} value default value of the input
8255 * @cfg {Number} labelWidth set the width of label
8256 * @cfg {Number} labellg set the width of label (1-12)
8257 * @cfg {Number} labelmd set the width of label (1-12)
8258 * @cfg {Number} labelsm set the width of label (1-12)
8259 * @cfg {Number} labelxs set the width of label (1-12)
8260 * @cfg {String} labelAlign (top|left)
8261 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8262 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8263 * @cfg {String} indicatorpos (left|right) default left
8265 * @cfg {String} align (left|center|right) Default left
8266 * @cfg {Boolean} forceFeedback (true|false) Default false
8272 * Create a new Input
8273 * @param {Object} config The config object
8276 Roo.bootstrap.Input = function(config){
8278 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8283 * Fires when this field receives input focus.
8284 * @param {Roo.form.Field} this
8289 * Fires when this field loses input focus.
8290 * @param {Roo.form.Field} this
8295 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8296 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8297 * @param {Roo.form.Field} this
8298 * @param {Roo.EventObject} e The event object
8303 * Fires just before the field blurs if the field value has changed.
8304 * @param {Roo.form.Field} this
8305 * @param {Mixed} newValue The new value
8306 * @param {Mixed} oldValue The original value
8311 * Fires after the field has been marked as invalid.
8312 * @param {Roo.form.Field} this
8313 * @param {String} msg The validation message
8318 * Fires after the field has been validated with no errors.
8319 * @param {Roo.form.Field} this
8324 * Fires after the key up
8325 * @param {Roo.form.Field} this
8326 * @param {Roo.EventObject} e The event Object
8332 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8334 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8335 automatic validation (defaults to "keyup").
8337 validationEvent : "keyup",
8339 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8341 validateOnBlur : true,
8343 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8345 validationDelay : 250,
8347 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8349 focusClass : "x-form-focus", // not needed???
8353 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8355 invalidClass : "has-warning",
8358 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8360 validClass : "has-success",
8363 * @cfg {Boolean} hasFeedback (true|false) default true
8368 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8370 invalidFeedbackClass : "glyphicon-warning-sign",
8373 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8375 validFeedbackClass : "glyphicon-ok",
8378 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8380 selectOnFocus : false,
8383 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8387 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8392 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8394 disableKeyFilter : false,
8397 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8401 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8405 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8407 blankText : "Please complete this mandatory field",
8410 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8414 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8416 maxLength : Number.MAX_VALUE,
8418 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8420 minLengthText : "The minimum length for this field is {0}",
8422 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8424 maxLengthText : "The maximum length for this field is {0}",
8428 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8429 * If available, this function will be called only after the basic validators all return true, and will be passed the
8430 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8434 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8435 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8436 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8440 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
8444 autocomplete: false,
8463 formatedValue : false,
8464 forceFeedback : false,
8466 indicatorpos : 'left',
8473 parentLabelAlign : function()
8476 while (parent.parent()) {
8477 parent = parent.parent();
8478 if (typeof(parent.labelAlign) !='undefined') {
8479 return parent.labelAlign;
8486 getAutoCreate : function()
8488 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8494 if(this.inputType != 'hidden'){
8495 cfg.cls = 'form-group' //input-group
8501 type : this.inputType,
8503 cls : 'form-control',
8504 placeholder : this.placeholder || '',
8505 autocomplete : this.autocomplete || 'new-password'
8509 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8512 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8513 input.maxLength = this.maxLength;
8516 if (this.disabled) {
8517 input.disabled=true;
8520 if (this.readOnly) {
8521 input.readonly=true;
8525 input.name = this.name;
8529 input.cls += ' input-' + this.size;
8533 ['xs','sm','md','lg'].map(function(size){
8534 if (settings[size]) {
8535 cfg.cls += ' col-' + size + '-' + settings[size];
8539 var inputblock = input;
8543 cls: 'glyphicon form-control-feedback'
8546 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8549 cls : 'has-feedback',
8557 if (this.before || this.after) {
8560 cls : 'input-group',
8564 if (this.before && typeof(this.before) == 'string') {
8566 inputblock.cn.push({
8568 cls : 'roo-input-before input-group-addon',
8572 if (this.before && typeof(this.before) == 'object') {
8573 this.before = Roo.factory(this.before);
8575 inputblock.cn.push({
8577 cls : 'roo-input-before input-group-' +
8578 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8582 inputblock.cn.push(input);
8584 if (this.after && typeof(this.after) == 'string') {
8585 inputblock.cn.push({
8587 cls : 'roo-input-after input-group-addon',
8591 if (this.after && typeof(this.after) == 'object') {
8592 this.after = Roo.factory(this.after);
8594 inputblock.cn.push({
8596 cls : 'roo-input-after input-group-' +
8597 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8601 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8602 inputblock.cls += ' has-feedback';
8603 inputblock.cn.push(feedback);
8607 if (align ==='left' && this.fieldLabel.length) {
8609 cfg.cls += ' roo-form-group-label-left';
8614 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8615 tooltip : 'This field is required'
8620 cls : 'control-label',
8621 html : this.fieldLabel
8632 var labelCfg = cfg.cn[1];
8633 var contentCfg = cfg.cn[2];
8635 if(this.indicatorpos == 'right'){
8640 cls : 'control-label',
8641 html : this.fieldLabel
8646 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8647 tooltip : 'This field is required'
8658 labelCfg = cfg.cn[0];
8659 contentCfg = cfg.cn[2];
8663 if(this.labelWidth > 12){
8664 labelCfg.style = "width: " + this.labelWidth + 'px';
8667 if(this.labelWidth < 13 && this.labelmd == 0){
8668 this.labelmd = this.labelWidth;
8671 if(this.labellg > 0){
8672 labelCfg.cls += ' col-lg-' + this.labellg;
8673 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8676 if(this.labelmd > 0){
8677 labelCfg.cls += ' col-md-' + this.labelmd;
8678 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8681 if(this.labelsm > 0){
8682 labelCfg.cls += ' col-sm-' + this.labelsm;
8683 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8686 if(this.labelxs > 0){
8687 labelCfg.cls += ' col-xs-' + this.labelxs;
8688 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8692 } else if ( this.fieldLabel.length) {
8697 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8698 tooltip : 'This field is required'
8702 //cls : 'input-group-addon',
8703 html : this.fieldLabel
8711 if(this.indicatorpos == 'right'){
8716 //cls : 'input-group-addon',
8717 html : this.fieldLabel
8722 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8723 tooltip : 'This field is required'
8743 if (this.parentType === 'Navbar' && this.parent().bar) {
8744 cfg.cls += ' navbar-form';
8747 if (this.parentType === 'NavGroup') {
8748 cfg.cls += ' navbar-form';
8756 * return the real input element.
8758 inputEl: function ()
8760 return this.el.select('input.form-control',true).first();
8763 tooltipEl : function()
8765 return this.inputEl();
8768 indicatorEl : function()
8770 var indicator = this.el.select('i.roo-required-indicator',true).first();
8780 setDisabled : function(v)
8782 var i = this.inputEl().dom;
8784 i.removeAttribute('disabled');
8788 i.setAttribute('disabled','true');
8790 initEvents : function()
8793 this.inputEl().on("keydown" , this.fireKey, this);
8794 this.inputEl().on("focus", this.onFocus, this);
8795 this.inputEl().on("blur", this.onBlur, this);
8797 this.inputEl().relayEvent('keyup', this);
8799 this.indicator = this.indicatorEl();
8802 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
8803 this.indicator.hide();
8806 // reference to original value for reset
8807 this.originalValue = this.getValue();
8808 //Roo.form.TextField.superclass.initEvents.call(this);
8809 if(this.validationEvent == 'keyup'){
8810 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
8811 this.inputEl().on('keyup', this.filterValidation, this);
8813 else if(this.validationEvent !== false){
8814 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
8817 if(this.selectOnFocus){
8818 this.on("focus", this.preFocus, this);
8821 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
8822 this.inputEl().on("keypress", this.filterKeys, this);
8824 this.inputEl().relayEvent('keypress', this);
8827 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
8828 this.el.on("click", this.autoSize, this);
8831 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
8832 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
8835 if (typeof(this.before) == 'object') {
8836 this.before.render(this.el.select('.roo-input-before',true).first());
8838 if (typeof(this.after) == 'object') {
8839 this.after.render(this.el.select('.roo-input-after',true).first());
8844 filterValidation : function(e){
8845 if(!e.isNavKeyPress()){
8846 this.validationTask.delay(this.validationDelay);
8850 * Validates the field value
8851 * @return {Boolean} True if the value is valid, else false
8853 validate : function(){
8854 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
8855 if(this.disabled || this.validateValue(this.getRawValue())){
8866 * Validates a value according to the field's validation rules and marks the field as invalid
8867 * if the validation fails
8868 * @param {Mixed} value The value to validate
8869 * @return {Boolean} True if the value is valid, else false
8871 validateValue : function(value){
8872 if(value.length < 1) { // if it's blank
8873 if(this.allowBlank){
8879 if(value.length < this.minLength){
8882 if(value.length > this.maxLength){
8886 var vt = Roo.form.VTypes;
8887 if(!vt[this.vtype](value, this)){
8891 if(typeof this.validator == "function"){
8892 var msg = this.validator(value);
8898 if(this.regex && !this.regex.test(value)){
8908 fireKey : function(e){
8909 //Roo.log('field ' + e.getKey());
8910 if(e.isNavKeyPress()){
8911 this.fireEvent("specialkey", this, e);
8914 focus : function (selectText){
8916 this.inputEl().focus();
8917 if(selectText === true){
8918 this.inputEl().dom.select();
8924 onFocus : function(){
8925 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8926 // this.el.addClass(this.focusClass);
8929 this.hasFocus = true;
8930 this.startValue = this.getValue();
8931 this.fireEvent("focus", this);
8935 beforeBlur : Roo.emptyFn,
8939 onBlur : function(){
8941 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
8942 //this.el.removeClass(this.focusClass);
8944 this.hasFocus = false;
8945 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
8948 var v = this.getValue();
8949 if(String(v) !== String(this.startValue)){
8950 this.fireEvent('change', this, v, this.startValue);
8952 this.fireEvent("blur", this);
8956 * Resets the current field value to the originally loaded value and clears any validation messages
8959 this.setValue(this.originalValue);
8963 * Returns the name of the field
8964 * @return {Mixed} name The name field
8966 getName: function(){
8970 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
8971 * @return {Mixed} value The field value
8973 getValue : function(){
8975 var v = this.inputEl().getValue();
8980 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
8981 * @return {Mixed} value The field value
8983 getRawValue : function(){
8984 var v = this.inputEl().getValue();
8990 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
8991 * @param {Mixed} value The value to set
8993 setRawValue : function(v){
8994 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8997 selectText : function(start, end){
8998 var v = this.getRawValue();
9000 start = start === undefined ? 0 : start;
9001 end = end === undefined ? v.length : end;
9002 var d = this.inputEl().dom;
9003 if(d.setSelectionRange){
9004 d.setSelectionRange(start, end);
9005 }else if(d.createTextRange){
9006 var range = d.createTextRange();
9007 range.moveStart("character", start);
9008 range.moveEnd("character", v.length-end);
9015 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9016 * @param {Mixed} value The value to set
9018 setValue : function(v){
9021 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9027 processValue : function(value){
9028 if(this.stripCharsRe){
9029 var newValue = value.replace(this.stripCharsRe, '');
9030 if(newValue !== value){
9031 this.setRawValue(newValue);
9038 preFocus : function(){
9040 if(this.selectOnFocus){
9041 this.inputEl().dom.select();
9044 filterKeys : function(e){
9046 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9049 var c = e.getCharCode(), cc = String.fromCharCode(c);
9050 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9053 if(!this.maskRe.test(cc)){
9058 * Clear any invalid styles/messages for this field
9060 clearInvalid : function(){
9062 if(!this.el || this.preventMark){ // not rendered
9067 this.indicator.hide();
9070 this.el.removeClass(this.invalidClass);
9072 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9074 var feedback = this.el.select('.form-control-feedback', true).first();
9077 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9082 this.fireEvent('valid', this);
9086 * Mark this field as valid
9088 markValid : function()
9090 if(!this.el || this.preventMark){ // not rendered...
9094 this.el.removeClass([this.invalidClass, this.validClass]);
9096 var feedback = this.el.select('.form-control-feedback', true).first();
9099 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9106 if(this.allowBlank && !this.getRawValue().length){
9111 this.indicator.hide();
9114 this.el.addClass(this.validClass);
9116 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9118 var feedback = this.el.select('.form-control-feedback', true).first();
9121 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9122 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9127 this.fireEvent('valid', this);
9131 * Mark this field as invalid
9132 * @param {String} msg The validation message
9134 markInvalid : function(msg)
9136 if(!this.el || this.preventMark){ // not rendered
9140 this.el.removeClass([this.invalidClass, this.validClass]);
9142 var feedback = this.el.select('.form-control-feedback', true).first();
9145 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9152 if(this.allowBlank && !this.getRawValue().length){
9157 this.indicator.show();
9160 this.el.addClass(this.invalidClass);
9162 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9164 var feedback = this.el.select('.form-control-feedback', true).first();
9167 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9169 if(this.getValue().length || this.forceFeedback){
9170 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9177 this.fireEvent('invalid', this, msg);
9180 SafariOnKeyDown : function(event)
9182 // this is a workaround for a password hang bug on chrome/ webkit.
9183 if (this.inputEl().dom.type != 'password') {
9187 var isSelectAll = false;
9189 if(this.inputEl().dom.selectionEnd > 0){
9190 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9192 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9193 event.preventDefault();
9198 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9200 event.preventDefault();
9201 // this is very hacky as keydown always get's upper case.
9203 var cc = String.fromCharCode(event.getCharCode());
9204 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9208 adjustWidth : function(tag, w){
9209 tag = tag.toLowerCase();
9210 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9211 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9215 if(tag == 'textarea'){
9218 }else if(Roo.isOpera){
9222 if(tag == 'textarea'){
9241 * @class Roo.bootstrap.TextArea
9242 * @extends Roo.bootstrap.Input
9243 * Bootstrap TextArea class
9244 * @cfg {Number} cols Specifies the visible width of a text area
9245 * @cfg {Number} rows Specifies the visible number of lines in a text area
9246 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9247 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9248 * @cfg {string} html text
9251 * Create a new TextArea
9252 * @param {Object} config The config object
9255 Roo.bootstrap.TextArea = function(config){
9256 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9260 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9270 getAutoCreate : function(){
9272 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9283 value : this.value || '',
9284 html: this.html || '',
9285 cls : 'form-control',
9286 placeholder : this.placeholder || ''
9290 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9291 input.maxLength = this.maxLength;
9295 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9299 input.cols = this.cols;
9302 if (this.readOnly) {
9303 input.readonly = true;
9307 input.name = this.name;
9311 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9315 ['xs','sm','md','lg'].map(function(size){
9316 if (settings[size]) {
9317 cfg.cls += ' col-' + size + '-' + settings[size];
9321 var inputblock = input;
9323 if(this.hasFeedback && !this.allowBlank){
9327 cls: 'glyphicon form-control-feedback'
9331 cls : 'has-feedback',
9340 if (this.before || this.after) {
9343 cls : 'input-group',
9347 inputblock.cn.push({
9349 cls : 'input-group-addon',
9354 inputblock.cn.push(input);
9356 if(this.hasFeedback && !this.allowBlank){
9357 inputblock.cls += ' has-feedback';
9358 inputblock.cn.push(feedback);
9362 inputblock.cn.push({
9364 cls : 'input-group-addon',
9371 if (align ==='left' && this.fieldLabel.length) {
9376 cls : 'control-label',
9377 html : this.fieldLabel
9388 if(this.labelWidth > 12){
9389 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9392 if(this.labelWidth < 13 && this.labelmd == 0){
9393 this.labelmd = this.labelWidth;
9396 if(this.labellg > 0){
9397 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9398 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9401 if(this.labelmd > 0){
9402 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9403 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9406 if(this.labelsm > 0){
9407 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9408 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9411 if(this.labelxs > 0){
9412 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9413 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9416 } else if ( this.fieldLabel.length) {
9421 //cls : 'input-group-addon',
9422 html : this.fieldLabel
9440 if (this.disabled) {
9441 input.disabled=true;
9448 * return the real textarea element.
9450 inputEl: function ()
9452 return this.el.select('textarea.form-control',true).first();
9456 * Clear any invalid styles/messages for this field
9458 clearInvalid : function()
9461 if(!this.el || this.preventMark){ // not rendered
9465 var label = this.el.select('label', true).first();
9466 var icon = this.el.select('i.fa-star', true).first();
9472 this.el.removeClass(this.invalidClass);
9474 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9476 var feedback = this.el.select('.form-control-feedback', true).first();
9479 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9484 this.fireEvent('valid', this);
9488 * Mark this field as valid
9490 markValid : function()
9492 if(!this.el || this.preventMark){ // not rendered
9496 this.el.removeClass([this.invalidClass, this.validClass]);
9498 var feedback = this.el.select('.form-control-feedback', true).first();
9501 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9504 if(this.disabled || this.allowBlank){
9508 var label = this.el.select('label', true).first();
9509 var icon = this.el.select('i.fa-star', true).first();
9515 this.el.addClass(this.validClass);
9517 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9519 var feedback = this.el.select('.form-control-feedback', true).first();
9522 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9523 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9528 this.fireEvent('valid', this);
9532 * Mark this field as invalid
9533 * @param {String} msg The validation message
9535 markInvalid : function(msg)
9537 if(!this.el || this.preventMark){ // not rendered
9541 this.el.removeClass([this.invalidClass, this.validClass]);
9543 var feedback = this.el.select('.form-control-feedback', true).first();
9546 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9549 if(this.disabled || this.allowBlank){
9553 var label = this.el.select('label', true).first();
9554 var icon = this.el.select('i.fa-star', true).first();
9556 if(!this.getValue().length && label && !icon){
9557 this.el.createChild({
9559 cls : 'text-danger fa fa-lg fa-star',
9560 tooltip : 'This field is required',
9561 style : 'margin-right:5px;'
9565 this.el.addClass(this.invalidClass);
9567 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9569 var feedback = this.el.select('.form-control-feedback', true).first();
9572 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9574 if(this.getValue().length || this.forceFeedback){
9575 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9582 this.fireEvent('invalid', this, msg);
9590 * trigger field - base class for combo..
9595 * @class Roo.bootstrap.TriggerField
9596 * @extends Roo.bootstrap.Input
9597 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9598 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9599 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9600 * for which you can provide a custom implementation. For example:
9602 var trigger = new Roo.bootstrap.TriggerField();
9603 trigger.onTriggerClick = myTriggerFn;
9604 trigger.applyTo('my-field');
9607 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9608 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9609 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9610 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9611 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9614 * Create a new TriggerField.
9615 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9616 * to the base TextField)
9618 Roo.bootstrap.TriggerField = function(config){
9619 this.mimicing = false;
9620 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9623 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9625 * @cfg {String} triggerClass A CSS class to apply to the trigger
9628 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9633 * @cfg {Boolean} removable (true|false) special filter default false
9637 /** @cfg {Boolean} grow @hide */
9638 /** @cfg {Number} growMin @hide */
9639 /** @cfg {Number} growMax @hide */
9645 autoSize: Roo.emptyFn,
9652 actionMode : 'wrap',
9657 getAutoCreate : function(){
9659 var align = this.labelAlign || this.parentLabelAlign();
9664 cls: 'form-group' //input-group
9671 type : this.inputType,
9672 cls : 'form-control',
9673 autocomplete: 'new-password',
9674 placeholder : this.placeholder || ''
9678 input.name = this.name;
9681 input.cls += ' input-' + this.size;
9684 if (this.disabled) {
9685 input.disabled=true;
9688 var inputblock = input;
9690 if(this.hasFeedback && !this.allowBlank){
9694 cls: 'glyphicon form-control-feedback'
9697 if(this.removable && !this.editable && !this.tickable){
9699 cls : 'has-feedback',
9705 cls : 'roo-combo-removable-btn close'
9712 cls : 'has-feedback',
9721 if(this.removable && !this.editable && !this.tickable){
9723 cls : 'roo-removable',
9729 cls : 'roo-combo-removable-btn close'
9736 if (this.before || this.after) {
9739 cls : 'input-group',
9743 inputblock.cn.push({
9745 cls : 'input-group-addon',
9750 inputblock.cn.push(input);
9752 if(this.hasFeedback && !this.allowBlank){
9753 inputblock.cls += ' has-feedback';
9754 inputblock.cn.push(feedback);
9758 inputblock.cn.push({
9760 cls : 'input-group-addon',
9773 cls: 'form-hidden-field'
9787 cls: 'form-hidden-field'
9791 cls: 'roo-select2-choices',
9795 cls: 'roo-select2-search-field',
9808 cls: 'roo-select2-container input-group',
9813 // cls: 'typeahead typeahead-long dropdown-menu',
9814 // style: 'display:none'
9819 if(!this.multiple && this.showToggleBtn){
9825 if (this.caret != false) {
9828 cls: 'fa fa-' + this.caret
9835 cls : 'input-group-addon btn dropdown-toggle',
9840 cls: 'combobox-clear',
9854 combobox.cls += ' roo-select2-container-multi';
9857 if (align ==='left' && this.fieldLabel.length) {
9859 cfg.cls += ' roo-form-group-label-left';
9864 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9865 tooltip : 'This field is required'
9870 cls : 'control-label',
9871 html : this.fieldLabel
9883 var labelCfg = cfg.cn[1];
9884 var contentCfg = cfg.cn[2];
9886 if(this.indicatorpos == 'right'){
9891 cls : 'control-label',
9892 html : this.fieldLabel
9896 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9897 tooltip : 'This field is required'
9908 labelCfg = cfg.cn[0];
9909 contentCfg = cfg.cn[2];
9912 if(this.labelWidth > 12){
9913 labelCfg.style = "width: " + this.labelWidth + 'px';
9916 if(this.labelWidth < 13 && this.labelmd == 0){
9917 this.labelmd = this.labelWidth;
9920 if(this.labellg > 0){
9921 labelCfg.cls += ' col-lg-' + this.labellg;
9922 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9925 if(this.labelmd > 0){
9926 labelCfg.cls += ' col-md-' + this.labelmd;
9927 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9930 if(this.labelsm > 0){
9931 labelCfg.cls += ' col-sm-' + this.labelsm;
9932 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9935 if(this.labelxs > 0){
9936 labelCfg.cls += ' col-xs-' + this.labelxs;
9937 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9940 } else if ( this.fieldLabel.length) {
9941 // Roo.log(" label");
9945 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9946 tooltip : 'This field is required'
9950 //cls : 'input-group-addon',
9951 html : this.fieldLabel
9959 if(this.indicatorpos == 'right'){
9964 //cls : 'input-group-addon',
9965 html : this.fieldLabel
9970 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9971 tooltip : 'This field is required'
9982 // Roo.log(" no label && no align");
9989 ['xs','sm','md','lg'].map(function(size){
9990 if (settings[size]) {
9991 cfg.cls += ' col-' + size + '-' + settings[size];
10002 onResize : function(w, h){
10003 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10004 // if(typeof w == 'number'){
10005 // var x = w - this.trigger.getWidth();
10006 // this.inputEl().setWidth(this.adjustWidth('input', x));
10007 // this.trigger.setStyle('left', x+'px');
10012 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10015 getResizeEl : function(){
10016 return this.inputEl();
10020 getPositionEl : function(){
10021 return this.inputEl();
10025 alignErrorIcon : function(){
10026 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10030 initEvents : function(){
10034 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10035 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10036 if(!this.multiple && this.showToggleBtn){
10037 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10038 if(this.hideTrigger){
10039 this.trigger.setDisplayed(false);
10041 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10045 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10048 if(this.removable && !this.editable && !this.tickable){
10049 var close = this.closeTriggerEl();
10052 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10053 close.on('click', this.removeBtnClick, this, close);
10057 //this.trigger.addClassOnOver('x-form-trigger-over');
10058 //this.trigger.addClassOnClick('x-form-trigger-click');
10061 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10065 closeTriggerEl : function()
10067 var close = this.el.select('.roo-combo-removable-btn', true).first();
10068 return close ? close : false;
10071 removeBtnClick : function(e, h, el)
10073 e.preventDefault();
10075 if(this.fireEvent("remove", this) !== false){
10077 this.fireEvent("afterremove", this)
10081 createList : function()
10083 this.list = Roo.get(document.body).createChild({
10085 cls: 'typeahead typeahead-long dropdown-menu',
10086 style: 'display:none'
10089 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10094 initTrigger : function(){
10099 onDestroy : function(){
10101 this.trigger.removeAllListeners();
10102 // this.trigger.remove();
10105 // this.wrap.remove();
10107 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10111 onFocus : function(){
10112 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10114 if(!this.mimicing){
10115 this.wrap.addClass('x-trigger-wrap-focus');
10116 this.mimicing = true;
10117 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10118 if(this.monitorTab){
10119 this.el.on("keydown", this.checkTab, this);
10126 checkTab : function(e){
10127 if(e.getKey() == e.TAB){
10128 this.triggerBlur();
10133 onBlur : function(){
10138 mimicBlur : function(e, t){
10140 if(!this.wrap.contains(t) && this.validateBlur()){
10141 this.triggerBlur();
10147 triggerBlur : function(){
10148 this.mimicing = false;
10149 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10150 if(this.monitorTab){
10151 this.el.un("keydown", this.checkTab, this);
10153 //this.wrap.removeClass('x-trigger-wrap-focus');
10154 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10158 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10159 validateBlur : function(e, t){
10164 onDisable : function(){
10165 this.inputEl().dom.disabled = true;
10166 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10168 // this.wrap.addClass('x-item-disabled');
10173 onEnable : function(){
10174 this.inputEl().dom.disabled = false;
10175 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10177 // this.el.removeClass('x-item-disabled');
10182 onShow : function(){
10183 var ae = this.getActionEl();
10186 ae.dom.style.display = '';
10187 ae.dom.style.visibility = 'visible';
10193 onHide : function(){
10194 var ae = this.getActionEl();
10195 ae.dom.style.display = 'none';
10199 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10200 * by an implementing function.
10202 * @param {EventObject} e
10204 onTriggerClick : Roo.emptyFn
10208 * Ext JS Library 1.1.1
10209 * Copyright(c) 2006-2007, Ext JS, LLC.
10211 * Originally Released Under LGPL - original licence link has changed is not relivant.
10214 * <script type="text/javascript">
10219 * @class Roo.data.SortTypes
10221 * Defines the default sorting (casting?) comparison functions used when sorting data.
10223 Roo.data.SortTypes = {
10225 * Default sort that does nothing
10226 * @param {Mixed} s The value being converted
10227 * @return {Mixed} The comparison value
10229 none : function(s){
10234 * The regular expression used to strip tags
10238 stripTagsRE : /<\/?[^>]+>/gi,
10241 * Strips all HTML tags to sort on text only
10242 * @param {Mixed} s The value being converted
10243 * @return {String} The comparison value
10245 asText : function(s){
10246 return String(s).replace(this.stripTagsRE, "");
10250 * Strips all HTML tags to sort on text only - Case insensitive
10251 * @param {Mixed} s The value being converted
10252 * @return {String} The comparison value
10254 asUCText : function(s){
10255 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10259 * Case insensitive string
10260 * @param {Mixed} s The value being converted
10261 * @return {String} The comparison value
10263 asUCString : function(s) {
10264 return String(s).toUpperCase();
10269 * @param {Mixed} s The value being converted
10270 * @return {Number} The comparison value
10272 asDate : function(s) {
10276 if(s instanceof Date){
10277 return s.getTime();
10279 return Date.parse(String(s));
10284 * @param {Mixed} s The value being converted
10285 * @return {Float} The comparison value
10287 asFloat : function(s) {
10288 var val = parseFloat(String(s).replace(/,/g, ""));
10297 * @param {Mixed} s The value being converted
10298 * @return {Number} The comparison value
10300 asInt : function(s) {
10301 var val = parseInt(String(s).replace(/,/g, ""));
10309 * Ext JS Library 1.1.1
10310 * Copyright(c) 2006-2007, Ext JS, LLC.
10312 * Originally Released Under LGPL - original licence link has changed is not relivant.
10315 * <script type="text/javascript">
10319 * @class Roo.data.Record
10320 * Instances of this class encapsulate both record <em>definition</em> information, and record
10321 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10322 * to access Records cached in an {@link Roo.data.Store} object.<br>
10324 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10325 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10328 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10330 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10331 * {@link #create}. The parameters are the same.
10332 * @param {Array} data An associative Array of data values keyed by the field name.
10333 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10334 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10335 * not specified an integer id is generated.
10337 Roo.data.Record = function(data, id){
10338 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10343 * Generate a constructor for a specific record layout.
10344 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10345 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10346 * Each field definition object may contain the following properties: <ul>
10347 * <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,
10348 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10349 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10350 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10351 * is being used, then this is a string containing the javascript expression to reference the data relative to
10352 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10353 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10354 * this may be omitted.</p></li>
10355 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10356 * <ul><li>auto (Default, implies no conversion)</li>
10361 * <li>date</li></ul></p></li>
10362 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10363 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10364 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10365 * by the Reader into an object that will be stored in the Record. It is passed the
10366 * following parameters:<ul>
10367 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10369 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10371 * <br>usage:<br><pre><code>
10372 var TopicRecord = Roo.data.Record.create(
10373 {name: 'title', mapping: 'topic_title'},
10374 {name: 'author', mapping: 'username'},
10375 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10376 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10377 {name: 'lastPoster', mapping: 'user2'},
10378 {name: 'excerpt', mapping: 'post_text'}
10381 var myNewRecord = new TopicRecord({
10382 title: 'Do my job please',
10385 lastPost: new Date(),
10386 lastPoster: 'Animal',
10387 excerpt: 'No way dude!'
10389 myStore.add(myNewRecord);
10394 Roo.data.Record.create = function(o){
10395 var f = function(){
10396 f.superclass.constructor.apply(this, arguments);
10398 Roo.extend(f, Roo.data.Record);
10399 var p = f.prototype;
10400 p.fields = new Roo.util.MixedCollection(false, function(field){
10403 for(var i = 0, len = o.length; i < len; i++){
10404 p.fields.add(new Roo.data.Field(o[i]));
10406 f.getField = function(name){
10407 return p.fields.get(name);
10412 Roo.data.Record.AUTO_ID = 1000;
10413 Roo.data.Record.EDIT = 'edit';
10414 Roo.data.Record.REJECT = 'reject';
10415 Roo.data.Record.COMMIT = 'commit';
10417 Roo.data.Record.prototype = {
10419 * Readonly flag - true if this record has been modified.
10428 join : function(store){
10429 this.store = store;
10433 * Set the named field to the specified value.
10434 * @param {String} name The name of the field to set.
10435 * @param {Object} value The value to set the field to.
10437 set : function(name, value){
10438 if(this.data[name] == value){
10442 if(!this.modified){
10443 this.modified = {};
10445 if(typeof this.modified[name] == 'undefined'){
10446 this.modified[name] = this.data[name];
10448 this.data[name] = value;
10449 if(!this.editing && this.store){
10450 this.store.afterEdit(this);
10455 * Get the value of the named field.
10456 * @param {String} name The name of the field to get the value of.
10457 * @return {Object} The value of the field.
10459 get : function(name){
10460 return this.data[name];
10464 beginEdit : function(){
10465 this.editing = true;
10466 this.modified = {};
10470 cancelEdit : function(){
10471 this.editing = false;
10472 delete this.modified;
10476 endEdit : function(){
10477 this.editing = false;
10478 if(this.dirty && this.store){
10479 this.store.afterEdit(this);
10484 * Usually called by the {@link Roo.data.Store} which owns the Record.
10485 * Rejects all changes made to the Record since either creation, or the last commit operation.
10486 * Modified fields are reverted to their original values.
10488 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10489 * of reject operations.
10491 reject : function(){
10492 var m = this.modified;
10494 if(typeof m[n] != "function"){
10495 this.data[n] = m[n];
10498 this.dirty = false;
10499 delete this.modified;
10500 this.editing = false;
10502 this.store.afterReject(this);
10507 * Usually called by the {@link Roo.data.Store} which owns the Record.
10508 * Commits all changes made to the Record since either creation, or the last commit operation.
10510 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10511 * of commit operations.
10513 commit : function(){
10514 this.dirty = false;
10515 delete this.modified;
10516 this.editing = false;
10518 this.store.afterCommit(this);
10523 hasError : function(){
10524 return this.error != null;
10528 clearError : function(){
10533 * Creates a copy of this record.
10534 * @param {String} id (optional) A new record id if you don't want to use this record's id
10537 copy : function(newId) {
10538 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10542 * Ext JS Library 1.1.1
10543 * Copyright(c) 2006-2007, Ext JS, LLC.
10545 * Originally Released Under LGPL - original licence link has changed is not relivant.
10548 * <script type="text/javascript">
10554 * @class Roo.data.Store
10555 * @extends Roo.util.Observable
10556 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10557 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10559 * 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
10560 * has no knowledge of the format of the data returned by the Proxy.<br>
10562 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10563 * instances from the data object. These records are cached and made available through accessor functions.
10565 * Creates a new Store.
10566 * @param {Object} config A config object containing the objects needed for the Store to access data,
10567 * and read the data into Records.
10569 Roo.data.Store = function(config){
10570 this.data = new Roo.util.MixedCollection(false);
10571 this.data.getKey = function(o){
10574 this.baseParams = {};
10576 this.paramNames = {
10581 "multisort" : "_multisort"
10584 if(config && config.data){
10585 this.inlineData = config.data;
10586 delete config.data;
10589 Roo.apply(this, config);
10591 if(this.reader){ // reader passed
10592 this.reader = Roo.factory(this.reader, Roo.data);
10593 this.reader.xmodule = this.xmodule || false;
10594 if(!this.recordType){
10595 this.recordType = this.reader.recordType;
10597 if(this.reader.onMetaChange){
10598 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10602 if(this.recordType){
10603 this.fields = this.recordType.prototype.fields;
10605 this.modified = [];
10609 * @event datachanged
10610 * Fires when the data cache has changed, and a widget which is using this Store
10611 * as a Record cache should refresh its view.
10612 * @param {Store} this
10614 datachanged : true,
10616 * @event metachange
10617 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10618 * @param {Store} this
10619 * @param {Object} meta The JSON metadata
10624 * Fires when Records have been added to the Store
10625 * @param {Store} this
10626 * @param {Roo.data.Record[]} records The array of Records added
10627 * @param {Number} index The index at which the record(s) were added
10632 * Fires when a Record has been removed from the Store
10633 * @param {Store} this
10634 * @param {Roo.data.Record} record The Record that was removed
10635 * @param {Number} index The index at which the record was removed
10640 * Fires when a Record has been updated
10641 * @param {Store} this
10642 * @param {Roo.data.Record} record The Record that was updated
10643 * @param {String} operation The update operation being performed. Value may be one of:
10645 Roo.data.Record.EDIT
10646 Roo.data.Record.REJECT
10647 Roo.data.Record.COMMIT
10653 * Fires when the data cache has been cleared.
10654 * @param {Store} this
10658 * @event beforeload
10659 * Fires before a request is made for a new data object. If the beforeload handler returns false
10660 * the load action will be canceled.
10661 * @param {Store} this
10662 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10666 * @event beforeloadadd
10667 * Fires after a new set of Records has been loaded.
10668 * @param {Store} this
10669 * @param {Roo.data.Record[]} records The Records that were loaded
10670 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10672 beforeloadadd : true,
10675 * Fires after a new set of Records has been loaded, before they are added to the store.
10676 * @param {Store} this
10677 * @param {Roo.data.Record[]} records The Records that were loaded
10678 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10679 * @params {Object} return from reader
10683 * @event loadexception
10684 * Fires if an exception occurs in the Proxy during loading.
10685 * Called with the signature of the Proxy's "loadexception" event.
10686 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
10689 * @param {Object} return from JsonData.reader() - success, totalRecords, records
10690 * @param {Object} load options
10691 * @param {Object} jsonData from your request (normally this contains the Exception)
10693 loadexception : true
10697 this.proxy = Roo.factory(this.proxy, Roo.data);
10698 this.proxy.xmodule = this.xmodule || false;
10699 this.relayEvents(this.proxy, ["loadexception"]);
10701 this.sortToggle = {};
10702 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
10704 Roo.data.Store.superclass.constructor.call(this);
10706 if(this.inlineData){
10707 this.loadData(this.inlineData);
10708 delete this.inlineData;
10712 Roo.extend(Roo.data.Store, Roo.util.Observable, {
10714 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
10715 * without a remote query - used by combo/forms at present.
10719 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
10722 * @cfg {Array} data Inline data to be loaded when the store is initialized.
10725 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
10726 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
10729 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
10730 * on any HTTP request
10733 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
10736 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
10740 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
10741 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
10743 remoteSort : false,
10746 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
10747 * loaded or when a record is removed. (defaults to false).
10749 pruneModifiedRecords : false,
10752 lastOptions : null,
10755 * Add Records to the Store and fires the add event.
10756 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10758 add : function(records){
10759 records = [].concat(records);
10760 for(var i = 0, len = records.length; i < len; i++){
10761 records[i].join(this);
10763 var index = this.data.length;
10764 this.data.addAll(records);
10765 this.fireEvent("add", this, records, index);
10769 * Remove a Record from the Store and fires the remove event.
10770 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
10772 remove : function(record){
10773 var index = this.data.indexOf(record);
10774 this.data.removeAt(index);
10775 if(this.pruneModifiedRecords){
10776 this.modified.remove(record);
10778 this.fireEvent("remove", this, record, index);
10782 * Remove all Records from the Store and fires the clear event.
10784 removeAll : function(){
10786 if(this.pruneModifiedRecords){
10787 this.modified = [];
10789 this.fireEvent("clear", this);
10793 * Inserts Records to the Store at the given index and fires the add event.
10794 * @param {Number} index The start index at which to insert the passed Records.
10795 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
10797 insert : function(index, records){
10798 records = [].concat(records);
10799 for(var i = 0, len = records.length; i < len; i++){
10800 this.data.insert(index, records[i]);
10801 records[i].join(this);
10803 this.fireEvent("add", this, records, index);
10807 * Get the index within the cache of the passed Record.
10808 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
10809 * @return {Number} The index of the passed Record. Returns -1 if not found.
10811 indexOf : function(record){
10812 return this.data.indexOf(record);
10816 * Get the index within the cache of the Record with the passed id.
10817 * @param {String} id The id of the Record to find.
10818 * @return {Number} The index of the Record. Returns -1 if not found.
10820 indexOfId : function(id){
10821 return this.data.indexOfKey(id);
10825 * Get the Record with the specified id.
10826 * @param {String} id The id of the Record to find.
10827 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
10829 getById : function(id){
10830 return this.data.key(id);
10834 * Get the Record at the specified index.
10835 * @param {Number} index The index of the Record to find.
10836 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
10838 getAt : function(index){
10839 return this.data.itemAt(index);
10843 * Returns a range of Records between specified indices.
10844 * @param {Number} startIndex (optional) The starting index (defaults to 0)
10845 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
10846 * @return {Roo.data.Record[]} An array of Records
10848 getRange : function(start, end){
10849 return this.data.getRange(start, end);
10853 storeOptions : function(o){
10854 o = Roo.apply({}, o);
10857 this.lastOptions = o;
10861 * Loads the Record cache from the configured Proxy using the configured Reader.
10863 * If using remote paging, then the first load call must specify the <em>start</em>
10864 * and <em>limit</em> properties in the options.params property to establish the initial
10865 * position within the dataset, and the number of Records to cache on each read from the Proxy.
10867 * <strong>It is important to note that for remote data sources, loading is asynchronous,
10868 * and this call will return before the new data has been loaded. Perform any post-processing
10869 * in a callback function, or in a "load" event handler.</strong>
10871 * @param {Object} options An object containing properties which control loading options:<ul>
10872 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
10873 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
10874 * passed the following arguments:<ul>
10875 * <li>r : Roo.data.Record[]</li>
10876 * <li>options: Options object from the load call</li>
10877 * <li>success: Boolean success indicator</li></ul></li>
10878 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
10879 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
10882 load : function(options){
10883 options = options || {};
10884 if(this.fireEvent("beforeload", this, options) !== false){
10885 this.storeOptions(options);
10886 var p = Roo.apply(options.params || {}, this.baseParams);
10887 // if meta was not loaded from remote source.. try requesting it.
10888 if (!this.reader.metaFromRemote) {
10889 p._requestMeta = 1;
10891 if(this.sortInfo && this.remoteSort){
10892 var pn = this.paramNames;
10893 p[pn["sort"]] = this.sortInfo.field;
10894 p[pn["dir"]] = this.sortInfo.direction;
10896 if (this.multiSort) {
10897 var pn = this.paramNames;
10898 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
10901 this.proxy.load(p, this.reader, this.loadRecords, this, options);
10906 * Reloads the Record cache from the configured Proxy using the configured Reader and
10907 * the options from the last load operation performed.
10908 * @param {Object} options (optional) An object containing properties which may override the options
10909 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
10910 * the most recently used options are reused).
10912 reload : function(options){
10913 this.load(Roo.applyIf(options||{}, this.lastOptions));
10917 // Called as a callback by the Reader during a load operation.
10918 loadRecords : function(o, options, success){
10919 if(!o || success === false){
10920 if(success !== false){
10921 this.fireEvent("load", this, [], options, o);
10923 if(options.callback){
10924 options.callback.call(options.scope || this, [], options, false);
10928 // if data returned failure - throw an exception.
10929 if (o.success === false) {
10930 // show a message if no listener is registered.
10931 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
10932 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
10934 // loadmask wil be hooked into this..
10935 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
10938 var r = o.records, t = o.totalRecords || r.length;
10940 this.fireEvent("beforeloadadd", this, r, options, o);
10942 if(!options || options.add !== true){
10943 if(this.pruneModifiedRecords){
10944 this.modified = [];
10946 for(var i = 0, len = r.length; i < len; i++){
10950 this.data = this.snapshot;
10951 delete this.snapshot;
10954 this.data.addAll(r);
10955 this.totalLength = t;
10957 this.fireEvent("datachanged", this);
10959 this.totalLength = Math.max(t, this.data.length+r.length);
10962 this.fireEvent("load", this, r, options, o);
10963 if(options.callback){
10964 options.callback.call(options.scope || this, r, options, true);
10970 * Loads data from a passed data block. A Reader which understands the format of the data
10971 * must have been configured in the constructor.
10972 * @param {Object} data The data block from which to read the Records. The format of the data expected
10973 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
10974 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
10976 loadData : function(o, append){
10977 var r = this.reader.readRecords(o);
10978 this.loadRecords(r, {add: append}, true);
10982 * Gets the number of cached records.
10984 * <em>If using paging, this may not be the total size of the dataset. If the data object
10985 * used by the Reader contains the dataset size, then the getTotalCount() function returns
10986 * the data set size</em>
10988 getCount : function(){
10989 return this.data.length || 0;
10993 * Gets the total number of records in the dataset as returned by the server.
10995 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
10996 * the dataset size</em>
10998 getTotalCount : function(){
10999 return this.totalLength || 0;
11003 * Returns the sort state of the Store as an object with two properties:
11005 field {String} The name of the field by which the Records are sorted
11006 direction {String} The sort order, "ASC" or "DESC"
11009 getSortState : function(){
11010 return this.sortInfo;
11014 applySort : function(){
11015 if(this.sortInfo && !this.remoteSort){
11016 var s = this.sortInfo, f = s.field;
11017 var st = this.fields.get(f).sortType;
11018 var fn = function(r1, r2){
11019 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11020 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11022 this.data.sort(s.direction, fn);
11023 if(this.snapshot && this.snapshot != this.data){
11024 this.snapshot.sort(s.direction, fn);
11030 * Sets the default sort column and order to be used by the next load operation.
11031 * @param {String} fieldName The name of the field to sort by.
11032 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11034 setDefaultSort : function(field, dir){
11035 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11039 * Sort the Records.
11040 * If remote sorting is used, the sort is performed on the server, and the cache is
11041 * reloaded. If local sorting is used, the cache is sorted internally.
11042 * @param {String} fieldName The name of the field to sort by.
11043 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11045 sort : function(fieldName, dir){
11046 var f = this.fields.get(fieldName);
11048 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11050 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11051 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11056 this.sortToggle[f.name] = dir;
11057 this.sortInfo = {field: f.name, direction: dir};
11058 if(!this.remoteSort){
11060 this.fireEvent("datachanged", this);
11062 this.load(this.lastOptions);
11067 * Calls the specified function for each of the Records in the cache.
11068 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11069 * Returning <em>false</em> aborts and exits the iteration.
11070 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11072 each : function(fn, scope){
11073 this.data.each(fn, scope);
11077 * Gets all records modified since the last commit. Modified records are persisted across load operations
11078 * (e.g., during paging).
11079 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11081 getModifiedRecords : function(){
11082 return this.modified;
11086 createFilterFn : function(property, value, anyMatch){
11087 if(!value.exec){ // not a regex
11088 value = String(value);
11089 if(value.length == 0){
11092 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11094 return function(r){
11095 return value.test(r.data[property]);
11100 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11101 * @param {String} property A field on your records
11102 * @param {Number} start The record index to start at (defaults to 0)
11103 * @param {Number} end The last record index to include (defaults to length - 1)
11104 * @return {Number} The sum
11106 sum : function(property, start, end){
11107 var rs = this.data.items, v = 0;
11108 start = start || 0;
11109 end = (end || end === 0) ? end : rs.length-1;
11111 for(var i = start; i <= end; i++){
11112 v += (rs[i].data[property] || 0);
11118 * Filter the records by a specified property.
11119 * @param {String} field A field on your records
11120 * @param {String/RegExp} value Either a string that the field
11121 * should start with or a RegExp to test against the field
11122 * @param {Boolean} anyMatch True to match any part not just the beginning
11124 filter : function(property, value, anyMatch){
11125 var fn = this.createFilterFn(property, value, anyMatch);
11126 return fn ? this.filterBy(fn) : this.clearFilter();
11130 * Filter by a function. The specified function will be called with each
11131 * record in this data source. If the function returns true the record is included,
11132 * otherwise it is filtered.
11133 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11134 * @param {Object} scope (optional) The scope of the function (defaults to this)
11136 filterBy : function(fn, scope){
11137 this.snapshot = this.snapshot || this.data;
11138 this.data = this.queryBy(fn, scope||this);
11139 this.fireEvent("datachanged", this);
11143 * Query 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
11148 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11150 query : function(property, value, anyMatch){
11151 var fn = this.createFilterFn(property, value, anyMatch);
11152 return fn ? this.queryBy(fn) : this.data.clone();
11156 * Query by a function. The specified function will be called with each
11157 * record in this data source. If the function returns true the record is included
11159 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11160 * @param {Object} scope (optional) The scope of the function (defaults to this)
11161 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11163 queryBy : function(fn, scope){
11164 var data = this.snapshot || this.data;
11165 return data.filterBy(fn, scope||this);
11169 * Collects unique values for a particular dataIndex from this store.
11170 * @param {String} dataIndex The property to collect
11171 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11172 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11173 * @return {Array} An array of the unique values
11175 collect : function(dataIndex, allowNull, bypassFilter){
11176 var d = (bypassFilter === true && this.snapshot) ?
11177 this.snapshot.items : this.data.items;
11178 var v, sv, r = [], l = {};
11179 for(var i = 0, len = d.length; i < len; i++){
11180 v = d[i].data[dataIndex];
11182 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11191 * Revert to a view of the Record cache with no filtering applied.
11192 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11194 clearFilter : function(suppressEvent){
11195 if(this.snapshot && this.snapshot != this.data){
11196 this.data = this.snapshot;
11197 delete this.snapshot;
11198 if(suppressEvent !== true){
11199 this.fireEvent("datachanged", this);
11205 afterEdit : function(record){
11206 if(this.modified.indexOf(record) == -1){
11207 this.modified.push(record);
11209 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11213 afterReject : function(record){
11214 this.modified.remove(record);
11215 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11219 afterCommit : function(record){
11220 this.modified.remove(record);
11221 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11225 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11226 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11228 commitChanges : function(){
11229 var m = this.modified.slice(0);
11230 this.modified = [];
11231 for(var i = 0, len = m.length; i < len; i++){
11237 * Cancel outstanding changes on all changed records.
11239 rejectChanges : function(){
11240 var m = this.modified.slice(0);
11241 this.modified = [];
11242 for(var i = 0, len = m.length; i < len; i++){
11247 onMetaChange : function(meta, rtype, o){
11248 this.recordType = rtype;
11249 this.fields = rtype.prototype.fields;
11250 delete this.snapshot;
11251 this.sortInfo = meta.sortInfo || this.sortInfo;
11252 this.modified = [];
11253 this.fireEvent('metachange', this, this.reader.meta);
11256 moveIndex : function(data, type)
11258 var index = this.indexOf(data);
11260 var newIndex = index + type;
11264 this.insert(newIndex, data);
11269 * Ext JS Library 1.1.1
11270 * Copyright(c) 2006-2007, Ext JS, LLC.
11272 * Originally Released Under LGPL - original licence link has changed is not relivant.
11275 * <script type="text/javascript">
11279 * @class Roo.data.SimpleStore
11280 * @extends Roo.data.Store
11281 * Small helper class to make creating Stores from Array data easier.
11282 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11283 * @cfg {Array} fields An array of field definition objects, or field name strings.
11284 * @cfg {Array} data The multi-dimensional array of data
11286 * @param {Object} config
11288 Roo.data.SimpleStore = function(config){
11289 Roo.data.SimpleStore.superclass.constructor.call(this, {
11291 reader: new Roo.data.ArrayReader({
11294 Roo.data.Record.create(config.fields)
11296 proxy : new Roo.data.MemoryProxy(config.data)
11300 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11302 * Ext JS Library 1.1.1
11303 * Copyright(c) 2006-2007, Ext JS, LLC.
11305 * Originally Released Under LGPL - original licence link has changed is not relivant.
11308 * <script type="text/javascript">
11313 * @extends Roo.data.Store
11314 * @class Roo.data.JsonStore
11315 * Small helper class to make creating Stores for JSON data easier. <br/>
11317 var store = new Roo.data.JsonStore({
11318 url: 'get-images.php',
11320 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11323 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11324 * JsonReader and HttpProxy (unless inline data is provided).</b>
11325 * @cfg {Array} fields An array of field definition objects, or field name strings.
11327 * @param {Object} config
11329 Roo.data.JsonStore = function(c){
11330 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11331 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11332 reader: new Roo.data.JsonReader(c, c.fields)
11335 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11337 * Ext JS Library 1.1.1
11338 * Copyright(c) 2006-2007, Ext JS, LLC.
11340 * Originally Released Under LGPL - original licence link has changed is not relivant.
11343 * <script type="text/javascript">
11347 Roo.data.Field = function(config){
11348 if(typeof config == "string"){
11349 config = {name: config};
11351 Roo.apply(this, config);
11354 this.type = "auto";
11357 var st = Roo.data.SortTypes;
11358 // named sortTypes are supported, here we look them up
11359 if(typeof this.sortType == "string"){
11360 this.sortType = st[this.sortType];
11363 // set default sortType for strings and dates
11364 if(!this.sortType){
11367 this.sortType = st.asUCString;
11370 this.sortType = st.asDate;
11373 this.sortType = st.none;
11378 var stripRe = /[\$,%]/g;
11380 // prebuilt conversion function for this field, instead of
11381 // switching every time we're reading a value
11383 var cv, dateFormat = this.dateFormat;
11388 cv = function(v){ return v; };
11391 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11395 return v !== undefined && v !== null && v !== '' ?
11396 parseInt(String(v).replace(stripRe, ""), 10) : '';
11401 return v !== undefined && v !== null && v !== '' ?
11402 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11407 cv = function(v){ return v === true || v === "true" || v == 1; };
11414 if(v instanceof Date){
11418 if(dateFormat == "timestamp"){
11419 return new Date(v*1000);
11421 return Date.parseDate(v, dateFormat);
11423 var parsed = Date.parse(v);
11424 return parsed ? new Date(parsed) : null;
11433 Roo.data.Field.prototype = {
11441 * Ext JS Library 1.1.1
11442 * Copyright(c) 2006-2007, Ext JS, LLC.
11444 * Originally Released Under LGPL - original licence link has changed is not relivant.
11447 * <script type="text/javascript">
11450 // Base class for reading structured data from a data source. This class is intended to be
11451 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11454 * @class Roo.data.DataReader
11455 * Base class for reading structured data from a data source. This class is intended to be
11456 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11459 Roo.data.DataReader = function(meta, recordType){
11463 this.recordType = recordType instanceof Array ?
11464 Roo.data.Record.create(recordType) : recordType;
11467 Roo.data.DataReader.prototype = {
11469 * Create an empty record
11470 * @param {Object} data (optional) - overlay some values
11471 * @return {Roo.data.Record} record created.
11473 newRow : function(d) {
11475 this.recordType.prototype.fields.each(function(c) {
11477 case 'int' : da[c.name] = 0; break;
11478 case 'date' : da[c.name] = new Date(); break;
11479 case 'float' : da[c.name] = 0.0; break;
11480 case 'boolean' : da[c.name] = false; break;
11481 default : da[c.name] = ""; break;
11485 return new this.recordType(Roo.apply(da, d));
11490 * Ext JS Library 1.1.1
11491 * Copyright(c) 2006-2007, Ext JS, LLC.
11493 * Originally Released Under LGPL - original licence link has changed is not relivant.
11496 * <script type="text/javascript">
11500 * @class Roo.data.DataProxy
11501 * @extends Roo.data.Observable
11502 * This class is an abstract base class for implementations which provide retrieval of
11503 * unformatted data objects.<br>
11505 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11506 * (of the appropriate type which knows how to parse the data object) to provide a block of
11507 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11509 * Custom implementations must implement the load method as described in
11510 * {@link Roo.data.HttpProxy#load}.
11512 Roo.data.DataProxy = function(){
11515 * @event beforeload
11516 * Fires before a network request is made to retrieve a data object.
11517 * @param {Object} This DataProxy object.
11518 * @param {Object} params The params parameter to the load function.
11523 * Fires before the load method's callback is called.
11524 * @param {Object} This DataProxy object.
11525 * @param {Object} o The data object.
11526 * @param {Object} arg The callback argument object passed to the load function.
11530 * @event loadexception
11531 * Fires if an Exception occurs during data retrieval.
11532 * @param {Object} This DataProxy object.
11533 * @param {Object} o The data object.
11534 * @param {Object} arg The callback argument object passed to the load function.
11535 * @param {Object} e The Exception.
11537 loadexception : true
11539 Roo.data.DataProxy.superclass.constructor.call(this);
11542 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11545 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11549 * Ext JS Library 1.1.1
11550 * Copyright(c) 2006-2007, Ext JS, LLC.
11552 * Originally Released Under LGPL - original licence link has changed is not relivant.
11555 * <script type="text/javascript">
11558 * @class Roo.data.MemoryProxy
11559 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11560 * to the Reader when its load method is called.
11562 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11564 Roo.data.MemoryProxy = function(data){
11568 Roo.data.MemoryProxy.superclass.constructor.call(this);
11572 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11575 * Load data from the requested source (in this case an in-memory
11576 * data object passed to the constructor), read the data object into
11577 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11578 * process that block using the passed callback.
11579 * @param {Object} params This parameter is not used by the MemoryProxy class.
11580 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11581 * object into a block of Roo.data.Records.
11582 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11583 * The function must be passed <ul>
11584 * <li>The Record block object</li>
11585 * <li>The "arg" argument from the load function</li>
11586 * <li>A boolean success indicator</li>
11588 * @param {Object} scope The scope in which to call the callback
11589 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11591 load : function(params, reader, callback, scope, arg){
11592 params = params || {};
11595 result = reader.readRecords(this.data);
11597 this.fireEvent("loadexception", this, arg, null, e);
11598 callback.call(scope, null, arg, false);
11601 callback.call(scope, result, arg, true);
11605 update : function(params, records){
11610 * Ext JS Library 1.1.1
11611 * Copyright(c) 2006-2007, Ext JS, LLC.
11613 * Originally Released Under LGPL - original licence link has changed is not relivant.
11616 * <script type="text/javascript">
11619 * @class Roo.data.HttpProxy
11620 * @extends Roo.data.DataProxy
11621 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11622 * configured to reference a certain URL.<br><br>
11624 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11625 * from which the running page was served.<br><br>
11627 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11629 * Be aware that to enable the browser to parse an XML document, the server must set
11630 * the Content-Type header in the HTTP response to "text/xml".
11632 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11633 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11634 * will be used to make the request.
11636 Roo.data.HttpProxy = function(conn){
11637 Roo.data.HttpProxy.superclass.constructor.call(this);
11638 // is conn a conn config or a real conn?
11640 this.useAjax = !conn || !conn.events;
11644 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11645 // thse are take from connection...
11648 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11651 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11652 * extra parameters to each request made by this object. (defaults to undefined)
11655 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11656 * to each request made by this object. (defaults to undefined)
11659 * @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)
11662 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11665 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11671 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11675 * Return the {@link Roo.data.Connection} object being used by this Proxy.
11676 * @return {Connection} The Connection object. This object may be used to subscribe to events on
11677 * a finer-grained basis than the DataProxy events.
11679 getConnection : function(){
11680 return this.useAjax ? Roo.Ajax : this.conn;
11684 * Load data from the configured {@link Roo.data.Connection}, read the data object into
11685 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
11686 * process that block using the passed callback.
11687 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11688 * for the request to the remote server.
11689 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11690 * object into a block of Roo.data.Records.
11691 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11692 * The function must be passed <ul>
11693 * <li>The Record block object</li>
11694 * <li>The "arg" argument from the load function</li>
11695 * <li>A boolean success indicator</li>
11697 * @param {Object} scope The scope in which to call the callback
11698 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11700 load : function(params, reader, callback, scope, arg){
11701 if(this.fireEvent("beforeload", this, params) !== false){
11703 params : params || {},
11705 callback : callback,
11710 callback : this.loadResponse,
11714 Roo.applyIf(o, this.conn);
11715 if(this.activeRequest){
11716 Roo.Ajax.abort(this.activeRequest);
11718 this.activeRequest = Roo.Ajax.request(o);
11720 this.conn.request(o);
11723 callback.call(scope||this, null, arg, false);
11728 loadResponse : function(o, success, response){
11729 delete this.activeRequest;
11731 this.fireEvent("loadexception", this, o, response);
11732 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11737 result = o.reader.read(response);
11739 this.fireEvent("loadexception", this, o, response, e);
11740 o.request.callback.call(o.request.scope, null, o.request.arg, false);
11744 this.fireEvent("load", this, o, o.request.arg);
11745 o.request.callback.call(o.request.scope, result, o.request.arg, true);
11749 update : function(dataSet){
11754 updateResponse : function(dataSet){
11759 * Ext JS Library 1.1.1
11760 * Copyright(c) 2006-2007, Ext JS, LLC.
11762 * Originally Released Under LGPL - original licence link has changed is not relivant.
11765 * <script type="text/javascript">
11769 * @class Roo.data.ScriptTagProxy
11770 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
11771 * other than the originating domain of the running page.<br><br>
11773 * <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
11774 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
11776 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
11777 * source code that is used as the source inside a <script> tag.<br><br>
11779 * In order for the browser to process the returned data, the server must wrap the data object
11780 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
11781 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
11782 * depending on whether the callback name was passed:
11785 boolean scriptTag = false;
11786 String cb = request.getParameter("callback");
11789 response.setContentType("text/javascript");
11791 response.setContentType("application/x-json");
11793 Writer out = response.getWriter();
11795 out.write(cb + "(");
11797 out.print(dataBlock.toJsonString());
11804 * @param {Object} config A configuration object.
11806 Roo.data.ScriptTagProxy = function(config){
11807 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
11808 Roo.apply(this, config);
11809 this.head = document.getElementsByTagName("head")[0];
11812 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
11814 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
11816 * @cfg {String} url The URL from which to request the data object.
11819 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
11823 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
11824 * the server the name of the callback function set up by the load call to process the returned data object.
11825 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
11826 * javascript output which calls this named function passing the data object as its only parameter.
11828 callbackParam : "callback",
11830 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
11831 * name to the request.
11836 * Load data from the configured URL, read the data object into
11837 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11838 * process that block using the passed callback.
11839 * @param {Object} params An object containing properties which are to be used as HTTP parameters
11840 * for the request to the remote server.
11841 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11842 * object into a block of Roo.data.Records.
11843 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
11844 * The function must be passed <ul>
11845 * <li>The Record block object</li>
11846 * <li>The "arg" argument from the load function</li>
11847 * <li>A boolean success indicator</li>
11849 * @param {Object} scope The scope in which to call the callback
11850 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11852 load : function(params, reader, callback, scope, arg){
11853 if(this.fireEvent("beforeload", this, params) !== false){
11855 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
11857 var url = this.url;
11858 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
11860 url += "&_dc=" + (new Date().getTime());
11862 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
11865 cb : "stcCallback"+transId,
11866 scriptId : "stcScript"+transId,
11870 callback : callback,
11876 window[trans.cb] = function(o){
11877 conn.handleResponse(o, trans);
11880 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
11882 if(this.autoAbort !== false){
11886 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
11888 var script = document.createElement("script");
11889 script.setAttribute("src", url);
11890 script.setAttribute("type", "text/javascript");
11891 script.setAttribute("id", trans.scriptId);
11892 this.head.appendChild(script);
11894 this.trans = trans;
11896 callback.call(scope||this, null, arg, false);
11901 isLoading : function(){
11902 return this.trans ? true : false;
11906 * Abort the current server request.
11908 abort : function(){
11909 if(this.isLoading()){
11910 this.destroyTrans(this.trans);
11915 destroyTrans : function(trans, isLoaded){
11916 this.head.removeChild(document.getElementById(trans.scriptId));
11917 clearTimeout(trans.timeoutId);
11919 window[trans.cb] = undefined;
11921 delete window[trans.cb];
11924 // if hasn't been loaded, wait for load to remove it to prevent script error
11925 window[trans.cb] = function(){
11926 window[trans.cb] = undefined;
11928 delete window[trans.cb];
11935 handleResponse : function(o, trans){
11936 this.trans = false;
11937 this.destroyTrans(trans, true);
11940 result = trans.reader.readRecords(o);
11942 this.fireEvent("loadexception", this, o, trans.arg, e);
11943 trans.callback.call(trans.scope||window, null, trans.arg, false);
11946 this.fireEvent("load", this, o, trans.arg);
11947 trans.callback.call(trans.scope||window, result, trans.arg, true);
11951 handleFailure : function(trans){
11952 this.trans = false;
11953 this.destroyTrans(trans, false);
11954 this.fireEvent("loadexception", this, null, trans.arg);
11955 trans.callback.call(trans.scope||window, null, trans.arg, false);
11959 * Ext JS Library 1.1.1
11960 * Copyright(c) 2006-2007, Ext JS, LLC.
11962 * Originally Released Under LGPL - original licence link has changed is not relivant.
11965 * <script type="text/javascript">
11969 * @class Roo.data.JsonReader
11970 * @extends Roo.data.DataReader
11971 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
11972 * based on mappings in a provided Roo.data.Record constructor.
11974 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
11975 * in the reply previously.
11980 var RecordDef = Roo.data.Record.create([
11981 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
11982 {name: 'occupation'} // This field will use "occupation" as the mapping.
11984 var myReader = new Roo.data.JsonReader({
11985 totalProperty: "results", // The property which contains the total dataset size (optional)
11986 root: "rows", // The property which contains an Array of row objects
11987 id: "id" // The property within each row object that provides an ID for the record (optional)
11991 * This would consume a JSON file like this:
11993 { 'results': 2, 'rows': [
11994 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
11995 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
11998 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
11999 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12000 * paged from the remote server.
12001 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12002 * @cfg {String} root name of the property which contains the Array of row objects.
12003 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12004 * @cfg {Array} fields Array of field definition objects
12006 * Create a new JsonReader
12007 * @param {Object} meta Metadata configuration options
12008 * @param {Object} recordType Either an Array of field definition objects,
12009 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12011 Roo.data.JsonReader = function(meta, recordType){
12014 // set some defaults:
12015 Roo.applyIf(meta, {
12016 totalProperty: 'total',
12017 successProperty : 'success',
12022 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12024 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12027 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12028 * Used by Store query builder to append _requestMeta to params.
12031 metaFromRemote : false,
12033 * This method is only used by a DataProxy which has retrieved data from a remote server.
12034 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12035 * @return {Object} data A data block which is used by an Roo.data.Store object as
12036 * a cache of Roo.data.Records.
12038 read : function(response){
12039 var json = response.responseText;
12041 var o = /* eval:var:o */ eval("("+json+")");
12043 throw {message: "JsonReader.read: Json object not found"};
12049 this.metaFromRemote = true;
12050 this.meta = o.metaData;
12051 this.recordType = Roo.data.Record.create(o.metaData.fields);
12052 this.onMetaChange(this.meta, this.recordType, o);
12054 return this.readRecords(o);
12057 // private function a store will implement
12058 onMetaChange : function(meta, recordType, o){
12065 simpleAccess: function(obj, subsc) {
12072 getJsonAccessor: function(){
12074 return function(expr) {
12076 return(re.test(expr))
12077 ? new Function("obj", "return obj." + expr)
12082 return Roo.emptyFn;
12087 * Create a data block containing Roo.data.Records from an XML document.
12088 * @param {Object} o An object which contains an Array of row objects in the property specified
12089 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12090 * which contains the total size of the dataset.
12091 * @return {Object} data A data block which is used by an Roo.data.Store object as
12092 * a cache of Roo.data.Records.
12094 readRecords : function(o){
12096 * After any data loads, the raw JSON data is available for further custom processing.
12100 var s = this.meta, Record = this.recordType,
12101 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12103 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12105 if(s.totalProperty) {
12106 this.getTotal = this.getJsonAccessor(s.totalProperty);
12108 if(s.successProperty) {
12109 this.getSuccess = this.getJsonAccessor(s.successProperty);
12111 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12113 var g = this.getJsonAccessor(s.id);
12114 this.getId = function(rec) {
12116 return (r === undefined || r === "") ? null : r;
12119 this.getId = function(){return null;};
12122 for(var jj = 0; jj < fl; jj++){
12124 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12125 this.ef[jj] = this.getJsonAccessor(map);
12129 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12130 if(s.totalProperty){
12131 var vt = parseInt(this.getTotal(o), 10);
12136 if(s.successProperty){
12137 var vs = this.getSuccess(o);
12138 if(vs === false || vs === 'false'){
12143 for(var i = 0; i < c; i++){
12146 var id = this.getId(n);
12147 for(var j = 0; j < fl; j++){
12149 var v = this.ef[j](n);
12151 Roo.log('missing convert for ' + f.name);
12155 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12157 var record = new Record(values, id);
12159 records[i] = record;
12165 totalRecords : totalRecords
12170 * Ext JS Library 1.1.1
12171 * Copyright(c) 2006-2007, Ext JS, LLC.
12173 * Originally Released Under LGPL - original licence link has changed is not relivant.
12176 * <script type="text/javascript">
12180 * @class Roo.data.ArrayReader
12181 * @extends Roo.data.DataReader
12182 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12183 * Each element of that Array represents a row of data fields. The
12184 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12185 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12189 var RecordDef = Roo.data.Record.create([
12190 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12191 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12193 var myReader = new Roo.data.ArrayReader({
12194 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12198 * This would consume an Array like this:
12200 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12202 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12204 * Create a new JsonReader
12205 * @param {Object} meta Metadata configuration options.
12206 * @param {Object} recordType Either an Array of field definition objects
12207 * as specified to {@link Roo.data.Record#create},
12208 * or an {@link Roo.data.Record} object
12209 * created using {@link Roo.data.Record#create}.
12211 Roo.data.ArrayReader = function(meta, recordType){
12212 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12215 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12217 * Create a data block containing Roo.data.Records from an XML document.
12218 * @param {Object} o An Array of row objects which represents the dataset.
12219 * @return {Object} data A data block which is used by an Roo.data.Store object as
12220 * a cache of Roo.data.Records.
12222 readRecords : function(o){
12223 var sid = this.meta ? this.meta.id : null;
12224 var recordType = this.recordType, fields = recordType.prototype.fields;
12227 for(var i = 0; i < root.length; i++){
12230 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12231 for(var j = 0, jlen = fields.length; j < jlen; j++){
12232 var f = fields.items[j];
12233 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12234 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12236 values[f.name] = v;
12238 var record = new recordType(values, id);
12240 records[records.length] = record;
12244 totalRecords : records.length
12253 * @class Roo.bootstrap.ComboBox
12254 * @extends Roo.bootstrap.TriggerField
12255 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12256 * @cfg {Boolean} append (true|false) default false
12257 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12258 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12259 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12260 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12261 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12262 * @cfg {Boolean} animate default true
12263 * @cfg {Boolean} emptyResultText only for touch device
12264 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12266 * Create a new ComboBox.
12267 * @param {Object} config Configuration options
12269 Roo.bootstrap.ComboBox = function(config){
12270 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12274 * Fires when the dropdown list is expanded
12275 * @param {Roo.bootstrap.ComboBox} combo This combo box
12280 * Fires when the dropdown list is collapsed
12281 * @param {Roo.bootstrap.ComboBox} combo This combo box
12285 * @event beforeselect
12286 * Fires before a list item is selected. Return false to cancel the selection.
12287 * @param {Roo.bootstrap.ComboBox} combo This combo box
12288 * @param {Roo.data.Record} record The data record returned from the underlying store
12289 * @param {Number} index The index of the selected item in the dropdown list
12291 'beforeselect' : true,
12294 * Fires when a list item is selected
12295 * @param {Roo.bootstrap.ComboBox} combo This combo box
12296 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12297 * @param {Number} index The index of the selected item in the dropdown list
12301 * @event beforequery
12302 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12303 * The event object passed has these properties:
12304 * @param {Roo.bootstrap.ComboBox} combo This combo box
12305 * @param {String} query The query
12306 * @param {Boolean} forceAll true to force "all" query
12307 * @param {Boolean} cancel true to cancel the query
12308 * @param {Object} e The query event object
12310 'beforequery': true,
12313 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12314 * @param {Roo.bootstrap.ComboBox} combo This combo box
12319 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12320 * @param {Roo.bootstrap.ComboBox} combo This combo box
12321 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12326 * Fires when the remove value from the combobox array
12327 * @param {Roo.bootstrap.ComboBox} combo This combo box
12331 * @event afterremove
12332 * Fires when the remove value from the combobox array
12333 * @param {Roo.bootstrap.ComboBox} combo This combo box
12335 'afterremove' : true,
12337 * @event specialfilter
12338 * Fires when specialfilter
12339 * @param {Roo.bootstrap.ComboBox} combo This combo box
12341 'specialfilter' : true,
12344 * Fires when tick the element
12345 * @param {Roo.bootstrap.ComboBox} combo This combo box
12349 * @event touchviewdisplay
12350 * Fires when touch view require special display (default is using displayField)
12351 * @param {Roo.bootstrap.ComboBox} combo This combo box
12352 * @param {Object} cfg set html .
12354 'touchviewdisplay' : true
12359 this.tickItems = [];
12361 this.selectedIndex = -1;
12362 if(this.mode == 'local'){
12363 if(config.queryDelay === undefined){
12364 this.queryDelay = 10;
12366 if(config.minChars === undefined){
12372 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12375 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12376 * rendering into an Roo.Editor, defaults to false)
12379 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12380 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12383 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12386 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12387 * the dropdown list (defaults to undefined, with no header element)
12391 * @cfg {String/Roo.Template} tpl The template to use to render the output
12395 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12397 listWidth: undefined,
12399 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12400 * mode = 'remote' or 'text' if mode = 'local')
12402 displayField: undefined,
12405 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12406 * mode = 'remote' or 'value' if mode = 'local').
12407 * Note: use of a valueField requires the user make a selection
12408 * in order for a value to be mapped.
12410 valueField: undefined,
12412 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12417 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12418 * field's data value (defaults to the underlying DOM element's name)
12420 hiddenName: undefined,
12422 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12426 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12428 selectedClass: 'active',
12431 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12435 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12436 * anchor positions (defaults to 'tl-bl')
12438 listAlign: 'tl-bl?',
12440 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12444 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12445 * query specified by the allQuery config option (defaults to 'query')
12447 triggerAction: 'query',
12449 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12450 * (defaults to 4, does not apply if editable = false)
12454 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12455 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12459 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12460 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12464 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12465 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12469 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12470 * when editable = true (defaults to false)
12472 selectOnFocus:false,
12474 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12476 queryParam: 'query',
12478 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12479 * when mode = 'remote' (defaults to 'Loading...')
12481 loadingText: 'Loading...',
12483 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12487 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12491 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12492 * traditional select (defaults to true)
12496 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12500 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12504 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12505 * listWidth has a higher value)
12509 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12510 * allow the user to set arbitrary text into the field (defaults to false)
12512 forceSelection:false,
12514 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12515 * if typeAhead = true (defaults to 250)
12517 typeAheadDelay : 250,
12519 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12520 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12522 valueNotFoundText : undefined,
12524 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12526 blockFocus : false,
12529 * @cfg {Boolean} disableClear Disable showing of clear button.
12531 disableClear : false,
12533 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12535 alwaysQuery : false,
12538 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12543 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12545 invalidClass : "has-warning",
12548 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12550 validClass : "has-success",
12553 * @cfg {Boolean} specialFilter (true|false) special filter default false
12555 specialFilter : false,
12558 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12560 mobileTouchView : true,
12563 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12565 useNativeIOS : false,
12567 ios_options : false,
12579 btnPosition : 'right',
12580 triggerList : true,
12581 showToggleBtn : true,
12583 emptyResultText: 'Empty',
12584 triggerText : 'Select',
12586 // element that contains real text value.. (when hidden is used..)
12588 getAutoCreate : function()
12593 * Render classic select for iso
12596 if(Roo.isIOS && this.useNativeIOS){
12597 cfg = this.getAutoCreateNativeIOS();
12605 if(Roo.isTouch && this.mobileTouchView){
12606 cfg = this.getAutoCreateTouchView();
12613 if(!this.tickable){
12614 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12615 if(this.name == 'info_year_invest_id_display_name'){
12616 Roo.log('cfg.................................................');
12623 * ComboBox with tickable selections
12626 var align = this.labelAlign || this.parentLabelAlign();
12629 cls : 'form-group roo-combobox-tickable' //input-group
12632 var btn_text_select = '';
12633 var btn_text_done = '';
12634 var btn_text_cancel = '';
12636 if (this.btn_text_show) {
12637 btn_text_select = 'Select';
12638 btn_text_done = 'Done';
12639 btn_text_cancel = 'Cancel';
12644 cls : 'tickable-buttons',
12649 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12650 //html : this.triggerText
12651 html: btn_text_select
12657 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12659 html: btn_text_done
12665 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12667 html: btn_text_cancel
12673 buttons.cn.unshift({
12675 cls: 'roo-select2-search-field-input'
12681 Roo.each(buttons.cn, function(c){
12683 c.cls += ' btn-' + _this.size;
12686 if (_this.disabled) {
12697 cls: 'form-hidden-field'
12701 cls: 'roo-select2-choices',
12705 cls: 'roo-select2-search-field',
12716 cls: 'roo-select2-container input-group roo-select2-container-multi',
12721 // cls: 'typeahead typeahead-long dropdown-menu',
12722 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
12727 if(this.hasFeedback && !this.allowBlank){
12731 cls: 'glyphicon form-control-feedback'
12734 combobox.cn.push(feedback);
12738 if (align ==='left' && this.fieldLabel.length) {
12740 cfg.cls += ' roo-form-group-label-left';
12745 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12746 tooltip : 'This field is required'
12751 cls : 'control-label',
12752 html : this.fieldLabel
12764 var labelCfg = cfg.cn[1];
12765 var contentCfg = cfg.cn[2];
12768 if(this.indicatorpos == 'right'){
12774 cls : 'control-label',
12775 html : this.fieldLabel,
12779 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12780 tooltip : 'This field is required'
12794 labelCfg = cfg.cn[0];
12795 contentCfg = cfg.cn[2];
12799 if(this.labelWidth > 12){
12800 labelCfg.style = "width: " + this.labelWidth + 'px';
12803 if(this.labelWidth < 13 && this.labelmd == 0){
12804 this.labelmd = this.labelWidth;
12807 if(this.labellg > 0){
12808 labelCfg.cls += ' col-lg-' + this.labellg;
12809 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12812 if(this.labelmd > 0){
12813 labelCfg.cls += ' col-md-' + this.labelmd;
12814 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12817 if(this.labelsm > 0){
12818 labelCfg.cls += ' col-sm-' + this.labelsm;
12819 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12822 if(this.labelxs > 0){
12823 labelCfg.cls += ' col-xs-' + this.labelxs;
12824 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12828 } else if ( this.fieldLabel.length) {
12829 // Roo.log(" label");
12833 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
12834 tooltip : 'This field is required'
12838 //cls : 'input-group-addon',
12839 html : this.fieldLabel
12847 if(this.indicatorpos == 'right'){
12852 //cls : 'input-group-addon',
12853 html : this.fieldLabel,
12857 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
12858 tooltip : 'This field is required'
12873 // Roo.log(" no label && no align");
12880 ['xs','sm','md','lg'].map(function(size){
12881 if (settings[size]) {
12882 cfg.cls += ' col-' + size + '-' + settings[size];
12890 _initEventsCalled : false,
12893 initEvents: function()
12895 if (this._initEventsCalled) { // as we call render... prevent looping...
12898 this._initEventsCalled = true;
12901 throw "can not find store for combo";
12904 this.store = Roo.factory(this.store, Roo.data);
12906 // if we are building from html. then this element is so complex, that we can not really
12907 // use the rendered HTML.
12908 // so we have to trash and replace the previous code.
12909 if (Roo.XComponent.build_from_html) {
12911 // remove this element....
12912 var e = this.el.dom, k=0;
12913 while (e ) { e = e.previousSibling; ++k;}
12918 this.rendered = false;
12920 this.render(this.parent().getChildContainer(true), k);
12926 if(Roo.isIOS && this.useNativeIOS){
12927 this.initIOSView();
12935 if(Roo.isTouch && this.mobileTouchView){
12936 this.initTouchView();
12941 this.initTickableEvents();
12945 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
12947 if(this.hiddenName){
12949 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
12951 this.hiddenField.dom.value =
12952 this.hiddenValue !== undefined ? this.hiddenValue :
12953 this.value !== undefined ? this.value : '';
12955 // prevent input submission
12956 this.el.dom.removeAttribute('name');
12957 this.hiddenField.dom.setAttribute('name', this.hiddenName);
12962 // this.el.dom.setAttribute('autocomplete', 'off');
12965 var cls = 'x-combo-list';
12967 //this.list = new Roo.Layer({
12968 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
12974 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
12975 _this.list.setWidth(lw);
12978 this.list.on('mouseover', this.onViewOver, this);
12979 this.list.on('mousemove', this.onViewMove, this);
12981 this.list.on('scroll', this.onViewScroll, this);
12984 this.list.swallowEvent('mousewheel');
12985 this.assetHeight = 0;
12988 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
12989 this.assetHeight += this.header.getHeight();
12992 this.innerList = this.list.createChild({cls:cls+'-inner'});
12993 this.innerList.on('mouseover', this.onViewOver, this);
12994 this.innerList.on('mousemove', this.onViewMove, this);
12995 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
12997 if(this.allowBlank && !this.pageSize && !this.disableClear){
12998 this.footer = this.list.createChild({cls:cls+'-ft'});
12999 this.pageTb = new Roo.Toolbar(this.footer);
13003 this.footer = this.list.createChild({cls:cls+'-ft'});
13004 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13005 {pageSize: this.pageSize});
13009 if (this.pageTb && this.allowBlank && !this.disableClear) {
13011 this.pageTb.add(new Roo.Toolbar.Fill(), {
13012 cls: 'x-btn-icon x-btn-clear',
13014 handler: function()
13017 _this.clearValue();
13018 _this.onSelect(false, -1);
13023 this.assetHeight += this.footer.getHeight();
13028 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13031 this.view = new Roo.View(this.list, this.tpl, {
13032 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13034 //this.view.wrapEl.setDisplayed(false);
13035 this.view.on('click', this.onViewClick, this);
13039 this.store.on('beforeload', this.onBeforeLoad, this);
13040 this.store.on('load', this.onLoad, this);
13041 this.store.on('loadexception', this.onLoadException, this);
13043 if(this.resizable){
13044 this.resizer = new Roo.Resizable(this.list, {
13045 pinned:true, handles:'se'
13047 this.resizer.on('resize', function(r, w, h){
13048 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13049 this.listWidth = w;
13050 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13051 this.restrictHeight();
13053 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13056 if(!this.editable){
13057 this.editable = true;
13058 this.setEditable(false);
13063 if (typeof(this.events.add.listeners) != 'undefined') {
13065 this.addicon = this.wrap.createChild(
13066 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13068 this.addicon.on('click', function(e) {
13069 this.fireEvent('add', this);
13072 if (typeof(this.events.edit.listeners) != 'undefined') {
13074 this.editicon = this.wrap.createChild(
13075 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13076 if (this.addicon) {
13077 this.editicon.setStyle('margin-left', '40px');
13079 this.editicon.on('click', function(e) {
13081 // we fire even if inothing is selected..
13082 this.fireEvent('edit', this, this.lastData );
13088 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13089 "up" : function(e){
13090 this.inKeyMode = true;
13094 "down" : function(e){
13095 if(!this.isExpanded()){
13096 this.onTriggerClick();
13098 this.inKeyMode = true;
13103 "enter" : function(e){
13104 // this.onViewClick();
13108 if(this.fireEvent("specialkey", this, e)){
13109 this.onViewClick(false);
13115 "esc" : function(e){
13119 "tab" : function(e){
13122 if(this.fireEvent("specialkey", this, e)){
13123 this.onViewClick(false);
13131 doRelay : function(foo, bar, hname){
13132 if(hname == 'down' || this.scope.isExpanded()){
13133 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13142 this.queryDelay = Math.max(this.queryDelay || 10,
13143 this.mode == 'local' ? 10 : 250);
13146 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13148 if(this.typeAhead){
13149 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13151 if(this.editable !== false){
13152 this.inputEl().on("keyup", this.onKeyUp, this);
13154 if(this.forceSelection){
13155 this.inputEl().on('blur', this.doForce, this);
13159 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13160 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13164 initTickableEvents: function()
13168 if(this.hiddenName){
13170 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13172 this.hiddenField.dom.value =
13173 this.hiddenValue !== undefined ? this.hiddenValue :
13174 this.value !== undefined ? this.value : '';
13176 // prevent input submission
13177 this.el.dom.removeAttribute('name');
13178 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13183 // this.list = this.el.select('ul.dropdown-menu',true).first();
13185 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13186 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13187 if(this.triggerList){
13188 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13191 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13192 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13194 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13195 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13197 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13198 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13200 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13201 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13202 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13205 this.cancelBtn.hide();
13210 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13211 _this.list.setWidth(lw);
13214 this.list.on('mouseover', this.onViewOver, this);
13215 this.list.on('mousemove', this.onViewMove, this);
13217 this.list.on('scroll', this.onViewScroll, this);
13220 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>';
13223 this.view = new Roo.View(this.list, this.tpl, {
13224 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13227 //this.view.wrapEl.setDisplayed(false);
13228 this.view.on('click', this.onViewClick, this);
13232 this.store.on('beforeload', this.onBeforeLoad, this);
13233 this.store.on('load', this.onLoad, this);
13234 this.store.on('loadexception', this.onLoadException, this);
13237 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13238 "up" : function(e){
13239 this.inKeyMode = true;
13243 "down" : function(e){
13244 this.inKeyMode = true;
13248 "enter" : function(e){
13249 if(this.fireEvent("specialkey", this, e)){
13250 this.onViewClick(false);
13256 "esc" : function(e){
13257 this.onTickableFooterButtonClick(e, false, false);
13260 "tab" : function(e){
13261 this.fireEvent("specialkey", this, e);
13263 this.onTickableFooterButtonClick(e, false, false);
13270 doRelay : function(e, fn, key){
13271 if(this.scope.isExpanded()){
13272 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13281 this.queryDelay = Math.max(this.queryDelay || 10,
13282 this.mode == 'local' ? 10 : 250);
13285 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13287 if(this.typeAhead){
13288 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13291 if(this.editable !== false){
13292 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13295 this.indicator = this.indicatorEl();
13297 if(this.indicator){
13298 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13299 this.indicator.hide();
13304 onDestroy : function(){
13306 this.view.setStore(null);
13307 this.view.el.removeAllListeners();
13308 this.view.el.remove();
13309 this.view.purgeListeners();
13312 this.list.dom.innerHTML = '';
13316 this.store.un('beforeload', this.onBeforeLoad, this);
13317 this.store.un('load', this.onLoad, this);
13318 this.store.un('loadexception', this.onLoadException, this);
13320 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13324 fireKey : function(e){
13325 if(e.isNavKeyPress() && !this.list.isVisible()){
13326 this.fireEvent("specialkey", this, e);
13331 onResize: function(w, h){
13332 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13334 // if(typeof w != 'number'){
13335 // // we do not handle it!?!?
13338 // var tw = this.trigger.getWidth();
13339 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13340 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13342 // this.inputEl().setWidth( this.adjustWidth('input', x));
13344 // //this.trigger.setStyle('left', x+'px');
13346 // if(this.list && this.listWidth === undefined){
13347 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13348 // this.list.setWidth(lw);
13349 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13357 * Allow or prevent the user from directly editing the field text. If false is passed,
13358 * the user will only be able to select from the items defined in the dropdown list. This method
13359 * is the runtime equivalent of setting the 'editable' config option at config time.
13360 * @param {Boolean} value True to allow the user to directly edit the field text
13362 setEditable : function(value){
13363 if(value == this.editable){
13366 this.editable = value;
13368 this.inputEl().dom.setAttribute('readOnly', true);
13369 this.inputEl().on('mousedown', this.onTriggerClick, this);
13370 this.inputEl().addClass('x-combo-noedit');
13372 this.inputEl().dom.setAttribute('readOnly', false);
13373 this.inputEl().un('mousedown', this.onTriggerClick, this);
13374 this.inputEl().removeClass('x-combo-noedit');
13380 onBeforeLoad : function(combo,opts){
13381 if(!this.hasFocus){
13385 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13387 this.restrictHeight();
13388 this.selectedIndex = -1;
13392 onLoad : function(){
13394 this.hasQuery = false;
13396 if(!this.hasFocus){
13400 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13401 this.loading.hide();
13404 if(this.store.getCount() > 0){
13406 this.restrictHeight();
13407 if(this.lastQuery == this.allQuery){
13408 if(this.editable && !this.tickable){
13409 this.inputEl().dom.select();
13413 !this.selectByValue(this.value, true) &&
13416 !this.store.lastOptions ||
13417 typeof(this.store.lastOptions.add) == 'undefined' ||
13418 this.store.lastOptions.add != true
13421 this.select(0, true);
13424 if(this.autoFocus){
13427 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13428 this.taTask.delay(this.typeAheadDelay);
13432 this.onEmptyResults();
13438 onLoadException : function()
13440 this.hasQuery = false;
13442 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13443 this.loading.hide();
13446 if(this.tickable && this.editable){
13451 // only causes errors at present
13452 //Roo.log(this.store.reader.jsonData);
13453 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13455 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13461 onTypeAhead : function(){
13462 if(this.store.getCount() > 0){
13463 var r = this.store.getAt(0);
13464 var newValue = r.data[this.displayField];
13465 var len = newValue.length;
13466 var selStart = this.getRawValue().length;
13468 if(selStart != len){
13469 this.setRawValue(newValue);
13470 this.selectText(selStart, newValue.length);
13476 onSelect : function(record, index){
13478 if(this.fireEvent('beforeselect', this, record, index) !== false){
13480 this.setFromData(index > -1 ? record.data : false);
13483 this.fireEvent('select', this, record, index);
13488 * Returns the currently selected field value or empty string if no value is set.
13489 * @return {String} value The selected value
13491 getValue : function()
13493 if(Roo.isIOS && this.useNativeIOS){
13494 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13498 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13501 if(this.valueField){
13502 return typeof this.value != 'undefined' ? this.value : '';
13504 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13508 getRawValue : function()
13510 if(Roo.isIOS && this.useNativeIOS){
13511 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13514 var v = this.inputEl().getValue();
13520 * Clears any text/value currently set in the field
13522 clearValue : function(){
13524 if(this.hiddenField){
13525 this.hiddenField.dom.value = '';
13528 this.setRawValue('');
13529 this.lastSelectionText = '';
13530 this.lastData = false;
13532 var close = this.closeTriggerEl();
13543 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13544 * will be displayed in the field. If the value does not match the data value of an existing item,
13545 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13546 * Otherwise the field will be blank (although the value will still be set).
13547 * @param {String} value The value to match
13549 setValue : function(v)
13551 if(Roo.isIOS && this.useNativeIOS){
13552 this.setIOSValue(v);
13562 if(this.valueField){
13563 var r = this.findRecord(this.valueField, v);
13565 text = r.data[this.displayField];
13566 }else if(this.valueNotFoundText !== undefined){
13567 text = this.valueNotFoundText;
13570 this.lastSelectionText = text;
13571 if(this.hiddenField){
13572 this.hiddenField.dom.value = v;
13574 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13577 var close = this.closeTriggerEl();
13580 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13586 * @property {Object} the last set data for the element
13591 * Sets the value of the field based on a object which is related to the record format for the store.
13592 * @param {Object} value the value to set as. or false on reset?
13594 setFromData : function(o){
13601 var dv = ''; // display value
13602 var vv = ''; // value value..
13604 if (this.displayField) {
13605 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13607 // this is an error condition!!!
13608 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13611 if(this.valueField){
13612 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13615 var close = this.closeTriggerEl();
13618 (vv.length || vv * 1 > 0) ? close.show() : close.hide();
13621 if(this.hiddenField){
13622 this.hiddenField.dom.value = vv;
13624 this.lastSelectionText = dv;
13625 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13629 // no hidden field.. - we store the value in 'value', but still display
13630 // display field!!!!
13631 this.lastSelectionText = dv;
13632 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13639 reset : function(){
13640 // overridden so that last data is reset..
13647 this.setValue(this.originalValue);
13648 //this.clearInvalid();
13649 this.lastData = false;
13651 this.view.clearSelections();
13657 findRecord : function(prop, value){
13659 if(this.store.getCount() > 0){
13660 this.store.each(function(r){
13661 if(r.data[prop] == value){
13671 getName: function()
13673 // returns hidden if it's set..
13674 if (!this.rendered) {return ''};
13675 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
13679 onViewMove : function(e, t){
13680 this.inKeyMode = false;
13684 onViewOver : function(e, t){
13685 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
13688 var item = this.view.findItemFromChild(t);
13691 var index = this.view.indexOf(item);
13692 this.select(index, false);
13697 onViewClick : function(view, doFocus, el, e)
13699 var index = this.view.getSelectedIndexes()[0];
13701 var r = this.store.getAt(index);
13705 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
13712 Roo.each(this.tickItems, function(v,k){
13714 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
13716 _this.tickItems.splice(k, 1);
13718 if(typeof(e) == 'undefined' && view == false){
13719 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
13731 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
13732 this.tickItems.push(r.data);
13735 if(typeof(e) == 'undefined' && view == false){
13736 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
13743 this.onSelect(r, index);
13745 if(doFocus !== false && !this.blockFocus){
13746 this.inputEl().focus();
13751 restrictHeight : function(){
13752 //this.innerList.dom.style.height = '';
13753 //var inner = this.innerList.dom;
13754 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
13755 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
13756 //this.list.beginUpdate();
13757 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
13758 this.list.alignTo(this.inputEl(), this.listAlign);
13759 this.list.alignTo(this.inputEl(), this.listAlign);
13760 //this.list.endUpdate();
13764 onEmptyResults : function(){
13766 if(this.tickable && this.editable){
13767 this.restrictHeight();
13775 * Returns true if the dropdown list is expanded, else false.
13777 isExpanded : function(){
13778 return this.list.isVisible();
13782 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
13783 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13784 * @param {String} value The data value of the item to select
13785 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13786 * selected item if it is not currently in view (defaults to true)
13787 * @return {Boolean} True if the value matched an item in the list, else false
13789 selectByValue : function(v, scrollIntoView){
13790 if(v !== undefined && v !== null){
13791 var r = this.findRecord(this.valueField || this.displayField, v);
13793 this.select(this.store.indexOf(r), scrollIntoView);
13801 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
13802 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
13803 * @param {Number} index The zero-based index of the list item to select
13804 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
13805 * selected item if it is not currently in view (defaults to true)
13807 select : function(index, scrollIntoView){
13808 this.selectedIndex = index;
13809 this.view.select(index);
13810 if(scrollIntoView !== false){
13811 var el = this.view.getNode(index);
13813 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
13816 this.list.scrollChildIntoView(el, false);
13822 selectNext : function(){
13823 var ct = this.store.getCount();
13825 if(this.selectedIndex == -1){
13827 }else if(this.selectedIndex < ct-1){
13828 this.select(this.selectedIndex+1);
13834 selectPrev : function(){
13835 var ct = this.store.getCount();
13837 if(this.selectedIndex == -1){
13839 }else if(this.selectedIndex != 0){
13840 this.select(this.selectedIndex-1);
13846 onKeyUp : function(e){
13847 if(this.editable !== false && !e.isSpecialKey()){
13848 this.lastKey = e.getKey();
13849 this.dqTask.delay(this.queryDelay);
13854 validateBlur : function(){
13855 return !this.list || !this.list.isVisible();
13859 initQuery : function(){
13861 var v = this.getRawValue();
13863 if(this.tickable && this.editable){
13864 v = this.tickableInputEl().getValue();
13871 doForce : function(){
13872 if(this.inputEl().dom.value.length > 0){
13873 this.inputEl().dom.value =
13874 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
13880 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
13881 * query allowing the query action to be canceled if needed.
13882 * @param {String} query The SQL query to execute
13883 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
13884 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
13885 * saved in the current store (defaults to false)
13887 doQuery : function(q, forceAll){
13889 if(q === undefined || q === null){
13894 forceAll: forceAll,
13898 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
13903 forceAll = qe.forceAll;
13904 if(forceAll === true || (q.length >= this.minChars)){
13906 this.hasQuery = true;
13908 if(this.lastQuery != q || this.alwaysQuery){
13909 this.lastQuery = q;
13910 if(this.mode == 'local'){
13911 this.selectedIndex = -1;
13913 this.store.clearFilter();
13916 if(this.specialFilter){
13917 this.fireEvent('specialfilter', this);
13922 this.store.filter(this.displayField, q);
13925 this.store.fireEvent("datachanged", this.store);
13932 this.store.baseParams[this.queryParam] = q;
13934 var options = {params : this.getParams(q)};
13937 options.add = true;
13938 options.params.start = this.page * this.pageSize;
13941 this.store.load(options);
13944 * this code will make the page width larger, at the beginning, the list not align correctly,
13945 * we should expand the list on onLoad
13946 * so command out it
13951 this.selectedIndex = -1;
13956 this.loadNext = false;
13960 getParams : function(q){
13962 //p[this.queryParam] = q;
13966 p.limit = this.pageSize;
13972 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
13974 collapse : function(){
13975 if(!this.isExpanded()){
13981 this.hasFocus = false;
13985 this.cancelBtn.hide();
13986 this.trigger.show();
13989 this.tickableInputEl().dom.value = '';
13990 this.tickableInputEl().blur();
13995 Roo.get(document).un('mousedown', this.collapseIf, this);
13996 Roo.get(document).un('mousewheel', this.collapseIf, this);
13997 if (!this.editable) {
13998 Roo.get(document).un('keydown', this.listKeyPress, this);
14000 this.fireEvent('collapse', this);
14006 collapseIf : function(e){
14007 var in_combo = e.within(this.el);
14008 var in_list = e.within(this.list);
14009 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14011 if (in_combo || in_list || is_list) {
14012 //e.stopPropagation();
14017 this.onTickableFooterButtonClick(e, false, false);
14025 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14027 expand : function(){
14029 if(this.isExpanded() || !this.hasFocus){
14033 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14034 this.list.setWidth(lw);
14040 this.restrictHeight();
14044 this.tickItems = Roo.apply([], this.item);
14047 this.cancelBtn.show();
14048 this.trigger.hide();
14051 this.tickableInputEl().focus();
14056 Roo.get(document).on('mousedown', this.collapseIf, this);
14057 Roo.get(document).on('mousewheel', this.collapseIf, this);
14058 if (!this.editable) {
14059 Roo.get(document).on('keydown', this.listKeyPress, this);
14062 this.fireEvent('expand', this);
14066 // Implements the default empty TriggerField.onTriggerClick function
14067 onTriggerClick : function(e)
14069 Roo.log('trigger click');
14071 if(this.disabled || !this.triggerList){
14076 this.loadNext = false;
14078 if(this.isExpanded()){
14080 if (!this.blockFocus) {
14081 this.inputEl().focus();
14085 this.hasFocus = true;
14086 if(this.triggerAction == 'all') {
14087 this.doQuery(this.allQuery, true);
14089 this.doQuery(this.getRawValue());
14091 if (!this.blockFocus) {
14092 this.inputEl().focus();
14097 onTickableTriggerClick : function(e)
14104 this.loadNext = false;
14105 this.hasFocus = true;
14107 if(this.triggerAction == 'all') {
14108 this.doQuery(this.allQuery, true);
14110 this.doQuery(this.getRawValue());
14114 onSearchFieldClick : function(e)
14116 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14117 this.onTickableFooterButtonClick(e, false, false);
14121 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14126 this.loadNext = false;
14127 this.hasFocus = true;
14129 if(this.triggerAction == 'all') {
14130 this.doQuery(this.allQuery, true);
14132 this.doQuery(this.getRawValue());
14136 listKeyPress : function(e)
14138 //Roo.log('listkeypress');
14139 // scroll to first matching element based on key pres..
14140 if (e.isSpecialKey()) {
14143 var k = String.fromCharCode(e.getKey()).toUpperCase();
14146 var csel = this.view.getSelectedNodes();
14147 var cselitem = false;
14149 var ix = this.view.indexOf(csel[0]);
14150 cselitem = this.store.getAt(ix);
14151 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14157 this.store.each(function(v) {
14159 // start at existing selection.
14160 if (cselitem.id == v.id) {
14166 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14167 match = this.store.indexOf(v);
14173 if (match === false) {
14174 return true; // no more action?
14177 this.view.select(match);
14178 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14179 sn.scrollIntoView(sn.dom.parentNode, false);
14182 onViewScroll : function(e, t){
14184 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){
14188 this.hasQuery = true;
14190 this.loading = this.list.select('.loading', true).first();
14192 if(this.loading === null){
14193 this.list.createChild({
14195 cls: 'loading roo-select2-more-results roo-select2-active',
14196 html: 'Loading more results...'
14199 this.loading = this.list.select('.loading', true).first();
14201 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14203 this.loading.hide();
14206 this.loading.show();
14211 this.loadNext = true;
14213 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14218 addItem : function(o)
14220 var dv = ''; // display value
14222 if (this.displayField) {
14223 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14225 // this is an error condition!!!
14226 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14233 var choice = this.choices.createChild({
14235 cls: 'roo-select2-search-choice',
14244 cls: 'roo-select2-search-choice-close',
14249 }, this.searchField);
14251 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14253 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14261 this.inputEl().dom.value = '';
14266 onRemoveItem : function(e, _self, o)
14268 e.preventDefault();
14270 this.lastItem = Roo.apply([], this.item);
14272 var index = this.item.indexOf(o.data) * 1;
14275 Roo.log('not this item?!');
14279 this.item.splice(index, 1);
14284 this.fireEvent('remove', this, e);
14290 syncValue : function()
14292 if(!this.item.length){
14299 Roo.each(this.item, function(i){
14300 if(_this.valueField){
14301 value.push(i[_this.valueField]);
14308 this.value = value.join(',');
14310 if(this.hiddenField){
14311 this.hiddenField.dom.value = this.value;
14314 this.store.fireEvent("datachanged", this.store);
14319 clearItem : function()
14321 if(!this.multiple){
14327 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14335 if(this.tickable && !Roo.isTouch){
14336 this.view.refresh();
14340 inputEl: function ()
14342 if(Roo.isIOS && this.useNativeIOS){
14343 return this.el.select('select.roo-ios-select', true).first();
14346 if(Roo.isTouch && this.mobileTouchView){
14347 return this.el.select('input.form-control',true).first();
14351 return this.searchField;
14354 return this.el.select('input.form-control',true).first();
14357 onTickableFooterButtonClick : function(e, btn, el)
14359 e.preventDefault();
14361 this.lastItem = Roo.apply([], this.item);
14363 if(btn && btn.name == 'cancel'){
14364 this.tickItems = Roo.apply([], this.item);
14373 Roo.each(this.tickItems, function(o){
14381 validate : function()
14383 var v = this.getRawValue();
14386 v = this.getValue();
14389 if(this.disabled || this.allowBlank || v.length){
14394 this.markInvalid();
14398 tickableInputEl : function()
14400 if(!this.tickable || !this.editable){
14401 return this.inputEl();
14404 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14408 getAutoCreateTouchView : function()
14413 cls: 'form-group' //input-group
14419 type : this.inputType,
14420 cls : 'form-control x-combo-noedit',
14421 autocomplete: 'new-password',
14422 placeholder : this.placeholder || '',
14427 input.name = this.name;
14431 input.cls += ' input-' + this.size;
14434 if (this.disabled) {
14435 input.disabled = true;
14446 inputblock.cls += ' input-group';
14448 inputblock.cn.unshift({
14450 cls : 'input-group-addon',
14455 if(this.removable && !this.multiple){
14456 inputblock.cls += ' roo-removable';
14458 inputblock.cn.push({
14461 cls : 'roo-combo-removable-btn close'
14465 if(this.hasFeedback && !this.allowBlank){
14467 inputblock.cls += ' has-feedback';
14469 inputblock.cn.push({
14471 cls: 'glyphicon form-control-feedback'
14478 inputblock.cls += (this.before) ? '' : ' input-group';
14480 inputblock.cn.push({
14482 cls : 'input-group-addon',
14493 cls: 'form-hidden-field'
14507 cls: 'form-hidden-field'
14511 cls: 'roo-select2-choices',
14515 cls: 'roo-select2-search-field',
14528 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14534 if(!this.multiple && this.showToggleBtn){
14541 if (this.caret != false) {
14544 cls: 'fa fa-' + this.caret
14551 cls : 'input-group-addon btn dropdown-toggle',
14556 cls: 'combobox-clear',
14570 combobox.cls += ' roo-select2-container-multi';
14573 var align = this.labelAlign || this.parentLabelAlign();
14575 if (align ==='left' && this.fieldLabel.length) {
14580 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14581 tooltip : 'This field is required'
14585 cls : 'control-label',
14586 html : this.fieldLabel
14597 var labelCfg = cfg.cn[1];
14598 var contentCfg = cfg.cn[2];
14601 if(this.indicatorpos == 'right'){
14605 cls : 'control-label',
14606 html : this.fieldLabel,
14610 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14611 tooltip : 'This field is required'
14624 labelCfg = cfg.cn[0];
14625 contentCfg = cfg.cn[2];
14627 if(this.labelWidth > 12){
14628 labelCfg.style = "width: " + this.labelWidth + 'px';
14631 if(this.labelWidth < 13 && this.labelmd == 0){
14632 this.labelmd = this.labelWidth;
14635 if(this.labellg > 0){
14636 labelCfg.cls += ' col-lg-' + this.labellg;
14637 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14640 if(this.labelmd > 0){
14641 labelCfg.cls += ' col-md-' + this.labelmd;
14642 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14645 if(this.labelsm > 0){
14646 labelCfg.cls += ' col-sm-' + this.labelsm;
14647 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14650 if(this.labelxs > 0){
14651 labelCfg.cls += ' col-xs-' + this.labelxs;
14652 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14656 } else if ( this.fieldLabel.length) {
14660 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14661 tooltip : 'This field is required'
14665 cls : 'control-label',
14666 html : this.fieldLabel
14677 if(this.indicatorpos == 'right'){
14681 cls : 'control-label',
14682 html : this.fieldLabel,
14686 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14687 tooltip : 'This field is required'
14704 var settings = this;
14706 ['xs','sm','md','lg'].map(function(size){
14707 if (settings[size]) {
14708 cfg.cls += ' col-' + size + '-' + settings[size];
14715 initTouchView : function()
14717 this.renderTouchView();
14719 this.touchViewEl.on('scroll', function(){
14720 this.el.dom.scrollTop = 0;
14723 this.originalValue = this.getValue();
14725 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
14727 this.inputEl().on("click", this.showTouchView, this);
14728 if (this.triggerEl) {
14729 this.triggerEl.on("click", this.showTouchView, this);
14733 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
14734 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
14736 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
14738 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
14739 this.store.on('load', this.onTouchViewLoad, this);
14740 this.store.on('loadexception', this.onTouchViewLoadException, this);
14742 if(this.hiddenName){
14744 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14746 this.hiddenField.dom.value =
14747 this.hiddenValue !== undefined ? this.hiddenValue :
14748 this.value !== undefined ? this.value : '';
14750 this.el.dom.removeAttribute('name');
14751 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14755 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14756 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14759 if(this.removable && !this.multiple){
14760 var close = this.closeTriggerEl();
14762 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
14763 close.on('click', this.removeBtnClick, this, close);
14767 * fix the bug in Safari iOS8
14769 this.inputEl().on("focus", function(e){
14770 document.activeElement.blur();
14778 renderTouchView : function()
14780 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
14781 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14783 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
14784 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14786 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
14787 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14788 this.touchViewBodyEl.setStyle('overflow', 'auto');
14790 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
14791 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14793 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
14794 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14798 showTouchView : function()
14804 this.touchViewHeaderEl.hide();
14806 if(this.modalTitle.length){
14807 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
14808 this.touchViewHeaderEl.show();
14811 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
14812 this.touchViewEl.show();
14814 this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
14815 this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
14816 Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14818 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14820 if(this.modalTitle.length){
14821 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14824 this.touchViewBodyEl.setHeight(bodyHeight);
14828 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
14830 this.touchViewEl.addClass('in');
14833 this.doTouchViewQuery();
14837 hideTouchView : function()
14839 this.touchViewEl.removeClass('in');
14843 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
14845 this.touchViewEl.setStyle('display', 'none');
14850 setTouchViewValue : function()
14857 Roo.each(this.tickItems, function(o){
14862 this.hideTouchView();
14865 doTouchViewQuery : function()
14874 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
14878 if(!this.alwaysQuery || this.mode == 'local'){
14879 this.onTouchViewLoad();
14886 onTouchViewBeforeLoad : function(combo,opts)
14892 onTouchViewLoad : function()
14894 if(this.store.getCount() < 1){
14895 this.onTouchViewEmptyResults();
14899 this.clearTouchView();
14901 var rawValue = this.getRawValue();
14903 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
14905 this.tickItems = [];
14907 this.store.data.each(function(d, rowIndex){
14908 var row = this.touchViewListGroup.createChild(template);
14910 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
14911 row.addClass(d.data.cls);
14914 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
14917 html : d.data[this.displayField]
14920 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
14921 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
14924 row.removeClass('selected');
14925 if(!this.multiple && this.valueField &&
14926 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
14929 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14930 row.addClass('selected');
14933 if(this.multiple && this.valueField &&
14934 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
14938 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
14939 this.tickItems.push(d.data);
14942 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
14946 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
14948 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
14950 if(this.modalTitle.length){
14951 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
14954 var listHeight = this.touchViewListGroup.getHeight();
14958 if(firstChecked && listHeight > bodyHeight){
14959 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
14964 onTouchViewLoadException : function()
14966 this.hideTouchView();
14969 onTouchViewEmptyResults : function()
14971 this.clearTouchView();
14973 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
14975 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
14979 clearTouchView : function()
14981 this.touchViewListGroup.dom.innerHTML = '';
14984 onTouchViewClick : function(e, el, o)
14986 e.preventDefault();
14989 var rowIndex = o.rowIndex;
14991 var r = this.store.getAt(rowIndex);
14993 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
14995 if(!this.multiple){
14996 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
14997 c.dom.removeAttribute('checked');
15000 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15002 this.setFromData(r.data);
15004 var close = this.closeTriggerEl();
15010 this.hideTouchView();
15012 this.fireEvent('select', this, r, rowIndex);
15017 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15018 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15019 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15023 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15024 this.addItem(r.data);
15025 this.tickItems.push(r.data);
15029 getAutoCreateNativeIOS : function()
15032 cls: 'form-group' //input-group,
15037 cls : 'roo-ios-select'
15041 combobox.name = this.name;
15044 if (this.disabled) {
15045 combobox.disabled = true;
15048 var settings = this;
15050 ['xs','sm','md','lg'].map(function(size){
15051 if (settings[size]) {
15052 cfg.cls += ' col-' + size + '-' + settings[size];
15062 initIOSView : function()
15064 this.store.on('load', this.onIOSViewLoad, this);
15069 onIOSViewLoad : function()
15071 if(this.store.getCount() < 1){
15075 this.clearIOSView();
15077 if(this.allowBlank) {
15079 var default_text = '-- SELECT --';
15081 var opt = this.inputEl().createChild({
15084 html : default_text
15088 o[this.valueField] = 0;
15089 o[this.displayField] = default_text;
15091 this.ios_options.push({
15098 this.store.data.each(function(d, rowIndex){
15102 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15103 html = d.data[this.displayField];
15108 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15109 value = d.data[this.valueField];
15118 if(this.value == d.data[this.valueField]){
15119 option['selected'] = true;
15122 var opt = this.inputEl().createChild(option);
15124 this.ios_options.push({
15131 this.inputEl().on('change', function(){
15132 this.fireEvent('select', this);
15137 clearIOSView: function()
15139 this.inputEl().dom.innerHTML = '';
15141 this.ios_options = [];
15144 setIOSValue: function(v)
15148 if(!this.ios_options){
15152 Roo.each(this.ios_options, function(opts){
15154 opts.el.dom.removeAttribute('selected');
15156 if(opts.data[this.valueField] != v){
15160 opts.el.dom.setAttribute('selected', true);
15166 * @cfg {Boolean} grow
15170 * @cfg {Number} growMin
15174 * @cfg {Number} growMax
15183 Roo.apply(Roo.bootstrap.ComboBox, {
15187 cls: 'modal-header',
15209 cls: 'list-group-item',
15213 cls: 'roo-combobox-list-group-item-value'
15217 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15231 listItemCheckbox : {
15233 cls: 'list-group-item',
15237 cls: 'roo-combobox-list-group-item-value'
15241 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15257 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15262 cls: 'modal-footer',
15270 cls: 'col-xs-6 text-left',
15273 cls: 'btn btn-danger roo-touch-view-cancel',
15279 cls: 'col-xs-6 text-right',
15282 cls: 'btn btn-success roo-touch-view-ok',
15293 Roo.apply(Roo.bootstrap.ComboBox, {
15295 touchViewTemplate : {
15297 cls: 'modal fade roo-combobox-touch-view',
15301 cls: 'modal-dialog',
15302 style : 'position:fixed', // we have to fix position....
15306 cls: 'modal-content',
15308 Roo.bootstrap.ComboBox.header,
15309 Roo.bootstrap.ComboBox.body,
15310 Roo.bootstrap.ComboBox.footer
15319 * Ext JS Library 1.1.1
15320 * Copyright(c) 2006-2007, Ext JS, LLC.
15322 * Originally Released Under LGPL - original licence link has changed is not relivant.
15325 * <script type="text/javascript">
15330 * @extends Roo.util.Observable
15331 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15332 * This class also supports single and multi selection modes. <br>
15333 * Create a data model bound view:
15335 var store = new Roo.data.Store(...);
15337 var view = new Roo.View({
15339 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15341 singleSelect: true,
15342 selectedClass: "ydataview-selected",
15346 // listen for node click?
15347 view.on("click", function(vw, index, node, e){
15348 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15352 dataModel.load("foobar.xml");
15354 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15356 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15357 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15359 * Note: old style constructor is still suported (container, template, config)
15362 * Create a new View
15363 * @param {Object} config The config object
15366 Roo.View = function(config, depreciated_tpl, depreciated_config){
15368 this.parent = false;
15370 if (typeof(depreciated_tpl) == 'undefined') {
15371 // new way.. - universal constructor.
15372 Roo.apply(this, config);
15373 this.el = Roo.get(this.el);
15376 this.el = Roo.get(config);
15377 this.tpl = depreciated_tpl;
15378 Roo.apply(this, depreciated_config);
15380 this.wrapEl = this.el.wrap().wrap();
15381 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15384 if(typeof(this.tpl) == "string"){
15385 this.tpl = new Roo.Template(this.tpl);
15387 // support xtype ctors..
15388 this.tpl = new Roo.factory(this.tpl, Roo);
15392 this.tpl.compile();
15397 * @event beforeclick
15398 * Fires before a click is processed. Returns false to cancel the default action.
15399 * @param {Roo.View} this
15400 * @param {Number} index The index of the target node
15401 * @param {HTMLElement} node The target node
15402 * @param {Roo.EventObject} e The raw event object
15404 "beforeclick" : true,
15407 * Fires when a template node is clicked.
15408 * @param {Roo.View} this
15409 * @param {Number} index The index of the target node
15410 * @param {HTMLElement} node The target node
15411 * @param {Roo.EventObject} e The raw event object
15416 * Fires when a template node is double clicked.
15417 * @param {Roo.View} this
15418 * @param {Number} index The index of the target node
15419 * @param {HTMLElement} node The target node
15420 * @param {Roo.EventObject} e The raw event object
15424 * @event contextmenu
15425 * Fires when a template node is right clicked.
15426 * @param {Roo.View} this
15427 * @param {Number} index The index of the target node
15428 * @param {HTMLElement} node The target node
15429 * @param {Roo.EventObject} e The raw event object
15431 "contextmenu" : true,
15433 * @event selectionchange
15434 * Fires when the selected nodes change.
15435 * @param {Roo.View} this
15436 * @param {Array} selections Array of the selected nodes
15438 "selectionchange" : true,
15441 * @event beforeselect
15442 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15443 * @param {Roo.View} this
15444 * @param {HTMLElement} node The node to be selected
15445 * @param {Array} selections Array of currently selected nodes
15447 "beforeselect" : true,
15449 * @event preparedata
15450 * Fires on every row to render, to allow you to change the data.
15451 * @param {Roo.View} this
15452 * @param {Object} data to be rendered (change this)
15454 "preparedata" : true
15462 "click": this.onClick,
15463 "dblclick": this.onDblClick,
15464 "contextmenu": this.onContextMenu,
15468 this.selections = [];
15470 this.cmp = new Roo.CompositeElementLite([]);
15472 this.store = Roo.factory(this.store, Roo.data);
15473 this.setStore(this.store, true);
15476 if ( this.footer && this.footer.xtype) {
15478 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15480 this.footer.dataSource = this.store;
15481 this.footer.container = fctr;
15482 this.footer = Roo.factory(this.footer, Roo);
15483 fctr.insertFirst(this.el);
15485 // this is a bit insane - as the paging toolbar seems to detach the el..
15486 // dom.parentNode.parentNode.parentNode
15487 // they get detached?
15491 Roo.View.superclass.constructor.call(this);
15496 Roo.extend(Roo.View, Roo.util.Observable, {
15499 * @cfg {Roo.data.Store} store Data store to load data from.
15504 * @cfg {String|Roo.Element} el The container element.
15509 * @cfg {String|Roo.Template} tpl The template used by this View
15513 * @cfg {String} dataName the named area of the template to use as the data area
15514 * Works with domtemplates roo-name="name"
15518 * @cfg {String} selectedClass The css class to add to selected nodes
15520 selectedClass : "x-view-selected",
15522 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15527 * @cfg {String} text to display on mask (default Loading)
15531 * @cfg {Boolean} multiSelect Allow multiple selection
15533 multiSelect : false,
15535 * @cfg {Boolean} singleSelect Allow single selection
15537 singleSelect: false,
15540 * @cfg {Boolean} toggleSelect - selecting
15542 toggleSelect : false,
15545 * @cfg {Boolean} tickable - selecting
15550 * Returns the element this view is bound to.
15551 * @return {Roo.Element}
15553 getEl : function(){
15554 return this.wrapEl;
15560 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15562 refresh : function(){
15563 //Roo.log('refresh');
15566 // if we are using something like 'domtemplate', then
15567 // the what gets used is:
15568 // t.applySubtemplate(NAME, data, wrapping data..)
15569 // the outer template then get' applied with
15570 // the store 'extra data'
15571 // and the body get's added to the
15572 // roo-name="data" node?
15573 // <span class='roo-tpl-{name}'></span> ?????
15577 this.clearSelections();
15578 this.el.update("");
15580 var records = this.store.getRange();
15581 if(records.length < 1) {
15583 // is this valid?? = should it render a template??
15585 this.el.update(this.emptyText);
15589 if (this.dataName) {
15590 this.el.update(t.apply(this.store.meta)); //????
15591 el = this.el.child('.roo-tpl-' + this.dataName);
15594 for(var i = 0, len = records.length; i < len; i++){
15595 var data = this.prepareData(records[i].data, i, records[i]);
15596 this.fireEvent("preparedata", this, data, i, records[i]);
15598 var d = Roo.apply({}, data);
15601 Roo.apply(d, {'roo-id' : Roo.id()});
15605 Roo.each(this.parent.item, function(item){
15606 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15609 Roo.apply(d, {'roo-data-checked' : 'checked'});
15613 html[html.length] = Roo.util.Format.trim(
15615 t.applySubtemplate(this.dataName, d, this.store.meta) :
15622 el.update(html.join(""));
15623 this.nodes = el.dom.childNodes;
15624 this.updateIndexes(0);
15629 * Function to override to reformat the data that is sent to
15630 * the template for each node.
15631 * DEPRICATED - use the preparedata event handler.
15632 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15633 * a JSON object for an UpdateManager bound view).
15635 prepareData : function(data, index, record)
15637 this.fireEvent("preparedata", this, data, index, record);
15641 onUpdate : function(ds, record){
15642 // Roo.log('on update');
15643 this.clearSelections();
15644 var index = this.store.indexOf(record);
15645 var n = this.nodes[index];
15646 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15647 n.parentNode.removeChild(n);
15648 this.updateIndexes(index, index);
15654 onAdd : function(ds, records, index)
15656 //Roo.log(['on Add', ds, records, index] );
15657 this.clearSelections();
15658 if(this.nodes.length == 0){
15662 var n = this.nodes[index];
15663 for(var i = 0, len = records.length; i < len; i++){
15664 var d = this.prepareData(records[i].data, i, records[i]);
15666 this.tpl.insertBefore(n, d);
15669 this.tpl.append(this.el, d);
15672 this.updateIndexes(index);
15675 onRemove : function(ds, record, index){
15676 // Roo.log('onRemove');
15677 this.clearSelections();
15678 var el = this.dataName ?
15679 this.el.child('.roo-tpl-' + this.dataName) :
15682 el.dom.removeChild(this.nodes[index]);
15683 this.updateIndexes(index);
15687 * Refresh an individual node.
15688 * @param {Number} index
15690 refreshNode : function(index){
15691 this.onUpdate(this.store, this.store.getAt(index));
15694 updateIndexes : function(startIndex, endIndex){
15695 var ns = this.nodes;
15696 startIndex = startIndex || 0;
15697 endIndex = endIndex || ns.length - 1;
15698 for(var i = startIndex; i <= endIndex; i++){
15699 ns[i].nodeIndex = i;
15704 * Changes the data store this view uses and refresh the view.
15705 * @param {Store} store
15707 setStore : function(store, initial){
15708 if(!initial && this.store){
15709 this.store.un("datachanged", this.refresh);
15710 this.store.un("add", this.onAdd);
15711 this.store.un("remove", this.onRemove);
15712 this.store.un("update", this.onUpdate);
15713 this.store.un("clear", this.refresh);
15714 this.store.un("beforeload", this.onBeforeLoad);
15715 this.store.un("load", this.onLoad);
15716 this.store.un("loadexception", this.onLoad);
15720 store.on("datachanged", this.refresh, this);
15721 store.on("add", this.onAdd, this);
15722 store.on("remove", this.onRemove, this);
15723 store.on("update", this.onUpdate, this);
15724 store.on("clear", this.refresh, this);
15725 store.on("beforeload", this.onBeforeLoad, this);
15726 store.on("load", this.onLoad, this);
15727 store.on("loadexception", this.onLoad, this);
15735 * onbeforeLoad - masks the loading area.
15738 onBeforeLoad : function(store,opts)
15740 //Roo.log('onBeforeLoad');
15742 this.el.update("");
15744 this.el.mask(this.mask ? this.mask : "Loading" );
15746 onLoad : function ()
15753 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
15754 * @param {HTMLElement} node
15755 * @return {HTMLElement} The template node
15757 findItemFromChild : function(node){
15758 var el = this.dataName ?
15759 this.el.child('.roo-tpl-' + this.dataName,true) :
15762 if(!node || node.parentNode == el){
15765 var p = node.parentNode;
15766 while(p && p != el){
15767 if(p.parentNode == el){
15776 onClick : function(e){
15777 var item = this.findItemFromChild(e.getTarget());
15779 var index = this.indexOf(item);
15780 if(this.onItemClick(item, index, e) !== false){
15781 this.fireEvent("click", this, index, item, e);
15784 this.clearSelections();
15789 onContextMenu : function(e){
15790 var item = this.findItemFromChild(e.getTarget());
15792 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
15797 onDblClick : function(e){
15798 var item = this.findItemFromChild(e.getTarget());
15800 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
15804 onItemClick : function(item, index, e)
15806 if(this.fireEvent("beforeclick", this, index, item, e) === false){
15809 if (this.toggleSelect) {
15810 var m = this.isSelected(item) ? 'unselect' : 'select';
15813 _t[m](item, true, false);
15816 if(this.multiSelect || this.singleSelect){
15817 if(this.multiSelect && e.shiftKey && this.lastSelection){
15818 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
15820 this.select(item, this.multiSelect && e.ctrlKey);
15821 this.lastSelection = item;
15824 if(!this.tickable){
15825 e.preventDefault();
15833 * Get the number of selected nodes.
15836 getSelectionCount : function(){
15837 return this.selections.length;
15841 * Get the currently selected nodes.
15842 * @return {Array} An array of HTMLElements
15844 getSelectedNodes : function(){
15845 return this.selections;
15849 * Get the indexes of the selected nodes.
15852 getSelectedIndexes : function(){
15853 var indexes = [], s = this.selections;
15854 for(var i = 0, len = s.length; i < len; i++){
15855 indexes.push(s[i].nodeIndex);
15861 * Clear all selections
15862 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
15864 clearSelections : function(suppressEvent){
15865 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
15866 this.cmp.elements = this.selections;
15867 this.cmp.removeClass(this.selectedClass);
15868 this.selections = [];
15869 if(!suppressEvent){
15870 this.fireEvent("selectionchange", this, this.selections);
15876 * Returns true if the passed node is selected
15877 * @param {HTMLElement/Number} node The node or node index
15878 * @return {Boolean}
15880 isSelected : function(node){
15881 var s = this.selections;
15885 node = this.getNode(node);
15886 return s.indexOf(node) !== -1;
15891 * @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
15892 * @param {Boolean} keepExisting (optional) true to keep existing selections
15893 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15895 select : function(nodeInfo, keepExisting, suppressEvent){
15896 if(nodeInfo instanceof Array){
15898 this.clearSelections(true);
15900 for(var i = 0, len = nodeInfo.length; i < len; i++){
15901 this.select(nodeInfo[i], true, true);
15905 var node = this.getNode(nodeInfo);
15906 if(!node || this.isSelected(node)){
15907 return; // already selected.
15910 this.clearSelections(true);
15913 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
15914 Roo.fly(node).addClass(this.selectedClass);
15915 this.selections.push(node);
15916 if(!suppressEvent){
15917 this.fireEvent("selectionchange", this, this.selections);
15925 * @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
15926 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
15927 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
15929 unselect : function(nodeInfo, keepExisting, suppressEvent)
15931 if(nodeInfo instanceof Array){
15932 Roo.each(this.selections, function(s) {
15933 this.unselect(s, nodeInfo);
15937 var node = this.getNode(nodeInfo);
15938 if(!node || !this.isSelected(node)){
15939 //Roo.log("not selected");
15940 return; // not selected.
15944 Roo.each(this.selections, function(s) {
15946 Roo.fly(node).removeClass(this.selectedClass);
15953 this.selections= ns;
15954 this.fireEvent("selectionchange", this, this.selections);
15958 * Gets a template node.
15959 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15960 * @return {HTMLElement} The node or null if it wasn't found
15962 getNode : function(nodeInfo){
15963 if(typeof nodeInfo == "string"){
15964 return document.getElementById(nodeInfo);
15965 }else if(typeof nodeInfo == "number"){
15966 return this.nodes[nodeInfo];
15972 * Gets a range template nodes.
15973 * @param {Number} startIndex
15974 * @param {Number} endIndex
15975 * @return {Array} An array of nodes
15977 getNodes : function(start, end){
15978 var ns = this.nodes;
15979 start = start || 0;
15980 end = typeof end == "undefined" ? ns.length - 1 : end;
15983 for(var i = start; i <= end; i++){
15987 for(var i = start; i >= end; i--){
15995 * Finds the index of the passed node
15996 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
15997 * @return {Number} The index of the node or -1
15999 indexOf : function(node){
16000 node = this.getNode(node);
16001 if(typeof node.nodeIndex == "number"){
16002 return node.nodeIndex;
16004 var ns = this.nodes;
16005 for(var i = 0, len = ns.length; i < len; i++){
16016 * based on jquery fullcalendar
16020 Roo.bootstrap = Roo.bootstrap || {};
16022 * @class Roo.bootstrap.Calendar
16023 * @extends Roo.bootstrap.Component
16024 * Bootstrap Calendar class
16025 * @cfg {Boolean} loadMask (true|false) default false
16026 * @cfg {Object} header generate the user specific header of the calendar, default false
16029 * Create a new Container
16030 * @param {Object} config The config object
16035 Roo.bootstrap.Calendar = function(config){
16036 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16040 * Fires when a date is selected
16041 * @param {DatePicker} this
16042 * @param {Date} date The selected date
16046 * @event monthchange
16047 * Fires when the displayed month changes
16048 * @param {DatePicker} this
16049 * @param {Date} date The selected month
16051 'monthchange': true,
16053 * @event evententer
16054 * Fires when mouse over an event
16055 * @param {Calendar} this
16056 * @param {event} Event
16058 'evententer': true,
16060 * @event eventleave
16061 * Fires when the mouse leaves an
16062 * @param {Calendar} this
16065 'eventleave': true,
16067 * @event eventclick
16068 * Fires when the mouse click an
16069 * @param {Calendar} this
16078 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16081 * @cfg {Number} startDay
16082 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16090 getAutoCreate : function(){
16093 var fc_button = function(name, corner, style, content ) {
16094 return Roo.apply({},{
16096 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16098 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16101 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16112 style : 'width:100%',
16119 cls : 'fc-header-left',
16121 fc_button('prev', 'left', 'arrow', '‹' ),
16122 fc_button('next', 'right', 'arrow', '›' ),
16123 { tag: 'span', cls: 'fc-header-space' },
16124 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16132 cls : 'fc-header-center',
16136 cls: 'fc-header-title',
16139 html : 'month / year'
16147 cls : 'fc-header-right',
16149 /* fc_button('month', 'left', '', 'month' ),
16150 fc_button('week', '', '', 'week' ),
16151 fc_button('day', 'right', '', 'day' )
16163 header = this.header;
16166 var cal_heads = function() {
16168 // fixme - handle this.
16170 for (var i =0; i < Date.dayNames.length; i++) {
16171 var d = Date.dayNames[i];
16174 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16175 html : d.substring(0,3)
16179 ret[0].cls += ' fc-first';
16180 ret[6].cls += ' fc-last';
16183 var cal_cell = function(n) {
16186 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16191 cls: 'fc-day-number',
16195 cls: 'fc-day-content',
16199 style: 'position: relative;' // height: 17px;
16211 var cal_rows = function() {
16214 for (var r = 0; r < 6; r++) {
16221 for (var i =0; i < Date.dayNames.length; i++) {
16222 var d = Date.dayNames[i];
16223 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16226 row.cn[0].cls+=' fc-first';
16227 row.cn[0].cn[0].style = 'min-height:90px';
16228 row.cn[6].cls+=' fc-last';
16232 ret[0].cls += ' fc-first';
16233 ret[4].cls += ' fc-prev-last';
16234 ret[5].cls += ' fc-last';
16241 cls: 'fc-border-separate',
16242 style : 'width:100%',
16250 cls : 'fc-first fc-last',
16268 cls : 'fc-content',
16269 style : "position: relative;",
16272 cls : 'fc-view fc-view-month fc-grid',
16273 style : 'position: relative',
16274 unselectable : 'on',
16277 cls : 'fc-event-container',
16278 style : 'position:absolute;z-index:8;top:0;left:0;'
16296 initEvents : function()
16299 throw "can not find store for calendar";
16305 style: "text-align:center",
16309 style: "background-color:white;width:50%;margin:250 auto",
16313 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16324 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16326 var size = this.el.select('.fc-content', true).first().getSize();
16327 this.maskEl.setSize(size.width, size.height);
16328 this.maskEl.enableDisplayMode("block");
16329 if(!this.loadMask){
16330 this.maskEl.hide();
16333 this.store = Roo.factory(this.store, Roo.data);
16334 this.store.on('load', this.onLoad, this);
16335 this.store.on('beforeload', this.onBeforeLoad, this);
16339 this.cells = this.el.select('.fc-day',true);
16340 //Roo.log(this.cells);
16341 this.textNodes = this.el.query('.fc-day-number');
16342 this.cells.addClassOnOver('fc-state-hover');
16344 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16345 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16346 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16347 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16349 this.on('monthchange', this.onMonthChange, this);
16351 this.update(new Date().clearTime());
16354 resize : function() {
16355 var sz = this.el.getSize();
16357 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16358 this.el.select('.fc-day-content div',true).setHeight(34);
16363 showPrevMonth : function(e){
16364 this.update(this.activeDate.add("mo", -1));
16366 showToday : function(e){
16367 this.update(new Date().clearTime());
16370 showNextMonth : function(e){
16371 this.update(this.activeDate.add("mo", 1));
16375 showPrevYear : function(){
16376 this.update(this.activeDate.add("y", -1));
16380 showNextYear : function(){
16381 this.update(this.activeDate.add("y", 1));
16386 update : function(date)
16388 var vd = this.activeDate;
16389 this.activeDate = date;
16390 // if(vd && this.el){
16391 // var t = date.getTime();
16392 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16393 // Roo.log('using add remove');
16395 // this.fireEvent('monthchange', this, date);
16397 // this.cells.removeClass("fc-state-highlight");
16398 // this.cells.each(function(c){
16399 // if(c.dateValue == t){
16400 // c.addClass("fc-state-highlight");
16401 // setTimeout(function(){
16402 // try{c.dom.firstChild.focus();}catch(e){}
16412 var days = date.getDaysInMonth();
16414 var firstOfMonth = date.getFirstDateOfMonth();
16415 var startingPos = firstOfMonth.getDay()-this.startDay;
16417 if(startingPos < this.startDay){
16421 var pm = date.add(Date.MONTH, -1);
16422 var prevStart = pm.getDaysInMonth()-startingPos;
16424 this.cells = this.el.select('.fc-day',true);
16425 this.textNodes = this.el.query('.fc-day-number');
16426 this.cells.addClassOnOver('fc-state-hover');
16428 var cells = this.cells.elements;
16429 var textEls = this.textNodes;
16431 Roo.each(cells, function(cell){
16432 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16435 days += startingPos;
16437 // convert everything to numbers so it's fast
16438 var day = 86400000;
16439 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16442 //Roo.log(prevStart);
16444 var today = new Date().clearTime().getTime();
16445 var sel = date.clearTime().getTime();
16446 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16447 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16448 var ddMatch = this.disabledDatesRE;
16449 var ddText = this.disabledDatesText;
16450 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16451 var ddaysText = this.disabledDaysText;
16452 var format = this.format;
16454 var setCellClass = function(cal, cell){
16458 //Roo.log('set Cell Class');
16460 var t = d.getTime();
16464 cell.dateValue = t;
16466 cell.className += " fc-today";
16467 cell.className += " fc-state-highlight";
16468 cell.title = cal.todayText;
16471 // disable highlight in other month..
16472 //cell.className += " fc-state-highlight";
16477 cell.className = " fc-state-disabled";
16478 cell.title = cal.minText;
16482 cell.className = " fc-state-disabled";
16483 cell.title = cal.maxText;
16487 if(ddays.indexOf(d.getDay()) != -1){
16488 cell.title = ddaysText;
16489 cell.className = " fc-state-disabled";
16492 if(ddMatch && format){
16493 var fvalue = d.dateFormat(format);
16494 if(ddMatch.test(fvalue)){
16495 cell.title = ddText.replace("%0", fvalue);
16496 cell.className = " fc-state-disabled";
16500 if (!cell.initialClassName) {
16501 cell.initialClassName = cell.dom.className;
16504 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16509 for(; i < startingPos; i++) {
16510 textEls[i].innerHTML = (++prevStart);
16511 d.setDate(d.getDate()+1);
16513 cells[i].className = "fc-past fc-other-month";
16514 setCellClass(this, cells[i]);
16519 for(; i < days; i++){
16520 intDay = i - startingPos + 1;
16521 textEls[i].innerHTML = (intDay);
16522 d.setDate(d.getDate()+1);
16524 cells[i].className = ''; // "x-date-active";
16525 setCellClass(this, cells[i]);
16529 for(; i < 42; i++) {
16530 textEls[i].innerHTML = (++extraDays);
16531 d.setDate(d.getDate()+1);
16533 cells[i].className = "fc-future fc-other-month";
16534 setCellClass(this, cells[i]);
16537 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16539 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16541 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16542 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16544 if(totalRows != 6){
16545 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16546 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16549 this.fireEvent('monthchange', this, date);
16553 if(!this.internalRender){
16554 var main = this.el.dom.firstChild;
16555 var w = main.offsetWidth;
16556 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16557 Roo.fly(main).setWidth(w);
16558 this.internalRender = true;
16559 // opera does not respect the auto grow header center column
16560 // then, after it gets a width opera refuses to recalculate
16561 // without a second pass
16562 if(Roo.isOpera && !this.secondPass){
16563 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16564 this.secondPass = true;
16565 this.update.defer(10, this, [date]);
16572 findCell : function(dt) {
16573 dt = dt.clearTime().getTime();
16575 this.cells.each(function(c){
16576 //Roo.log("check " +c.dateValue + '?=' + dt);
16577 if(c.dateValue == dt){
16587 findCells : function(ev) {
16588 var s = ev.start.clone().clearTime().getTime();
16590 var e= ev.end.clone().clearTime().getTime();
16593 this.cells.each(function(c){
16594 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16596 if(c.dateValue > e){
16599 if(c.dateValue < s){
16608 // findBestRow: function(cells)
16612 // for (var i =0 ; i < cells.length;i++) {
16613 // ret = Math.max(cells[i].rows || 0,ret);
16620 addItem : function(ev)
16622 // look for vertical location slot in
16623 var cells = this.findCells(ev);
16625 // ev.row = this.findBestRow(cells);
16627 // work out the location.
16631 for(var i =0; i < cells.length; i++) {
16633 cells[i].row = cells[0].row;
16636 cells[i].row = cells[i].row + 1;
16646 if (crow.start.getY() == cells[i].getY()) {
16648 crow.end = cells[i];
16665 cells[0].events.push(ev);
16667 this.calevents.push(ev);
16670 clearEvents: function() {
16672 if(!this.calevents){
16676 Roo.each(this.cells.elements, function(c){
16682 Roo.each(this.calevents, function(e) {
16683 Roo.each(e.els, function(el) {
16684 el.un('mouseenter' ,this.onEventEnter, this);
16685 el.un('mouseleave' ,this.onEventLeave, this);
16690 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
16696 renderEvents: function()
16700 this.cells.each(function(c) {
16709 if(c.row != c.events.length){
16710 r = 4 - (4 - (c.row - c.events.length));
16713 c.events = ev.slice(0, r);
16714 c.more = ev.slice(r);
16716 if(c.more.length && c.more.length == 1){
16717 c.events.push(c.more.pop());
16720 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
16724 this.cells.each(function(c) {
16726 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
16729 for (var e = 0; e < c.events.length; e++){
16730 var ev = c.events[e];
16731 var rows = ev.rows;
16733 for(var i = 0; i < rows.length; i++) {
16735 // how many rows should it span..
16738 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
16739 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
16741 unselectable : "on",
16744 cls: 'fc-event-inner',
16748 // cls: 'fc-event-time',
16749 // html : cells.length > 1 ? '' : ev.time
16753 cls: 'fc-event-title',
16754 html : String.format('{0}', ev.title)
16761 cls: 'ui-resizable-handle ui-resizable-e',
16762 html : '  '
16769 cfg.cls += ' fc-event-start';
16771 if ((i+1) == rows.length) {
16772 cfg.cls += ' fc-event-end';
16775 var ctr = _this.el.select('.fc-event-container',true).first();
16776 var cg = ctr.createChild(cfg);
16778 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
16779 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
16781 var r = (c.more.length) ? 1 : 0;
16782 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
16783 cg.setWidth(ebox.right - sbox.x -2);
16785 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
16786 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
16787 cg.on('click', _this.onEventClick, _this, ev);
16798 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
16799 style : 'position: absolute',
16800 unselectable : "on",
16803 cls: 'fc-event-inner',
16807 cls: 'fc-event-title',
16815 cls: 'ui-resizable-handle ui-resizable-e',
16816 html : '  '
16822 var ctr = _this.el.select('.fc-event-container',true).first();
16823 var cg = ctr.createChild(cfg);
16825 var sbox = c.select('.fc-day-content',true).first().getBox();
16826 var ebox = c.select('.fc-day-content',true).first().getBox();
16828 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
16829 cg.setWidth(ebox.right - sbox.x -2);
16831 cg.on('click', _this.onMoreEventClick, _this, c.more);
16841 onEventEnter: function (e, el,event,d) {
16842 this.fireEvent('evententer', this, el, event);
16845 onEventLeave: function (e, el,event,d) {
16846 this.fireEvent('eventleave', this, el, event);
16849 onEventClick: function (e, el,event,d) {
16850 this.fireEvent('eventclick', this, el, event);
16853 onMonthChange: function () {
16857 onMoreEventClick: function(e, el, more)
16861 this.calpopover.placement = 'right';
16862 this.calpopover.setTitle('More');
16864 this.calpopover.setContent('');
16866 var ctr = this.calpopover.el.select('.popover-content', true).first();
16868 Roo.each(more, function(m){
16870 cls : 'fc-event-hori fc-event-draggable',
16873 var cg = ctr.createChild(cfg);
16875 cg.on('click', _this.onEventClick, _this, m);
16878 this.calpopover.show(el);
16883 onLoad: function ()
16885 this.calevents = [];
16888 if(this.store.getCount() > 0){
16889 this.store.data.each(function(d){
16892 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
16893 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
16894 time : d.data.start_time,
16895 title : d.data.title,
16896 description : d.data.description,
16897 venue : d.data.venue
16902 this.renderEvents();
16904 if(this.calevents.length && this.loadMask){
16905 this.maskEl.hide();
16909 onBeforeLoad: function()
16911 this.clearEvents();
16913 this.maskEl.show();
16927 * @class Roo.bootstrap.Popover
16928 * @extends Roo.bootstrap.Component
16929 * Bootstrap Popover class
16930 * @cfg {String} html contents of the popover (or false to use children..)
16931 * @cfg {String} title of popover (or false to hide)
16932 * @cfg {String} placement how it is placed
16933 * @cfg {String} trigger click || hover (or false to trigger manually)
16934 * @cfg {String} over what (parent or false to trigger manually.)
16935 * @cfg {Number} delay - delay before showing
16938 * Create a new Popover
16939 * @param {Object} config The config object
16942 Roo.bootstrap.Popover = function(config){
16943 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
16949 * After the popover show
16951 * @param {Roo.bootstrap.Popover} this
16956 * After the popover hide
16958 * @param {Roo.bootstrap.Popover} this
16964 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
16966 title: 'Fill in a title',
16969 placement : 'right',
16970 trigger : 'hover', // hover
16976 can_build_overlaid : false,
16978 getChildContainer : function()
16980 return this.el.select('.popover-content',true).first();
16983 getAutoCreate : function(){
16986 cls : 'popover roo-dynamic',
16987 style: 'display:block',
16993 cls : 'popover-inner',
16997 cls: 'popover-title',
17001 cls : 'popover-content',
17012 setTitle: function(str)
17015 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17017 setContent: function(str)
17020 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17022 // as it get's added to the bottom of the page.
17023 onRender : function(ct, position)
17025 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17027 var cfg = Roo.apply({}, this.getAutoCreate());
17031 cfg.cls += ' ' + this.cls;
17034 cfg.style = this.style;
17036 //Roo.log("adding to ");
17037 this.el = Roo.get(document.body).createChild(cfg, position);
17038 // Roo.log(this.el);
17043 initEvents : function()
17045 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17046 this.el.enableDisplayMode('block');
17048 if (this.over === false) {
17051 if (this.triggers === false) {
17054 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17055 var triggers = this.trigger ? this.trigger.split(' ') : [];
17056 Roo.each(triggers, function(trigger) {
17058 if (trigger == 'click') {
17059 on_el.on('click', this.toggle, this);
17060 } else if (trigger != 'manual') {
17061 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17062 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17064 on_el.on(eventIn ,this.enter, this);
17065 on_el.on(eventOut, this.leave, this);
17076 toggle : function () {
17077 this.hoverState == 'in' ? this.leave() : this.enter();
17080 enter : function () {
17082 clearTimeout(this.timeout);
17084 this.hoverState = 'in';
17086 if (!this.delay || !this.delay.show) {
17091 this.timeout = setTimeout(function () {
17092 if (_t.hoverState == 'in') {
17095 }, this.delay.show)
17098 leave : function() {
17099 clearTimeout(this.timeout);
17101 this.hoverState = 'out';
17103 if (!this.delay || !this.delay.hide) {
17108 this.timeout = setTimeout(function () {
17109 if (_t.hoverState == 'out') {
17112 }, this.delay.hide)
17115 show : function (on_el)
17118 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17122 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17123 if (this.html !== false) {
17124 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17126 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17127 if (!this.title.length) {
17128 this.el.select('.popover-title',true).hide();
17131 var placement = typeof this.placement == 'function' ?
17132 this.placement.call(this, this.el, on_el) :
17135 var autoToken = /\s?auto?\s?/i;
17136 var autoPlace = autoToken.test(placement);
17138 placement = placement.replace(autoToken, '') || 'top';
17142 //this.el.setXY([0,0]);
17144 this.el.dom.style.display='block';
17145 this.el.addClass(placement);
17147 //this.el.appendTo(on_el);
17149 var p = this.getPosition();
17150 var box = this.el.getBox();
17155 var align = Roo.bootstrap.Popover.alignment[placement];
17156 this.el.alignTo(on_el, align[0],align[1]);
17157 //var arrow = this.el.select('.arrow',true).first();
17158 //arrow.set(align[2],
17160 this.el.addClass('in');
17163 if (this.el.hasClass('fade')) {
17167 this.hoverState = 'in';
17169 this.fireEvent('show', this);
17174 this.el.setXY([0,0]);
17175 this.el.removeClass('in');
17177 this.hoverState = null;
17179 this.fireEvent('hide', this);
17184 Roo.bootstrap.Popover.alignment = {
17185 'left' : ['r-l', [-10,0], 'right'],
17186 'right' : ['l-r', [10,0], 'left'],
17187 'bottom' : ['t-b', [0,10], 'top'],
17188 'top' : [ 'b-t', [0,-10], 'bottom']
17199 * @class Roo.bootstrap.Progress
17200 * @extends Roo.bootstrap.Component
17201 * Bootstrap Progress class
17202 * @cfg {Boolean} striped striped of the progress bar
17203 * @cfg {Boolean} active animated of the progress bar
17207 * Create a new Progress
17208 * @param {Object} config The config object
17211 Roo.bootstrap.Progress = function(config){
17212 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17215 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17220 getAutoCreate : function(){
17228 cfg.cls += ' progress-striped';
17232 cfg.cls += ' active';
17251 * @class Roo.bootstrap.ProgressBar
17252 * @extends Roo.bootstrap.Component
17253 * Bootstrap ProgressBar class
17254 * @cfg {Number} aria_valuenow aria-value now
17255 * @cfg {Number} aria_valuemin aria-value min
17256 * @cfg {Number} aria_valuemax aria-value max
17257 * @cfg {String} label label for the progress bar
17258 * @cfg {String} panel (success | info | warning | danger )
17259 * @cfg {String} role role of the progress bar
17260 * @cfg {String} sr_only text
17264 * Create a new ProgressBar
17265 * @param {Object} config The config object
17268 Roo.bootstrap.ProgressBar = function(config){
17269 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17272 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17276 aria_valuemax : 100,
17282 getAutoCreate : function()
17287 cls: 'progress-bar',
17288 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17300 cfg.role = this.role;
17303 if(this.aria_valuenow){
17304 cfg['aria-valuenow'] = this.aria_valuenow;
17307 if(this.aria_valuemin){
17308 cfg['aria-valuemin'] = this.aria_valuemin;
17311 if(this.aria_valuemax){
17312 cfg['aria-valuemax'] = this.aria_valuemax;
17315 if(this.label && !this.sr_only){
17316 cfg.html = this.label;
17320 cfg.cls += ' progress-bar-' + this.panel;
17326 update : function(aria_valuenow)
17328 this.aria_valuenow = aria_valuenow;
17330 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17345 * @class Roo.bootstrap.TabGroup
17346 * @extends Roo.bootstrap.Column
17347 * Bootstrap Column class
17348 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17349 * @cfg {Boolean} carousel true to make the group behave like a carousel
17350 * @cfg {Boolean} bullets show bullets for the panels
17351 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17352 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17353 * @cfg {Boolean} showarrow (true|false) show arrow default true
17356 * Create a new TabGroup
17357 * @param {Object} config The config object
17360 Roo.bootstrap.TabGroup = function(config){
17361 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17363 this.navId = Roo.id();
17366 Roo.bootstrap.TabGroup.register(this);
17370 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17373 transition : false,
17378 slideOnTouch : false,
17381 getAutoCreate : function()
17383 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17385 cfg.cls += ' tab-content';
17387 if (this.carousel) {
17388 cfg.cls += ' carousel slide';
17391 cls : 'carousel-inner',
17395 if(this.bullets && !Roo.isTouch){
17398 cls : 'carousel-bullets',
17402 if(this.bullets_cls){
17403 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17410 cfg.cn[0].cn.push(bullets);
17413 if(this.showarrow){
17414 cfg.cn[0].cn.push({
17416 class : 'carousel-arrow',
17420 class : 'carousel-prev',
17424 class : 'fa fa-chevron-left'
17430 class : 'carousel-next',
17434 class : 'fa fa-chevron-right'
17447 initEvents: function()
17449 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17450 // this.el.on("touchstart", this.onTouchStart, this);
17453 if(this.autoslide){
17456 this.slideFn = window.setInterval(function() {
17457 _this.showPanelNext();
17461 if(this.showarrow){
17462 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17463 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17469 // onTouchStart : function(e, el, o)
17471 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17475 // this.showPanelNext();
17479 getChildContainer : function()
17481 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17485 * register a Navigation item
17486 * @param {Roo.bootstrap.NavItem} the navitem to add
17488 register : function(item)
17490 this.tabs.push( item);
17491 item.navId = this.navId; // not really needed..
17496 getActivePanel : function()
17499 Roo.each(this.tabs, function(t) {
17509 getPanelByName : function(n)
17512 Roo.each(this.tabs, function(t) {
17513 if (t.tabId == n) {
17521 indexOfPanel : function(p)
17524 Roo.each(this.tabs, function(t,i) {
17525 if (t.tabId == p.tabId) {
17534 * show a specific panel
17535 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17536 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17538 showPanel : function (pan)
17540 if(this.transition || typeof(pan) == 'undefined'){
17541 Roo.log("waiting for the transitionend");
17545 if (typeof(pan) == 'number') {
17546 pan = this.tabs[pan];
17549 if (typeof(pan) == 'string') {
17550 pan = this.getPanelByName(pan);
17553 var cur = this.getActivePanel();
17556 Roo.log('pan or acitve pan is undefined');
17560 if (pan.tabId == this.getActivePanel().tabId) {
17564 if (false === cur.fireEvent('beforedeactivate')) {
17568 if(this.bullets > 0 && !Roo.isTouch){
17569 this.setActiveBullet(this.indexOfPanel(pan));
17572 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17574 this.transition = true;
17575 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17576 var lr = dir == 'next' ? 'left' : 'right';
17577 pan.el.addClass(dir); // or prev
17578 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17579 cur.el.addClass(lr); // or right
17580 pan.el.addClass(lr);
17583 cur.el.on('transitionend', function() {
17584 Roo.log("trans end?");
17586 pan.el.removeClass([lr,dir]);
17587 pan.setActive(true);
17589 cur.el.removeClass([lr]);
17590 cur.setActive(false);
17592 _this.transition = false;
17594 }, this, { single: true } );
17599 cur.setActive(false);
17600 pan.setActive(true);
17605 showPanelNext : function()
17607 var i = this.indexOfPanel(this.getActivePanel());
17609 if (i >= this.tabs.length - 1 && !this.autoslide) {
17613 if (i >= this.tabs.length - 1 && this.autoslide) {
17617 this.showPanel(this.tabs[i+1]);
17620 showPanelPrev : function()
17622 var i = this.indexOfPanel(this.getActivePanel());
17624 if (i < 1 && !this.autoslide) {
17628 if (i < 1 && this.autoslide) {
17629 i = this.tabs.length;
17632 this.showPanel(this.tabs[i-1]);
17636 addBullet: function()
17638 if(!this.bullets || Roo.isTouch){
17641 var ctr = this.el.select('.carousel-bullets',true).first();
17642 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17643 var bullet = ctr.createChild({
17644 cls : 'bullet bullet-' + i
17645 },ctr.dom.lastChild);
17650 bullet.on('click', (function(e, el, o, ii, t){
17652 e.preventDefault();
17654 this.showPanel(ii);
17656 if(this.autoslide && this.slideFn){
17657 clearInterval(this.slideFn);
17658 this.slideFn = window.setInterval(function() {
17659 _this.showPanelNext();
17663 }).createDelegate(this, [i, bullet], true));
17668 setActiveBullet : function(i)
17674 Roo.each(this.el.select('.bullet', true).elements, function(el){
17675 el.removeClass('selected');
17678 var bullet = this.el.select('.bullet-' + i, true).first();
17684 bullet.addClass('selected');
17695 Roo.apply(Roo.bootstrap.TabGroup, {
17699 * register a Navigation Group
17700 * @param {Roo.bootstrap.NavGroup} the navgroup to add
17702 register : function(navgrp)
17704 this.groups[navgrp.navId] = navgrp;
17708 * fetch a Navigation Group based on the navigation ID
17709 * if one does not exist , it will get created.
17710 * @param {string} the navgroup to add
17711 * @returns {Roo.bootstrap.NavGroup} the navgroup
17713 get: function(navId) {
17714 if (typeof(this.groups[navId]) == 'undefined') {
17715 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
17717 return this.groups[navId] ;
17732 * @class Roo.bootstrap.TabPanel
17733 * @extends Roo.bootstrap.Component
17734 * Bootstrap TabPanel class
17735 * @cfg {Boolean} active panel active
17736 * @cfg {String} html panel content
17737 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
17738 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
17739 * @cfg {String} href click to link..
17743 * Create a new TabPanel
17744 * @param {Object} config The config object
17747 Roo.bootstrap.TabPanel = function(config){
17748 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
17752 * Fires when the active status changes
17753 * @param {Roo.bootstrap.TabPanel} this
17754 * @param {Boolean} state the new state
17759 * @event beforedeactivate
17760 * Fires before a tab is de-activated - can be used to do validation on a form.
17761 * @param {Roo.bootstrap.TabPanel} this
17762 * @return {Boolean} false if there is an error
17765 'beforedeactivate': true
17768 this.tabId = this.tabId || Roo.id();
17772 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
17780 getAutoCreate : function(){
17783 // item is needed for carousel - not sure if it has any effect otherwise
17784 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
17785 html: this.html || ''
17789 cfg.cls += ' active';
17793 cfg.tabId = this.tabId;
17800 initEvents: function()
17802 var p = this.parent();
17804 this.navId = this.navId || p.navId;
17806 if (typeof(this.navId) != 'undefined') {
17807 // not really needed.. but just in case.. parent should be a NavGroup.
17808 var tg = Roo.bootstrap.TabGroup.get(this.navId);
17812 var i = tg.tabs.length - 1;
17814 if(this.active && tg.bullets > 0 && i < tg.bullets){
17815 tg.setActiveBullet(i);
17819 this.el.on('click', this.onClick, this);
17822 this.el.on("touchstart", this.onTouchStart, this);
17823 this.el.on("touchmove", this.onTouchMove, this);
17824 this.el.on("touchend", this.onTouchEnd, this);
17829 onRender : function(ct, position)
17831 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
17834 setActive : function(state)
17836 Roo.log("panel - set active " + this.tabId + "=" + state);
17838 this.active = state;
17840 this.el.removeClass('active');
17842 } else if (!this.el.hasClass('active')) {
17843 this.el.addClass('active');
17846 this.fireEvent('changed', this, state);
17849 onClick : function(e)
17851 e.preventDefault();
17853 if(!this.href.length){
17857 window.location.href = this.href;
17866 onTouchStart : function(e)
17868 this.swiping = false;
17870 this.startX = e.browserEvent.touches[0].clientX;
17871 this.startY = e.browserEvent.touches[0].clientY;
17874 onTouchMove : function(e)
17876 this.swiping = true;
17878 this.endX = e.browserEvent.touches[0].clientX;
17879 this.endY = e.browserEvent.touches[0].clientY;
17882 onTouchEnd : function(e)
17889 var tabGroup = this.parent();
17891 if(this.endX > this.startX){ // swiping right
17892 tabGroup.showPanelPrev();
17896 if(this.startX > this.endX){ // swiping left
17897 tabGroup.showPanelNext();
17916 * @class Roo.bootstrap.DateField
17917 * @extends Roo.bootstrap.Input
17918 * Bootstrap DateField class
17919 * @cfg {Number} weekStart default 0
17920 * @cfg {String} viewMode default empty, (months|years)
17921 * @cfg {String} minViewMode default empty, (months|years)
17922 * @cfg {Number} startDate default -Infinity
17923 * @cfg {Number} endDate default Infinity
17924 * @cfg {Boolean} todayHighlight default false
17925 * @cfg {Boolean} todayBtn default false
17926 * @cfg {Boolean} calendarWeeks default false
17927 * @cfg {Object} daysOfWeekDisabled default empty
17928 * @cfg {Boolean} singleMode default false (true | false)
17930 * @cfg {Boolean} keyboardNavigation default true
17931 * @cfg {String} language default en
17934 * Create a new DateField
17935 * @param {Object} config The config object
17938 Roo.bootstrap.DateField = function(config){
17939 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
17943 * Fires when this field show.
17944 * @param {Roo.bootstrap.DateField} this
17945 * @param {Mixed} date The date value
17950 * Fires when this field hide.
17951 * @param {Roo.bootstrap.DateField} this
17952 * @param {Mixed} date The date value
17957 * Fires when select a date.
17958 * @param {Roo.bootstrap.DateField} this
17959 * @param {Mixed} date The date value
17963 * @event beforeselect
17964 * Fires when before select a date.
17965 * @param {Roo.bootstrap.DateField} this
17966 * @param {Mixed} date The date value
17968 beforeselect : true
17972 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
17975 * @cfg {String} format
17976 * The default date format string which can be overriden for localization support. The format must be
17977 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
17981 * @cfg {String} altFormats
17982 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
17983 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
17985 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
17993 todayHighlight : false,
17999 keyboardNavigation: true,
18001 calendarWeeks: false,
18003 startDate: -Infinity,
18007 daysOfWeekDisabled: [],
18011 singleMode : false,
18013 UTCDate: function()
18015 return new Date(Date.UTC.apply(Date, arguments));
18018 UTCToday: function()
18020 var today = new Date();
18021 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18024 getDate: function() {
18025 var d = this.getUTCDate();
18026 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18029 getUTCDate: function() {
18033 setDate: function(d) {
18034 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18037 setUTCDate: function(d) {
18039 this.setValue(this.formatDate(this.date));
18042 onRender: function(ct, position)
18045 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18047 this.language = this.language || 'en';
18048 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18049 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18051 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18052 this.format = this.format || 'm/d/y';
18053 this.isInline = false;
18054 this.isInput = true;
18055 this.component = this.el.select('.add-on', true).first() || false;
18056 this.component = (this.component && this.component.length === 0) ? false : this.component;
18057 this.hasInput = this.component && this.inputEl().length;
18059 if (typeof(this.minViewMode === 'string')) {
18060 switch (this.minViewMode) {
18062 this.minViewMode = 1;
18065 this.minViewMode = 2;
18068 this.minViewMode = 0;
18073 if (typeof(this.viewMode === 'string')) {
18074 switch (this.viewMode) {
18087 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18089 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18091 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18093 this.picker().on('mousedown', this.onMousedown, this);
18094 this.picker().on('click', this.onClick, this);
18096 this.picker().addClass('datepicker-dropdown');
18098 this.startViewMode = this.viewMode;
18100 if(this.singleMode){
18101 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18102 v.setVisibilityMode(Roo.Element.DISPLAY);
18106 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18107 v.setStyle('width', '189px');
18111 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18112 if(!this.calendarWeeks){
18117 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18118 v.attr('colspan', function(i, val){
18119 return parseInt(val) + 1;
18124 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18126 this.setStartDate(this.startDate);
18127 this.setEndDate(this.endDate);
18129 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18136 if(this.isInline) {
18141 picker : function()
18143 return this.pickerEl;
18144 // return this.el.select('.datepicker', true).first();
18147 fillDow: function()
18149 var dowCnt = this.weekStart;
18158 if(this.calendarWeeks){
18166 while (dowCnt < this.weekStart + 7) {
18170 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18174 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18177 fillMonths: function()
18180 var months = this.picker().select('>.datepicker-months td', true).first();
18182 months.dom.innerHTML = '';
18188 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18191 months.createChild(month);
18198 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;
18200 if (this.date < this.startDate) {
18201 this.viewDate = new Date(this.startDate);
18202 } else if (this.date > this.endDate) {
18203 this.viewDate = new Date(this.endDate);
18205 this.viewDate = new Date(this.date);
18213 var d = new Date(this.viewDate),
18214 year = d.getUTCFullYear(),
18215 month = d.getUTCMonth(),
18216 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18217 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18218 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18219 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18220 currentDate = this.date && this.date.valueOf(),
18221 today = this.UTCToday();
18223 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18225 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18227 // this.picker.select('>tfoot th.today').
18228 // .text(dates[this.language].today)
18229 // .toggle(this.todayBtn !== false);
18231 this.updateNavArrows();
18234 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18236 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18238 prevMonth.setUTCDate(day);
18240 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18242 var nextMonth = new Date(prevMonth);
18244 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18246 nextMonth = nextMonth.valueOf();
18248 var fillMonths = false;
18250 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18252 while(prevMonth.valueOf() < nextMonth) {
18255 if (prevMonth.getUTCDay() === this.weekStart) {
18257 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18265 if(this.calendarWeeks){
18266 // ISO 8601: First week contains first thursday.
18267 // ISO also states week starts on Monday, but we can be more abstract here.
18269 // Start of current week: based on weekstart/current date
18270 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18271 // Thursday of this week
18272 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18273 // First Thursday of year, year from thursday
18274 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18275 // Calendar week: ms between thursdays, div ms per day, div 7 days
18276 calWeek = (th - yth) / 864e5 / 7 + 1;
18278 fillMonths.cn.push({
18286 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18288 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18291 if (this.todayHighlight &&
18292 prevMonth.getUTCFullYear() == today.getFullYear() &&
18293 prevMonth.getUTCMonth() == today.getMonth() &&
18294 prevMonth.getUTCDate() == today.getDate()) {
18295 clsName += ' today';
18298 if (currentDate && prevMonth.valueOf() === currentDate) {
18299 clsName += ' active';
18302 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18303 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18304 clsName += ' disabled';
18307 fillMonths.cn.push({
18309 cls: 'day ' + clsName,
18310 html: prevMonth.getDate()
18313 prevMonth.setDate(prevMonth.getDate()+1);
18316 var currentYear = this.date && this.date.getUTCFullYear();
18317 var currentMonth = this.date && this.date.getUTCMonth();
18319 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18321 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18322 v.removeClass('active');
18324 if(currentYear === year && k === currentMonth){
18325 v.addClass('active');
18328 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18329 v.addClass('disabled');
18335 year = parseInt(year/10, 10) * 10;
18337 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18339 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18342 for (var i = -1; i < 11; i++) {
18343 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18345 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18353 showMode: function(dir)
18356 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18359 Roo.each(this.picker().select('>div',true).elements, function(v){
18360 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18363 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18368 if(this.isInline) {
18372 this.picker().removeClass(['bottom', 'top']);
18374 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18376 * place to the top of element!
18380 this.picker().addClass('top');
18381 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18386 this.picker().addClass('bottom');
18388 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18391 parseDate : function(value)
18393 if(!value || value instanceof Date){
18396 var v = Date.parseDate(value, this.format);
18397 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18398 v = Date.parseDate(value, 'Y-m-d');
18400 if(!v && this.altFormats){
18401 if(!this.altFormatsArray){
18402 this.altFormatsArray = this.altFormats.split("|");
18404 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18405 v = Date.parseDate(value, this.altFormatsArray[i]);
18411 formatDate : function(date, fmt)
18413 return (!date || !(date instanceof Date)) ?
18414 date : date.dateFormat(fmt || this.format);
18417 onFocus : function()
18419 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18423 onBlur : function()
18425 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18427 var d = this.inputEl().getValue();
18436 this.picker().show();
18440 this.fireEvent('show', this, this.date);
18445 if(this.isInline) {
18448 this.picker().hide();
18449 this.viewMode = this.startViewMode;
18452 this.fireEvent('hide', this, this.date);
18456 onMousedown: function(e)
18458 e.stopPropagation();
18459 e.preventDefault();
18464 Roo.bootstrap.DateField.superclass.keyup.call(this);
18468 setValue: function(v)
18470 if(this.fireEvent('beforeselect', this, v) !== false){
18471 var d = new Date(this.parseDate(v) ).clearTime();
18473 if(isNaN(d.getTime())){
18474 this.date = this.viewDate = '';
18475 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18479 v = this.formatDate(d);
18481 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18483 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18487 this.fireEvent('select', this, this.date);
18491 getValue: function()
18493 return this.formatDate(this.date);
18496 fireKey: function(e)
18498 if (!this.picker().isVisible()){
18499 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18505 var dateChanged = false,
18507 newDate, newViewDate;
18512 e.preventDefault();
18516 if (!this.keyboardNavigation) {
18519 dir = e.keyCode == 37 ? -1 : 1;
18522 newDate = this.moveYear(this.date, dir);
18523 newViewDate = this.moveYear(this.viewDate, dir);
18524 } else if (e.shiftKey){
18525 newDate = this.moveMonth(this.date, dir);
18526 newViewDate = this.moveMonth(this.viewDate, dir);
18528 newDate = new Date(this.date);
18529 newDate.setUTCDate(this.date.getUTCDate() + dir);
18530 newViewDate = new Date(this.viewDate);
18531 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18533 if (this.dateWithinRange(newDate)){
18534 this.date = newDate;
18535 this.viewDate = newViewDate;
18536 this.setValue(this.formatDate(this.date));
18538 e.preventDefault();
18539 dateChanged = true;
18544 if (!this.keyboardNavigation) {
18547 dir = e.keyCode == 38 ? -1 : 1;
18549 newDate = this.moveYear(this.date, dir);
18550 newViewDate = this.moveYear(this.viewDate, dir);
18551 } else if (e.shiftKey){
18552 newDate = this.moveMonth(this.date, dir);
18553 newViewDate = this.moveMonth(this.viewDate, dir);
18555 newDate = new Date(this.date);
18556 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18557 newViewDate = new Date(this.viewDate);
18558 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18560 if (this.dateWithinRange(newDate)){
18561 this.date = newDate;
18562 this.viewDate = newViewDate;
18563 this.setValue(this.formatDate(this.date));
18565 e.preventDefault();
18566 dateChanged = true;
18570 this.setValue(this.formatDate(this.date));
18572 e.preventDefault();
18575 this.setValue(this.formatDate(this.date));
18589 onClick: function(e)
18591 e.stopPropagation();
18592 e.preventDefault();
18594 var target = e.getTarget();
18596 if(target.nodeName.toLowerCase() === 'i'){
18597 target = Roo.get(target).dom.parentNode;
18600 var nodeName = target.nodeName;
18601 var className = target.className;
18602 var html = target.innerHTML;
18603 //Roo.log(nodeName);
18605 switch(nodeName.toLowerCase()) {
18607 switch(className) {
18613 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18614 switch(this.viewMode){
18616 this.viewDate = this.moveMonth(this.viewDate, dir);
18620 this.viewDate = this.moveYear(this.viewDate, dir);
18626 var date = new Date();
18627 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18629 this.setValue(this.formatDate(this.date));
18636 if (className.indexOf('disabled') < 0) {
18637 this.viewDate.setUTCDate(1);
18638 if (className.indexOf('month') > -1) {
18639 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18641 var year = parseInt(html, 10) || 0;
18642 this.viewDate.setUTCFullYear(year);
18646 if(this.singleMode){
18647 this.setValue(this.formatDate(this.viewDate));
18658 //Roo.log(className);
18659 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
18660 var day = parseInt(html, 10) || 1;
18661 var year = this.viewDate.getUTCFullYear(),
18662 month = this.viewDate.getUTCMonth();
18664 if (className.indexOf('old') > -1) {
18671 } else if (className.indexOf('new') > -1) {
18679 //Roo.log([year,month,day]);
18680 this.date = this.UTCDate(year, month, day,0,0,0,0);
18681 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
18683 //Roo.log(this.formatDate(this.date));
18684 this.setValue(this.formatDate(this.date));
18691 setStartDate: function(startDate)
18693 this.startDate = startDate || -Infinity;
18694 if (this.startDate !== -Infinity) {
18695 this.startDate = this.parseDate(this.startDate);
18698 this.updateNavArrows();
18701 setEndDate: function(endDate)
18703 this.endDate = endDate || Infinity;
18704 if (this.endDate !== Infinity) {
18705 this.endDate = this.parseDate(this.endDate);
18708 this.updateNavArrows();
18711 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
18713 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
18714 if (typeof(this.daysOfWeekDisabled) !== 'object') {
18715 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
18717 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
18718 return parseInt(d, 10);
18721 this.updateNavArrows();
18724 updateNavArrows: function()
18726 if(this.singleMode){
18730 var d = new Date(this.viewDate),
18731 year = d.getUTCFullYear(),
18732 month = d.getUTCMonth();
18734 Roo.each(this.picker().select('.prev', true).elements, function(v){
18736 switch (this.viewMode) {
18739 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
18745 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
18752 Roo.each(this.picker().select('.next', true).elements, function(v){
18754 switch (this.viewMode) {
18757 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
18763 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
18771 moveMonth: function(date, dir)
18776 var new_date = new Date(date.valueOf()),
18777 day = new_date.getUTCDate(),
18778 month = new_date.getUTCMonth(),
18779 mag = Math.abs(dir),
18781 dir = dir > 0 ? 1 : -1;
18784 // If going back one month, make sure month is not current month
18785 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
18787 return new_date.getUTCMonth() == month;
18789 // If going forward one month, make sure month is as expected
18790 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
18792 return new_date.getUTCMonth() != new_month;
18794 new_month = month + dir;
18795 new_date.setUTCMonth(new_month);
18796 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
18797 if (new_month < 0 || new_month > 11) {
18798 new_month = (new_month + 12) % 12;
18801 // For magnitudes >1, move one month at a time...
18802 for (var i=0; i<mag; i++) {
18803 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
18804 new_date = this.moveMonth(new_date, dir);
18806 // ...then reset the day, keeping it in the new month
18807 new_month = new_date.getUTCMonth();
18808 new_date.setUTCDate(day);
18810 return new_month != new_date.getUTCMonth();
18813 // Common date-resetting loop -- if date is beyond end of month, make it
18816 new_date.setUTCDate(--day);
18817 new_date.setUTCMonth(new_month);
18822 moveYear: function(date, dir)
18824 return this.moveMonth(date, dir*12);
18827 dateWithinRange: function(date)
18829 return date >= this.startDate && date <= this.endDate;
18835 this.picker().remove();
18838 validateValue : function(value)
18840 if(value.length < 1) {
18841 if(this.allowBlank){
18847 if(value.length < this.minLength){
18850 if(value.length > this.maxLength){
18854 var vt = Roo.form.VTypes;
18855 if(!vt[this.vtype](value, this)){
18859 if(typeof this.validator == "function"){
18860 var msg = this.validator(value);
18866 if(this.regex && !this.regex.test(value)){
18870 if(typeof(this.parseDate(value)) == 'undefined'){
18874 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
18878 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
18888 Roo.apply(Roo.bootstrap.DateField, {
18899 html: '<i class="fa fa-arrow-left"/>'
18909 html: '<i class="fa fa-arrow-right"/>'
18951 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
18952 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
18953 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
18954 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
18955 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
18968 navFnc: 'FullYear',
18973 navFnc: 'FullYear',
18978 Roo.apply(Roo.bootstrap.DateField, {
18982 cls: 'datepicker dropdown-menu roo-dynamic',
18986 cls: 'datepicker-days',
18990 cls: 'table-condensed',
18992 Roo.bootstrap.DateField.head,
18996 Roo.bootstrap.DateField.footer
19003 cls: 'datepicker-months',
19007 cls: 'table-condensed',
19009 Roo.bootstrap.DateField.head,
19010 Roo.bootstrap.DateField.content,
19011 Roo.bootstrap.DateField.footer
19018 cls: 'datepicker-years',
19022 cls: 'table-condensed',
19024 Roo.bootstrap.DateField.head,
19025 Roo.bootstrap.DateField.content,
19026 Roo.bootstrap.DateField.footer
19045 * @class Roo.bootstrap.TimeField
19046 * @extends Roo.bootstrap.Input
19047 * Bootstrap DateField class
19051 * Create a new TimeField
19052 * @param {Object} config The config object
19055 Roo.bootstrap.TimeField = function(config){
19056 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19060 * Fires when this field show.
19061 * @param {Roo.bootstrap.DateField} thisthis
19062 * @param {Mixed} date The date value
19067 * Fires when this field hide.
19068 * @param {Roo.bootstrap.DateField} this
19069 * @param {Mixed} date The date value
19074 * Fires when select a date.
19075 * @param {Roo.bootstrap.DateField} this
19076 * @param {Mixed} date The date value
19082 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19085 * @cfg {String} format
19086 * The default time format string which can be overriden for localization support. The format must be
19087 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19091 onRender: function(ct, position)
19094 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19096 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19098 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19100 this.pop = this.picker().select('>.datepicker-time',true).first();
19101 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19103 this.picker().on('mousedown', this.onMousedown, this);
19104 this.picker().on('click', this.onClick, this);
19106 this.picker().addClass('datepicker-dropdown');
19111 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19112 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19113 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19114 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19115 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19116 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19120 fireKey: function(e){
19121 if (!this.picker().isVisible()){
19122 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19128 e.preventDefault();
19136 this.onTogglePeriod();
19139 this.onIncrementMinutes();
19142 this.onDecrementMinutes();
19151 onClick: function(e) {
19152 e.stopPropagation();
19153 e.preventDefault();
19156 picker : function()
19158 return this.el.select('.datepicker', true).first();
19161 fillTime: function()
19163 var time = this.pop.select('tbody', true).first();
19165 time.dom.innerHTML = '';
19180 cls: 'hours-up glyphicon glyphicon-chevron-up'
19200 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19221 cls: 'timepicker-hour',
19236 cls: 'timepicker-minute',
19251 cls: 'btn btn-primary period',
19273 cls: 'hours-down glyphicon glyphicon-chevron-down'
19293 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19311 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19318 var hours = this.time.getHours();
19319 var minutes = this.time.getMinutes();
19332 hours = hours - 12;
19336 hours = '0' + hours;
19340 minutes = '0' + minutes;
19343 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19344 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19345 this.pop.select('button', true).first().dom.innerHTML = period;
19351 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19353 var cls = ['bottom'];
19355 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19362 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19367 this.picker().addClass(cls.join('-'));
19371 Roo.each(cls, function(c){
19373 _this.picker().setTop(_this.inputEl().getHeight());
19377 _this.picker().setTop(0 - _this.picker().getHeight());
19382 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19386 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19393 onFocus : function()
19395 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19399 onBlur : function()
19401 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19407 this.picker().show();
19412 this.fireEvent('show', this, this.date);
19417 this.picker().hide();
19420 this.fireEvent('hide', this, this.date);
19423 setTime : function()
19426 this.setValue(this.time.format(this.format));
19428 this.fireEvent('select', this, this.date);
19433 onMousedown: function(e){
19434 e.stopPropagation();
19435 e.preventDefault();
19438 onIncrementHours: function()
19440 Roo.log('onIncrementHours');
19441 this.time = this.time.add(Date.HOUR, 1);
19446 onDecrementHours: function()
19448 Roo.log('onDecrementHours');
19449 this.time = this.time.add(Date.HOUR, -1);
19453 onIncrementMinutes: function()
19455 Roo.log('onIncrementMinutes');
19456 this.time = this.time.add(Date.MINUTE, 1);
19460 onDecrementMinutes: function()
19462 Roo.log('onDecrementMinutes');
19463 this.time = this.time.add(Date.MINUTE, -1);
19467 onTogglePeriod: function()
19469 Roo.log('onTogglePeriod');
19470 this.time = this.time.add(Date.HOUR, 12);
19477 Roo.apply(Roo.bootstrap.TimeField, {
19507 cls: 'btn btn-info ok',
19519 Roo.apply(Roo.bootstrap.TimeField, {
19523 cls: 'datepicker dropdown-menu',
19527 cls: 'datepicker-time',
19531 cls: 'table-condensed',
19533 Roo.bootstrap.TimeField.content,
19534 Roo.bootstrap.TimeField.footer
19553 * @class Roo.bootstrap.MonthField
19554 * @extends Roo.bootstrap.Input
19555 * Bootstrap MonthField class
19557 * @cfg {String} language default en
19560 * Create a new MonthField
19561 * @param {Object} config The config object
19564 Roo.bootstrap.MonthField = function(config){
19565 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19570 * Fires when this field show.
19571 * @param {Roo.bootstrap.MonthField} this
19572 * @param {Mixed} date The date value
19577 * Fires when this field hide.
19578 * @param {Roo.bootstrap.MonthField} this
19579 * @param {Mixed} date The date value
19584 * Fires when select a date.
19585 * @param {Roo.bootstrap.MonthField} this
19586 * @param {String} oldvalue The old value
19587 * @param {String} newvalue The new value
19593 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19595 onRender: function(ct, position)
19598 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19600 this.language = this.language || 'en';
19601 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19602 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19604 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19605 this.isInline = false;
19606 this.isInput = true;
19607 this.component = this.el.select('.add-on', true).first() || false;
19608 this.component = (this.component && this.component.length === 0) ? false : this.component;
19609 this.hasInput = this.component && this.inputEL().length;
19611 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19613 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19615 this.picker().on('mousedown', this.onMousedown, this);
19616 this.picker().on('click', this.onClick, this);
19618 this.picker().addClass('datepicker-dropdown');
19620 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19621 v.setStyle('width', '189px');
19628 if(this.isInline) {
19634 setValue: function(v, suppressEvent)
19636 var o = this.getValue();
19638 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
19642 if(suppressEvent !== true){
19643 this.fireEvent('select', this, o, v);
19648 getValue: function()
19653 onClick: function(e)
19655 e.stopPropagation();
19656 e.preventDefault();
19658 var target = e.getTarget();
19660 if(target.nodeName.toLowerCase() === 'i'){
19661 target = Roo.get(target).dom.parentNode;
19664 var nodeName = target.nodeName;
19665 var className = target.className;
19666 var html = target.innerHTML;
19668 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
19672 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
19674 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19680 picker : function()
19682 return this.pickerEl;
19685 fillMonths: function()
19688 var months = this.picker().select('>.datepicker-months td', true).first();
19690 months.dom.innerHTML = '';
19696 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
19699 months.createChild(month);
19708 if(typeof(this.vIndex) == 'undefined' && this.value.length){
19709 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
19712 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
19713 e.removeClass('active');
19715 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
19716 e.addClass('active');
19723 if(this.isInline) {
19727 this.picker().removeClass(['bottom', 'top']);
19729 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19731 * place to the top of element!
19735 this.picker().addClass('top');
19736 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19741 this.picker().addClass('bottom');
19743 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19746 onFocus : function()
19748 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
19752 onBlur : function()
19754 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
19756 var d = this.inputEl().getValue();
19765 this.picker().show();
19766 this.picker().select('>.datepicker-months', true).first().show();
19770 this.fireEvent('show', this, this.date);
19775 if(this.isInline) {
19778 this.picker().hide();
19779 this.fireEvent('hide', this, this.date);
19783 onMousedown: function(e)
19785 e.stopPropagation();
19786 e.preventDefault();
19791 Roo.bootstrap.MonthField.superclass.keyup.call(this);
19795 fireKey: function(e)
19797 if (!this.picker().isVisible()){
19798 if (e.keyCode == 27) {// allow escape to hide and re-show picker
19809 e.preventDefault();
19813 dir = e.keyCode == 37 ? -1 : 1;
19815 this.vIndex = this.vIndex + dir;
19817 if(this.vIndex < 0){
19821 if(this.vIndex > 11){
19825 if(isNaN(this.vIndex)){
19829 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19835 dir = e.keyCode == 38 ? -1 : 1;
19837 this.vIndex = this.vIndex + dir * 4;
19839 if(this.vIndex < 0){
19843 if(this.vIndex > 11){
19847 if(isNaN(this.vIndex)){
19851 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19856 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19857 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19861 e.preventDefault();
19864 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
19865 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
19881 this.picker().remove();
19886 Roo.apply(Roo.bootstrap.MonthField, {
19905 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19906 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
19911 Roo.apply(Roo.bootstrap.MonthField, {
19915 cls: 'datepicker dropdown-menu roo-dynamic',
19919 cls: 'datepicker-months',
19923 cls: 'table-condensed',
19925 Roo.bootstrap.DateField.content
19945 * @class Roo.bootstrap.CheckBox
19946 * @extends Roo.bootstrap.Input
19947 * Bootstrap CheckBox class
19949 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
19950 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
19951 * @cfg {String} boxLabel The text that appears beside the checkbox
19952 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
19953 * @cfg {Boolean} checked initnal the element
19954 * @cfg {Boolean} inline inline the element (default false)
19955 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
19958 * Create a new CheckBox
19959 * @param {Object} config The config object
19962 Roo.bootstrap.CheckBox = function(config){
19963 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
19968 * Fires when the element is checked or unchecked.
19969 * @param {Roo.bootstrap.CheckBox} this This input
19970 * @param {Boolean} checked The new checked value
19977 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
19979 inputType: 'checkbox',
19987 getAutoCreate : function()
19989 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
19995 cfg.cls = 'form-group ' + this.inputType; //input-group
19998 cfg.cls += ' ' + this.inputType + '-inline';
20004 type : this.inputType,
20005 value : this.inputValue,
20006 cls : 'roo-' + this.inputType, //'form-box',
20007 placeholder : this.placeholder || ''
20011 if(this.inputType != 'radio'){
20015 cls : 'roo-hidden-value',
20016 value : this.checked ? this.valueOff : this.inputValue
20021 if (this.weight) { // Validity check?
20022 cfg.cls += " " + this.inputType + "-" + this.weight;
20025 if (this.disabled) {
20026 input.disabled=true;
20030 input.checked = this.checked;
20037 input.name = this.name;
20039 if(this.inputType != 'radio'){
20040 hidden.name = this.name;
20041 input.name = '_hidden_' + this.name;
20046 input.cls += ' input-' + this.size;
20051 ['xs','sm','md','lg'].map(function(size){
20052 if (settings[size]) {
20053 cfg.cls += ' col-' + size + '-' + settings[size];
20057 var inputblock = input;
20059 if (this.before || this.after) {
20062 cls : 'input-group',
20067 inputblock.cn.push({
20069 cls : 'input-group-addon',
20074 inputblock.cn.push(input);
20076 if(this.inputType != 'radio'){
20077 inputblock.cn.push(hidden);
20081 inputblock.cn.push({
20083 cls : 'input-group-addon',
20090 if (align ==='left' && this.fieldLabel.length) {
20091 // Roo.log("left and has label");
20096 cls : 'control-label',
20097 html : this.fieldLabel
20108 if(this.labelWidth > 12){
20109 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20112 if(this.labelWidth < 13 && this.labelmd == 0){
20113 this.labelmd = this.labelWidth;
20116 if(this.labellg > 0){
20117 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20118 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20121 if(this.labelmd > 0){
20122 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20123 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20126 if(this.labelsm > 0){
20127 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20128 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20131 if(this.labelxs > 0){
20132 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20133 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20136 } else if ( this.fieldLabel.length) {
20137 // Roo.log(" label");
20141 tag: this.boxLabel ? 'span' : 'label',
20143 cls: 'control-label box-input-label',
20144 //cls : 'input-group-addon',
20145 html : this.fieldLabel
20155 // Roo.log(" no label && no align");
20156 cfg.cn = [ inputblock ] ;
20162 var boxLabelCfg = {
20164 //'for': id, // box label is handled by onclick - so no for...
20166 html: this.boxLabel
20170 boxLabelCfg.tooltip = this.tooltip;
20173 cfg.cn.push(boxLabelCfg);
20176 if(this.inputType != 'radio'){
20177 cfg.cn.push(hidden);
20185 * return the real input element.
20187 inputEl: function ()
20189 return this.el.select('input.roo-' + this.inputType,true).first();
20191 hiddenEl: function ()
20193 return this.el.select('input.roo-hidden-value',true).first();
20196 labelEl: function()
20198 return this.el.select('label.control-label',true).first();
20200 /* depricated... */
20204 return this.labelEl();
20207 boxLabelEl: function()
20209 return this.el.select('label.box-label',true).first();
20212 initEvents : function()
20214 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20216 this.inputEl().on('click', this.onClick, this);
20218 if (this.boxLabel) {
20219 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20222 this.startValue = this.getValue();
20225 Roo.bootstrap.CheckBox.register(this);
20229 onClick : function()
20231 this.setChecked(!this.checked);
20234 setChecked : function(state,suppressEvent)
20236 this.startValue = this.getValue();
20238 if(this.inputType == 'radio'){
20240 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20241 e.dom.checked = false;
20244 this.inputEl().dom.checked = true;
20246 this.inputEl().dom.value = this.inputValue;
20248 if(suppressEvent !== true){
20249 this.fireEvent('check', this, true);
20257 this.checked = state;
20259 this.inputEl().dom.checked = state;
20262 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20264 if(suppressEvent !== true){
20265 this.fireEvent('check', this, state);
20271 getValue : function()
20273 if(this.inputType == 'radio'){
20274 return this.getGroupValue();
20277 return this.hiddenEl().dom.value;
20281 getGroupValue : function()
20283 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20287 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20290 setValue : function(v,suppressEvent)
20292 if(this.inputType == 'radio'){
20293 this.setGroupValue(v, suppressEvent);
20297 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20302 setGroupValue : function(v, suppressEvent)
20304 this.startValue = this.getValue();
20306 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20307 e.dom.checked = false;
20309 if(e.dom.value == v){
20310 e.dom.checked = true;
20314 if(suppressEvent !== true){
20315 this.fireEvent('check', this, true);
20323 validate : function()
20327 (this.inputType == 'radio' && this.validateRadio()) ||
20328 (this.inputType == 'checkbox' && this.validateCheckbox())
20334 this.markInvalid();
20338 validateRadio : function()
20340 if(this.allowBlank){
20346 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20347 if(!e.dom.checked){
20359 validateCheckbox : function()
20362 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20363 //return (this.getValue() == this.inputValue) ? true : false;
20366 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20374 for(var i in group){
20379 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20386 * Mark this field as valid
20388 markValid : function()
20392 this.fireEvent('valid', this);
20394 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20397 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20404 if(this.inputType == 'radio'){
20405 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20406 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20407 e.findParent('.form-group', false, true).addClass(_this.validClass);
20414 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20415 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20419 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20425 for(var i in group){
20426 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20427 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20432 * Mark this field as invalid
20433 * @param {String} msg The validation message
20435 markInvalid : function(msg)
20437 if(this.allowBlank){
20443 this.fireEvent('invalid', this, msg);
20445 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20448 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20452 label.markInvalid();
20455 if(this.inputType == 'radio'){
20456 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20457 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20458 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20465 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20466 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20470 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20476 for(var i in group){
20477 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20478 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20483 clearInvalid : function()
20485 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20487 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20489 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20492 label.iconEl.removeClass(label.validClass);
20493 label.iconEl.removeClass(label.invalidClass);
20497 disable : function()
20499 if(this.inputType != 'radio'){
20500 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20507 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20508 _this.getActionEl().addClass(this.disabledClass);
20509 e.dom.disabled = true;
20513 this.disabled = true;
20514 this.fireEvent("disable", this);
20518 enable : function()
20520 if(this.inputType != 'radio'){
20521 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20528 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20529 _this.getActionEl().removeClass(this.disabledClass);
20530 e.dom.disabled = false;
20534 this.disabled = false;
20535 this.fireEvent("enable", this);
20541 Roo.apply(Roo.bootstrap.CheckBox, {
20546 * register a CheckBox Group
20547 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20549 register : function(checkbox)
20551 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20552 this.groups[checkbox.groupId] = {};
20555 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20559 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20563 * fetch a CheckBox Group based on the group ID
20564 * @param {string} the group ID
20565 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20567 get: function(groupId) {
20568 if (typeof(this.groups[groupId]) == 'undefined') {
20572 return this.groups[groupId] ;
20585 * @class Roo.bootstrap.Radio
20586 * @extends Roo.bootstrap.Component
20587 * Bootstrap Radio class
20588 * @cfg {String} boxLabel - the label associated
20589 * @cfg {String} value - the value of radio
20592 * Create a new Radio
20593 * @param {Object} config The config object
20595 Roo.bootstrap.Radio = function(config){
20596 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20600 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
20606 getAutoCreate : function()
20610 cls : 'form-group radio',
20615 html : this.boxLabel
20623 initEvents : function()
20625 this.parent().register(this);
20627 this.el.on('click', this.onClick, this);
20631 onClick : function()
20633 this.setChecked(true);
20636 setChecked : function(state, suppressEvent)
20638 this.parent().setValue(this.value, suppressEvent);
20645 //<script type="text/javascript">
20648 * Based Ext JS Library 1.1.1
20649 * Copyright(c) 2006-2007, Ext JS, LLC.
20655 * @class Roo.HtmlEditorCore
20656 * @extends Roo.Component
20657 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
20659 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
20662 Roo.HtmlEditorCore = function(config){
20665 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
20670 * @event initialize
20671 * Fires when the editor is fully initialized (including the iframe)
20672 * @param {Roo.HtmlEditorCore} this
20677 * Fires when the editor is first receives the focus. Any insertion must wait
20678 * until after this event.
20679 * @param {Roo.HtmlEditorCore} this
20683 * @event beforesync
20684 * Fires before the textarea is updated with content from the editor iframe. Return false
20685 * to cancel the sync.
20686 * @param {Roo.HtmlEditorCore} this
20687 * @param {String} html
20691 * @event beforepush
20692 * Fires before the iframe editor is updated with content from the textarea. Return false
20693 * to cancel the push.
20694 * @param {Roo.HtmlEditorCore} this
20695 * @param {String} html
20700 * Fires when the textarea is updated with content from the editor iframe.
20701 * @param {Roo.HtmlEditorCore} this
20702 * @param {String} html
20707 * Fires when the iframe editor is updated with content from the textarea.
20708 * @param {Roo.HtmlEditorCore} this
20709 * @param {String} html
20714 * @event editorevent
20715 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
20716 * @param {Roo.HtmlEditorCore} this
20722 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
20724 // defaults : white / black...
20725 this.applyBlacklists();
20732 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
20736 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
20742 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
20747 * @cfg {Number} height (in pixels)
20751 * @cfg {Number} width (in pixels)
20756 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
20759 stylesheets: false,
20764 // private properties
20765 validationEvent : false,
20767 initialized : false,
20769 sourceEditMode : false,
20770 onFocus : Roo.emptyFn,
20772 hideMode:'offsets',
20776 // blacklist + whitelisted elements..
20783 * Protected method that will not generally be called directly. It
20784 * is called when the editor initializes the iframe with HTML contents. Override this method if you
20785 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
20787 getDocMarkup : function(){
20791 // inherit styels from page...??
20792 if (this.stylesheets === false) {
20794 Roo.get(document.head).select('style').each(function(node) {
20795 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20798 Roo.get(document.head).select('link').each(function(node) {
20799 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
20802 } else if (!this.stylesheets.length) {
20804 st = '<style type="text/css">' +
20805 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20811 st += '<style type="text/css">' +
20812 'IMG { cursor: pointer } ' +
20816 return '<html><head>' + st +
20817 //<style type="text/css">' +
20818 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
20820 ' </head><body class="roo-htmleditor-body"></body></html>';
20824 onRender : function(ct, position)
20827 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
20828 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
20831 this.el.dom.style.border = '0 none';
20832 this.el.dom.setAttribute('tabIndex', -1);
20833 this.el.addClass('x-hidden hide');
20837 if(Roo.isIE){ // fix IE 1px bogus margin
20838 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
20842 this.frameId = Roo.id();
20846 var iframe = this.owner.wrap.createChild({
20848 cls: 'form-control', // bootstrap..
20850 name: this.frameId,
20851 frameBorder : 'no',
20852 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
20857 this.iframe = iframe.dom;
20859 this.assignDocWin();
20861 this.doc.designMode = 'on';
20864 this.doc.write(this.getDocMarkup());
20868 var task = { // must defer to wait for browser to be ready
20870 //console.log("run task?" + this.doc.readyState);
20871 this.assignDocWin();
20872 if(this.doc.body || this.doc.readyState == 'complete'){
20874 this.doc.designMode="on";
20878 Roo.TaskMgr.stop(task);
20879 this.initEditor.defer(10, this);
20886 Roo.TaskMgr.start(task);
20891 onResize : function(w, h)
20893 Roo.log('resize: ' +w + ',' + h );
20894 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
20898 if(typeof w == 'number'){
20900 this.iframe.style.width = w + 'px';
20902 if(typeof h == 'number'){
20904 this.iframe.style.height = h + 'px';
20906 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
20913 * Toggles the editor between standard and source edit mode.
20914 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
20916 toggleSourceEdit : function(sourceEditMode){
20918 this.sourceEditMode = sourceEditMode === true;
20920 if(this.sourceEditMode){
20922 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
20925 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
20926 //this.iframe.className = '';
20929 //this.setSize(this.owner.wrap.getSize());
20930 //this.fireEvent('editmodechange', this, this.sourceEditMode);
20937 * Protected method that will not generally be called directly. If you need/want
20938 * custom HTML cleanup, this is the method you should override.
20939 * @param {String} html The HTML to be cleaned
20940 * return {String} The cleaned HTML
20942 cleanHtml : function(html){
20943 html = String(html);
20944 if(html.length > 5){
20945 if(Roo.isSafari){ // strip safari nonsense
20946 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
20949 if(html == ' '){
20956 * HTML Editor -> Textarea
20957 * Protected method that will not generally be called directly. Syncs the contents
20958 * of the editor iframe with the textarea.
20960 syncValue : function(){
20961 if(this.initialized){
20962 var bd = (this.doc.body || this.doc.documentElement);
20963 //this.cleanUpPaste(); -- this is done else where and causes havoc..
20964 var html = bd.innerHTML;
20966 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
20967 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
20969 html = '<div style="'+m[0]+'">' + html + '</div>';
20972 html = this.cleanHtml(html);
20973 // fix up the special chars.. normaly like back quotes in word...
20974 // however we do not want to do this with chinese..
20975 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
20976 var cc = b.charCodeAt();
20978 (cc >= 0x4E00 && cc < 0xA000 ) ||
20979 (cc >= 0x3400 && cc < 0x4E00 ) ||
20980 (cc >= 0xf900 && cc < 0xfb00 )
20986 if(this.owner.fireEvent('beforesync', this, html) !== false){
20987 this.el.dom.value = html;
20988 this.owner.fireEvent('sync', this, html);
20994 * Protected method that will not generally be called directly. Pushes the value of the textarea
20995 * into the iframe editor.
20997 pushValue : function(){
20998 if(this.initialized){
20999 var v = this.el.dom.value.trim();
21001 // if(v.length < 1){
21005 if(this.owner.fireEvent('beforepush', this, v) !== false){
21006 var d = (this.doc.body || this.doc.documentElement);
21008 this.cleanUpPaste();
21009 this.el.dom.value = d.innerHTML;
21010 this.owner.fireEvent('push', this, v);
21016 deferFocus : function(){
21017 this.focus.defer(10, this);
21021 focus : function(){
21022 if(this.win && !this.sourceEditMode){
21029 assignDocWin: function()
21031 var iframe = this.iframe;
21034 this.doc = iframe.contentWindow.document;
21035 this.win = iframe.contentWindow;
21037 // if (!Roo.get(this.frameId)) {
21040 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21041 // this.win = Roo.get(this.frameId).dom.contentWindow;
21043 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21047 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21048 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21053 initEditor : function(){
21054 //console.log("INIT EDITOR");
21055 this.assignDocWin();
21059 this.doc.designMode="on";
21061 this.doc.write(this.getDocMarkup());
21064 var dbody = (this.doc.body || this.doc.documentElement);
21065 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21066 // this copies styles from the containing element into thsi one..
21067 // not sure why we need all of this..
21068 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21070 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21071 //ss['background-attachment'] = 'fixed'; // w3c
21072 dbody.bgProperties = 'fixed'; // ie
21073 //Roo.DomHelper.applyStyles(dbody, ss);
21074 Roo.EventManager.on(this.doc, {
21075 //'mousedown': this.onEditorEvent,
21076 'mouseup': this.onEditorEvent,
21077 'dblclick': this.onEditorEvent,
21078 'click': this.onEditorEvent,
21079 'keyup': this.onEditorEvent,
21084 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21086 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21087 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21089 this.initialized = true;
21091 this.owner.fireEvent('initialize', this);
21096 onDestroy : function(){
21102 //for (var i =0; i < this.toolbars.length;i++) {
21103 // // fixme - ask toolbars for heights?
21104 // this.toolbars[i].onDestroy();
21107 //this.wrap.dom.innerHTML = '';
21108 //this.wrap.remove();
21113 onFirstFocus : function(){
21115 this.assignDocWin();
21118 this.activated = true;
21121 if(Roo.isGecko){ // prevent silly gecko errors
21123 var s = this.win.getSelection();
21124 if(!s.focusNode || s.focusNode.nodeType != 3){
21125 var r = s.getRangeAt(0);
21126 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21131 this.execCmd('useCSS', true);
21132 this.execCmd('styleWithCSS', false);
21135 this.owner.fireEvent('activate', this);
21139 adjustFont: function(btn){
21140 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21141 //if(Roo.isSafari){ // safari
21144 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21145 if(Roo.isSafari){ // safari
21146 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21147 v = (v < 10) ? 10 : v;
21148 v = (v > 48) ? 48 : v;
21149 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21154 v = Math.max(1, v+adjust);
21156 this.execCmd('FontSize', v );
21159 onEditorEvent : function(e)
21161 this.owner.fireEvent('editorevent', this, e);
21162 // this.updateToolbar();
21163 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21166 insertTag : function(tg)
21168 // could be a bit smarter... -> wrap the current selected tRoo..
21169 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21171 range = this.createRange(this.getSelection());
21172 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21173 wrappingNode.appendChild(range.extractContents());
21174 range.insertNode(wrappingNode);
21181 this.execCmd("formatblock", tg);
21185 insertText : function(txt)
21189 var range = this.createRange();
21190 range.deleteContents();
21191 //alert(Sender.getAttribute('label'));
21193 range.insertNode(this.doc.createTextNode(txt));
21199 * Executes a Midas editor command on the editor document and performs necessary focus and
21200 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21201 * @param {String} cmd The Midas command
21202 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21204 relayCmd : function(cmd, value){
21206 this.execCmd(cmd, value);
21207 this.owner.fireEvent('editorevent', this);
21208 //this.updateToolbar();
21209 this.owner.deferFocus();
21213 * Executes a Midas editor command directly on the editor document.
21214 * For visual commands, you should use {@link #relayCmd} instead.
21215 * <b>This should only be called after the editor is initialized.</b>
21216 * @param {String} cmd The Midas command
21217 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21219 execCmd : function(cmd, value){
21220 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21227 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21229 * @param {String} text | dom node..
21231 insertAtCursor : function(text)
21236 if(!this.activated){
21242 var r = this.doc.selection.createRange();
21253 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
21257 // from jquery ui (MIT licenced)
21259 var win = this.win;
21261 if (win.getSelection && win.getSelection().getRangeAt) {
21262 range = win.getSelection().getRangeAt(0);
21263 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
21264 range.insertNode(node);
21265 } else if (win.document.selection && win.document.selection.createRange) {
21266 // no firefox support
21267 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21268 win.document.selection.createRange().pasteHTML(txt);
21270 // no firefox support
21271 var txt = typeof(text) == 'string' ? text : text.outerHTML;
21272 this.execCmd('InsertHTML', txt);
21281 mozKeyPress : function(e){
21283 var c = e.getCharCode(), cmd;
21286 c = String.fromCharCode(c).toLowerCase();
21300 this.cleanUpPaste.defer(100, this);
21308 e.preventDefault();
21316 fixKeys : function(){ // load time branching for fastest keydown performance
21318 return function(e){
21319 var k = e.getKey(), r;
21322 r = this.doc.selection.createRange();
21325 r.pasteHTML('    ');
21332 r = this.doc.selection.createRange();
21334 var target = r.parentElement();
21335 if(!target || target.tagName.toLowerCase() != 'li'){
21337 r.pasteHTML('<br />');
21343 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21344 this.cleanUpPaste.defer(100, this);
21350 }else if(Roo.isOpera){
21351 return function(e){
21352 var k = e.getKey();
21356 this.execCmd('InsertHTML','    ');
21359 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21360 this.cleanUpPaste.defer(100, this);
21365 }else if(Roo.isSafari){
21366 return function(e){
21367 var k = e.getKey();
21371 this.execCmd('InsertText','\t');
21375 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
21376 this.cleanUpPaste.defer(100, this);
21384 getAllAncestors: function()
21386 var p = this.getSelectedNode();
21389 a.push(p); // push blank onto stack..
21390 p = this.getParentElement();
21394 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
21398 a.push(this.doc.body);
21402 lastSelNode : false,
21405 getSelection : function()
21407 this.assignDocWin();
21408 return Roo.isIE ? this.doc.selection : this.win.getSelection();
21411 getSelectedNode: function()
21413 // this may only work on Gecko!!!
21415 // should we cache this!!!!
21420 var range = this.createRange(this.getSelection()).cloneRange();
21423 var parent = range.parentElement();
21425 var testRange = range.duplicate();
21426 testRange.moveToElementText(parent);
21427 if (testRange.inRange(range)) {
21430 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
21433 parent = parent.parentElement;
21438 // is ancestor a text element.
21439 var ac = range.commonAncestorContainer;
21440 if (ac.nodeType == 3) {
21441 ac = ac.parentNode;
21444 var ar = ac.childNodes;
21447 var other_nodes = [];
21448 var has_other_nodes = false;
21449 for (var i=0;i<ar.length;i++) {
21450 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
21453 // fullly contained node.
21455 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
21460 // probably selected..
21461 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
21462 other_nodes.push(ar[i]);
21466 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
21471 has_other_nodes = true;
21473 if (!nodes.length && other_nodes.length) {
21474 nodes= other_nodes;
21476 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
21482 createRange: function(sel)
21484 // this has strange effects when using with
21485 // top toolbar - not sure if it's a great idea.
21486 //this.editor.contentWindow.focus();
21487 if (typeof sel != "undefined") {
21489 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
21491 return this.doc.createRange();
21494 return this.doc.createRange();
21497 getParentElement: function()
21500 this.assignDocWin();
21501 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
21503 var range = this.createRange(sel);
21506 var p = range.commonAncestorContainer;
21507 while (p.nodeType == 3) { // text node
21518 * Range intersection.. the hard stuff...
21522 * [ -- selected range --- ]
21526 * if end is before start or hits it. fail.
21527 * if start is after end or hits it fail.
21529 * if either hits (but other is outside. - then it's not
21535 // @see http://www.thismuchiknow.co.uk/?p=64.
21536 rangeIntersectsNode : function(range, node)
21538 var nodeRange = node.ownerDocument.createRange();
21540 nodeRange.selectNode(node);
21542 nodeRange.selectNodeContents(node);
21545 var rangeStartRange = range.cloneRange();
21546 rangeStartRange.collapse(true);
21548 var rangeEndRange = range.cloneRange();
21549 rangeEndRange.collapse(false);
21551 var nodeStartRange = nodeRange.cloneRange();
21552 nodeStartRange.collapse(true);
21554 var nodeEndRange = nodeRange.cloneRange();
21555 nodeEndRange.collapse(false);
21557 return rangeStartRange.compareBoundaryPoints(
21558 Range.START_TO_START, nodeEndRange) == -1 &&
21559 rangeEndRange.compareBoundaryPoints(
21560 Range.START_TO_START, nodeStartRange) == 1;
21564 rangeCompareNode : function(range, node)
21566 var nodeRange = node.ownerDocument.createRange();
21568 nodeRange.selectNode(node);
21570 nodeRange.selectNodeContents(node);
21574 range.collapse(true);
21576 nodeRange.collapse(true);
21578 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
21579 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
21581 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
21583 var nodeIsBefore = ss == 1;
21584 var nodeIsAfter = ee == -1;
21586 if (nodeIsBefore && nodeIsAfter) {
21589 if (!nodeIsBefore && nodeIsAfter) {
21590 return 1; //right trailed.
21593 if (nodeIsBefore && !nodeIsAfter) {
21594 return 2; // left trailed.
21600 // private? - in a new class?
21601 cleanUpPaste : function()
21603 // cleans up the whole document..
21604 Roo.log('cleanuppaste');
21606 this.cleanUpChildren(this.doc.body);
21607 var clean = this.cleanWordChars(this.doc.body.innerHTML);
21608 if (clean != this.doc.body.innerHTML) {
21609 this.doc.body.innerHTML = clean;
21614 cleanWordChars : function(input) {// change the chars to hex code
21615 var he = Roo.HtmlEditorCore;
21617 var output = input;
21618 Roo.each(he.swapCodes, function(sw) {
21619 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
21621 output = output.replace(swapper, sw[1]);
21628 cleanUpChildren : function (n)
21630 if (!n.childNodes.length) {
21633 for (var i = n.childNodes.length-1; i > -1 ; i--) {
21634 this.cleanUpChild(n.childNodes[i]);
21641 cleanUpChild : function (node)
21644 //console.log(node);
21645 if (node.nodeName == "#text") {
21646 // clean up silly Windows -- stuff?
21649 if (node.nodeName == "#comment") {
21650 node.parentNode.removeChild(node);
21651 // clean up silly Windows -- stuff?
21654 var lcname = node.tagName.toLowerCase();
21655 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
21656 // whitelist of tags..
21658 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
21660 node.parentNode.removeChild(node);
21665 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
21667 // remove <a name=....> as rendering on yahoo mailer is borked with this.
21668 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
21670 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
21671 // remove_keep_children = true;
21674 if (remove_keep_children) {
21675 this.cleanUpChildren(node);
21676 // inserts everything just before this node...
21677 while (node.childNodes.length) {
21678 var cn = node.childNodes[0];
21679 node.removeChild(cn);
21680 node.parentNode.insertBefore(cn, node);
21682 node.parentNode.removeChild(node);
21686 if (!node.attributes || !node.attributes.length) {
21687 this.cleanUpChildren(node);
21691 function cleanAttr(n,v)
21694 if (v.match(/^\./) || v.match(/^\//)) {
21697 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
21700 if (v.match(/^#/)) {
21703 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
21704 node.removeAttribute(n);
21708 var cwhite = this.cwhite;
21709 var cblack = this.cblack;
21711 function cleanStyle(n,v)
21713 if (v.match(/expression/)) { //XSS?? should we even bother..
21714 node.removeAttribute(n);
21718 var parts = v.split(/;/);
21721 Roo.each(parts, function(p) {
21722 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
21726 var l = p.split(':').shift().replace(/\s+/g,'');
21727 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
21729 if ( cwhite.length && cblack.indexOf(l) > -1) {
21730 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21731 //node.removeAttribute(n);
21735 // only allow 'c whitelisted system attributes'
21736 if ( cwhite.length && cwhite.indexOf(l) < 0) {
21737 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
21738 //node.removeAttribute(n);
21748 if (clean.length) {
21749 node.setAttribute(n, clean.join(';'));
21751 node.removeAttribute(n);
21757 for (var i = node.attributes.length-1; i > -1 ; i--) {
21758 var a = node.attributes[i];
21761 if (a.name.toLowerCase().substr(0,2)=='on') {
21762 node.removeAttribute(a.name);
21765 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
21766 node.removeAttribute(a.name);
21769 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
21770 cleanAttr(a.name,a.value); // fixme..
21773 if (a.name == 'style') {
21774 cleanStyle(a.name,a.value);
21777 /// clean up MS crap..
21778 // tecnically this should be a list of valid class'es..
21781 if (a.name == 'class') {
21782 if (a.value.match(/^Mso/)) {
21783 node.className = '';
21786 if (a.value.match(/body/)) {
21787 node.className = '';
21798 this.cleanUpChildren(node);
21804 * Clean up MS wordisms...
21806 cleanWord : function(node)
21811 this.cleanWord(this.doc.body);
21814 if (node.nodeName == "#text") {
21815 // clean up silly Windows -- stuff?
21818 if (node.nodeName == "#comment") {
21819 node.parentNode.removeChild(node);
21820 // clean up silly Windows -- stuff?
21824 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
21825 node.parentNode.removeChild(node);
21829 // remove - but keep children..
21830 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
21831 while (node.childNodes.length) {
21832 var cn = node.childNodes[0];
21833 node.removeChild(cn);
21834 node.parentNode.insertBefore(cn, node);
21836 node.parentNode.removeChild(node);
21837 this.iterateChildren(node, this.cleanWord);
21841 if (node.className.length) {
21843 var cn = node.className.split(/\W+/);
21845 Roo.each(cn, function(cls) {
21846 if (cls.match(/Mso[a-zA-Z]+/)) {
21851 node.className = cna.length ? cna.join(' ') : '';
21853 node.removeAttribute("class");
21857 if (node.hasAttribute("lang")) {
21858 node.removeAttribute("lang");
21861 if (node.hasAttribute("style")) {
21863 var styles = node.getAttribute("style").split(";");
21865 Roo.each(styles, function(s) {
21866 if (!s.match(/:/)) {
21869 var kv = s.split(":");
21870 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
21873 // what ever is left... we allow.
21876 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21877 if (!nstyle.length) {
21878 node.removeAttribute('style');
21881 this.iterateChildren(node, this.cleanWord);
21887 * iterateChildren of a Node, calling fn each time, using this as the scole..
21888 * @param {DomNode} node node to iterate children of.
21889 * @param {Function} fn method of this class to call on each item.
21891 iterateChildren : function(node, fn)
21893 if (!node.childNodes.length) {
21896 for (var i = node.childNodes.length-1; i > -1 ; i--) {
21897 fn.call(this, node.childNodes[i])
21903 * cleanTableWidths.
21905 * Quite often pasting from word etc.. results in tables with column and widths.
21906 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
21909 cleanTableWidths : function(node)
21914 this.cleanTableWidths(this.doc.body);
21919 if (node.nodeName == "#text" || node.nodeName == "#comment") {
21922 Roo.log(node.tagName);
21923 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
21924 this.iterateChildren(node, this.cleanTableWidths);
21927 if (node.hasAttribute('width')) {
21928 node.removeAttribute('width');
21932 if (node.hasAttribute("style")) {
21935 var styles = node.getAttribute("style").split(";");
21937 Roo.each(styles, function(s) {
21938 if (!s.match(/:/)) {
21941 var kv = s.split(":");
21942 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
21945 // what ever is left... we allow.
21948 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
21949 if (!nstyle.length) {
21950 node.removeAttribute('style');
21954 this.iterateChildren(node, this.cleanTableWidths);
21962 domToHTML : function(currentElement, depth, nopadtext) {
21964 depth = depth || 0;
21965 nopadtext = nopadtext || false;
21967 if (!currentElement) {
21968 return this.domToHTML(this.doc.body);
21971 //Roo.log(currentElement);
21973 var allText = false;
21974 var nodeName = currentElement.nodeName;
21975 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
21977 if (nodeName == '#text') {
21979 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
21984 if (nodeName != 'BODY') {
21987 // Prints the node tagName, such as <A>, <IMG>, etc
21990 for(i = 0; i < currentElement.attributes.length;i++) {
21992 var aname = currentElement.attributes.item(i).name;
21993 if (!currentElement.attributes.item(i).value.length) {
21996 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
21999 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22008 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22011 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22016 // Traverse the tree
22018 var currentElementChild = currentElement.childNodes.item(i);
22019 var allText = true;
22020 var innerHTML = '';
22022 while (currentElementChild) {
22023 // Formatting code (indent the tree so it looks nice on the screen)
22024 var nopad = nopadtext;
22025 if (lastnode == 'SPAN') {
22029 if (currentElementChild.nodeName == '#text') {
22030 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22031 toadd = nopadtext ? toadd : toadd.trim();
22032 if (!nopad && toadd.length > 80) {
22033 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22035 innerHTML += toadd;
22038 currentElementChild = currentElement.childNodes.item(i);
22044 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22046 // Recursively traverse the tree structure of the child node
22047 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22048 lastnode = currentElementChild.nodeName;
22050 currentElementChild=currentElement.childNodes.item(i);
22056 // The remaining code is mostly for formatting the tree
22057 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22062 ret+= "</"+tagName+">";
22068 applyBlacklists : function()
22070 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22071 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22075 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22076 if (b.indexOf(tag) > -1) {
22079 this.white.push(tag);
22083 Roo.each(w, function(tag) {
22084 if (b.indexOf(tag) > -1) {
22087 if (this.white.indexOf(tag) > -1) {
22090 this.white.push(tag);
22095 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22096 if (w.indexOf(tag) > -1) {
22099 this.black.push(tag);
22103 Roo.each(b, function(tag) {
22104 if (w.indexOf(tag) > -1) {
22107 if (this.black.indexOf(tag) > -1) {
22110 this.black.push(tag);
22115 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22116 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22120 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22121 if (b.indexOf(tag) > -1) {
22124 this.cwhite.push(tag);
22128 Roo.each(w, function(tag) {
22129 if (b.indexOf(tag) > -1) {
22132 if (this.cwhite.indexOf(tag) > -1) {
22135 this.cwhite.push(tag);
22140 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22141 if (w.indexOf(tag) > -1) {
22144 this.cblack.push(tag);
22148 Roo.each(b, function(tag) {
22149 if (w.indexOf(tag) > -1) {
22152 if (this.cblack.indexOf(tag) > -1) {
22155 this.cblack.push(tag);
22160 setStylesheets : function(stylesheets)
22162 if(typeof(stylesheets) == 'string'){
22163 Roo.get(this.iframe.contentDocument.head).createChild({
22165 rel : 'stylesheet',
22174 Roo.each(stylesheets, function(s) {
22179 Roo.get(_this.iframe.contentDocument.head).createChild({
22181 rel : 'stylesheet',
22190 removeStylesheets : function()
22194 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22199 // hide stuff that is not compatible
22213 * @event specialkey
22217 * @cfg {String} fieldClass @hide
22220 * @cfg {String} focusClass @hide
22223 * @cfg {String} autoCreate @hide
22226 * @cfg {String} inputType @hide
22229 * @cfg {String} invalidClass @hide
22232 * @cfg {String} invalidText @hide
22235 * @cfg {String} msgFx @hide
22238 * @cfg {String} validateOnBlur @hide
22242 Roo.HtmlEditorCore.white = [
22243 'area', 'br', 'img', 'input', 'hr', 'wbr',
22245 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
22246 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
22247 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
22248 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
22249 'table', 'ul', 'xmp',
22251 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
22254 'dir', 'menu', 'ol', 'ul', 'dl',
22260 Roo.HtmlEditorCore.black = [
22261 // 'embed', 'object', // enable - backend responsiblity to clean thiese
22263 'base', 'basefont', 'bgsound', 'blink', 'body',
22264 'frame', 'frameset', 'head', 'html', 'ilayer',
22265 'iframe', 'layer', 'link', 'meta', 'object',
22266 'script', 'style' ,'title', 'xml' // clean later..
22268 Roo.HtmlEditorCore.clean = [
22269 'script', 'style', 'title', 'xml'
22271 Roo.HtmlEditorCore.remove = [
22276 Roo.HtmlEditorCore.ablack = [
22280 Roo.HtmlEditorCore.aclean = [
22281 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
22285 Roo.HtmlEditorCore.pwhite= [
22286 'http', 'https', 'mailto'
22289 // white listed style attributes.
22290 Roo.HtmlEditorCore.cwhite= [
22291 // 'text-align', /// default is to allow most things..
22297 // black listed style attributes.
22298 Roo.HtmlEditorCore.cblack= [
22299 // 'font-size' -- this can be set by the project
22303 Roo.HtmlEditorCore.swapCodes =[
22322 * @class Roo.bootstrap.HtmlEditor
22323 * @extends Roo.bootstrap.TextArea
22324 * Bootstrap HtmlEditor class
22327 * Create a new HtmlEditor
22328 * @param {Object} config The config object
22331 Roo.bootstrap.HtmlEditor = function(config){
22332 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
22333 if (!this.toolbars) {
22334 this.toolbars = [];
22336 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
22339 * @event initialize
22340 * Fires when the editor is fully initialized (including the iframe)
22341 * @param {HtmlEditor} this
22346 * Fires when the editor is first receives the focus. Any insertion must wait
22347 * until after this event.
22348 * @param {HtmlEditor} this
22352 * @event beforesync
22353 * Fires before the textarea is updated with content from the editor iframe. Return false
22354 * to cancel the sync.
22355 * @param {HtmlEditor} this
22356 * @param {String} html
22360 * @event beforepush
22361 * Fires before the iframe editor is updated with content from the textarea. Return false
22362 * to cancel the push.
22363 * @param {HtmlEditor} this
22364 * @param {String} html
22369 * Fires when the textarea is updated with content from the editor iframe.
22370 * @param {HtmlEditor} this
22371 * @param {String} html
22376 * Fires when the iframe editor is updated with content from the textarea.
22377 * @param {HtmlEditor} this
22378 * @param {String} html
22382 * @event editmodechange
22383 * Fires when the editor switches edit modes
22384 * @param {HtmlEditor} this
22385 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
22387 editmodechange: true,
22389 * @event editorevent
22390 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22391 * @param {HtmlEditor} this
22395 * @event firstfocus
22396 * Fires when on first focus - needed by toolbars..
22397 * @param {HtmlEditor} this
22402 * Auto save the htmlEditor value as a file into Events
22403 * @param {HtmlEditor} this
22407 * @event savedpreview
22408 * preview the saved version of htmlEditor
22409 * @param {HtmlEditor} this
22416 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
22420 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
22425 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22430 * @cfg {Number} height (in pixels)
22434 * @cfg {Number} width (in pixels)
22439 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22442 stylesheets: false,
22447 // private properties
22448 validationEvent : false,
22450 initialized : false,
22453 onFocus : Roo.emptyFn,
22455 hideMode:'offsets',
22458 tbContainer : false,
22460 toolbarContainer :function() {
22461 return this.wrap.select('.x-html-editor-tb',true).first();
22465 * Protected method that will not generally be called directly. It
22466 * is called when the editor creates its toolbar. Override this method if you need to
22467 * add custom toolbar buttons.
22468 * @param {HtmlEditor} editor
22470 createToolbar : function(){
22472 Roo.log("create toolbars");
22474 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
22475 this.toolbars[0].render(this.toolbarContainer());
22479 // if (!editor.toolbars || !editor.toolbars.length) {
22480 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
22483 // for (var i =0 ; i < editor.toolbars.length;i++) {
22484 // editor.toolbars[i] = Roo.factory(
22485 // typeof(editor.toolbars[i]) == 'string' ?
22486 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
22487 // Roo.bootstrap.HtmlEditor);
22488 // editor.toolbars[i].init(editor);
22494 onRender : function(ct, position)
22496 // Roo.log("Call onRender: " + this.xtype);
22498 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
22500 this.wrap = this.inputEl().wrap({
22501 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
22504 this.editorcore.onRender(ct, position);
22506 if (this.resizable) {
22507 this.resizeEl = new Roo.Resizable(this.wrap, {
22511 minHeight : this.height,
22512 height: this.height,
22513 handles : this.resizable,
22516 resize : function(r, w, h) {
22517 _t.onResize(w,h); // -something
22523 this.createToolbar(this);
22526 if(!this.width && this.resizable){
22527 this.setSize(this.wrap.getSize());
22529 if (this.resizeEl) {
22530 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
22531 // should trigger onReize..
22537 onResize : function(w, h)
22539 Roo.log('resize: ' +w + ',' + h );
22540 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
22544 if(this.inputEl() ){
22545 if(typeof w == 'number'){
22546 var aw = w - this.wrap.getFrameWidth('lr');
22547 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
22550 if(typeof h == 'number'){
22551 var tbh = -11; // fixme it needs to tool bar size!
22552 for (var i =0; i < this.toolbars.length;i++) {
22553 // fixme - ask toolbars for heights?
22554 tbh += this.toolbars[i].el.getHeight();
22555 //if (this.toolbars[i].footer) {
22556 // tbh += this.toolbars[i].footer.el.getHeight();
22564 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
22565 ah -= 5; // knock a few pixes off for look..
22566 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
22570 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
22571 this.editorcore.onResize(ew,eh);
22576 * Toggles the editor between standard and source edit mode.
22577 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22579 toggleSourceEdit : function(sourceEditMode)
22581 this.editorcore.toggleSourceEdit(sourceEditMode);
22583 if(this.editorcore.sourceEditMode){
22584 Roo.log('editor - showing textarea');
22587 // Roo.log(this.syncValue());
22589 this.inputEl().removeClass(['hide', 'x-hidden']);
22590 this.inputEl().dom.removeAttribute('tabIndex');
22591 this.inputEl().focus();
22593 Roo.log('editor - hiding textarea');
22595 // Roo.log(this.pushValue());
22598 this.inputEl().addClass(['hide', 'x-hidden']);
22599 this.inputEl().dom.setAttribute('tabIndex', -1);
22600 //this.deferFocus();
22603 if(this.resizable){
22604 this.setSize(this.wrap.getSize());
22607 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
22610 // private (for BoxComponent)
22611 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22613 // private (for BoxComponent)
22614 getResizeEl : function(){
22618 // private (for BoxComponent)
22619 getPositionEl : function(){
22624 initEvents : function(){
22625 this.originalValue = this.getValue();
22629 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22632 // markInvalid : Roo.emptyFn,
22634 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
22637 // clearInvalid : Roo.emptyFn,
22639 setValue : function(v){
22640 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
22641 this.editorcore.pushValue();
22646 deferFocus : function(){
22647 this.focus.defer(10, this);
22651 focus : function(){
22652 this.editorcore.focus();
22658 onDestroy : function(){
22664 for (var i =0; i < this.toolbars.length;i++) {
22665 // fixme - ask toolbars for heights?
22666 this.toolbars[i].onDestroy();
22669 this.wrap.dom.innerHTML = '';
22670 this.wrap.remove();
22675 onFirstFocus : function(){
22676 //Roo.log("onFirstFocus");
22677 this.editorcore.onFirstFocus();
22678 for (var i =0; i < this.toolbars.length;i++) {
22679 this.toolbars[i].onFirstFocus();
22685 syncValue : function()
22687 this.editorcore.syncValue();
22690 pushValue : function()
22692 this.editorcore.pushValue();
22696 // hide stuff that is not compatible
22710 * @event specialkey
22714 * @cfg {String} fieldClass @hide
22717 * @cfg {String} focusClass @hide
22720 * @cfg {String} autoCreate @hide
22723 * @cfg {String} inputType @hide
22726 * @cfg {String} invalidClass @hide
22729 * @cfg {String} invalidText @hide
22732 * @cfg {String} msgFx @hide
22735 * @cfg {String} validateOnBlur @hide
22744 Roo.namespace('Roo.bootstrap.htmleditor');
22746 * @class Roo.bootstrap.HtmlEditorToolbar1
22751 new Roo.bootstrap.HtmlEditor({
22754 new Roo.bootstrap.HtmlEditorToolbar1({
22755 disable : { fonts: 1 , format: 1, ..., ... , ...],
22761 * @cfg {Object} disable List of elements to disable..
22762 * @cfg {Array} btns List of additional buttons.
22766 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
22769 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
22772 Roo.apply(this, config);
22774 // default disabled, based on 'good practice'..
22775 this.disable = this.disable || {};
22776 Roo.applyIf(this.disable, {
22779 specialElements : true
22781 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
22783 this.editor = config.editor;
22784 this.editorcore = config.editor.editorcore;
22786 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
22788 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
22789 // dont call parent... till later.
22791 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
22796 editorcore : false,
22801 "h1","h2","h3","h4","h5","h6",
22803 "abbr", "acronym", "address", "cite", "samp", "var",
22807 onRender : function(ct, position)
22809 // Roo.log("Call onRender: " + this.xtype);
22811 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
22813 this.el.dom.style.marginBottom = '0';
22815 var editorcore = this.editorcore;
22816 var editor= this.editor;
22819 var btn = function(id,cmd , toggle, handler){
22821 var event = toggle ? 'toggle' : 'click';
22826 xns: Roo.bootstrap,
22829 enableToggle:toggle !== false,
22831 pressed : toggle ? false : null,
22834 a.listeners[toggle ? 'toggle' : 'click'] = function() {
22835 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
22844 xns: Roo.bootstrap,
22845 glyphicon : 'font',
22849 xns: Roo.bootstrap,
22853 Roo.each(this.formats, function(f) {
22854 style.menu.items.push({
22856 xns: Roo.bootstrap,
22857 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
22862 editorcore.insertTag(this.tagname);
22869 children.push(style);
22872 btn('bold',false,true);
22873 btn('italic',false,true);
22874 btn('align-left', 'justifyleft',true);
22875 btn('align-center', 'justifycenter',true);
22876 btn('align-right' , 'justifyright',true);
22877 btn('link', false, false, function(btn) {
22878 //Roo.log("create link?");
22879 var url = prompt(this.createLinkText, this.defaultLinkValue);
22880 if(url && url != 'http:/'+'/'){
22881 this.editorcore.relayCmd('createlink', url);
22884 btn('list','insertunorderedlist',true);
22885 btn('pencil', false,true, function(btn){
22888 this.toggleSourceEdit(btn.pressed);
22894 xns: Roo.bootstrap,
22899 xns: Roo.bootstrap,
22904 cog.menu.items.push({
22906 xns: Roo.bootstrap,
22907 html : Clean styles,
22912 editorcore.insertTag(this.tagname);
22921 this.xtype = 'NavSimplebar';
22923 for(var i=0;i< children.length;i++) {
22925 this.buttons.add(this.addxtypeChild(children[i]));
22929 editor.on('editorevent', this.updateToolbar, this);
22931 onBtnClick : function(id)
22933 this.editorcore.relayCmd(id);
22934 this.editorcore.focus();
22938 * Protected method that will not generally be called directly. It triggers
22939 * a toolbar update by reading the markup state of the current selection in the editor.
22941 updateToolbar: function(){
22943 if(!this.editorcore.activated){
22944 this.editor.onFirstFocus(); // is this neeed?
22948 var btns = this.buttons;
22949 var doc = this.editorcore.doc;
22950 btns.get('bold').setActive(doc.queryCommandState('bold'));
22951 btns.get('italic').setActive(doc.queryCommandState('italic'));
22952 //btns.get('underline').setActive(doc.queryCommandState('underline'));
22954 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
22955 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
22956 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
22958 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
22959 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
22962 var ans = this.editorcore.getAllAncestors();
22963 if (this.formatCombo) {
22966 var store = this.formatCombo.store;
22967 this.formatCombo.setValue("");
22968 for (var i =0; i < ans.length;i++) {
22969 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
22971 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
22979 // hides menus... - so this cant be on a menu...
22980 Roo.bootstrap.MenuMgr.hideAll();
22982 Roo.bootstrap.MenuMgr.hideAll();
22983 //this.editorsyncValue();
22985 onFirstFocus: function() {
22986 this.buttons.each(function(item){
22990 toggleSourceEdit : function(sourceEditMode){
22993 if(sourceEditMode){
22994 Roo.log("disabling buttons");
22995 this.buttons.each( function(item){
22996 if(item.cmd != 'pencil'){
23002 Roo.log("enabling buttons");
23003 if(this.editorcore.initialized){
23004 this.buttons.each( function(item){
23010 Roo.log("calling toggole on editor");
23011 // tell the editor that it's been pressed..
23012 this.editor.toggleSourceEdit(sourceEditMode);
23022 * @class Roo.bootstrap.Table.AbstractSelectionModel
23023 * @extends Roo.util.Observable
23024 * Abstract base class for grid SelectionModels. It provides the interface that should be
23025 * implemented by descendant classes. This class should not be directly instantiated.
23028 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23029 this.locked = false;
23030 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23034 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23035 /** @ignore Called by the grid automatically. Do not call directly. */
23036 init : function(grid){
23042 * Locks the selections.
23045 this.locked = true;
23049 * Unlocks the selections.
23051 unlock : function(){
23052 this.locked = false;
23056 * Returns true if the selections are locked.
23057 * @return {Boolean}
23059 isLocked : function(){
23060 return this.locked;
23064 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23065 * @class Roo.bootstrap.Table.RowSelectionModel
23066 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23067 * It supports multiple selections and keyboard selection/navigation.
23069 * @param {Object} config
23072 Roo.bootstrap.Table.RowSelectionModel = function(config){
23073 Roo.apply(this, config);
23074 this.selections = new Roo.util.MixedCollection(false, function(o){
23079 this.lastActive = false;
23083 * @event selectionchange
23084 * Fires when the selection changes
23085 * @param {SelectionModel} this
23087 "selectionchange" : true,
23089 * @event afterselectionchange
23090 * Fires after the selection changes (eg. by key press or clicking)
23091 * @param {SelectionModel} this
23093 "afterselectionchange" : true,
23095 * @event beforerowselect
23096 * Fires when a row is selected being selected, return false to cancel.
23097 * @param {SelectionModel} this
23098 * @param {Number} rowIndex The selected index
23099 * @param {Boolean} keepExisting False if other selections will be cleared
23101 "beforerowselect" : true,
23104 * Fires when a row is selected.
23105 * @param {SelectionModel} this
23106 * @param {Number} rowIndex The selected index
23107 * @param {Roo.data.Record} r The record
23109 "rowselect" : true,
23111 * @event rowdeselect
23112 * Fires when a row is deselected.
23113 * @param {SelectionModel} this
23114 * @param {Number} rowIndex The selected index
23116 "rowdeselect" : true
23118 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23119 this.locked = false;
23122 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23124 * @cfg {Boolean} singleSelect
23125 * True to allow selection of only one row at a time (defaults to false)
23127 singleSelect : false,
23130 initEvents : function()
23133 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23134 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23135 //}else{ // allow click to work like normal
23136 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23138 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23139 this.grid.on("rowclick", this.handleMouseDown, this);
23141 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23142 "up" : function(e){
23144 this.selectPrevious(e.shiftKey);
23145 }else if(this.last !== false && this.lastActive !== false){
23146 var last = this.last;
23147 this.selectRange(this.last, this.lastActive-1);
23148 this.grid.getView().focusRow(this.lastActive);
23149 if(last !== false){
23153 this.selectFirstRow();
23155 this.fireEvent("afterselectionchange", this);
23157 "down" : function(e){
23159 this.selectNext(e.shiftKey);
23160 }else if(this.last !== false && this.lastActive !== false){
23161 var last = this.last;
23162 this.selectRange(this.last, this.lastActive+1);
23163 this.grid.getView().focusRow(this.lastActive);
23164 if(last !== false){
23168 this.selectFirstRow();
23170 this.fireEvent("afterselectionchange", this);
23174 this.grid.store.on('load', function(){
23175 this.selections.clear();
23178 var view = this.grid.view;
23179 view.on("refresh", this.onRefresh, this);
23180 view.on("rowupdated", this.onRowUpdated, this);
23181 view.on("rowremoved", this.onRemove, this);
23186 onRefresh : function()
23188 var ds = this.grid.store, i, v = this.grid.view;
23189 var s = this.selections;
23190 s.each(function(r){
23191 if((i = ds.indexOfId(r.id)) != -1){
23200 onRemove : function(v, index, r){
23201 this.selections.remove(r);
23205 onRowUpdated : function(v, index, r){
23206 if(this.isSelected(r)){
23207 v.onRowSelect(index);
23213 * @param {Array} records The records to select
23214 * @param {Boolean} keepExisting (optional) True to keep existing selections
23216 selectRecords : function(records, keepExisting)
23219 this.clearSelections();
23221 var ds = this.grid.store;
23222 for(var i = 0, len = records.length; i < len; i++){
23223 this.selectRow(ds.indexOf(records[i]), true);
23228 * Gets the number of selected rows.
23231 getCount : function(){
23232 return this.selections.length;
23236 * Selects the first row in the grid.
23238 selectFirstRow : function(){
23243 * Select the last row.
23244 * @param {Boolean} keepExisting (optional) True to keep existing selections
23246 selectLastRow : function(keepExisting){
23247 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
23248 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
23252 * Selects the row immediately following the last selected row.
23253 * @param {Boolean} keepExisting (optional) True to keep existing selections
23255 selectNext : function(keepExisting)
23257 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
23258 this.selectRow(this.last+1, keepExisting);
23259 this.grid.getView().focusRow(this.last);
23264 * Selects the row that precedes the last selected row.
23265 * @param {Boolean} keepExisting (optional) True to keep existing selections
23267 selectPrevious : function(keepExisting){
23269 this.selectRow(this.last-1, keepExisting);
23270 this.grid.getView().focusRow(this.last);
23275 * Returns the selected records
23276 * @return {Array} Array of selected records
23278 getSelections : function(){
23279 return [].concat(this.selections.items);
23283 * Returns the first selected record.
23286 getSelected : function(){
23287 return this.selections.itemAt(0);
23292 * Clears all selections.
23294 clearSelections : function(fast)
23300 var ds = this.grid.store;
23301 var s = this.selections;
23302 s.each(function(r){
23303 this.deselectRow(ds.indexOfId(r.id));
23307 this.selections.clear();
23314 * Selects all rows.
23316 selectAll : function(){
23320 this.selections.clear();
23321 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
23322 this.selectRow(i, true);
23327 * Returns True if there is a selection.
23328 * @return {Boolean}
23330 hasSelection : function(){
23331 return this.selections.length > 0;
23335 * Returns True if the specified row is selected.
23336 * @param {Number/Record} record The record or index of the record to check
23337 * @return {Boolean}
23339 isSelected : function(index){
23340 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
23341 return (r && this.selections.key(r.id) ? true : false);
23345 * Returns True if the specified record id is selected.
23346 * @param {String} id The id of record to check
23347 * @return {Boolean}
23349 isIdSelected : function(id){
23350 return (this.selections.key(id) ? true : false);
23355 handleMouseDBClick : function(e, t){
23359 handleMouseDown : function(e, t)
23361 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
23362 if(this.isLocked() || rowIndex < 0 ){
23365 if(e.shiftKey && this.last !== false){
23366 var last = this.last;
23367 this.selectRange(last, rowIndex, e.ctrlKey);
23368 this.last = last; // reset the last
23372 var isSelected = this.isSelected(rowIndex);
23373 //Roo.log("select row:" + rowIndex);
23375 this.deselectRow(rowIndex);
23377 this.selectRow(rowIndex, true);
23381 if(e.button !== 0 && isSelected){
23382 alert('rowIndex 2: ' + rowIndex);
23383 view.focusRow(rowIndex);
23384 }else if(e.ctrlKey && isSelected){
23385 this.deselectRow(rowIndex);
23386 }else if(!isSelected){
23387 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
23388 view.focusRow(rowIndex);
23392 this.fireEvent("afterselectionchange", this);
23395 handleDragableRowClick : function(grid, rowIndex, e)
23397 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
23398 this.selectRow(rowIndex, false);
23399 grid.view.focusRow(rowIndex);
23400 this.fireEvent("afterselectionchange", this);
23405 * Selects multiple rows.
23406 * @param {Array} rows Array of the indexes of the row to select
23407 * @param {Boolean} keepExisting (optional) True to keep existing selections
23409 selectRows : function(rows, keepExisting){
23411 this.clearSelections();
23413 for(var i = 0, len = rows.length; i < len; i++){
23414 this.selectRow(rows[i], true);
23419 * Selects a range of rows. All rows in between startRow and endRow are also selected.
23420 * @param {Number} startRow The index of the first row in the range
23421 * @param {Number} endRow The index of the last row in the range
23422 * @param {Boolean} keepExisting (optional) True to retain existing selections
23424 selectRange : function(startRow, endRow, keepExisting){
23429 this.clearSelections();
23431 if(startRow <= endRow){
23432 for(var i = startRow; i <= endRow; i++){
23433 this.selectRow(i, true);
23436 for(var i = startRow; i >= endRow; i--){
23437 this.selectRow(i, true);
23443 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
23444 * @param {Number} startRow The index of the first row in the range
23445 * @param {Number} endRow The index of the last row in the range
23447 deselectRange : function(startRow, endRow, preventViewNotify){
23451 for(var i = startRow; i <= endRow; i++){
23452 this.deselectRow(i, preventViewNotify);
23458 * @param {Number} row The index of the row to select
23459 * @param {Boolean} keepExisting (optional) True to keep existing selections
23461 selectRow : function(index, keepExisting, preventViewNotify)
23463 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
23466 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
23467 if(!keepExisting || this.singleSelect){
23468 this.clearSelections();
23471 var r = this.grid.store.getAt(index);
23472 //console.log('selectRow - record id :' + r.id);
23474 this.selections.add(r);
23475 this.last = this.lastActive = index;
23476 if(!preventViewNotify){
23477 var proxy = new Roo.Element(
23478 this.grid.getRowDom(index)
23480 proxy.addClass('bg-info info');
23482 this.fireEvent("rowselect", this, index, r);
23483 this.fireEvent("selectionchange", this);
23489 * @param {Number} row The index of the row to deselect
23491 deselectRow : function(index, preventViewNotify)
23496 if(this.last == index){
23499 if(this.lastActive == index){
23500 this.lastActive = false;
23503 var r = this.grid.store.getAt(index);
23508 this.selections.remove(r);
23509 //.console.log('deselectRow - record id :' + r.id);
23510 if(!preventViewNotify){
23512 var proxy = new Roo.Element(
23513 this.grid.getRowDom(index)
23515 proxy.removeClass('bg-info info');
23517 this.fireEvent("rowdeselect", this, index);
23518 this.fireEvent("selectionchange", this);
23522 restoreLast : function(){
23524 this.last = this._last;
23529 acceptsNav : function(row, col, cm){
23530 return !cm.isHidden(col) && cm.isCellEditable(col, row);
23534 onEditorKey : function(field, e){
23535 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
23540 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
23542 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
23544 }else if(k == e.ENTER && !e.ctrlKey){
23548 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
23550 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
23552 }else if(k == e.ESC){
23556 g.startEditing(newCell[0], newCell[1]);
23562 * Ext JS Library 1.1.1
23563 * Copyright(c) 2006-2007, Ext JS, LLC.
23565 * Originally Released Under LGPL - original licence link has changed is not relivant.
23568 * <script type="text/javascript">
23572 * @class Roo.bootstrap.PagingToolbar
23573 * @extends Roo.bootstrap.NavSimplebar
23574 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
23576 * Create a new PagingToolbar
23577 * @param {Object} config The config object
23578 * @param {Roo.data.Store} store
23580 Roo.bootstrap.PagingToolbar = function(config)
23582 // old args format still supported... - xtype is prefered..
23583 // created from xtype...
23585 this.ds = config.dataSource;
23587 if (config.store && !this.ds) {
23588 this.store= Roo.factory(config.store, Roo.data);
23589 this.ds = this.store;
23590 this.ds.xmodule = this.xmodule || false;
23593 this.toolbarItems = [];
23594 if (config.items) {
23595 this.toolbarItems = config.items;
23598 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
23603 this.bind(this.ds);
23606 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
23610 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
23612 * @cfg {Roo.data.Store} dataSource
23613 * The underlying data store providing the paged data
23616 * @cfg {String/HTMLElement/Element} container
23617 * container The id or element that will contain the toolbar
23620 * @cfg {Boolean} displayInfo
23621 * True to display the displayMsg (defaults to false)
23624 * @cfg {Number} pageSize
23625 * The number of records to display per page (defaults to 20)
23629 * @cfg {String} displayMsg
23630 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
23632 displayMsg : 'Displaying {0} - {1} of {2}',
23634 * @cfg {String} emptyMsg
23635 * The message to display when no records are found (defaults to "No data to display")
23637 emptyMsg : 'No data to display',
23639 * Customizable piece of the default paging text (defaults to "Page")
23642 beforePageText : "Page",
23644 * Customizable piece of the default paging text (defaults to "of %0")
23647 afterPageText : "of {0}",
23649 * Customizable piece of the default paging text (defaults to "First Page")
23652 firstText : "First Page",
23654 * Customizable piece of the default paging text (defaults to "Previous Page")
23657 prevText : "Previous Page",
23659 * Customizable piece of the default paging text (defaults to "Next Page")
23662 nextText : "Next Page",
23664 * Customizable piece of the default paging text (defaults to "Last Page")
23667 lastText : "Last Page",
23669 * Customizable piece of the default paging text (defaults to "Refresh")
23672 refreshText : "Refresh",
23676 onRender : function(ct, position)
23678 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
23679 this.navgroup.parentId = this.id;
23680 this.navgroup.onRender(this.el, null);
23681 // add the buttons to the navgroup
23683 if(this.displayInfo){
23684 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
23685 this.displayEl = this.el.select('.x-paging-info', true).first();
23686 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
23687 // this.displayEl = navel.el.select('span',true).first();
23693 Roo.each(_this.buttons, function(e){ // this might need to use render????
23694 Roo.factory(e).onRender(_this.el, null);
23698 Roo.each(_this.toolbarItems, function(e) {
23699 _this.navgroup.addItem(e);
23703 this.first = this.navgroup.addItem({
23704 tooltip: this.firstText,
23706 icon : 'fa fa-backward',
23708 preventDefault: true,
23709 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
23712 this.prev = this.navgroup.addItem({
23713 tooltip: this.prevText,
23715 icon : 'fa fa-step-backward',
23717 preventDefault: true,
23718 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
23720 //this.addSeparator();
23723 var field = this.navgroup.addItem( {
23725 cls : 'x-paging-position',
23727 html : this.beforePageText +
23728 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
23729 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
23732 this.field = field.el.select('input', true).first();
23733 this.field.on("keydown", this.onPagingKeydown, this);
23734 this.field.on("focus", function(){this.dom.select();});
23737 this.afterTextEl = field.el.select('.x-paging-after',true).first();
23738 //this.field.setHeight(18);
23739 //this.addSeparator();
23740 this.next = this.navgroup.addItem({
23741 tooltip: this.nextText,
23743 html : ' <i class="fa fa-step-forward">',
23745 preventDefault: true,
23746 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
23748 this.last = this.navgroup.addItem({
23749 tooltip: this.lastText,
23750 icon : 'fa fa-forward',
23753 preventDefault: true,
23754 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
23756 //this.addSeparator();
23757 this.loading = this.navgroup.addItem({
23758 tooltip: this.refreshText,
23759 icon: 'fa fa-refresh',
23760 preventDefault: true,
23761 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
23767 updateInfo : function(){
23768 if(this.displayEl){
23769 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
23770 var msg = count == 0 ?
23774 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
23776 this.displayEl.update(msg);
23781 onLoad : function(ds, r, o){
23782 this.cursor = o.params ? o.params.start : 0;
23783 var d = this.getPageData(),
23787 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
23788 this.field.dom.value = ap;
23789 this.first.setDisabled(ap == 1);
23790 this.prev.setDisabled(ap == 1);
23791 this.next.setDisabled(ap == ps);
23792 this.last.setDisabled(ap == ps);
23793 this.loading.enable();
23798 getPageData : function(){
23799 var total = this.ds.getTotalCount();
23802 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
23803 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
23808 onLoadError : function(){
23809 this.loading.enable();
23813 onPagingKeydown : function(e){
23814 var k = e.getKey();
23815 var d = this.getPageData();
23817 var v = this.field.dom.value, pageNum;
23818 if(!v || isNaN(pageNum = parseInt(v, 10))){
23819 this.field.dom.value = d.activePage;
23822 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
23823 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23826 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))
23828 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
23829 this.field.dom.value = pageNum;
23830 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
23833 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
23835 var v = this.field.dom.value, pageNum;
23836 var increment = (e.shiftKey) ? 10 : 1;
23837 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
23840 if(!v || isNaN(pageNum = parseInt(v, 10))) {
23841 this.field.dom.value = d.activePage;
23844 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
23846 this.field.dom.value = parseInt(v, 10) + increment;
23847 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
23848 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
23855 beforeLoad : function(){
23857 this.loading.disable();
23862 onClick : function(which){
23871 ds.load({params:{start: 0, limit: this.pageSize}});
23874 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
23877 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
23880 var total = ds.getTotalCount();
23881 var extra = total % this.pageSize;
23882 var lastStart = extra ? (total - extra) : total-this.pageSize;
23883 ds.load({params:{start: lastStart, limit: this.pageSize}});
23886 ds.load({params:{start: this.cursor, limit: this.pageSize}});
23892 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
23893 * @param {Roo.data.Store} store The data store to unbind
23895 unbind : function(ds){
23896 ds.un("beforeload", this.beforeLoad, this);
23897 ds.un("load", this.onLoad, this);
23898 ds.un("loadexception", this.onLoadError, this);
23899 ds.un("remove", this.updateInfo, this);
23900 ds.un("add", this.updateInfo, this);
23901 this.ds = undefined;
23905 * Binds the paging toolbar to the specified {@link Roo.data.Store}
23906 * @param {Roo.data.Store} store The data store to bind
23908 bind : function(ds){
23909 ds.on("beforeload", this.beforeLoad, this);
23910 ds.on("load", this.onLoad, this);
23911 ds.on("loadexception", this.onLoadError, this);
23912 ds.on("remove", this.updateInfo, this);
23913 ds.on("add", this.updateInfo, this);
23924 * @class Roo.bootstrap.MessageBar
23925 * @extends Roo.bootstrap.Component
23926 * Bootstrap MessageBar class
23927 * @cfg {String} html contents of the MessageBar
23928 * @cfg {String} weight (info | success | warning | danger) default info
23929 * @cfg {String} beforeClass insert the bar before the given class
23930 * @cfg {Boolean} closable (true | false) default false
23931 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
23934 * Create a new Element
23935 * @param {Object} config The config object
23938 Roo.bootstrap.MessageBar = function(config){
23939 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
23942 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
23948 beforeClass: 'bootstrap-sticky-wrap',
23950 getAutoCreate : function(){
23954 cls: 'alert alert-dismissable alert-' + this.weight,
23959 html: this.html || ''
23965 cfg.cls += ' alert-messages-fixed';
23979 onRender : function(ct, position)
23981 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
23984 var cfg = Roo.apply({}, this.getAutoCreate());
23988 cfg.cls += ' ' + this.cls;
23991 cfg.style = this.style;
23993 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
23995 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23998 this.el.select('>button.close').on('click', this.hide, this);
24004 if (!this.rendered) {
24010 this.fireEvent('show', this);
24016 if (!this.rendered) {
24022 this.fireEvent('hide', this);
24025 update : function()
24027 // var e = this.el.dom.firstChild;
24029 // if(this.closable){
24030 // e = e.nextSibling;
24033 // e.data = this.html || '';
24035 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24051 * @class Roo.bootstrap.Graph
24052 * @extends Roo.bootstrap.Component
24053 * Bootstrap Graph class
24057 @cfg {String} graphtype bar | vbar | pie
24058 @cfg {number} g_x coodinator | centre x (pie)
24059 @cfg {number} g_y coodinator | centre y (pie)
24060 @cfg {number} g_r radius (pie)
24061 @cfg {number} g_height height of the chart (respected by all elements in the set)
24062 @cfg {number} g_width width of the chart (respected by all elements in the set)
24063 @cfg {Object} title The title of the chart
24066 -opts (object) options for the chart
24068 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24069 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24071 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.
24072 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24074 o stretch (boolean)
24076 -opts (object) options for the pie
24079 o startAngle (number)
24080 o endAngle (number)
24084 * Create a new Input
24085 * @param {Object} config The config object
24088 Roo.bootstrap.Graph = function(config){
24089 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24095 * The img click event for the img.
24096 * @param {Roo.EventObject} e
24102 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24113 //g_colors: this.colors,
24120 getAutoCreate : function(){
24131 onRender : function(ct,position){
24134 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24136 if (typeof(Raphael) == 'undefined') {
24137 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24141 this.raphael = Raphael(this.el.dom);
24143 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24144 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24145 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24146 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24148 r.text(160, 10, "Single Series Chart").attr(txtattr);
24149 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24150 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24151 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24153 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24154 r.barchart(330, 10, 300, 220, data1);
24155 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24156 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24159 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24160 // r.barchart(30, 30, 560, 250, xdata, {
24161 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24162 // axis : "0 0 1 1",
24163 // axisxlabels : xdata
24164 // //yvalues : cols,
24167 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24169 // this.load(null,xdata,{
24170 // axis : "0 0 1 1",
24171 // axisxlabels : xdata
24176 load : function(graphtype,xdata,opts)
24178 this.raphael.clear();
24180 graphtype = this.graphtype;
24185 var r = this.raphael,
24186 fin = function () {
24187 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24189 fout = function () {
24190 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24192 pfin = function() {
24193 this.sector.stop();
24194 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24197 this.label[0].stop();
24198 this.label[0].attr({ r: 7.5 });
24199 this.label[1].attr({ "font-weight": 800 });
24202 pfout = function() {
24203 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
24206 this.label[0].animate({ r: 5 }, 500, "bounce");
24207 this.label[1].attr({ "font-weight": 400 });
24213 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24216 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
24219 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
24220 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
24222 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
24229 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
24234 setTitle: function(o)
24239 initEvents: function() {
24242 this.el.on('click', this.onClick, this);
24246 onClick : function(e)
24248 Roo.log('img onclick');
24249 this.fireEvent('click', this, e);
24261 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24264 * @class Roo.bootstrap.dash.NumberBox
24265 * @extends Roo.bootstrap.Component
24266 * Bootstrap NumberBox class
24267 * @cfg {String} headline Box headline
24268 * @cfg {String} content Box content
24269 * @cfg {String} icon Box icon
24270 * @cfg {String} footer Footer text
24271 * @cfg {String} fhref Footer href
24274 * Create a new NumberBox
24275 * @param {Object} config The config object
24279 Roo.bootstrap.dash.NumberBox = function(config){
24280 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
24284 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
24293 getAutoCreate : function(){
24297 cls : 'small-box ',
24305 cls : 'roo-headline',
24306 html : this.headline
24310 cls : 'roo-content',
24311 html : this.content
24325 cls : 'ion ' + this.icon
24334 cls : 'small-box-footer',
24335 href : this.fhref || '#',
24339 cfg.cn.push(footer);
24346 onRender : function(ct,position){
24347 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
24354 setHeadline: function (value)
24356 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
24359 setFooter: function (value, href)
24361 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
24364 this.el.select('a.small-box-footer',true).first().attr('href', href);
24369 setContent: function (value)
24371 this.el.select('.roo-content',true).first().dom.innerHTML = value;
24374 initEvents: function()
24388 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24391 * @class Roo.bootstrap.dash.TabBox
24392 * @extends Roo.bootstrap.Component
24393 * Bootstrap TabBox class
24394 * @cfg {String} title Title of the TabBox
24395 * @cfg {String} icon Icon of the TabBox
24396 * @cfg {Boolean} showtabs (true|false) show the tabs default true
24397 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
24400 * Create a new TabBox
24401 * @param {Object} config The config object
24405 Roo.bootstrap.dash.TabBox = function(config){
24406 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
24411 * When a pane is added
24412 * @param {Roo.bootstrap.dash.TabPane} pane
24416 * @event activatepane
24417 * When a pane is activated
24418 * @param {Roo.bootstrap.dash.TabPane} pane
24420 "activatepane" : true
24428 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
24433 tabScrollable : false,
24435 getChildContainer : function()
24437 return this.el.select('.tab-content', true).first();
24440 getAutoCreate : function(){
24444 cls: 'pull-left header',
24452 cls: 'fa ' + this.icon
24458 cls: 'nav nav-tabs pull-right',
24464 if(this.tabScrollable){
24471 cls: 'nav nav-tabs pull-right',
24482 cls: 'nav-tabs-custom',
24487 cls: 'tab-content no-padding',
24495 initEvents : function()
24497 //Roo.log('add add pane handler');
24498 this.on('addpane', this.onAddPane, this);
24501 * Updates the box title
24502 * @param {String} html to set the title to.
24504 setTitle : function(value)
24506 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
24508 onAddPane : function(pane)
24510 this.panes.push(pane);
24511 //Roo.log('addpane');
24513 // tabs are rendere left to right..
24514 if(!this.showtabs){
24518 var ctr = this.el.select('.nav-tabs', true).first();
24521 var existing = ctr.select('.nav-tab',true);
24522 var qty = existing.getCount();;
24525 var tab = ctr.createChild({
24527 cls : 'nav-tab' + (qty ? '' : ' active'),
24535 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
24538 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
24540 pane.el.addClass('active');
24545 onTabClick : function(ev,un,ob,pane)
24547 //Roo.log('tab - prev default');
24548 ev.preventDefault();
24551 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
24552 pane.tab.addClass('active');
24553 //Roo.log(pane.title);
24554 this.getChildContainer().select('.tab-pane',true).removeClass('active');
24555 // technically we should have a deactivate event.. but maybe add later.
24556 // and it should not de-activate the selected tab...
24557 this.fireEvent('activatepane', pane);
24558 pane.el.addClass('active');
24559 pane.fireEvent('activate');
24564 getActivePane : function()
24567 Roo.each(this.panes, function(p) {
24568 if(p.el.hasClass('active')){
24589 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
24591 * @class Roo.bootstrap.TabPane
24592 * @extends Roo.bootstrap.Component
24593 * Bootstrap TabPane class
24594 * @cfg {Boolean} active (false | true) Default false
24595 * @cfg {String} title title of panel
24599 * Create a new TabPane
24600 * @param {Object} config The config object
24603 Roo.bootstrap.dash.TabPane = function(config){
24604 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
24610 * When a pane is activated
24611 * @param {Roo.bootstrap.dash.TabPane} pane
24618 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
24623 // the tabBox that this is attached to.
24626 getAutoCreate : function()
24634 cfg.cls += ' active';
24639 initEvents : function()
24641 //Roo.log('trigger add pane handler');
24642 this.parent().fireEvent('addpane', this)
24646 * Updates the tab title
24647 * @param {String} html to set the title to.
24649 setTitle: function(str)
24655 this.tab.select('a', true).first().dom.innerHTML = str;
24672 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24675 * @class Roo.bootstrap.menu.Menu
24676 * @extends Roo.bootstrap.Component
24677 * Bootstrap Menu class - container for Menu
24678 * @cfg {String} html Text of the menu
24679 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
24680 * @cfg {String} icon Font awesome icon
24681 * @cfg {String} pos Menu align to (top | bottom) default bottom
24685 * Create a new Menu
24686 * @param {Object} config The config object
24690 Roo.bootstrap.menu.Menu = function(config){
24691 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
24695 * @event beforeshow
24696 * Fires before this menu is displayed
24697 * @param {Roo.bootstrap.menu.Menu} this
24701 * @event beforehide
24702 * Fires before this menu is hidden
24703 * @param {Roo.bootstrap.menu.Menu} this
24708 * Fires after this menu is displayed
24709 * @param {Roo.bootstrap.menu.Menu} this
24714 * Fires after this menu is hidden
24715 * @param {Roo.bootstrap.menu.Menu} this
24720 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
24721 * @param {Roo.bootstrap.menu.Menu} this
24722 * @param {Roo.EventObject} e
24729 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
24733 weight : 'default',
24738 getChildContainer : function() {
24739 if(this.isSubMenu){
24743 return this.el.select('ul.dropdown-menu', true).first();
24746 getAutoCreate : function()
24751 cls : 'roo-menu-text',
24759 cls : 'fa ' + this.icon
24770 cls : 'dropdown-button btn btn-' + this.weight,
24775 cls : 'dropdown-toggle btn btn-' + this.weight,
24785 cls : 'dropdown-menu'
24791 if(this.pos == 'top'){
24792 cfg.cls += ' dropup';
24795 if(this.isSubMenu){
24798 cls : 'dropdown-menu'
24805 onRender : function(ct, position)
24807 this.isSubMenu = ct.hasClass('dropdown-submenu');
24809 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
24812 initEvents : function()
24814 if(this.isSubMenu){
24818 this.hidden = true;
24820 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
24821 this.triggerEl.on('click', this.onTriggerPress, this);
24823 this.buttonEl = this.el.select('button.dropdown-button', true).first();
24824 this.buttonEl.on('click', this.onClick, this);
24830 if(this.isSubMenu){
24834 return this.el.select('ul.dropdown-menu', true).first();
24837 onClick : function(e)
24839 this.fireEvent("click", this, e);
24842 onTriggerPress : function(e)
24844 if (this.isVisible()) {
24851 isVisible : function(){
24852 return !this.hidden;
24857 this.fireEvent("beforeshow", this);
24859 this.hidden = false;
24860 this.el.addClass('open');
24862 Roo.get(document).on("mouseup", this.onMouseUp, this);
24864 this.fireEvent("show", this);
24871 this.fireEvent("beforehide", this);
24873 this.hidden = true;
24874 this.el.removeClass('open');
24876 Roo.get(document).un("mouseup", this.onMouseUp);
24878 this.fireEvent("hide", this);
24881 onMouseUp : function()
24895 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
24898 * @class Roo.bootstrap.menu.Item
24899 * @extends Roo.bootstrap.Component
24900 * Bootstrap MenuItem class
24901 * @cfg {Boolean} submenu (true | false) default false
24902 * @cfg {String} html text of the item
24903 * @cfg {String} href the link
24904 * @cfg {Boolean} disable (true | false) default false
24905 * @cfg {Boolean} preventDefault (true | false) default true
24906 * @cfg {String} icon Font awesome icon
24907 * @cfg {String} pos Submenu align to (left | right) default right
24911 * Create a new Item
24912 * @param {Object} config The config object
24916 Roo.bootstrap.menu.Item = function(config){
24917 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
24921 * Fires when the mouse is hovering over this menu
24922 * @param {Roo.bootstrap.menu.Item} this
24923 * @param {Roo.EventObject} e
24928 * Fires when the mouse exits this menu
24929 * @param {Roo.bootstrap.menu.Item} this
24930 * @param {Roo.EventObject} e
24936 * The raw click event for the entire grid.
24937 * @param {Roo.EventObject} e
24943 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
24948 preventDefault: true,
24953 getAutoCreate : function()
24958 cls : 'roo-menu-item-text',
24966 cls : 'fa ' + this.icon
24975 href : this.href || '#',
24982 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
24986 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
24988 if(this.pos == 'left'){
24989 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
24996 initEvents : function()
24998 this.el.on('mouseover', this.onMouseOver, this);
24999 this.el.on('mouseout', this.onMouseOut, this);
25001 this.el.select('a', true).first().on('click', this.onClick, this);
25005 onClick : function(e)
25007 if(this.preventDefault){
25008 e.preventDefault();
25011 this.fireEvent("click", this, e);
25014 onMouseOver : function(e)
25016 if(this.submenu && this.pos == 'left'){
25017 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25020 this.fireEvent("mouseover", this, e);
25023 onMouseOut : function(e)
25025 this.fireEvent("mouseout", this, e);
25037 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25040 * @class Roo.bootstrap.menu.Separator
25041 * @extends Roo.bootstrap.Component
25042 * Bootstrap Separator class
25045 * Create a new Separator
25046 * @param {Object} config The config object
25050 Roo.bootstrap.menu.Separator = function(config){
25051 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25054 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25056 getAutoCreate : function(){
25077 * @class Roo.bootstrap.Tooltip
25078 * Bootstrap Tooltip class
25079 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25080 * to determine which dom element triggers the tooltip.
25082 * It needs to add support for additional attributes like tooltip-position
25085 * Create a new Toolti
25086 * @param {Object} config The config object
25089 Roo.bootstrap.Tooltip = function(config){
25090 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25092 this.alignment = Roo.bootstrap.Tooltip.alignment;
25094 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25095 this.alignment = config.alignment;
25100 Roo.apply(Roo.bootstrap.Tooltip, {
25102 * @function init initialize tooltip monitoring.
25106 currentTip : false,
25107 currentRegion : false,
25113 Roo.get(document).on('mouseover', this.enter ,this);
25114 Roo.get(document).on('mouseout', this.leave, this);
25117 this.currentTip = new Roo.bootstrap.Tooltip();
25120 enter : function(ev)
25122 var dom = ev.getTarget();
25124 //Roo.log(['enter',dom]);
25125 var el = Roo.fly(dom);
25126 if (this.currentEl) {
25128 //Roo.log(this.currentEl);
25129 //Roo.log(this.currentEl.contains(dom));
25130 if (this.currentEl == el) {
25133 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25139 if (this.currentTip.el) {
25140 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25144 if(!el || el.dom == document){
25150 // you can not look for children, as if el is the body.. then everythign is the child..
25151 if (!el.attr('tooltip')) { //
25152 if (!el.select("[tooltip]").elements.length) {
25155 // is the mouse over this child...?
25156 bindEl = el.select("[tooltip]").first();
25157 var xy = ev.getXY();
25158 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25159 //Roo.log("not in region.");
25162 //Roo.log("child element over..");
25165 this.currentEl = bindEl;
25166 this.currentTip.bind(bindEl);
25167 this.currentRegion = Roo.lib.Region.getRegion(dom);
25168 this.currentTip.enter();
25171 leave : function(ev)
25173 var dom = ev.getTarget();
25174 //Roo.log(['leave',dom]);
25175 if (!this.currentEl) {
25180 if (dom != this.currentEl.dom) {
25183 var xy = ev.getXY();
25184 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25187 // only activate leave if mouse cursor is outside... bounding box..
25192 if (this.currentTip) {
25193 this.currentTip.leave();
25195 //Roo.log('clear currentEl');
25196 this.currentEl = false;
25201 'left' : ['r-l', [-2,0], 'right'],
25202 'right' : ['l-r', [2,0], 'left'],
25203 'bottom' : ['t-b', [0,2], 'top'],
25204 'top' : [ 'b-t', [0,-2], 'bottom']
25210 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
25215 delay : null, // can be { show : 300 , hide: 500}
25219 hoverState : null, //???
25221 placement : 'bottom',
25225 getAutoCreate : function(){
25232 cls : 'tooltip-arrow'
25235 cls : 'tooltip-inner'
25242 bind : function(el)
25248 enter : function () {
25250 if (this.timeout != null) {
25251 clearTimeout(this.timeout);
25254 this.hoverState = 'in';
25255 //Roo.log("enter - show");
25256 if (!this.delay || !this.delay.show) {
25261 this.timeout = setTimeout(function () {
25262 if (_t.hoverState == 'in') {
25265 }, this.delay.show);
25269 clearTimeout(this.timeout);
25271 this.hoverState = 'out';
25272 if (!this.delay || !this.delay.hide) {
25278 this.timeout = setTimeout(function () {
25279 //Roo.log("leave - timeout");
25281 if (_t.hoverState == 'out') {
25283 Roo.bootstrap.Tooltip.currentEl = false;
25288 show : function (msg)
25291 this.render(document.body);
25294 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
25296 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
25298 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
25300 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
25302 var placement = typeof this.placement == 'function' ?
25303 this.placement.call(this, this.el, on_el) :
25306 var autoToken = /\s?auto?\s?/i;
25307 var autoPlace = autoToken.test(placement);
25309 placement = placement.replace(autoToken, '') || 'top';
25313 //this.el.setXY([0,0]);
25315 //this.el.dom.style.display='block';
25317 //this.el.appendTo(on_el);
25319 var p = this.getPosition();
25320 var box = this.el.getBox();
25326 var align = this.alignment[placement];
25328 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
25330 if(placement == 'top' || placement == 'bottom'){
25332 placement = 'right';
25335 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
25336 placement = 'left';
25339 var scroll = Roo.select('body', true).first().getScroll();
25341 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
25347 this.el.alignTo(this.bindEl, align[0],align[1]);
25348 //var arrow = this.el.select('.arrow',true).first();
25349 //arrow.set(align[2],
25351 this.el.addClass(placement);
25353 this.el.addClass('in fade');
25355 this.hoverState = null;
25357 if (this.el.hasClass('fade')) {
25368 //this.el.setXY([0,0]);
25369 this.el.removeClass('in');
25385 * @class Roo.bootstrap.LocationPicker
25386 * @extends Roo.bootstrap.Component
25387 * Bootstrap LocationPicker class
25388 * @cfg {Number} latitude Position when init default 0
25389 * @cfg {Number} longitude Position when init default 0
25390 * @cfg {Number} zoom default 15
25391 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
25392 * @cfg {Boolean} mapTypeControl default false
25393 * @cfg {Boolean} disableDoubleClickZoom default false
25394 * @cfg {Boolean} scrollwheel default true
25395 * @cfg {Boolean} streetViewControl default false
25396 * @cfg {Number} radius default 0
25397 * @cfg {String} locationName
25398 * @cfg {Boolean} draggable default true
25399 * @cfg {Boolean} enableAutocomplete default false
25400 * @cfg {Boolean} enableReverseGeocode default true
25401 * @cfg {String} markerTitle
25404 * Create a new LocationPicker
25405 * @param {Object} config The config object
25409 Roo.bootstrap.LocationPicker = function(config){
25411 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
25416 * Fires when the picker initialized.
25417 * @param {Roo.bootstrap.LocationPicker} this
25418 * @param {Google Location} location
25422 * @event positionchanged
25423 * Fires when the picker position changed.
25424 * @param {Roo.bootstrap.LocationPicker} this
25425 * @param {Google Location} location
25427 positionchanged : true,
25430 * Fires when the map resize.
25431 * @param {Roo.bootstrap.LocationPicker} this
25436 * Fires when the map show.
25437 * @param {Roo.bootstrap.LocationPicker} this
25442 * Fires when the map hide.
25443 * @param {Roo.bootstrap.LocationPicker} this
25448 * Fires when click the map.
25449 * @param {Roo.bootstrap.LocationPicker} this
25450 * @param {Map event} e
25454 * @event mapRightClick
25455 * Fires when right click the map.
25456 * @param {Roo.bootstrap.LocationPicker} this
25457 * @param {Map event} e
25459 mapRightClick : true,
25461 * @event markerClick
25462 * Fires when click the marker.
25463 * @param {Roo.bootstrap.LocationPicker} this
25464 * @param {Map event} e
25466 markerClick : true,
25468 * @event markerRightClick
25469 * Fires when right click the marker.
25470 * @param {Roo.bootstrap.LocationPicker} this
25471 * @param {Map event} e
25473 markerRightClick : true,
25475 * @event OverlayViewDraw
25476 * Fires when OverlayView Draw
25477 * @param {Roo.bootstrap.LocationPicker} this
25479 OverlayViewDraw : true,
25481 * @event OverlayViewOnAdd
25482 * Fires when OverlayView Draw
25483 * @param {Roo.bootstrap.LocationPicker} this
25485 OverlayViewOnAdd : true,
25487 * @event OverlayViewOnRemove
25488 * Fires when OverlayView Draw
25489 * @param {Roo.bootstrap.LocationPicker} this
25491 OverlayViewOnRemove : true,
25493 * @event OverlayViewShow
25494 * Fires when OverlayView Draw
25495 * @param {Roo.bootstrap.LocationPicker} this
25496 * @param {Pixel} cpx
25498 OverlayViewShow : true,
25500 * @event OverlayViewHide
25501 * Fires when OverlayView Draw
25502 * @param {Roo.bootstrap.LocationPicker} this
25504 OverlayViewHide : true,
25506 * @event loadexception
25507 * Fires when load google lib failed.
25508 * @param {Roo.bootstrap.LocationPicker} this
25510 loadexception : true
25515 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
25517 gMapContext: false,
25523 mapTypeControl: false,
25524 disableDoubleClickZoom: false,
25526 streetViewControl: false,
25530 enableAutocomplete: false,
25531 enableReverseGeocode: true,
25534 getAutoCreate: function()
25539 cls: 'roo-location-picker'
25545 initEvents: function(ct, position)
25547 if(!this.el.getWidth() || this.isApplied()){
25551 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25556 initial: function()
25558 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
25559 this.fireEvent('loadexception', this);
25563 if(!this.mapTypeId){
25564 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
25567 this.gMapContext = this.GMapContext();
25569 this.initOverlayView();
25571 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
25575 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
25576 _this.setPosition(_this.gMapContext.marker.position);
25579 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
25580 _this.fireEvent('mapClick', this, event);
25584 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
25585 _this.fireEvent('mapRightClick', this, event);
25589 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
25590 _this.fireEvent('markerClick', this, event);
25594 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
25595 _this.fireEvent('markerRightClick', this, event);
25599 this.setPosition(this.gMapContext.location);
25601 this.fireEvent('initial', this, this.gMapContext.location);
25604 initOverlayView: function()
25608 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
25612 _this.fireEvent('OverlayViewDraw', _this);
25617 _this.fireEvent('OverlayViewOnAdd', _this);
25620 onRemove: function()
25622 _this.fireEvent('OverlayViewOnRemove', _this);
25625 show: function(cpx)
25627 _this.fireEvent('OverlayViewShow', _this, cpx);
25632 _this.fireEvent('OverlayViewHide', _this);
25638 fromLatLngToContainerPixel: function(event)
25640 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
25643 isApplied: function()
25645 return this.getGmapContext() == false ? false : true;
25648 getGmapContext: function()
25650 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
25653 GMapContext: function()
25655 var position = new google.maps.LatLng(this.latitude, this.longitude);
25657 var _map = new google.maps.Map(this.el.dom, {
25660 mapTypeId: this.mapTypeId,
25661 mapTypeControl: this.mapTypeControl,
25662 disableDoubleClickZoom: this.disableDoubleClickZoom,
25663 scrollwheel: this.scrollwheel,
25664 streetViewControl: this.streetViewControl,
25665 locationName: this.locationName,
25666 draggable: this.draggable,
25667 enableAutocomplete: this.enableAutocomplete,
25668 enableReverseGeocode: this.enableReverseGeocode
25671 var _marker = new google.maps.Marker({
25672 position: position,
25674 title: this.markerTitle,
25675 draggable: this.draggable
25682 location: position,
25683 radius: this.radius,
25684 locationName: this.locationName,
25685 addressComponents: {
25686 formatted_address: null,
25687 addressLine1: null,
25688 addressLine2: null,
25690 streetNumber: null,
25694 stateOrProvince: null
25697 domContainer: this.el.dom,
25698 geodecoder: new google.maps.Geocoder()
25702 drawCircle: function(center, radius, options)
25704 if (this.gMapContext.circle != null) {
25705 this.gMapContext.circle.setMap(null);
25709 options = Roo.apply({}, options, {
25710 strokeColor: "#0000FF",
25711 strokeOpacity: .35,
25713 fillColor: "#0000FF",
25717 options.map = this.gMapContext.map;
25718 options.radius = radius;
25719 options.center = center;
25720 this.gMapContext.circle = new google.maps.Circle(options);
25721 return this.gMapContext.circle;
25727 setPosition: function(location)
25729 this.gMapContext.location = location;
25730 this.gMapContext.marker.setPosition(location);
25731 this.gMapContext.map.panTo(location);
25732 this.drawCircle(location, this.gMapContext.radius, {});
25736 if (this.gMapContext.settings.enableReverseGeocode) {
25737 this.gMapContext.geodecoder.geocode({
25738 latLng: this.gMapContext.location
25739 }, function(results, status) {
25741 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
25742 _this.gMapContext.locationName = results[0].formatted_address;
25743 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
25745 _this.fireEvent('positionchanged', this, location);
25752 this.fireEvent('positionchanged', this, location);
25757 google.maps.event.trigger(this.gMapContext.map, "resize");
25759 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
25761 this.fireEvent('resize', this);
25764 setPositionByLatLng: function(latitude, longitude)
25766 this.setPosition(new google.maps.LatLng(latitude, longitude));
25769 getCurrentPosition: function()
25772 latitude: this.gMapContext.location.lat(),
25773 longitude: this.gMapContext.location.lng()
25777 getAddressName: function()
25779 return this.gMapContext.locationName;
25782 getAddressComponents: function()
25784 return this.gMapContext.addressComponents;
25787 address_component_from_google_geocode: function(address_components)
25791 for (var i = 0; i < address_components.length; i++) {
25792 var component = address_components[i];
25793 if (component.types.indexOf("postal_code") >= 0) {
25794 result.postalCode = component.short_name;
25795 } else if (component.types.indexOf("street_number") >= 0) {
25796 result.streetNumber = component.short_name;
25797 } else if (component.types.indexOf("route") >= 0) {
25798 result.streetName = component.short_name;
25799 } else if (component.types.indexOf("neighborhood") >= 0) {
25800 result.city = component.short_name;
25801 } else if (component.types.indexOf("locality") >= 0) {
25802 result.city = component.short_name;
25803 } else if (component.types.indexOf("sublocality") >= 0) {
25804 result.district = component.short_name;
25805 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
25806 result.stateOrProvince = component.short_name;
25807 } else if (component.types.indexOf("country") >= 0) {
25808 result.country = component.short_name;
25812 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
25813 result.addressLine2 = "";
25817 setZoomLevel: function(zoom)
25819 this.gMapContext.map.setZoom(zoom);
25832 this.fireEvent('show', this);
25843 this.fireEvent('hide', this);
25848 Roo.apply(Roo.bootstrap.LocationPicker, {
25850 OverlayView : function(map, options)
25852 options = options || {};
25866 * @class Roo.bootstrap.Alert
25867 * @extends Roo.bootstrap.Component
25868 * Bootstrap Alert class
25869 * @cfg {String} title The title of alert
25870 * @cfg {String} html The content of alert
25871 * @cfg {String} weight ( success | info | warning | danger )
25872 * @cfg {String} faicon font-awesomeicon
25875 * Create a new alert
25876 * @param {Object} config The config object
25880 Roo.bootstrap.Alert = function(config){
25881 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
25885 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
25892 getAutoCreate : function()
25901 cls : 'roo-alert-icon'
25906 cls : 'roo-alert-title',
25911 cls : 'roo-alert-text',
25918 cfg.cn[0].cls += ' fa ' + this.faicon;
25922 cfg.cls += ' alert-' + this.weight;
25928 initEvents: function()
25930 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25933 setTitle : function(str)
25935 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
25938 setText : function(str)
25940 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
25943 setWeight : function(weight)
25946 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
25949 this.weight = weight;
25951 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
25954 setIcon : function(icon)
25957 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
25960 this.faicon = icon;
25962 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
25983 * @class Roo.bootstrap.UploadCropbox
25984 * @extends Roo.bootstrap.Component
25985 * Bootstrap UploadCropbox class
25986 * @cfg {String} emptyText show when image has been loaded
25987 * @cfg {String} rotateNotify show when image too small to rotate
25988 * @cfg {Number} errorTimeout default 3000
25989 * @cfg {Number} minWidth default 300
25990 * @cfg {Number} minHeight default 300
25991 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
25992 * @cfg {Boolean} isDocument (true|false) default false
25993 * @cfg {String} url action url
25994 * @cfg {String} paramName default 'imageUpload'
25995 * @cfg {String} method default POST
25996 * @cfg {Boolean} loadMask (true|false) default true
25997 * @cfg {Boolean} loadingText default 'Loading...'
26000 * Create a new UploadCropbox
26001 * @param {Object} config The config object
26004 Roo.bootstrap.UploadCropbox = function(config){
26005 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26009 * @event beforeselectfile
26010 * Fire before select file
26011 * @param {Roo.bootstrap.UploadCropbox} this
26013 "beforeselectfile" : true,
26016 * Fire after initEvent
26017 * @param {Roo.bootstrap.UploadCropbox} this
26022 * Fire after initEvent
26023 * @param {Roo.bootstrap.UploadCropbox} this
26024 * @param {String} data
26029 * Fire when preparing the file data
26030 * @param {Roo.bootstrap.UploadCropbox} this
26031 * @param {Object} file
26036 * Fire when get exception
26037 * @param {Roo.bootstrap.UploadCropbox} this
26038 * @param {XMLHttpRequest} xhr
26040 "exception" : true,
26042 * @event beforeloadcanvas
26043 * Fire before load the canvas
26044 * @param {Roo.bootstrap.UploadCropbox} this
26045 * @param {String} src
26047 "beforeloadcanvas" : true,
26050 * Fire when trash image
26051 * @param {Roo.bootstrap.UploadCropbox} this
26056 * Fire when download the image
26057 * @param {Roo.bootstrap.UploadCropbox} this
26061 * @event footerbuttonclick
26062 * Fire when footerbuttonclick
26063 * @param {Roo.bootstrap.UploadCropbox} this
26064 * @param {String} type
26066 "footerbuttonclick" : true,
26070 * @param {Roo.bootstrap.UploadCropbox} this
26075 * Fire when rotate the image
26076 * @param {Roo.bootstrap.UploadCropbox} this
26077 * @param {String} pos
26082 * Fire when inspect the file
26083 * @param {Roo.bootstrap.UploadCropbox} this
26084 * @param {Object} file
26089 * Fire when xhr upload the file
26090 * @param {Roo.bootstrap.UploadCropbox} this
26091 * @param {Object} data
26096 * Fire when arrange the file data
26097 * @param {Roo.bootstrap.UploadCropbox} this
26098 * @param {Object} formData
26103 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26106 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26108 emptyText : 'Click to upload image',
26109 rotateNotify : 'Image is too small to rotate',
26110 errorTimeout : 3000,
26124 cropType : 'image/jpeg',
26126 canvasLoaded : false,
26127 isDocument : false,
26129 paramName : 'imageUpload',
26131 loadingText : 'Loading...',
26134 getAutoCreate : function()
26138 cls : 'roo-upload-cropbox',
26142 cls : 'roo-upload-cropbox-selector',
26147 cls : 'roo-upload-cropbox-body',
26148 style : 'cursor:pointer',
26152 cls : 'roo-upload-cropbox-preview'
26156 cls : 'roo-upload-cropbox-thumb'
26160 cls : 'roo-upload-cropbox-empty-notify',
26161 html : this.emptyText
26165 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26166 html : this.rotateNotify
26172 cls : 'roo-upload-cropbox-footer',
26175 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26185 onRender : function(ct, position)
26187 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26189 if (this.buttons.length) {
26191 Roo.each(this.buttons, function(bb) {
26193 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26195 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26201 this.maskEl = this.el;
26205 initEvents : function()
26207 this.urlAPI = (window.createObjectURL && window) ||
26208 (window.URL && URL.revokeObjectURL && URL) ||
26209 (window.webkitURL && webkitURL);
26211 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
26212 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26214 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
26215 this.selectorEl.hide();
26217 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
26218 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26220 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
26221 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26222 this.thumbEl.hide();
26224 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
26225 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26227 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
26228 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26229 this.errorEl.hide();
26231 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
26232 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
26233 this.footerEl.hide();
26235 this.setThumbBoxSize();
26241 this.fireEvent('initial', this);
26248 window.addEventListener("resize", function() { _this.resize(); } );
26250 this.bodyEl.on('click', this.beforeSelectFile, this);
26253 this.bodyEl.on('touchstart', this.onTouchStart, this);
26254 this.bodyEl.on('touchmove', this.onTouchMove, this);
26255 this.bodyEl.on('touchend', this.onTouchEnd, this);
26259 this.bodyEl.on('mousedown', this.onMouseDown, this);
26260 this.bodyEl.on('mousemove', this.onMouseMove, this);
26261 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
26262 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
26263 Roo.get(document).on('mouseup', this.onMouseUp, this);
26266 this.selectorEl.on('change', this.onFileSelected, this);
26272 this.baseScale = 1;
26274 this.baseRotate = 1;
26275 this.dragable = false;
26276 this.pinching = false;
26279 this.cropData = false;
26280 this.notifyEl.dom.innerHTML = this.emptyText;
26282 this.selectorEl.dom.value = '';
26286 resize : function()
26288 if(this.fireEvent('resize', this) != false){
26289 this.setThumbBoxPosition();
26290 this.setCanvasPosition();
26294 onFooterButtonClick : function(e, el, o, type)
26297 case 'rotate-left' :
26298 this.onRotateLeft(e);
26300 case 'rotate-right' :
26301 this.onRotateRight(e);
26304 this.beforeSelectFile(e);
26319 this.fireEvent('footerbuttonclick', this, type);
26322 beforeSelectFile : function(e)
26324 e.preventDefault();
26326 if(this.fireEvent('beforeselectfile', this) != false){
26327 this.selectorEl.dom.click();
26331 onFileSelected : function(e)
26333 e.preventDefault();
26335 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
26339 var file = this.selectorEl.dom.files[0];
26341 if(this.fireEvent('inspect', this, file) != false){
26342 this.prepare(file);
26347 trash : function(e)
26349 this.fireEvent('trash', this);
26352 download : function(e)
26354 this.fireEvent('download', this);
26357 loadCanvas : function(src)
26359 if(this.fireEvent('beforeloadcanvas', this, src) != false){
26363 this.imageEl = document.createElement('img');
26367 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
26369 this.imageEl.src = src;
26373 onLoadCanvas : function()
26375 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
26376 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
26378 this.bodyEl.un('click', this.beforeSelectFile, this);
26380 this.notifyEl.hide();
26381 this.thumbEl.show();
26382 this.footerEl.show();
26384 this.baseRotateLevel();
26386 if(this.isDocument){
26387 this.setThumbBoxSize();
26390 this.setThumbBoxPosition();
26392 this.baseScaleLevel();
26398 this.canvasLoaded = true;
26401 this.maskEl.unmask();
26406 setCanvasPosition : function()
26408 if(!this.canvasEl){
26412 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
26413 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
26415 this.previewEl.setLeft(pw);
26416 this.previewEl.setTop(ph);
26420 onMouseDown : function(e)
26424 this.dragable = true;
26425 this.pinching = false;
26427 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
26428 this.dragable = false;
26432 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26433 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26437 onMouseMove : function(e)
26441 if(!this.canvasLoaded){
26445 if (!this.dragable){
26449 var minX = Math.ceil(this.thumbEl.getLeft(true));
26450 var minY = Math.ceil(this.thumbEl.getTop(true));
26452 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
26453 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
26455 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26456 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26458 x = x - this.mouseX;
26459 y = y - this.mouseY;
26461 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
26462 var bgY = Math.ceil(y + this.previewEl.getTop(true));
26464 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
26465 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
26467 this.previewEl.setLeft(bgX);
26468 this.previewEl.setTop(bgY);
26470 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
26471 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
26474 onMouseUp : function(e)
26478 this.dragable = false;
26481 onMouseWheel : function(e)
26485 this.startScale = this.scale;
26487 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
26489 if(!this.zoomable()){
26490 this.scale = this.startScale;
26499 zoomable : function()
26501 var minScale = this.thumbEl.getWidth() / this.minWidth;
26503 if(this.minWidth < this.minHeight){
26504 minScale = this.thumbEl.getHeight() / this.minHeight;
26507 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
26508 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
26512 (this.rotate == 0 || this.rotate == 180) &&
26514 width > this.imageEl.OriginWidth ||
26515 height > this.imageEl.OriginHeight ||
26516 (width < this.minWidth && height < this.minHeight)
26524 (this.rotate == 90 || this.rotate == 270) &&
26526 width > this.imageEl.OriginWidth ||
26527 height > this.imageEl.OriginHeight ||
26528 (width < this.minHeight && height < this.minWidth)
26535 !this.isDocument &&
26536 (this.rotate == 0 || this.rotate == 180) &&
26538 width < this.minWidth ||
26539 width > this.imageEl.OriginWidth ||
26540 height < this.minHeight ||
26541 height > this.imageEl.OriginHeight
26548 !this.isDocument &&
26549 (this.rotate == 90 || this.rotate == 270) &&
26551 width < this.minHeight ||
26552 width > this.imageEl.OriginWidth ||
26553 height < this.minWidth ||
26554 height > this.imageEl.OriginHeight
26564 onRotateLeft : function(e)
26566 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26568 var minScale = this.thumbEl.getWidth() / this.minWidth;
26570 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26571 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26573 this.startScale = this.scale;
26575 while (this.getScaleLevel() < minScale){
26577 this.scale = this.scale + 1;
26579 if(!this.zoomable()){
26584 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26585 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26590 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26597 this.scale = this.startScale;
26599 this.onRotateFail();
26604 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
26606 if(this.isDocument){
26607 this.setThumbBoxSize();
26608 this.setThumbBoxPosition();
26609 this.setCanvasPosition();
26614 this.fireEvent('rotate', this, 'left');
26618 onRotateRight : function(e)
26620 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
26622 var minScale = this.thumbEl.getWidth() / this.minWidth;
26624 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
26625 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
26627 this.startScale = this.scale;
26629 while (this.getScaleLevel() < minScale){
26631 this.scale = this.scale + 1;
26633 if(!this.zoomable()){
26638 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
26639 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
26644 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26651 this.scale = this.startScale;
26653 this.onRotateFail();
26658 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
26660 if(this.isDocument){
26661 this.setThumbBoxSize();
26662 this.setThumbBoxPosition();
26663 this.setCanvasPosition();
26668 this.fireEvent('rotate', this, 'right');
26671 onRotateFail : function()
26673 this.errorEl.show(true);
26677 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
26682 this.previewEl.dom.innerHTML = '';
26684 var canvasEl = document.createElement("canvas");
26686 var contextEl = canvasEl.getContext("2d");
26688 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26689 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26690 var center = this.imageEl.OriginWidth / 2;
26692 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
26693 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26694 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26695 center = this.imageEl.OriginHeight / 2;
26698 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
26700 contextEl.translate(center, center);
26701 contextEl.rotate(this.rotate * Math.PI / 180);
26703 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26705 this.canvasEl = document.createElement("canvas");
26707 this.contextEl = this.canvasEl.getContext("2d");
26709 switch (this.rotate) {
26712 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26713 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26715 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26720 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26721 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26723 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26724 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);
26728 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26733 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
26734 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
26736 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26737 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);
26741 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);
26746 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
26747 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
26749 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
26750 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
26754 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);
26761 this.previewEl.appendChild(this.canvasEl);
26763 this.setCanvasPosition();
26768 if(!this.canvasLoaded){
26772 var imageCanvas = document.createElement("canvas");
26774 var imageContext = imageCanvas.getContext("2d");
26776 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26777 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
26779 var center = imageCanvas.width / 2;
26781 imageContext.translate(center, center);
26783 imageContext.rotate(this.rotate * Math.PI / 180);
26785 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
26787 var canvas = document.createElement("canvas");
26789 var context = canvas.getContext("2d");
26791 canvas.width = this.minWidth;
26792 canvas.height = this.minHeight;
26794 switch (this.rotate) {
26797 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26798 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26800 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26801 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26803 var targetWidth = this.minWidth - 2 * x;
26804 var targetHeight = this.minHeight - 2 * y;
26808 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26809 scale = targetWidth / width;
26812 if(x > 0 && y == 0){
26813 scale = targetHeight / height;
26816 if(x > 0 && y > 0){
26817 scale = targetWidth / width;
26819 if(width < height){
26820 scale = targetHeight / height;
26824 context.scale(scale, scale);
26826 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26827 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26829 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26830 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26832 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26837 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26838 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26840 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26841 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26843 var targetWidth = this.minWidth - 2 * x;
26844 var targetHeight = this.minHeight - 2 * y;
26848 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26849 scale = targetWidth / width;
26852 if(x > 0 && y == 0){
26853 scale = targetHeight / height;
26856 if(x > 0 && y > 0){
26857 scale = targetWidth / width;
26859 if(width < height){
26860 scale = targetHeight / height;
26864 context.scale(scale, scale);
26866 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26867 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26869 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26870 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26872 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26874 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26879 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
26880 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
26882 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26883 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26885 var targetWidth = this.minWidth - 2 * x;
26886 var targetHeight = this.minHeight - 2 * y;
26890 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26891 scale = targetWidth / width;
26894 if(x > 0 && y == 0){
26895 scale = targetHeight / height;
26898 if(x > 0 && y > 0){
26899 scale = targetWidth / width;
26901 if(width < height){
26902 scale = targetHeight / height;
26906 context.scale(scale, scale);
26908 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26909 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26911 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26912 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26914 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26915 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
26917 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26922 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
26923 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
26925 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
26926 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
26928 var targetWidth = this.minWidth - 2 * x;
26929 var targetHeight = this.minHeight - 2 * y;
26933 if((x == 0 && y == 0) || (x == 0 && y > 0)){
26934 scale = targetWidth / width;
26937 if(x > 0 && y == 0){
26938 scale = targetHeight / height;
26941 if(x > 0 && y > 0){
26942 scale = targetWidth / width;
26944 if(width < height){
26945 scale = targetHeight / height;
26949 context.scale(scale, scale);
26951 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
26952 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
26954 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
26955 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
26957 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
26959 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
26966 this.cropData = canvas.toDataURL(this.cropType);
26968 if(this.fireEvent('crop', this, this.cropData) !== false){
26969 this.process(this.file, this.cropData);
26976 setThumbBoxSize : function()
26980 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
26981 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
26982 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
26984 this.minWidth = width;
26985 this.minHeight = height;
26987 if(this.rotate == 90 || this.rotate == 270){
26988 this.minWidth = height;
26989 this.minHeight = width;
26994 width = Math.ceil(this.minWidth * height / this.minHeight);
26996 if(this.minWidth > this.minHeight){
26998 height = Math.ceil(this.minHeight * width / this.minWidth);
27001 this.thumbEl.setStyle({
27002 width : width + 'px',
27003 height : height + 'px'
27010 setThumbBoxPosition : function()
27012 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27013 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27015 this.thumbEl.setLeft(x);
27016 this.thumbEl.setTop(y);
27020 baseRotateLevel : function()
27022 this.baseRotate = 1;
27025 typeof(this.exif) != 'undefined' &&
27026 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27027 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27029 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27032 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27036 baseScaleLevel : function()
27040 if(this.isDocument){
27042 if(this.baseRotate == 6 || this.baseRotate == 8){
27044 height = this.thumbEl.getHeight();
27045 this.baseScale = height / this.imageEl.OriginWidth;
27047 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27048 width = this.thumbEl.getWidth();
27049 this.baseScale = width / this.imageEl.OriginHeight;
27055 height = this.thumbEl.getHeight();
27056 this.baseScale = height / this.imageEl.OriginHeight;
27058 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27059 width = this.thumbEl.getWidth();
27060 this.baseScale = width / this.imageEl.OriginWidth;
27066 if(this.baseRotate == 6 || this.baseRotate == 8){
27068 width = this.thumbEl.getHeight();
27069 this.baseScale = width / this.imageEl.OriginHeight;
27071 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27072 height = this.thumbEl.getWidth();
27073 this.baseScale = height / this.imageEl.OriginHeight;
27076 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27077 height = this.thumbEl.getWidth();
27078 this.baseScale = height / this.imageEl.OriginHeight;
27080 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27081 width = this.thumbEl.getHeight();
27082 this.baseScale = width / this.imageEl.OriginWidth;
27089 width = this.thumbEl.getWidth();
27090 this.baseScale = width / this.imageEl.OriginWidth;
27092 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27093 height = this.thumbEl.getHeight();
27094 this.baseScale = height / this.imageEl.OriginHeight;
27097 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27099 height = this.thumbEl.getHeight();
27100 this.baseScale = height / this.imageEl.OriginHeight;
27102 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27103 width = this.thumbEl.getWidth();
27104 this.baseScale = width / this.imageEl.OriginWidth;
27112 getScaleLevel : function()
27114 return this.baseScale * Math.pow(1.1, this.scale);
27117 onTouchStart : function(e)
27119 if(!this.canvasLoaded){
27120 this.beforeSelectFile(e);
27124 var touches = e.browserEvent.touches;
27130 if(touches.length == 1){
27131 this.onMouseDown(e);
27135 if(touches.length != 2){
27141 for(var i = 0, finger; finger = touches[i]; i++){
27142 coords.push(finger.pageX, finger.pageY);
27145 var x = Math.pow(coords[0] - coords[2], 2);
27146 var y = Math.pow(coords[1] - coords[3], 2);
27148 this.startDistance = Math.sqrt(x + y);
27150 this.startScale = this.scale;
27152 this.pinching = true;
27153 this.dragable = false;
27157 onTouchMove : function(e)
27159 if(!this.pinching && !this.dragable){
27163 var touches = e.browserEvent.touches;
27170 this.onMouseMove(e);
27176 for(var i = 0, finger; finger = touches[i]; i++){
27177 coords.push(finger.pageX, finger.pageY);
27180 var x = Math.pow(coords[0] - coords[2], 2);
27181 var y = Math.pow(coords[1] - coords[3], 2);
27183 this.endDistance = Math.sqrt(x + y);
27185 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27187 if(!this.zoomable()){
27188 this.scale = this.startScale;
27196 onTouchEnd : function(e)
27198 this.pinching = false;
27199 this.dragable = false;
27203 process : function(file, crop)
27206 this.maskEl.mask(this.loadingText);
27209 this.xhr = new XMLHttpRequest();
27211 file.xhr = this.xhr;
27213 this.xhr.open(this.method, this.url, true);
27216 "Accept": "application/json",
27217 "Cache-Control": "no-cache",
27218 "X-Requested-With": "XMLHttpRequest"
27221 for (var headerName in headers) {
27222 var headerValue = headers[headerName];
27224 this.xhr.setRequestHeader(headerName, headerValue);
27230 this.xhr.onload = function()
27232 _this.xhrOnLoad(_this.xhr);
27235 this.xhr.onerror = function()
27237 _this.xhrOnError(_this.xhr);
27240 var formData = new FormData();
27242 formData.append('returnHTML', 'NO');
27245 formData.append('crop', crop);
27248 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
27249 formData.append(this.paramName, file, file.name);
27252 if(typeof(file.filename) != 'undefined'){
27253 formData.append('filename', file.filename);
27256 if(typeof(file.mimetype) != 'undefined'){
27257 formData.append('mimetype', file.mimetype);
27260 if(this.fireEvent('arrange', this, formData) != false){
27261 this.xhr.send(formData);
27265 xhrOnLoad : function(xhr)
27268 this.maskEl.unmask();
27271 if (xhr.readyState !== 4) {
27272 this.fireEvent('exception', this, xhr);
27276 var response = Roo.decode(xhr.responseText);
27278 if(!response.success){
27279 this.fireEvent('exception', this, xhr);
27283 var response = Roo.decode(xhr.responseText);
27285 this.fireEvent('upload', this, response);
27289 xhrOnError : function()
27292 this.maskEl.unmask();
27295 Roo.log('xhr on error');
27297 var response = Roo.decode(xhr.responseText);
27303 prepare : function(file)
27306 this.maskEl.mask(this.loadingText);
27312 if(typeof(file) === 'string'){
27313 this.loadCanvas(file);
27317 if(!file || !this.urlAPI){
27322 this.cropType = file.type;
27326 if(this.fireEvent('prepare', this, this.file) != false){
27328 var reader = new FileReader();
27330 reader.onload = function (e) {
27331 if (e.target.error) {
27332 Roo.log(e.target.error);
27336 var buffer = e.target.result,
27337 dataView = new DataView(buffer),
27339 maxOffset = dataView.byteLength - 4,
27343 if (dataView.getUint16(0) === 0xffd8) {
27344 while (offset < maxOffset) {
27345 markerBytes = dataView.getUint16(offset);
27347 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
27348 markerLength = dataView.getUint16(offset + 2) + 2;
27349 if (offset + markerLength > dataView.byteLength) {
27350 Roo.log('Invalid meta data: Invalid segment size.');
27354 if(markerBytes == 0xffe1){
27355 _this.parseExifData(
27362 offset += markerLength;
27372 var url = _this.urlAPI.createObjectURL(_this.file);
27374 _this.loadCanvas(url);
27379 reader.readAsArrayBuffer(this.file);
27385 parseExifData : function(dataView, offset, length)
27387 var tiffOffset = offset + 10,
27391 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27392 // No Exif data, might be XMP data instead
27396 // Check for the ASCII code for "Exif" (0x45786966):
27397 if (dataView.getUint32(offset + 4) !== 0x45786966) {
27398 // No Exif data, might be XMP data instead
27401 if (tiffOffset + 8 > dataView.byteLength) {
27402 Roo.log('Invalid Exif data: Invalid segment size.');
27405 // Check for the two null bytes:
27406 if (dataView.getUint16(offset + 8) !== 0x0000) {
27407 Roo.log('Invalid Exif data: Missing byte alignment offset.');
27410 // Check the byte alignment:
27411 switch (dataView.getUint16(tiffOffset)) {
27413 littleEndian = true;
27416 littleEndian = false;
27419 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
27422 // Check for the TIFF tag marker (0x002A):
27423 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
27424 Roo.log('Invalid Exif data: Missing TIFF marker.');
27427 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
27428 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
27430 this.parseExifTags(
27433 tiffOffset + dirOffset,
27438 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
27443 if (dirOffset + 6 > dataView.byteLength) {
27444 Roo.log('Invalid Exif data: Invalid directory offset.');
27447 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
27448 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
27449 if (dirEndOffset + 4 > dataView.byteLength) {
27450 Roo.log('Invalid Exif data: Invalid directory size.');
27453 for (i = 0; i < tagsNumber; i += 1) {
27457 dirOffset + 2 + 12 * i, // tag offset
27461 // Return the offset to the next directory:
27462 return dataView.getUint32(dirEndOffset, littleEndian);
27465 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
27467 var tag = dataView.getUint16(offset, littleEndian);
27469 this.exif[tag] = this.getExifValue(
27473 dataView.getUint16(offset + 2, littleEndian), // tag type
27474 dataView.getUint32(offset + 4, littleEndian), // tag length
27479 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
27481 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
27490 Roo.log('Invalid Exif data: Invalid tag type.');
27494 tagSize = tagType.size * length;
27495 // Determine if the value is contained in the dataOffset bytes,
27496 // or if the value at the dataOffset is a pointer to the actual data:
27497 dataOffset = tagSize > 4 ?
27498 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
27499 if (dataOffset + tagSize > dataView.byteLength) {
27500 Roo.log('Invalid Exif data: Invalid data offset.');
27503 if (length === 1) {
27504 return tagType.getValue(dataView, dataOffset, littleEndian);
27507 for (i = 0; i < length; i += 1) {
27508 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
27511 if (tagType.ascii) {
27513 // Concatenate the chars:
27514 for (i = 0; i < values.length; i += 1) {
27516 // Ignore the terminating NULL byte(s):
27517 if (c === '\u0000') {
27529 Roo.apply(Roo.bootstrap.UploadCropbox, {
27531 'Orientation': 0x0112
27535 1: 0, //'top-left',
27537 3: 180, //'bottom-right',
27538 // 4: 'bottom-left',
27540 6: 90, //'right-top',
27541 // 7: 'right-bottom',
27542 8: 270 //'left-bottom'
27546 // byte, 8-bit unsigned int:
27548 getValue: function (dataView, dataOffset) {
27549 return dataView.getUint8(dataOffset);
27553 // ascii, 8-bit byte:
27555 getValue: function (dataView, dataOffset) {
27556 return String.fromCharCode(dataView.getUint8(dataOffset));
27561 // short, 16 bit int:
27563 getValue: function (dataView, dataOffset, littleEndian) {
27564 return dataView.getUint16(dataOffset, littleEndian);
27568 // long, 32 bit int:
27570 getValue: function (dataView, dataOffset, littleEndian) {
27571 return dataView.getUint32(dataOffset, littleEndian);
27575 // rational = two long values, first is numerator, second is denominator:
27577 getValue: function (dataView, dataOffset, littleEndian) {
27578 return dataView.getUint32(dataOffset, littleEndian) /
27579 dataView.getUint32(dataOffset + 4, littleEndian);
27583 // slong, 32 bit signed int:
27585 getValue: function (dataView, dataOffset, littleEndian) {
27586 return dataView.getInt32(dataOffset, littleEndian);
27590 // srational, two slongs, first is numerator, second is denominator:
27592 getValue: function (dataView, dataOffset, littleEndian) {
27593 return dataView.getInt32(dataOffset, littleEndian) /
27594 dataView.getInt32(dataOffset + 4, littleEndian);
27604 cls : 'btn-group roo-upload-cropbox-rotate-left',
27605 action : 'rotate-left',
27609 cls : 'btn btn-default',
27610 html : '<i class="fa fa-undo"></i>'
27616 cls : 'btn-group roo-upload-cropbox-picture',
27617 action : 'picture',
27621 cls : 'btn btn-default',
27622 html : '<i class="fa fa-picture-o"></i>'
27628 cls : 'btn-group roo-upload-cropbox-rotate-right',
27629 action : 'rotate-right',
27633 cls : 'btn btn-default',
27634 html : '<i class="fa fa-repeat"></i>'
27642 cls : 'btn-group roo-upload-cropbox-rotate-left',
27643 action : 'rotate-left',
27647 cls : 'btn btn-default',
27648 html : '<i class="fa fa-undo"></i>'
27654 cls : 'btn-group roo-upload-cropbox-download',
27655 action : 'download',
27659 cls : 'btn btn-default',
27660 html : '<i class="fa fa-download"></i>'
27666 cls : 'btn-group roo-upload-cropbox-crop',
27671 cls : 'btn btn-default',
27672 html : '<i class="fa fa-crop"></i>'
27678 cls : 'btn-group roo-upload-cropbox-trash',
27683 cls : 'btn btn-default',
27684 html : '<i class="fa fa-trash"></i>'
27690 cls : 'btn-group roo-upload-cropbox-rotate-right',
27691 action : 'rotate-right',
27695 cls : 'btn btn-default',
27696 html : '<i class="fa fa-repeat"></i>'
27704 cls : 'btn-group roo-upload-cropbox-rotate-left',
27705 action : 'rotate-left',
27709 cls : 'btn btn-default',
27710 html : '<i class="fa fa-undo"></i>'
27716 cls : 'btn-group roo-upload-cropbox-rotate-right',
27717 action : 'rotate-right',
27721 cls : 'btn btn-default',
27722 html : '<i class="fa fa-repeat"></i>'
27735 * @class Roo.bootstrap.DocumentManager
27736 * @extends Roo.bootstrap.Component
27737 * Bootstrap DocumentManager class
27738 * @cfg {String} paramName default 'imageUpload'
27739 * @cfg {String} toolTipName default 'filename'
27740 * @cfg {String} method default POST
27741 * @cfg {String} url action url
27742 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
27743 * @cfg {Boolean} multiple multiple upload default true
27744 * @cfg {Number} thumbSize default 300
27745 * @cfg {String} fieldLabel
27746 * @cfg {Number} labelWidth default 4
27747 * @cfg {String} labelAlign (left|top) default left
27748 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
27749 * @cfg {Number} labellg set the width of label (1-12)
27750 * @cfg {Number} labelmd set the width of label (1-12)
27751 * @cfg {Number} labelsm set the width of label (1-12)
27752 * @cfg {Number} labelxs set the width of label (1-12)
27755 * Create a new DocumentManager
27756 * @param {Object} config The config object
27759 Roo.bootstrap.DocumentManager = function(config){
27760 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
27763 this.delegates = [];
27768 * Fire when initial the DocumentManager
27769 * @param {Roo.bootstrap.DocumentManager} this
27774 * inspect selected file
27775 * @param {Roo.bootstrap.DocumentManager} this
27776 * @param {File} file
27781 * Fire when xhr load exception
27782 * @param {Roo.bootstrap.DocumentManager} this
27783 * @param {XMLHttpRequest} xhr
27785 "exception" : true,
27787 * @event afterupload
27788 * Fire when xhr load exception
27789 * @param {Roo.bootstrap.DocumentManager} this
27790 * @param {XMLHttpRequest} xhr
27792 "afterupload" : true,
27795 * prepare the form data
27796 * @param {Roo.bootstrap.DocumentManager} this
27797 * @param {Object} formData
27802 * Fire when remove the file
27803 * @param {Roo.bootstrap.DocumentManager} this
27804 * @param {Object} file
27809 * Fire after refresh the file
27810 * @param {Roo.bootstrap.DocumentManager} this
27815 * Fire after click the image
27816 * @param {Roo.bootstrap.DocumentManager} this
27817 * @param {Object} file
27822 * Fire when upload a image and editable set to true
27823 * @param {Roo.bootstrap.DocumentManager} this
27824 * @param {Object} file
27828 * @event beforeselectfile
27829 * Fire before select file
27830 * @param {Roo.bootstrap.DocumentManager} this
27832 "beforeselectfile" : true,
27835 * Fire before process file
27836 * @param {Roo.bootstrap.DocumentManager} this
27837 * @param {Object} file
27844 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
27853 paramName : 'imageUpload',
27854 toolTipName : 'filename',
27857 labelAlign : 'left',
27867 getAutoCreate : function()
27869 var managerWidget = {
27871 cls : 'roo-document-manager',
27875 cls : 'roo-document-manager-selector',
27880 cls : 'roo-document-manager-uploader',
27884 cls : 'roo-document-manager-upload-btn',
27885 html : '<i class="fa fa-plus"></i>'
27896 cls : 'column col-md-12',
27901 if(this.fieldLabel.length){
27906 cls : 'column col-md-12',
27907 html : this.fieldLabel
27911 cls : 'column col-md-12',
27916 if(this.labelAlign == 'left'){
27921 html : this.fieldLabel
27930 if(this.labelWidth > 12){
27931 content[0].style = "width: " + this.labelWidth + 'px';
27934 if(this.labelWidth < 13 && this.labelmd == 0){
27935 this.labelmd = this.labelWidth;
27938 if(this.labellg > 0){
27939 content[0].cls += ' col-lg-' + this.labellg;
27940 content[1].cls += ' col-lg-' + (12 - this.labellg);
27943 if(this.labelmd > 0){
27944 content[0].cls += ' col-md-' + this.labelmd;
27945 content[1].cls += ' col-md-' + (12 - this.labelmd);
27948 if(this.labelsm > 0){
27949 content[0].cls += ' col-sm-' + this.labelsm;
27950 content[1].cls += ' col-sm-' + (12 - this.labelsm);
27953 if(this.labelxs > 0){
27954 content[0].cls += ' col-xs-' + this.labelxs;
27955 content[1].cls += ' col-xs-' + (12 - this.labelxs);
27963 cls : 'row clearfix',
27971 initEvents : function()
27973 this.managerEl = this.el.select('.roo-document-manager', true).first();
27974 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27976 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
27977 this.selectorEl.hide();
27980 this.selectorEl.attr('multiple', 'multiple');
27983 this.selectorEl.on('change', this.onFileSelected, this);
27985 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
27986 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27988 this.uploader.on('click', this.onUploaderClick, this);
27990 this.renderProgressDialog();
27994 window.addEventListener("resize", function() { _this.refresh(); } );
27996 this.fireEvent('initial', this);
27999 renderProgressDialog : function()
28003 this.progressDialog = new Roo.bootstrap.Modal({
28004 cls : 'roo-document-manager-progress-dialog',
28005 allow_close : false,
28015 btnclick : function() {
28016 _this.uploadCancel();
28022 this.progressDialog.render(Roo.get(document.body));
28024 this.progress = new Roo.bootstrap.Progress({
28025 cls : 'roo-document-manager-progress',
28030 this.progress.render(this.progressDialog.getChildContainer());
28032 this.progressBar = new Roo.bootstrap.ProgressBar({
28033 cls : 'roo-document-manager-progress-bar',
28036 aria_valuemax : 12,
28040 this.progressBar.render(this.progress.getChildContainer());
28043 onUploaderClick : function(e)
28045 e.preventDefault();
28047 if(this.fireEvent('beforeselectfile', this) != false){
28048 this.selectorEl.dom.click();
28053 onFileSelected : function(e)
28055 e.preventDefault();
28057 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28061 Roo.each(this.selectorEl.dom.files, function(file){
28062 if(this.fireEvent('inspect', this, file) != false){
28063 this.files.push(file);
28073 this.selectorEl.dom.value = '';
28075 if(!this.files.length){
28079 if(this.boxes > 0 && this.files.length > this.boxes){
28080 this.files = this.files.slice(0, this.boxes);
28083 this.uploader.show();
28085 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28086 this.uploader.hide();
28095 Roo.each(this.files, function(file){
28097 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28098 var f = this.renderPreview(file);
28103 if(file.type.indexOf('image') != -1){
28104 this.delegates.push(
28106 _this.process(file);
28107 }).createDelegate(this)
28115 _this.process(file);
28116 }).createDelegate(this)
28121 this.files = files;
28123 this.delegates = this.delegates.concat(docs);
28125 if(!this.delegates.length){
28130 this.progressBar.aria_valuemax = this.delegates.length;
28137 arrange : function()
28139 if(!this.delegates.length){
28140 this.progressDialog.hide();
28145 var delegate = this.delegates.shift();
28147 this.progressDialog.show();
28149 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28151 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28156 refresh : function()
28158 this.uploader.show();
28160 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28161 this.uploader.hide();
28164 Roo.isTouch ? this.closable(false) : this.closable(true);
28166 this.fireEvent('refresh', this);
28169 onRemove : function(e, el, o)
28171 e.preventDefault();
28173 this.fireEvent('remove', this, o);
28177 remove : function(o)
28181 Roo.each(this.files, function(file){
28182 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28191 this.files = files;
28198 Roo.each(this.files, function(file){
28203 file.target.remove();
28212 onClick : function(e, el, o)
28214 e.preventDefault();
28216 this.fireEvent('click', this, o);
28220 closable : function(closable)
28222 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
28224 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28236 xhrOnLoad : function(xhr)
28238 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28242 if (xhr.readyState !== 4) {
28244 this.fireEvent('exception', this, xhr);
28248 var response = Roo.decode(xhr.responseText);
28250 if(!response.success){
28252 this.fireEvent('exception', this, xhr);
28256 var file = this.renderPreview(response.data);
28258 this.files.push(file);
28262 this.fireEvent('afterupload', this, xhr);
28266 xhrOnError : function(xhr)
28268 Roo.log('xhr on error');
28270 var response = Roo.decode(xhr.responseText);
28277 process : function(file)
28279 if(this.fireEvent('process', this, file) !== false){
28280 if(this.editable && file.type.indexOf('image') != -1){
28281 this.fireEvent('edit', this, file);
28285 this.uploadStart(file, false);
28292 uploadStart : function(file, crop)
28294 this.xhr = new XMLHttpRequest();
28296 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28301 file.xhr = this.xhr;
28303 this.managerEl.createChild({
28305 cls : 'roo-document-manager-loading',
28309 tooltip : file.name,
28310 cls : 'roo-document-manager-thumb',
28311 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28317 this.xhr.open(this.method, this.url, true);
28320 "Accept": "application/json",
28321 "Cache-Control": "no-cache",
28322 "X-Requested-With": "XMLHttpRequest"
28325 for (var headerName in headers) {
28326 var headerValue = headers[headerName];
28328 this.xhr.setRequestHeader(headerName, headerValue);
28334 this.xhr.onload = function()
28336 _this.xhrOnLoad(_this.xhr);
28339 this.xhr.onerror = function()
28341 _this.xhrOnError(_this.xhr);
28344 var formData = new FormData();
28346 formData.append('returnHTML', 'NO');
28349 formData.append('crop', crop);
28352 formData.append(this.paramName, file, file.name);
28359 if(this.fireEvent('prepare', this, formData, options) != false){
28361 if(options.manually){
28365 this.xhr.send(formData);
28369 this.uploadCancel();
28372 uploadCancel : function()
28378 this.delegates = [];
28380 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
28387 renderPreview : function(file)
28389 if(typeof(file.target) != 'undefined' && file.target){
28393 var previewEl = this.managerEl.createChild({
28395 cls : 'roo-document-manager-preview',
28399 tooltip : file[this.toolTipName],
28400 cls : 'roo-document-manager-thumb',
28401 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
28406 html : '<i class="fa fa-times-circle"></i>'
28411 var close = previewEl.select('button.close', true).first();
28413 close.on('click', this.onRemove, this, file);
28415 file.target = previewEl;
28417 var image = previewEl.select('img', true).first();
28421 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
28423 image.on('click', this.onClick, this, file);
28429 onPreviewLoad : function(file, image)
28431 if(typeof(file.target) == 'undefined' || !file.target){
28435 var width = image.dom.naturalWidth || image.dom.width;
28436 var height = image.dom.naturalHeight || image.dom.height;
28438 if(width > height){
28439 file.target.addClass('wide');
28443 file.target.addClass('tall');
28448 uploadFromSource : function(file, crop)
28450 this.xhr = new XMLHttpRequest();
28452 this.managerEl.createChild({
28454 cls : 'roo-document-manager-loading',
28458 tooltip : file.name,
28459 cls : 'roo-document-manager-thumb',
28460 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
28466 this.xhr.open(this.method, this.url, true);
28469 "Accept": "application/json",
28470 "Cache-Control": "no-cache",
28471 "X-Requested-With": "XMLHttpRequest"
28474 for (var headerName in headers) {
28475 var headerValue = headers[headerName];
28477 this.xhr.setRequestHeader(headerName, headerValue);
28483 this.xhr.onload = function()
28485 _this.xhrOnLoad(_this.xhr);
28488 this.xhr.onerror = function()
28490 _this.xhrOnError(_this.xhr);
28493 var formData = new FormData();
28495 formData.append('returnHTML', 'NO');
28497 formData.append('crop', crop);
28499 if(typeof(file.filename) != 'undefined'){
28500 formData.append('filename', file.filename);
28503 if(typeof(file.mimetype) != 'undefined'){
28504 formData.append('mimetype', file.mimetype);
28509 if(this.fireEvent('prepare', this, formData) != false){
28510 this.xhr.send(formData);
28520 * @class Roo.bootstrap.DocumentViewer
28521 * @extends Roo.bootstrap.Component
28522 * Bootstrap DocumentViewer class
28523 * @cfg {Boolean} showDownload (true|false) show download button (default true)
28524 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
28527 * Create a new DocumentViewer
28528 * @param {Object} config The config object
28531 Roo.bootstrap.DocumentViewer = function(config){
28532 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
28537 * Fire after initEvent
28538 * @param {Roo.bootstrap.DocumentViewer} this
28544 * @param {Roo.bootstrap.DocumentViewer} this
28549 * Fire after download button
28550 * @param {Roo.bootstrap.DocumentViewer} this
28555 * Fire after trash button
28556 * @param {Roo.bootstrap.DocumentViewer} this
28563 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
28565 showDownload : true,
28569 getAutoCreate : function()
28573 cls : 'roo-document-viewer',
28577 cls : 'roo-document-viewer-body',
28581 cls : 'roo-document-viewer-thumb',
28585 cls : 'roo-document-viewer-image'
28593 cls : 'roo-document-viewer-footer',
28596 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
28600 cls : 'btn-group roo-document-viewer-download',
28604 cls : 'btn btn-default',
28605 html : '<i class="fa fa-download"></i>'
28611 cls : 'btn-group roo-document-viewer-trash',
28615 cls : 'btn btn-default',
28616 html : '<i class="fa fa-trash"></i>'
28629 initEvents : function()
28631 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
28632 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
28634 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
28635 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
28637 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
28638 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
28640 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
28641 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
28643 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
28644 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
28646 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
28647 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
28649 this.bodyEl.on('click', this.onClick, this);
28650 this.downloadBtn.on('click', this.onDownload, this);
28651 this.trashBtn.on('click', this.onTrash, this);
28653 this.downloadBtn.hide();
28654 this.trashBtn.hide();
28656 if(this.showDownload){
28657 this.downloadBtn.show();
28660 if(this.showTrash){
28661 this.trashBtn.show();
28664 if(!this.showDownload && !this.showTrash) {
28665 this.footerEl.hide();
28670 initial : function()
28672 this.fireEvent('initial', this);
28676 onClick : function(e)
28678 e.preventDefault();
28680 this.fireEvent('click', this);
28683 onDownload : function(e)
28685 e.preventDefault();
28687 this.fireEvent('download', this);
28690 onTrash : function(e)
28692 e.preventDefault();
28694 this.fireEvent('trash', this);
28706 * @class Roo.bootstrap.NavProgressBar
28707 * @extends Roo.bootstrap.Component
28708 * Bootstrap NavProgressBar class
28711 * Create a new nav progress bar
28712 * @param {Object} config The config object
28715 Roo.bootstrap.NavProgressBar = function(config){
28716 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
28718 this.bullets = this.bullets || [];
28720 // Roo.bootstrap.NavProgressBar.register(this);
28724 * Fires when the active item changes
28725 * @param {Roo.bootstrap.NavProgressBar} this
28726 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
28727 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
28734 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
28739 getAutoCreate : function()
28741 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
28745 cls : 'roo-navigation-bar-group',
28749 cls : 'roo-navigation-top-bar'
28753 cls : 'roo-navigation-bullets-bar',
28757 cls : 'roo-navigation-bar'
28764 cls : 'roo-navigation-bottom-bar'
28774 initEvents: function()
28779 onRender : function(ct, position)
28781 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
28783 if(this.bullets.length){
28784 Roo.each(this.bullets, function(b){
28793 addItem : function(cfg)
28795 var item = new Roo.bootstrap.NavProgressItem(cfg);
28797 item.parentId = this.id;
28798 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
28801 var top = new Roo.bootstrap.Element({
28803 cls : 'roo-navigation-bar-text'
28806 var bottom = new Roo.bootstrap.Element({
28808 cls : 'roo-navigation-bar-text'
28811 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
28812 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
28814 var topText = new Roo.bootstrap.Element({
28816 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
28819 var bottomText = new Roo.bootstrap.Element({
28821 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
28824 topText.onRender(top.el, null);
28825 bottomText.onRender(bottom.el, null);
28828 item.bottomEl = bottom;
28831 this.barItems.push(item);
28836 getActive : function()
28838 var active = false;
28840 Roo.each(this.barItems, function(v){
28842 if (!v.isActive()) {
28854 setActiveItem : function(item)
28858 Roo.each(this.barItems, function(v){
28859 if (v.rid == item.rid) {
28863 if (v.isActive()) {
28864 v.setActive(false);
28869 item.setActive(true);
28871 this.fireEvent('changed', this, item, prev);
28874 getBarItem: function(rid)
28878 Roo.each(this.barItems, function(e) {
28879 if (e.rid != rid) {
28890 indexOfItem : function(item)
28894 Roo.each(this.barItems, function(v, i){
28896 if (v.rid != item.rid) {
28907 setActiveNext : function()
28909 var i = this.indexOfItem(this.getActive());
28911 if (i > this.barItems.length) {
28915 this.setActiveItem(this.barItems[i+1]);
28918 setActivePrev : function()
28920 var i = this.indexOfItem(this.getActive());
28926 this.setActiveItem(this.barItems[i-1]);
28929 format : function()
28931 if(!this.barItems.length){
28935 var width = 100 / this.barItems.length;
28937 Roo.each(this.barItems, function(i){
28938 i.el.setStyle('width', width + '%');
28939 i.topEl.el.setStyle('width', width + '%');
28940 i.bottomEl.el.setStyle('width', width + '%');
28949 * Nav Progress Item
28954 * @class Roo.bootstrap.NavProgressItem
28955 * @extends Roo.bootstrap.Component
28956 * Bootstrap NavProgressItem class
28957 * @cfg {String} rid the reference id
28958 * @cfg {Boolean} active (true|false) Is item active default false
28959 * @cfg {Boolean} disabled (true|false) Is item active default false
28960 * @cfg {String} html
28961 * @cfg {String} position (top|bottom) text position default bottom
28962 * @cfg {String} icon show icon instead of number
28965 * Create a new NavProgressItem
28966 * @param {Object} config The config object
28968 Roo.bootstrap.NavProgressItem = function(config){
28969 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
28974 * The raw click event for the entire grid.
28975 * @param {Roo.bootstrap.NavProgressItem} this
28976 * @param {Roo.EventObject} e
28983 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
28989 position : 'bottom',
28992 getAutoCreate : function()
28994 var iconCls = 'roo-navigation-bar-item-icon';
28996 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29000 cls: 'roo-navigation-bar-item',
29010 cfg.cls += ' active';
29013 cfg.cls += ' disabled';
29019 disable : function()
29021 this.setDisabled(true);
29024 enable : function()
29026 this.setDisabled(false);
29029 initEvents: function()
29031 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29033 this.iconEl.on('click', this.onClick, this);
29036 onClick : function(e)
29038 e.preventDefault();
29044 if(this.fireEvent('click', this, e) === false){
29048 this.parent().setActiveItem(this);
29051 isActive: function ()
29053 return this.active;
29056 setActive : function(state)
29058 if(this.active == state){
29062 this.active = state;
29065 this.el.addClass('active');
29069 this.el.removeClass('active');
29074 setDisabled : function(state)
29076 if(this.disabled == state){
29080 this.disabled = state;
29083 this.el.addClass('disabled');
29087 this.el.removeClass('disabled');
29090 tooltipEl : function()
29092 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29105 * @class Roo.bootstrap.FieldLabel
29106 * @extends Roo.bootstrap.Component
29107 * Bootstrap FieldLabel class
29108 * @cfg {String} html contents of the element
29109 * @cfg {String} tag tag of the element default label
29110 * @cfg {String} cls class of the element
29111 * @cfg {String} target label target
29112 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29113 * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
29114 * @cfg {String} validClass default "text-success fa fa-lg fa-check"
29115 * @cfg {String} iconTooltip default "This field is required"
29118 * Create a new FieldLabel
29119 * @param {Object} config The config object
29122 Roo.bootstrap.FieldLabel = function(config){
29123 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29128 * Fires after the field has been marked as invalid.
29129 * @param {Roo.form.FieldLabel} this
29130 * @param {String} msg The validation message
29135 * Fires after the field has been validated with no errors.
29136 * @param {Roo.form.FieldLabel} this
29142 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29149 invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
29150 validClass : 'text-success fa fa-lg fa-check',
29151 iconTooltip : 'This field is required',
29153 getAutoCreate : function(){
29157 cls : 'roo-bootstrap-field-label ' + this.cls,
29163 tooltip : this.iconTooltip
29175 initEvents: function()
29177 Roo.bootstrap.Element.superclass.initEvents.call(this);
29179 this.iconEl = this.el.select('i', true).first();
29181 this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
29183 Roo.bootstrap.FieldLabel.register(this);
29187 * Mark this field as valid
29189 markValid : function()
29191 this.iconEl.show();
29193 this.iconEl.removeClass(this.invalidClass);
29195 this.iconEl.addClass(this.validClass);
29197 this.fireEvent('valid', this);
29201 * Mark this field as invalid
29202 * @param {String} msg The validation message
29204 markInvalid : function(msg)
29206 this.iconEl.show();
29208 this.iconEl.removeClass(this.validClass);
29210 this.iconEl.addClass(this.invalidClass);
29212 this.fireEvent('invalid', this, msg);
29218 Roo.apply(Roo.bootstrap.FieldLabel, {
29223 * register a FieldLabel Group
29224 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
29226 register : function(label)
29228 if(this.groups.hasOwnProperty(label.target)){
29232 this.groups[label.target] = label;
29236 * fetch a FieldLabel Group based on the target
29237 * @param {string} target
29238 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
29240 get: function(target) {
29241 if (typeof(this.groups[target]) == 'undefined') {
29245 return this.groups[target] ;
29254 * page DateSplitField.
29260 * @class Roo.bootstrap.DateSplitField
29261 * @extends Roo.bootstrap.Component
29262 * Bootstrap DateSplitField class
29263 * @cfg {string} fieldLabel - the label associated
29264 * @cfg {Number} labelWidth set the width of label (0-12)
29265 * @cfg {String} labelAlign (top|left)
29266 * @cfg {Boolean} dayAllowBlank (true|false) default false
29267 * @cfg {Boolean} monthAllowBlank (true|false) default false
29268 * @cfg {Boolean} yearAllowBlank (true|false) default false
29269 * @cfg {string} dayPlaceholder
29270 * @cfg {string} monthPlaceholder
29271 * @cfg {string} yearPlaceholder
29272 * @cfg {string} dayFormat default 'd'
29273 * @cfg {string} monthFormat default 'm'
29274 * @cfg {string} yearFormat default 'Y'
29275 * @cfg {Number} labellg set the width of label (1-12)
29276 * @cfg {Number} labelmd set the width of label (1-12)
29277 * @cfg {Number} labelsm set the width of label (1-12)
29278 * @cfg {Number} labelxs set the width of label (1-12)
29282 * Create a new DateSplitField
29283 * @param {Object} config The config object
29286 Roo.bootstrap.DateSplitField = function(config){
29287 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
29293 * getting the data of years
29294 * @param {Roo.bootstrap.DateSplitField} this
29295 * @param {Object} years
29300 * getting the data of days
29301 * @param {Roo.bootstrap.DateSplitField} this
29302 * @param {Object} days
29307 * Fires after the field has been marked as invalid.
29308 * @param {Roo.form.Field} this
29309 * @param {String} msg The validation message
29314 * Fires after the field has been validated with no errors.
29315 * @param {Roo.form.Field} this
29321 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
29324 labelAlign : 'top',
29326 dayAllowBlank : false,
29327 monthAllowBlank : false,
29328 yearAllowBlank : false,
29329 dayPlaceholder : '',
29330 monthPlaceholder : '',
29331 yearPlaceholder : '',
29335 isFormField : true,
29341 getAutoCreate : function()
29345 cls : 'row roo-date-split-field-group',
29350 cls : 'form-hidden-field roo-date-split-field-group-value',
29356 var labelCls = 'col-md-12';
29357 var contentCls = 'col-md-4';
29359 if(this.fieldLabel){
29363 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
29367 html : this.fieldLabel
29372 if(this.labelAlign == 'left'){
29374 if(this.labelWidth > 12){
29375 label.style = "width: " + this.labelWidth + 'px';
29378 if(this.labelWidth < 13 && this.labelmd == 0){
29379 this.labelmd = this.labelWidth;
29382 if(this.labellg > 0){
29383 labelCls = ' col-lg-' + this.labellg;
29384 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
29387 if(this.labelmd > 0){
29388 labelCls = ' col-md-' + this.labelmd;
29389 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
29392 if(this.labelsm > 0){
29393 labelCls = ' col-sm-' + this.labelsm;
29394 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
29397 if(this.labelxs > 0){
29398 labelCls = ' col-xs-' + this.labelxs;
29399 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
29403 label.cls += ' ' + labelCls;
29405 cfg.cn.push(label);
29408 Roo.each(['day', 'month', 'year'], function(t){
29411 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
29418 inputEl: function ()
29420 return this.el.select('.roo-date-split-field-group-value', true).first();
29423 onRender : function(ct, position)
29427 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29429 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
29431 this.dayField = new Roo.bootstrap.ComboBox({
29432 allowBlank : this.dayAllowBlank,
29433 alwaysQuery : true,
29434 displayField : 'value',
29437 forceSelection : true,
29439 placeholder : this.dayPlaceholder,
29440 selectOnFocus : true,
29441 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29442 triggerAction : 'all',
29444 valueField : 'value',
29445 store : new Roo.data.SimpleStore({
29446 data : (function() {
29448 _this.fireEvent('days', _this, days);
29451 fields : [ 'value' ]
29454 select : function (_self, record, index)
29456 _this.setValue(_this.getValue());
29461 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
29463 this.monthField = new Roo.bootstrap.MonthField({
29464 after : '<i class=\"fa fa-calendar\"></i>',
29465 allowBlank : this.monthAllowBlank,
29466 placeholder : this.monthPlaceholder,
29469 render : function (_self)
29471 this.el.select('span.input-group-addon', true).first().on('click', function(e){
29472 e.preventDefault();
29476 select : function (_self, oldvalue, newvalue)
29478 _this.setValue(_this.getValue());
29483 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
29485 this.yearField = new Roo.bootstrap.ComboBox({
29486 allowBlank : this.yearAllowBlank,
29487 alwaysQuery : true,
29488 displayField : 'value',
29491 forceSelection : true,
29493 placeholder : this.yearPlaceholder,
29494 selectOnFocus : true,
29495 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
29496 triggerAction : 'all',
29498 valueField : 'value',
29499 store : new Roo.data.SimpleStore({
29500 data : (function() {
29502 _this.fireEvent('years', _this, years);
29505 fields : [ 'value' ]
29508 select : function (_self, record, index)
29510 _this.setValue(_this.getValue());
29515 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
29518 setValue : function(v, format)
29520 this.inputEl.dom.value = v;
29522 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
29524 var d = Date.parseDate(v, f);
29531 this.setDay(d.format(this.dayFormat));
29532 this.setMonth(d.format(this.monthFormat));
29533 this.setYear(d.format(this.yearFormat));
29540 setDay : function(v)
29542 this.dayField.setValue(v);
29543 this.inputEl.dom.value = this.getValue();
29548 setMonth : function(v)
29550 this.monthField.setValue(v, true);
29551 this.inputEl.dom.value = this.getValue();
29556 setYear : function(v)
29558 this.yearField.setValue(v);
29559 this.inputEl.dom.value = this.getValue();
29564 getDay : function()
29566 return this.dayField.getValue();
29569 getMonth : function()
29571 return this.monthField.getValue();
29574 getYear : function()
29576 return this.yearField.getValue();
29579 getValue : function()
29581 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
29583 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
29593 this.inputEl.dom.value = '';
29598 validate : function()
29600 var d = this.dayField.validate();
29601 var m = this.monthField.validate();
29602 var y = this.yearField.validate();
29607 (!this.dayAllowBlank && !d) ||
29608 (!this.monthAllowBlank && !m) ||
29609 (!this.yearAllowBlank && !y)
29614 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
29623 this.markInvalid();
29628 markValid : function()
29631 var label = this.el.select('label', true).first();
29632 var icon = this.el.select('i.fa-star', true).first();
29638 this.fireEvent('valid', this);
29642 * Mark this field as invalid
29643 * @param {String} msg The validation message
29645 markInvalid : function(msg)
29648 var label = this.el.select('label', true).first();
29649 var icon = this.el.select('i.fa-star', true).first();
29651 if(label && !icon){
29652 this.el.select('.roo-date-split-field-label', true).createChild({
29654 cls : 'text-danger fa fa-lg fa-star',
29655 tooltip : 'This field is required',
29656 style : 'margin-right:5px;'
29660 this.fireEvent('invalid', this, msg);
29663 clearInvalid : function()
29665 var label = this.el.select('label', true).first();
29666 var icon = this.el.select('i.fa-star', true).first();
29672 this.fireEvent('valid', this);
29675 getName: function()
29685 * http://masonry.desandro.com
29687 * The idea is to render all the bricks based on vertical width...
29689 * The original code extends 'outlayer' - we might need to use that....
29695 * @class Roo.bootstrap.LayoutMasonry
29696 * @extends Roo.bootstrap.Component
29697 * Bootstrap Layout Masonry class
29700 * Create a new Element
29701 * @param {Object} config The config object
29704 Roo.bootstrap.LayoutMasonry = function(config){
29705 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
29711 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
29714 * @cfg {Boolean} isLayoutInstant = no animation?
29716 isLayoutInstant : false, // needed?
29719 * @cfg {Number} boxWidth width of the columns
29724 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
29729 * @cfg {Number} padWidth padding below box..
29734 * @cfg {Number} gutter gutter width..
29739 * @cfg {Number} maxCols maximum number of columns
29745 * @cfg {Boolean} isAutoInitial defalut true
29747 isAutoInitial : true,
29752 * @cfg {Boolean} isHorizontal defalut false
29754 isHorizontal : false,
29756 currentSize : null,
29762 bricks: null, //CompositeElement
29766 _isLayoutInited : false,
29768 // isAlternative : false, // only use for vertical layout...
29771 * @cfg {Number} alternativePadWidth padding below box..
29773 alternativePadWidth : 50,
29775 getAutoCreate : function(){
29779 cls: 'blog-masonary-wrapper ' + this.cls,
29781 cls : 'mas-boxes masonary'
29788 getChildContainer: function( )
29790 if (this.boxesEl) {
29791 return this.boxesEl;
29794 this.boxesEl = this.el.select('.mas-boxes').first();
29796 return this.boxesEl;
29800 initEvents : function()
29804 if(this.isAutoInitial){
29805 Roo.log('hook children rendered');
29806 this.on('childrenrendered', function() {
29807 Roo.log('children rendered');
29813 initial : function()
29815 this.currentSize = this.el.getBox(true);
29817 Roo.EventManager.onWindowResize(this.resize, this);
29819 if(!this.isAutoInitial){
29827 //this.layout.defer(500,this);
29831 resize : function()
29835 var cs = this.el.getBox(true);
29837 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
29838 Roo.log("no change in with or X");
29842 this.currentSize = cs;
29848 layout : function()
29850 this._resetLayout();
29852 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
29854 this.layoutItems( isInstant );
29856 this._isLayoutInited = true;
29860 _resetLayout : function()
29862 if(this.isHorizontal){
29863 this.horizontalMeasureColumns();
29867 this.verticalMeasureColumns();
29871 verticalMeasureColumns : function()
29873 this.getContainerWidth();
29875 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29876 // this.colWidth = Math.floor(this.containerWidth * 0.8);
29880 var boxWidth = this.boxWidth + this.padWidth;
29882 if(this.containerWidth < this.boxWidth){
29883 boxWidth = this.containerWidth
29886 var containerWidth = this.containerWidth;
29888 var cols = Math.floor(containerWidth / boxWidth);
29890 this.cols = Math.max( cols, 1 );
29892 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
29894 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
29896 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
29898 this.colWidth = boxWidth + avail - this.padWidth;
29900 this.unitWidth = Math.floor((this.colWidth - (this.gutter * 2)) / 3);
29901 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
29904 horizontalMeasureColumns : function()
29906 this.getContainerWidth();
29908 var boxWidth = this.boxWidth;
29910 if(this.containerWidth < boxWidth){
29911 boxWidth = this.containerWidth;
29914 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
29916 this.el.setHeight(boxWidth);
29920 getContainerWidth : function()
29922 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
29925 layoutItems : function( isInstant )
29927 var items = Roo.apply([], this.bricks);
29929 if(this.isHorizontal){
29930 this._horizontalLayoutItems( items , isInstant );
29934 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
29935 // this._verticalAlternativeLayoutItems( items , isInstant );
29939 this._verticalLayoutItems( items , isInstant );
29943 _verticalLayoutItems : function ( items , isInstant)
29945 if ( !items || !items.length ) {
29950 ['xs', 'xs', 'xs', 'tall'],
29951 ['xs', 'xs', 'tall'],
29952 ['xs', 'xs', 'sm'],
29953 ['xs', 'xs', 'xs'],
29959 ['sm', 'xs', 'xs'],
29963 ['tall', 'xs', 'xs', 'xs'],
29964 ['tall', 'xs', 'xs'],
29976 Roo.each(items, function(item, k){
29978 switch (item.size) {
29979 // these layouts take up a full box,
29990 boxes.push([item]);
30013 var filterPattern = function(box, length)
30021 var pattern = box.slice(0, length);
30025 Roo.each(pattern, function(i){
30026 format.push(i.size);
30029 Roo.each(standard, function(s){
30031 if(String(s) != String(format)){
30040 if(!match && length == 1){
30045 filterPattern(box, length - 1);
30049 queue.push(pattern);
30051 box = box.slice(length, box.length);
30053 filterPattern(box, 4);
30059 Roo.each(boxes, function(box, k){
30065 if(box.length == 1){
30070 filterPattern(box, 4);
30074 this._processVerticalLayoutQueue( queue, isInstant );
30078 // _verticalAlternativeLayoutItems : function( items , isInstant )
30080 // if ( !items || !items.length ) {
30084 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30088 _horizontalLayoutItems : function ( items , isInstant)
30090 if ( !items || !items.length || items.length < 3) {
30096 var eItems = items.slice(0, 3);
30098 items = items.slice(3, items.length);
30101 ['xs', 'xs', 'xs', 'wide'],
30102 ['xs', 'xs', 'wide'],
30103 ['xs', 'xs', 'sm'],
30104 ['xs', 'xs', 'xs'],
30110 ['sm', 'xs', 'xs'],
30114 ['wide', 'xs', 'xs', 'xs'],
30115 ['wide', 'xs', 'xs'],
30128 Roo.each(items, function(item, k){
30130 switch (item.size) {
30141 boxes.push([item]);
30165 var filterPattern = function(box, length)
30173 var pattern = box.slice(0, length);
30177 Roo.each(pattern, function(i){
30178 format.push(i.size);
30181 Roo.each(standard, function(s){
30183 if(String(s) != String(format)){
30192 if(!match && length == 1){
30197 filterPattern(box, length - 1);
30201 queue.push(pattern);
30203 box = box.slice(length, box.length);
30205 filterPattern(box, 4);
30211 Roo.each(boxes, function(box, k){
30217 if(box.length == 1){
30222 filterPattern(box, 4);
30229 var pos = this.el.getBox(true);
30233 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30235 var hit_end = false;
30237 Roo.each(queue, function(box){
30241 Roo.each(box, function(b){
30243 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30253 Roo.each(box, function(b){
30255 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30258 mx = Math.max(mx, b.x);
30262 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
30266 Roo.each(box, function(b){
30268 b.el.setVisibilityMode(Roo.Element.DISPLAY);
30282 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
30285 /** Sets position of item in DOM
30286 * @param {Element} item
30287 * @param {Number} x - horizontal position
30288 * @param {Number} y - vertical position
30289 * @param {Boolean} isInstant - disables transitions
30291 _processVerticalLayoutQueue : function( queue, isInstant )
30293 var pos = this.el.getBox(true);
30298 for (var i = 0; i < this.cols; i++){
30302 Roo.each(queue, function(box, k){
30304 var col = k % this.cols;
30306 Roo.each(box, function(b,kk){
30308 b.el.position('absolute');
30310 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30311 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30313 if(b.size == 'md-left' || b.size == 'md-right'){
30314 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30315 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30318 b.el.setWidth(width);
30319 b.el.setHeight(height);
30321 b.el.select('iframe',true).setSize(width,height);
30325 for (var i = 0; i < this.cols; i++){
30327 if(maxY[i] < maxY[col]){
30332 col = Math.min(col, i);
30336 x = pos.x + col * (this.colWidth + this.padWidth);
30340 var positions = [];
30342 switch (box.length){
30344 positions = this.getVerticalOneBoxColPositions(x, y, box);
30347 positions = this.getVerticalTwoBoxColPositions(x, y, box);
30350 positions = this.getVerticalThreeBoxColPositions(x, y, box);
30353 positions = this.getVerticalFourBoxColPositions(x, y, box);
30359 Roo.each(box, function(b,kk){
30361 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30363 var sz = b.el.getSize();
30365 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
30373 for (var i = 0; i < this.cols; i++){
30374 mY = Math.max(mY, maxY[i]);
30377 this.el.setHeight(mY - pos.y);
30381 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
30383 // var pos = this.el.getBox(true);
30386 // var maxX = pos.right;
30388 // var maxHeight = 0;
30390 // Roo.each(items, function(item, k){
30394 // item.el.position('absolute');
30396 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
30398 // item.el.setWidth(width);
30400 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
30402 // item.el.setHeight(height);
30405 // item.el.setXY([x, y], isInstant ? false : true);
30407 // item.el.setXY([maxX - width, y], isInstant ? false : true);
30410 // y = y + height + this.alternativePadWidth;
30412 // maxHeight = maxHeight + height + this.alternativePadWidth;
30416 // this.el.setHeight(maxHeight);
30420 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
30422 var pos = this.el.getBox(true);
30427 var maxX = pos.right;
30429 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
30431 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
30433 Roo.each(queue, function(box, k){
30435 Roo.each(box, function(b, kk){
30437 b.el.position('absolute');
30439 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30440 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30442 if(b.size == 'md-left' || b.size == 'md-right'){
30443 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
30444 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
30447 b.el.setWidth(width);
30448 b.el.setHeight(height);
30456 var positions = [];
30458 switch (box.length){
30460 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
30463 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
30466 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
30469 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
30475 Roo.each(box, function(b,kk){
30477 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
30479 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
30487 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
30489 Roo.each(eItems, function(b,k){
30491 b.size = (k == 0) ? 'sm' : 'xs';
30492 b.x = (k == 0) ? 2 : 1;
30493 b.y = (k == 0) ? 2 : 1;
30495 b.el.position('absolute');
30497 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
30499 b.el.setWidth(width);
30501 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
30503 b.el.setHeight(height);
30507 var positions = [];
30510 x : maxX - this.unitWidth * 2 - this.gutter,
30515 x : maxX - this.unitWidth,
30516 y : minY + (this.unitWidth + this.gutter) * 2
30520 x : maxX - this.unitWidth * 3 - this.gutter * 2,
30524 Roo.each(eItems, function(b,k){
30526 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
30532 getVerticalOneBoxColPositions : function(x, y, box)
30536 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
30538 if(box[0].size == 'md-left'){
30542 if(box[0].size == 'md-right'){
30547 x : x + (this.unitWidth + this.gutter) * rand,
30554 getVerticalTwoBoxColPositions : function(x, y, box)
30558 if(box[0].size == 'xs'){
30562 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
30566 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
30580 x : x + (this.unitWidth + this.gutter) * 2,
30581 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
30588 getVerticalThreeBoxColPositions : function(x, y, box)
30592 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30600 x : x + (this.unitWidth + this.gutter) * 1,
30605 x : x + (this.unitWidth + this.gutter) * 2,
30613 if(box[0].size == 'xs' && box[1].size == 'xs'){
30622 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
30626 x : x + (this.unitWidth + this.gutter) * 1,
30640 x : x + (this.unitWidth + this.gutter) * 2,
30645 x : x + (this.unitWidth + this.gutter) * 2,
30646 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
30653 getVerticalFourBoxColPositions : function(x, y, box)
30657 if(box[0].size == 'xs'){
30666 y : y + (this.unitHeight + this.gutter) * 1
30671 y : y + (this.unitHeight + this.gutter) * 2
30675 x : x + (this.unitWidth + this.gutter) * 1,
30689 x : x + (this.unitWidth + this.gutter) * 2,
30694 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
30695 y : y + (this.unitHeight + this.gutter) * 1
30699 x : x + (this.unitWidth + this.gutter) * 2,
30700 y : y + (this.unitWidth + this.gutter) * 2
30707 getHorizontalOneBoxColPositions : function(maxX, minY, box)
30711 if(box[0].size == 'md-left'){
30713 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30720 if(box[0].size == 'md-right'){
30722 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
30723 y : minY + (this.unitWidth + this.gutter) * 1
30729 var rand = Math.floor(Math.random() * (4 - box[0].y));
30732 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30733 y : minY + (this.unitWidth + this.gutter) * rand
30740 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
30744 if(box[0].size == 'xs'){
30747 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30752 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30753 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
30761 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30766 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30767 y : minY + (this.unitWidth + this.gutter) * 2
30774 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
30778 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
30781 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30786 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30787 y : minY + (this.unitWidth + this.gutter) * 1
30791 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30792 y : minY + (this.unitWidth + this.gutter) * 2
30799 if(box[0].size == 'xs' && box[1].size == 'xs'){
30802 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30807 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30812 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30813 y : minY + (this.unitWidth + this.gutter) * 1
30821 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30826 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30827 y : minY + (this.unitWidth + this.gutter) * 2
30831 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30832 y : minY + (this.unitWidth + this.gutter) * 2
30839 getHorizontalFourBoxColPositions : function(maxX, minY, box)
30843 if(box[0].size == 'xs'){
30846 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30851 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30856 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),
30861 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
30862 y : minY + (this.unitWidth + this.gutter) * 1
30870 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
30875 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
30876 y : minY + (this.unitWidth + this.gutter) * 2
30880 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
30881 y : minY + (this.unitWidth + this.gutter) * 2
30885 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),
30886 y : minY + (this.unitWidth + this.gutter) * 2
30900 * http://masonry.desandro.com
30902 * The idea is to render all the bricks based on vertical width...
30904 * The original code extends 'outlayer' - we might need to use that....
30910 * @class Roo.bootstrap.LayoutMasonryAuto
30911 * @extends Roo.bootstrap.Component
30912 * Bootstrap Layout Masonry class
30915 * Create a new Element
30916 * @param {Object} config The config object
30919 Roo.bootstrap.LayoutMasonryAuto = function(config){
30920 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
30923 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
30926 * @cfg {Boolean} isFitWidth - resize the width..
30928 isFitWidth : false, // options..
30930 * @cfg {Boolean} isOriginLeft = left align?
30932 isOriginLeft : true,
30934 * @cfg {Boolean} isOriginTop = top align?
30936 isOriginTop : false,
30938 * @cfg {Boolean} isLayoutInstant = no animation?
30940 isLayoutInstant : false, // needed?
30942 * @cfg {Boolean} isResizingContainer = not sure if this is used..
30944 isResizingContainer : true,
30946 * @cfg {Number} columnWidth width of the columns
30952 * @cfg {Number} maxCols maximum number of columns
30957 * @cfg {Number} padHeight padding below box..
30963 * @cfg {Boolean} isAutoInitial defalut true
30966 isAutoInitial : true,
30972 initialColumnWidth : 0,
30973 currentSize : null,
30975 colYs : null, // array.
30982 bricks: null, //CompositeElement
30983 cols : 0, // array?
30984 // element : null, // wrapped now this.el
30985 _isLayoutInited : null,
30988 getAutoCreate : function(){
30992 cls: 'blog-masonary-wrapper ' + this.cls,
30994 cls : 'mas-boxes masonary'
31001 getChildContainer: function( )
31003 if (this.boxesEl) {
31004 return this.boxesEl;
31007 this.boxesEl = this.el.select('.mas-boxes').first();
31009 return this.boxesEl;
31013 initEvents : function()
31017 if(this.isAutoInitial){
31018 Roo.log('hook children rendered');
31019 this.on('childrenrendered', function() {
31020 Roo.log('children rendered');
31027 initial : function()
31029 this.reloadItems();
31031 this.currentSize = this.el.getBox(true);
31033 /// was window resize... - let's see if this works..
31034 Roo.EventManager.onWindowResize(this.resize, this);
31036 if(!this.isAutoInitial){
31041 this.layout.defer(500,this);
31044 reloadItems: function()
31046 this.bricks = this.el.select('.masonry-brick', true);
31048 this.bricks.each(function(b) {
31049 //Roo.log(b.getSize());
31050 if (!b.attr('originalwidth')) {
31051 b.attr('originalwidth', b.getSize().width);
31056 Roo.log(this.bricks.elements.length);
31059 resize : function()
31062 var cs = this.el.getBox(true);
31064 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
31065 Roo.log("no change in with or X");
31068 this.currentSize = cs;
31072 layout : function()
31075 this._resetLayout();
31076 //this._manageStamps();
31078 // don't animate first layout
31079 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31080 this.layoutItems( isInstant );
31082 // flag for initalized
31083 this._isLayoutInited = true;
31086 layoutItems : function( isInstant )
31088 //var items = this._getItemsForLayout( this.items );
31089 // original code supports filtering layout items.. we just ignore it..
31091 this._layoutItems( this.bricks , isInstant );
31093 this._postLayout();
31095 _layoutItems : function ( items , isInstant)
31097 //this.fireEvent( 'layout', this, items );
31100 if ( !items || !items.elements.length ) {
31101 // no items, emit event with empty array
31106 items.each(function(item) {
31107 Roo.log("layout item");
31109 // get x/y object from method
31110 var position = this._getItemLayoutPosition( item );
31112 position.item = item;
31113 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
31114 queue.push( position );
31117 this._processLayoutQueue( queue );
31119 /** Sets position of item in DOM
31120 * @param {Element} item
31121 * @param {Number} x - horizontal position
31122 * @param {Number} y - vertical position
31123 * @param {Boolean} isInstant - disables transitions
31125 _processLayoutQueue : function( queue )
31127 for ( var i=0, len = queue.length; i < len; i++ ) {
31128 var obj = queue[i];
31129 obj.item.position('absolute');
31130 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
31136 * Any logic you want to do after each layout,
31137 * i.e. size the container
31139 _postLayout : function()
31141 this.resizeContainer();
31144 resizeContainer : function()
31146 if ( !this.isResizingContainer ) {
31149 var size = this._getContainerSize();
31151 this.el.setSize(size.width,size.height);
31152 this.boxesEl.setSize(size.width,size.height);
31158 _resetLayout : function()
31160 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
31161 this.colWidth = this.el.getWidth();
31162 //this.gutter = this.el.getWidth();
31164 this.measureColumns();
31170 this.colYs.push( 0 );
31176 measureColumns : function()
31178 this.getContainerWidth();
31179 // if columnWidth is 0, default to outerWidth of first item
31180 if ( !this.columnWidth ) {
31181 var firstItem = this.bricks.first();
31182 Roo.log(firstItem);
31183 this.columnWidth = this.containerWidth;
31184 if (firstItem && firstItem.attr('originalwidth') ) {
31185 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
31187 // columnWidth fall back to item of first element
31188 Roo.log("set column width?");
31189 this.initialColumnWidth = this.columnWidth ;
31191 // if first elem has no width, default to size of container
31196 if (this.initialColumnWidth) {
31197 this.columnWidth = this.initialColumnWidth;
31202 // column width is fixed at the top - however if container width get's smaller we should
31205 // this bit calcs how man columns..
31207 var columnWidth = this.columnWidth += this.gutter;
31209 // calculate columns
31210 var containerWidth = this.containerWidth + this.gutter;
31212 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
31213 // fix rounding errors, typically with gutters
31214 var excess = columnWidth - containerWidth % columnWidth;
31217 // if overshoot is less than a pixel, round up, otherwise floor it
31218 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
31219 cols = Math[ mathMethod ]( cols );
31220 this.cols = Math.max( cols, 1 );
31221 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31223 // padding positioning..
31224 var totalColWidth = this.cols * this.columnWidth;
31225 var padavail = this.containerWidth - totalColWidth;
31226 // so for 2 columns - we need 3 'pads'
31228 var padNeeded = (1+this.cols) * this.padWidth;
31230 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
31232 this.columnWidth += padExtra
31233 //this.padWidth = Math.floor(padavail / ( this.cols));
31235 // adjust colum width so that padding is fixed??
31237 // we have 3 columns ... total = width * 3
31238 // we have X left over... that should be used by
31240 //if (this.expandC) {
31248 getContainerWidth : function()
31250 /* // container is parent if fit width
31251 var container = this.isFitWidth ? this.element.parentNode : this.element;
31252 // check that this.size and size are there
31253 // IE8 triggers resize on body size change, so they might not be
31255 var size = getSize( container ); //FIXME
31256 this.containerWidth = size && size.innerWidth; //FIXME
31259 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31263 _getItemLayoutPosition : function( item ) // what is item?
31265 // we resize the item to our columnWidth..
31267 item.setWidth(this.columnWidth);
31268 item.autoBoxAdjust = false;
31270 var sz = item.getSize();
31272 // how many columns does this brick span
31273 var remainder = this.containerWidth % this.columnWidth;
31275 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
31276 // round if off by 1 pixel, otherwise use ceil
31277 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
31278 colSpan = Math.min( colSpan, this.cols );
31280 // normally this should be '1' as we dont' currently allow multi width columns..
31282 var colGroup = this._getColGroup( colSpan );
31283 // get the minimum Y value from the columns
31284 var minimumY = Math.min.apply( Math, colGroup );
31285 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31287 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
31289 // position the brick
31291 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
31292 y: this.currentSize.y + minimumY + this.padHeight
31296 // apply setHeight to necessary columns
31297 var setHeight = minimumY + sz.height + this.padHeight;
31298 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
31300 var setSpan = this.cols + 1 - colGroup.length;
31301 for ( var i = 0; i < setSpan; i++ ) {
31302 this.colYs[ shortColIndex + i ] = setHeight ;
31309 * @param {Number} colSpan - number of columns the element spans
31310 * @returns {Array} colGroup
31312 _getColGroup : function( colSpan )
31314 if ( colSpan < 2 ) {
31315 // if brick spans only one column, use all the column Ys
31320 // how many different places could this brick fit horizontally
31321 var groupCount = this.cols + 1 - colSpan;
31322 // for each group potential horizontal position
31323 for ( var i = 0; i < groupCount; i++ ) {
31324 // make an array of colY values for that one group
31325 var groupColYs = this.colYs.slice( i, i + colSpan );
31326 // and get the max value of the array
31327 colGroup[i] = Math.max.apply( Math, groupColYs );
31332 _manageStamp : function( stamp )
31334 var stampSize = stamp.getSize();
31335 var offset = stamp.getBox();
31336 // get the columns that this stamp affects
31337 var firstX = this.isOriginLeft ? offset.x : offset.right;
31338 var lastX = firstX + stampSize.width;
31339 var firstCol = Math.floor( firstX / this.columnWidth );
31340 firstCol = Math.max( 0, firstCol );
31342 var lastCol = Math.floor( lastX / this.columnWidth );
31343 // lastCol should not go over if multiple of columnWidth #425
31344 lastCol -= lastX % this.columnWidth ? 0 : 1;
31345 lastCol = Math.min( this.cols - 1, lastCol );
31347 // set colYs to bottom of the stamp
31348 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
31351 for ( var i = firstCol; i <= lastCol; i++ ) {
31352 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
31357 _getContainerSize : function()
31359 this.maxY = Math.max.apply( Math, this.colYs );
31364 if ( this.isFitWidth ) {
31365 size.width = this._getContainerFitWidth();
31371 _getContainerFitWidth : function()
31373 var unusedCols = 0;
31374 // count unused columns
31377 if ( this.colYs[i] !== 0 ) {
31382 // fit container to columns that have been used
31383 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
31386 needsResizeLayout : function()
31388 var previousWidth = this.containerWidth;
31389 this.getContainerWidth();
31390 return previousWidth !== this.containerWidth;
31405 * @class Roo.bootstrap.MasonryBrick
31406 * @extends Roo.bootstrap.Component
31407 * Bootstrap MasonryBrick class
31410 * Create a new MasonryBrick
31411 * @param {Object} config The config object
31414 Roo.bootstrap.MasonryBrick = function(config){
31415 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
31421 * When a MasonryBrick is clcik
31422 * @param {Roo.bootstrap.MasonryBrick} this
31423 * @param {Roo.EventObject} e
31429 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
31432 * @cfg {String} title
31436 * @cfg {String} html
31440 * @cfg {String} bgimage
31444 * @cfg {String} videourl
31448 * @cfg {String} cls
31452 * @cfg {String} href
31456 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
31461 * @cfg {String} placetitle (center|bottom)
31466 * @cfg {Boolean} isFitContainer defalut true
31468 isFitContainer : true,
31471 * @cfg {Boolean} preventDefault defalut false
31473 preventDefault : false,
31476 * @cfg {Boolean} inverse defalut false
31478 maskInverse : false,
31480 getAutoCreate : function()
31482 if(!this.isFitContainer){
31483 return this.getSplitAutoCreate();
31486 var cls = 'masonry-brick masonry-brick-full';
31488 if(this.href.length){
31489 cls += ' masonry-brick-link';
31492 if(this.bgimage.length){
31493 cls += ' masonry-brick-image';
31496 if(this.maskInverse){
31497 cls += ' mask-inverse';
31500 if(!this.html.length && !this.maskInverse){
31501 cls += ' enable-mask';
31505 cls += ' masonry-' + this.size + '-brick';
31508 if(this.placetitle.length){
31510 switch (this.placetitle) {
31512 cls += ' masonry-center-title';
31515 cls += ' masonry-bottom-title';
31522 if(!this.html.length && !this.bgimage.length){
31523 cls += ' masonry-center-title';
31526 if(!this.html.length && this.bgimage.length){
31527 cls += ' masonry-bottom-title';
31532 cls += ' ' + this.cls;
31536 tag: (this.href.length) ? 'a' : 'div',
31541 cls: 'masonry-brick-paragraph',
31547 if(this.href.length){
31548 cfg.href = this.href;
31551 var cn = cfg.cn[0].cn;
31553 if(this.title.length){
31556 cls: 'masonry-brick-title',
31561 if(this.html.length){
31564 cls: 'masonry-brick-text',
31568 if (!this.title.length && !this.html.length) {
31569 cfg.cn[0].cls += ' hide';
31572 if(this.bgimage.length){
31575 cls: 'masonry-brick-image-view',
31580 if(this.videourl.length){
31581 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31582 // youtube support only?
31585 cls: 'masonry-brick-image-view',
31588 allowfullscreen : true
31596 cls: 'masonry-brick-mask'
31603 getSplitAutoCreate : function()
31605 var cls = 'masonry-brick masonry-brick-split';
31607 if(this.href.length){
31608 cls += ' masonry-brick-link';
31611 if(this.bgimage.length){
31612 cls += ' masonry-brick-image';
31616 cls += ' masonry-' + this.size + '-brick';
31619 switch (this.placetitle) {
31621 cls += ' masonry-center-title';
31624 cls += ' masonry-bottom-title';
31627 if(!this.bgimage.length){
31628 cls += ' masonry-center-title';
31631 if(this.bgimage.length){
31632 cls += ' masonry-bottom-title';
31638 cls += ' ' + this.cls;
31642 tag: (this.href.length) ? 'a' : 'div',
31647 cls: 'masonry-brick-split-head',
31651 cls: 'masonry-brick-paragraph',
31658 cls: 'masonry-brick-split-body',
31664 if(this.href.length){
31665 cfg.href = this.href;
31668 if(this.title.length){
31669 cfg.cn[0].cn[0].cn.push({
31671 cls: 'masonry-brick-title',
31676 if(this.html.length){
31677 cfg.cn[1].cn.push({
31679 cls: 'masonry-brick-text',
31684 if(this.bgimage.length){
31685 cfg.cn[0].cn.push({
31687 cls: 'masonry-brick-image-view',
31692 if(this.videourl.length){
31693 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
31694 // youtube support only?
31695 cfg.cn[0].cn.cn.push({
31697 cls: 'masonry-brick-image-view',
31700 allowfullscreen : true
31707 initEvents: function()
31709 switch (this.size) {
31742 this.el.on('touchstart', this.onTouchStart, this);
31743 this.el.on('touchmove', this.onTouchMove, this);
31744 this.el.on('touchend', this.onTouchEnd, this);
31745 this.el.on('contextmenu', this.onContextMenu, this);
31747 this.el.on('mouseenter' ,this.enter, this);
31748 this.el.on('mouseleave', this.leave, this);
31749 this.el.on('click', this.onClick, this);
31752 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
31753 this.parent().bricks.push(this);
31758 onClick: function(e, el)
31760 var time = this.endTimer - this.startTimer;
31764 e.preventDefault();
31769 if(!this.preventDefault){
31773 e.preventDefault();
31774 this.fireEvent('click', this);
31777 enter: function(e, el)
31779 e.preventDefault();
31781 if(!this.isFitContainer || this.maskInverse){
31785 if(this.bgimage.length && this.html.length){
31786 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31790 leave: function(e, el)
31792 e.preventDefault();
31794 if(!this.isFitContainer || this.maskInverse){
31798 if(this.bgimage.length && this.html.length){
31799 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31803 onTouchStart: function(e, el)
31805 // e.preventDefault();
31807 this.touchmoved = false;
31809 if(!this.isFitContainer){
31813 if(!this.bgimage.length || !this.html.length){
31817 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
31819 this.timer = new Date().getTime();
31823 onTouchMove: function(e, el)
31825 this.touchmoved = true;
31828 onContextMenu : function(e,el)
31830 e.preventDefault();
31831 e.stopPropagation();
31835 onTouchEnd: function(e, el)
31837 // e.preventDefault();
31839 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
31846 if(!this.bgimage.length || !this.html.length){
31848 if(this.href.length){
31849 window.location.href = this.href;
31855 if(!this.isFitContainer){
31859 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
31861 window.location.href = this.href;
31876 * @class Roo.bootstrap.Brick
31877 * @extends Roo.bootstrap.Component
31878 * Bootstrap Brick class
31881 * Create a new Brick
31882 * @param {Object} config The config object
31885 Roo.bootstrap.Brick = function(config){
31886 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
31892 * When a Brick is click
31893 * @param {Roo.bootstrap.Brick} this
31894 * @param {Roo.EventObject} e
31900 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
31903 * @cfg {String} title
31907 * @cfg {String} html
31911 * @cfg {String} bgimage
31915 * @cfg {String} cls
31919 * @cfg {String} href
31923 * @cfg {String} video
31927 * @cfg {Boolean} square
31931 getAutoCreate : function()
31933 var cls = 'roo-brick';
31935 if(this.href.length){
31936 cls += ' roo-brick-link';
31939 if(this.bgimage.length){
31940 cls += ' roo-brick-image';
31943 if(!this.html.length && !this.bgimage.length){
31944 cls += ' roo-brick-center-title';
31947 if(!this.html.length && this.bgimage.length){
31948 cls += ' roo-brick-bottom-title';
31952 cls += ' ' + this.cls;
31956 tag: (this.href.length) ? 'a' : 'div',
31961 cls: 'roo-brick-paragraph',
31967 if(this.href.length){
31968 cfg.href = this.href;
31971 var cn = cfg.cn[0].cn;
31973 if(this.title.length){
31976 cls: 'roo-brick-title',
31981 if(this.html.length){
31984 cls: 'roo-brick-text',
31991 if(this.bgimage.length){
31994 cls: 'roo-brick-image-view',
32002 initEvents: function()
32004 if(this.title.length || this.html.length){
32005 this.el.on('mouseenter' ,this.enter, this);
32006 this.el.on('mouseleave', this.leave, this);
32010 Roo.EventManager.onWindowResize(this.resize, this);
32015 resize : function()
32017 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
32019 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
32021 if(this.bgimage.length){
32022 var image = this.el.select('.roo-brick-image-view', true).first();
32023 image.setWidth(paragraph.getWidth());
32024 image.setHeight(paragraph.getWidth());
32026 this.el.setHeight(paragraph.getWidth());
32032 enter: function(e, el)
32034 e.preventDefault();
32036 if(this.bgimage.length){
32037 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
32038 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
32042 leave: function(e, el)
32044 e.preventDefault();
32046 if(this.bgimage.length){
32047 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
32048 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
32064 * @class Roo.bootstrap.NumberField
32065 * @extends Roo.bootstrap.Input
32066 * Bootstrap NumberField class
32072 * Create a new NumberField
32073 * @param {Object} config The config object
32076 Roo.bootstrap.NumberField = function(config){
32077 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
32080 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
32083 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
32085 allowDecimals : true,
32087 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
32089 decimalSeparator : ".",
32091 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
32093 decimalPrecision : 2,
32095 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
32097 allowNegative : true,
32099 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
32101 minValue : Number.NEGATIVE_INFINITY,
32103 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
32105 maxValue : Number.MAX_VALUE,
32107 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
32109 minText : "The minimum value for this field is {0}",
32111 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
32113 maxText : "The maximum value for this field is {0}",
32115 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
32116 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
32118 nanText : "{0} is not a valid number",
32120 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
32125 initEvents : function()
32127 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
32129 var allowed = "0123456789";
32131 if(this.allowDecimals){
32132 allowed += this.decimalSeparator;
32135 if(this.allowNegative){
32139 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
32141 var keyPress = function(e){
32143 var k = e.getKey();
32145 var c = e.getCharCode();
32148 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
32149 allowed.indexOf(String.fromCharCode(c)) === -1
32155 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
32159 if(allowed.indexOf(String.fromCharCode(c)) === -1){
32164 this.el.on("keypress", keyPress, this);
32167 validateValue : function(value)
32170 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
32174 var num = this.parseValue(value);
32177 this.markInvalid(String.format(this.nanText, value));
32181 if(num < this.minValue){
32182 this.markInvalid(String.format(this.minText, this.minValue));
32186 if(num > this.maxValue){
32187 this.markInvalid(String.format(this.maxText, this.maxValue));
32194 getValue : function()
32196 return this.fixPrecision(this.parseValue(Roo.bootstrap.NumberField.superclass.getValue.call(this)));
32199 parseValue : function(value)
32201 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
32202 return isNaN(value) ? '' : value;
32205 fixPrecision : function(value)
32207 var nan = isNaN(value);
32209 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
32210 return nan ? '' : value;
32212 return parseFloat(value).toFixed(this.decimalPrecision);
32215 setValue : function(v)
32217 v = this.fixPrecision(v);
32218 Roo.bootstrap.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
32221 decimalPrecisionFcn : function(v)
32223 return Math.floor(v);
32226 beforeBlur : function()
32232 var v = this.parseValue(this.getRawValue());
32247 * @class Roo.bootstrap.DocumentSlider
32248 * @extends Roo.bootstrap.Component
32249 * Bootstrap DocumentSlider class
32252 * Create a new DocumentViewer
32253 * @param {Object} config The config object
32256 Roo.bootstrap.DocumentSlider = function(config){
32257 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
32264 * Fire after initEvent
32265 * @param {Roo.bootstrap.DocumentSlider} this
32270 * Fire after update
32271 * @param {Roo.bootstrap.DocumentSlider} this
32277 * @param {Roo.bootstrap.DocumentSlider} this
32283 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
32289 getAutoCreate : function()
32293 cls : 'roo-document-slider',
32297 cls : 'roo-document-slider-header',
32301 cls : 'roo-document-slider-header-title'
32307 cls : 'roo-document-slider-body',
32311 cls : 'roo-document-slider-prev',
32315 cls : 'fa fa-chevron-left'
32321 cls : 'roo-document-slider-thumb',
32325 cls : 'roo-document-slider-image'
32331 cls : 'roo-document-slider-next',
32335 cls : 'fa fa-chevron-right'
32347 initEvents : function()
32349 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
32350 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
32352 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
32353 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
32355 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
32356 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32358 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
32359 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32361 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
32362 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32364 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
32365 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32367 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
32368 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
32370 this.thumbEl.on('click', this.onClick, this);
32372 this.prevIndicator.on('click', this.prev, this);
32374 this.nextIndicator.on('click', this.next, this);
32378 initial : function()
32380 if(this.files.length){
32381 this.indicator = 1;
32385 this.fireEvent('initial', this);
32388 update : function()
32390 this.imageEl.attr('src', this.files[this.indicator - 1]);
32392 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
32394 this.prevIndicator.show();
32396 if(this.indicator == 1){
32397 this.prevIndicator.hide();
32400 this.nextIndicator.show();
32402 if(this.indicator == this.files.length){
32403 this.nextIndicator.hide();
32406 this.thumbEl.scrollTo('top');
32408 this.fireEvent('update', this);
32411 onClick : function(e)
32413 e.preventDefault();
32415 this.fireEvent('click', this);
32420 e.preventDefault();
32422 this.indicator = Math.max(1, this.indicator - 1);
32429 e.preventDefault();
32431 this.indicator = Math.min(this.files.length, this.indicator + 1);
32445 * @class Roo.bootstrap.RadioSet
32446 * @extends Roo.bootstrap.Input
32447 * Bootstrap RadioSet class
32448 * @cfg {String} indicatorpos (left|right) default left
32449 * @cfg {Boolean} inline (true|false) inline the element (default true)
32450 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
32452 * Create a new RadioSet
32453 * @param {Object} config The config object
32456 Roo.bootstrap.RadioSet = function(config){
32458 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
32462 Roo.bootstrap.RadioSet.register(this);
32467 * Fires when the element is checked or unchecked.
32468 * @param {Roo.bootstrap.RadioSet} this This radio
32469 * @param {Roo.bootstrap.Radio} item The checked item
32476 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
32484 indicatorpos : 'left',
32486 getAutoCreate : function()
32490 cls : 'roo-radio-set-label',
32494 html : this.fieldLabel
32499 if(this.indicatorpos == 'left'){
32502 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
32503 tooltip : 'This field is required'
32508 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
32509 tooltip : 'This field is required'
32515 cls : 'roo-radio-set-items'
32518 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
32520 if (align === 'left' && this.fieldLabel.length) {
32523 cls : "roo-radio-set-right",
32529 if(this.labelWidth > 12){
32530 label.style = "width: " + this.labelWidth + 'px';
32533 if(this.labelWidth < 13 && this.labelmd == 0){
32534 this.labelmd = this.labelWidth;
32537 if(this.labellg > 0){
32538 label.cls += ' col-lg-' + this.labellg;
32539 items.cls += ' col-lg-' + (12 - this.labellg);
32542 if(this.labelmd > 0){
32543 label.cls += ' col-md-' + this.labelmd;
32544 items.cls += ' col-md-' + (12 - this.labelmd);
32547 if(this.labelsm > 0){
32548 label.cls += ' col-sm-' + this.labelsm;
32549 items.cls += ' col-sm-' + (12 - this.labelsm);
32552 if(this.labelxs > 0){
32553 label.cls += ' col-xs-' + this.labelxs;
32554 items.cls += ' col-xs-' + (12 - this.labelxs);
32560 cls : 'roo-radio-set',
32564 cls : 'roo-radio-set-input',
32567 value : this.value ? this.value : ''
32574 if(this.weight.length){
32575 cfg.cls += ' roo-radio-' + this.weight;
32579 cfg.cls += ' roo-radio-set-inline';
32586 initEvents : function()
32588 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
32589 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
32591 if(!this.fieldLabel.length){
32592 this.labelEl.hide();
32595 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
32596 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
32598 this.indicatorEl().setVisibilityMode(Roo.Element.DISPLAY);
32599 this.indicatorEl().hide();
32601 this.originalValue = this.getValue();
32605 inputEl: function ()
32607 return this.el.select('.roo-radio-set-input', true).first();
32610 getChildContainer : function()
32612 return this.itemsEl;
32615 register : function(item)
32617 this.radioes.push(item);
32621 validate : function()
32625 Roo.each(this.radioes, function(i){
32634 if(this.allowBlank) {
32638 if(this.disabled || valid){
32643 this.markInvalid();
32648 markValid : function()
32650 if(this.labelEl.isVisible(true)){
32651 this.indicatorEl().hide();
32654 this.el.removeClass([this.invalidClass, this.validClass]);
32655 this.el.addClass(this.validClass);
32657 this.fireEvent('valid', this);
32660 markInvalid : function(msg)
32662 if(this.allowBlank || this.disabled){
32666 if(this.labelEl.isVisible(true)){
32667 this.indicatorEl().show();
32670 this.el.removeClass([this.invalidClass, this.validClass]);
32671 this.el.addClass(this.invalidClass);
32673 this.fireEvent('invalid', this, msg);
32677 setValue : function(v, suppressEvent)
32679 Roo.each(this.radioes, function(i){
32682 i.el.removeClass('checked');
32684 if(i.value === v || i.value.toString() === v.toString()){
32686 i.el.addClass('checked');
32688 if(suppressEvent !== true){
32689 this.fireEvent('check', this, i);
32695 Roo.bootstrap.RadioSet.superclass.setValue.call(this, v);
32699 clearInvalid : function(){
32701 if(!this.el || this.preventMark){
32705 if(this.labelEl.isVisible(true)){
32706 this.indicatorEl().hide();
32709 this.el.removeClass([this.invalidClass]);
32711 this.fireEvent('valid', this);
32716 Roo.apply(Roo.bootstrap.RadioSet, {
32720 register : function(set)
32722 this.groups[set.name] = set;
32725 get: function(name)
32727 if (typeof(this.groups[name]) == 'undefined') {
32731 return this.groups[name] ;
32737 * Ext JS Library 1.1.1
32738 * Copyright(c) 2006-2007, Ext JS, LLC.
32740 * Originally Released Under LGPL - original licence link has changed is not relivant.
32743 * <script type="text/javascript">
32748 * @class Roo.bootstrap.SplitBar
32749 * @extends Roo.util.Observable
32750 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
32754 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
32755 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
32756 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
32757 split.minSize = 100;
32758 split.maxSize = 600;
32759 split.animate = true;
32760 split.on('moved', splitterMoved);
32763 * Create a new SplitBar
32764 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
32765 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
32766 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32767 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
32768 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
32769 position of the SplitBar).
32771 Roo.bootstrap.SplitBar = function(cfg){
32776 // dragElement : elm
32777 // resizingElement: el,
32779 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
32780 // placement : Roo.bootstrap.SplitBar.LEFT ,
32781 // existingProxy ???
32784 this.el = Roo.get(cfg.dragElement, true);
32785 this.el.dom.unselectable = "on";
32787 this.resizingEl = Roo.get(cfg.resizingElement, true);
32791 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
32792 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
32795 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
32798 * The minimum size of the resizing element. (Defaults to 0)
32804 * The maximum size of the resizing element. (Defaults to 2000)
32807 this.maxSize = 2000;
32810 * Whether to animate the transition to the new size
32813 this.animate = false;
32816 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
32819 this.useShim = false;
32824 if(!cfg.existingProxy){
32826 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
32828 this.proxy = Roo.get(cfg.existingProxy).dom;
32831 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
32834 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
32837 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
32840 this.dragSpecs = {};
32843 * @private The adapter to use to positon and resize elements
32845 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
32846 this.adapter.init(this);
32848 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32850 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
32851 this.el.addClass("roo-splitbar-h");
32854 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
32855 this.el.addClass("roo-splitbar-v");
32861 * Fires when the splitter is moved (alias for {@link #event-moved})
32862 * @param {Roo.bootstrap.SplitBar} this
32863 * @param {Number} newSize the new width or height
32868 * Fires when the splitter is moved
32869 * @param {Roo.bootstrap.SplitBar} this
32870 * @param {Number} newSize the new width or height
32874 * @event beforeresize
32875 * Fires before the splitter is dragged
32876 * @param {Roo.bootstrap.SplitBar} this
32878 "beforeresize" : true,
32880 "beforeapply" : true
32883 Roo.util.Observable.call(this);
32886 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
32887 onStartProxyDrag : function(x, y){
32888 this.fireEvent("beforeresize", this);
32890 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
32892 o.enableDisplayMode("block");
32893 // all splitbars share the same overlay
32894 Roo.bootstrap.SplitBar.prototype.overlay = o;
32896 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32897 this.overlay.show();
32898 Roo.get(this.proxy).setDisplayed("block");
32899 var size = this.adapter.getElementSize(this);
32900 this.activeMinSize = this.getMinimumSize();;
32901 this.activeMaxSize = this.getMaximumSize();;
32902 var c1 = size - this.activeMinSize;
32903 var c2 = Math.max(this.activeMaxSize - size, 0);
32904 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32905 this.dd.resetConstraints();
32906 this.dd.setXConstraint(
32907 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
32908 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
32910 this.dd.setYConstraint(0, 0);
32912 this.dd.resetConstraints();
32913 this.dd.setXConstraint(0, 0);
32914 this.dd.setYConstraint(
32915 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
32916 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
32919 this.dragSpecs.startSize = size;
32920 this.dragSpecs.startPoint = [x, y];
32921 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
32925 * @private Called after the drag operation by the DDProxy
32927 onEndProxyDrag : function(e){
32928 Roo.get(this.proxy).setDisplayed(false);
32929 var endPoint = Roo.lib.Event.getXY(e);
32931 this.overlay.hide();
32934 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
32935 newSize = this.dragSpecs.startSize +
32936 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
32937 endPoint[0] - this.dragSpecs.startPoint[0] :
32938 this.dragSpecs.startPoint[0] - endPoint[0]
32941 newSize = this.dragSpecs.startSize +
32942 (this.placement == Roo.bootstrap.SplitBar.TOP ?
32943 endPoint[1] - this.dragSpecs.startPoint[1] :
32944 this.dragSpecs.startPoint[1] - endPoint[1]
32947 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
32948 if(newSize != this.dragSpecs.startSize){
32949 if(this.fireEvent('beforeapply', this, newSize) !== false){
32950 this.adapter.setElementSize(this, newSize);
32951 this.fireEvent("moved", this, newSize);
32952 this.fireEvent("resize", this, newSize);
32958 * Get the adapter this SplitBar uses
32959 * @return The adapter object
32961 getAdapter : function(){
32962 return this.adapter;
32966 * Set the adapter this SplitBar uses
32967 * @param {Object} adapter A SplitBar adapter object
32969 setAdapter : function(adapter){
32970 this.adapter = adapter;
32971 this.adapter.init(this);
32975 * Gets the minimum size for the resizing element
32976 * @return {Number} The minimum size
32978 getMinimumSize : function(){
32979 return this.minSize;
32983 * Sets the minimum size for the resizing element
32984 * @param {Number} minSize The minimum size
32986 setMinimumSize : function(minSize){
32987 this.minSize = minSize;
32991 * Gets the maximum size for the resizing element
32992 * @return {Number} The maximum size
32994 getMaximumSize : function(){
32995 return this.maxSize;
32999 * Sets the maximum size for the resizing element
33000 * @param {Number} maxSize The maximum size
33002 setMaximumSize : function(maxSize){
33003 this.maxSize = maxSize;
33007 * Sets the initialize size for the resizing element
33008 * @param {Number} size The initial size
33010 setCurrentSize : function(size){
33011 var oldAnimate = this.animate;
33012 this.animate = false;
33013 this.adapter.setElementSize(this, size);
33014 this.animate = oldAnimate;
33018 * Destroy this splitbar.
33019 * @param {Boolean} removeEl True to remove the element
33021 destroy : function(removeEl){
33023 this.shim.remove();
33026 this.proxy.parentNode.removeChild(this.proxy);
33034 * @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.
33036 Roo.bootstrap.SplitBar.createProxy = function(dir){
33037 var proxy = new Roo.Element(document.createElement("div"));
33038 proxy.unselectable();
33039 var cls = 'roo-splitbar-proxy';
33040 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
33041 document.body.appendChild(proxy.dom);
33046 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
33047 * Default Adapter. It assumes the splitter and resizing element are not positioned
33048 * elements and only gets/sets the width of the element. Generally used for table based layouts.
33050 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
33053 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
33054 // do nothing for now
33055 init : function(s){
33059 * Called before drag operations to get the current size of the resizing element.
33060 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33062 getElementSize : function(s){
33063 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33064 return s.resizingEl.getWidth();
33066 return s.resizingEl.getHeight();
33071 * Called after drag operations to set the size of the resizing element.
33072 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
33073 * @param {Number} newSize The new size to set
33074 * @param {Function} onComplete A function to be invoked when resizing is complete
33076 setElementSize : function(s, newSize, onComplete){
33077 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
33079 s.resizingEl.setWidth(newSize);
33081 onComplete(s, newSize);
33084 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
33089 s.resizingEl.setHeight(newSize);
33091 onComplete(s, newSize);
33094 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
33101 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
33102 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
33103 * Adapter that moves the splitter element to align with the resized sizing element.
33104 * Used with an absolute positioned SplitBar.
33105 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
33106 * document.body, make sure you assign an id to the body element.
33108 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
33109 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
33110 this.container = Roo.get(container);
33113 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
33114 init : function(s){
33115 this.basic.init(s);
33118 getElementSize : function(s){
33119 return this.basic.getElementSize(s);
33122 setElementSize : function(s, newSize, onComplete){
33123 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
33126 moveSplitter : function(s){
33127 var yes = Roo.bootstrap.SplitBar;
33128 switch(s.placement){
33130 s.el.setX(s.resizingEl.getRight());
33133 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
33136 s.el.setY(s.resizingEl.getBottom());
33139 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
33146 * Orientation constant - Create a vertical SplitBar
33150 Roo.bootstrap.SplitBar.VERTICAL = 1;
33153 * Orientation constant - Create a horizontal SplitBar
33157 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
33160 * Placement constant - The resizing element is to the left of the splitter element
33164 Roo.bootstrap.SplitBar.LEFT = 1;
33167 * Placement constant - The resizing element is to the right of the splitter element
33171 Roo.bootstrap.SplitBar.RIGHT = 2;
33174 * Placement constant - The resizing element is positioned above the splitter element
33178 Roo.bootstrap.SplitBar.TOP = 3;
33181 * Placement constant - The resizing element is positioned under splitter element
33185 Roo.bootstrap.SplitBar.BOTTOM = 4;
33186 Roo.namespace("Roo.bootstrap.layout");/*
33188 * Ext JS Library 1.1.1
33189 * Copyright(c) 2006-2007, Ext JS, LLC.
33191 * Originally Released Under LGPL - original licence link has changed is not relivant.
33194 * <script type="text/javascript">
33198 * @class Roo.bootstrap.layout.Manager
33199 * @extends Roo.bootstrap.Component
33200 * Base class for layout managers.
33202 Roo.bootstrap.layout.Manager = function(config)
33204 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
33210 /** false to disable window resize monitoring @type Boolean */
33211 this.monitorWindowResize = true;
33216 * Fires when a layout is performed.
33217 * @param {Roo.LayoutManager} this
33221 * @event regionresized
33222 * Fires when the user resizes a region.
33223 * @param {Roo.LayoutRegion} region The resized region
33224 * @param {Number} newSize The new size (width for east/west, height for north/south)
33226 "regionresized" : true,
33228 * @event regioncollapsed
33229 * Fires when a region is collapsed.
33230 * @param {Roo.LayoutRegion} region The collapsed region
33232 "regioncollapsed" : true,
33234 * @event regionexpanded
33235 * Fires when a region is expanded.
33236 * @param {Roo.LayoutRegion} region The expanded region
33238 "regionexpanded" : true
33240 this.updating = false;
33243 this.el = Roo.get(config.el);
33249 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
33254 monitorWindowResize : true,
33260 onRender : function(ct, position)
33263 this.el = Roo.get(ct);
33266 //this.fireEvent('render',this);
33270 initEvents: function()
33274 // ie scrollbar fix
33275 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
33276 document.body.scroll = "no";
33277 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
33278 this.el.position('relative');
33280 this.id = this.el.id;
33281 this.el.addClass("roo-layout-container");
33282 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33283 if(this.el.dom != document.body ) {
33284 this.el.on('resize', this.layout,this);
33285 this.el.on('show', this.layout,this);
33291 * Returns true if this layout is currently being updated
33292 * @return {Boolean}
33294 isUpdating : function(){
33295 return this.updating;
33299 * Suspend the LayoutManager from doing auto-layouts while
33300 * making multiple add or remove calls
33302 beginUpdate : function(){
33303 this.updating = true;
33307 * Restore auto-layouts and optionally disable the manager from performing a layout
33308 * @param {Boolean} noLayout true to disable a layout update
33310 endUpdate : function(noLayout){
33311 this.updating = false;
33317 layout: function(){
33321 onRegionResized : function(region, newSize){
33322 this.fireEvent("regionresized", region, newSize);
33326 onRegionCollapsed : function(region){
33327 this.fireEvent("regioncollapsed", region);
33330 onRegionExpanded : function(region){
33331 this.fireEvent("regionexpanded", region);
33335 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
33336 * performs box-model adjustments.
33337 * @return {Object} The size as an object {width: (the width), height: (the height)}
33339 getViewSize : function()
33342 if(this.el.dom != document.body){
33343 size = this.el.getSize();
33345 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
33347 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
33348 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
33353 * Returns the Element this layout is bound to.
33354 * @return {Roo.Element}
33356 getEl : function(){
33361 * Returns the specified region.
33362 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
33363 * @return {Roo.LayoutRegion}
33365 getRegion : function(target){
33366 return this.regions[target.toLowerCase()];
33369 onWindowResize : function(){
33370 if(this.monitorWindowResize){
33377 * Ext JS Library 1.1.1
33378 * Copyright(c) 2006-2007, Ext JS, LLC.
33380 * Originally Released Under LGPL - original licence link has changed is not relivant.
33383 * <script type="text/javascript">
33386 * @class Roo.bootstrap.layout.Border
33387 * @extends Roo.bootstrap.layout.Manager
33388 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
33389 * please see: examples/bootstrap/nested.html<br><br>
33391 <b>The container the layout is rendered into can be either the body element or any other element.
33392 If it is not the body element, the container needs to either be an absolute positioned element,
33393 or you will need to add "position:relative" to the css of the container. You will also need to specify
33394 the container size if it is not the body element.</b>
33397 * Create a new Border
33398 * @param {Object} config Configuration options
33400 Roo.bootstrap.layout.Border = function(config){
33401 config = config || {};
33402 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
33406 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33407 if(config[region]){
33408 config[region].region = region;
33409 this.addRegion(config[region]);
33415 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
33417 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
33419 * Creates and adds a new region if it doesn't already exist.
33420 * @param {String} target The target region key (north, south, east, west or center).
33421 * @param {Object} config The regions config object
33422 * @return {BorderLayoutRegion} The new region
33424 addRegion : function(config)
33426 if(!this.regions[config.region]){
33427 var r = this.factory(config);
33428 this.bindRegion(r);
33430 return this.regions[config.region];
33434 bindRegion : function(r){
33435 this.regions[r.config.region] = r;
33437 r.on("visibilitychange", this.layout, this);
33438 r.on("paneladded", this.layout, this);
33439 r.on("panelremoved", this.layout, this);
33440 r.on("invalidated", this.layout, this);
33441 r.on("resized", this.onRegionResized, this);
33442 r.on("collapsed", this.onRegionCollapsed, this);
33443 r.on("expanded", this.onRegionExpanded, this);
33447 * Performs a layout update.
33449 layout : function()
33451 if(this.updating) {
33455 // render all the rebions if they have not been done alreayd?
33456 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
33457 if(this.regions[region] && !this.regions[region].bodyEl){
33458 this.regions[region].onRender(this.el)
33462 var size = this.getViewSize();
33463 var w = size.width;
33464 var h = size.height;
33469 //var x = 0, y = 0;
33471 var rs = this.regions;
33472 var north = rs["north"];
33473 var south = rs["south"];
33474 var west = rs["west"];
33475 var east = rs["east"];
33476 var center = rs["center"];
33477 //if(this.hideOnLayout){ // not supported anymore
33478 //c.el.setStyle("display", "none");
33480 if(north && north.isVisible()){
33481 var b = north.getBox();
33482 var m = north.getMargins();
33483 b.width = w - (m.left+m.right);
33486 centerY = b.height + b.y + m.bottom;
33487 centerH -= centerY;
33488 north.updateBox(this.safeBox(b));
33490 if(south && south.isVisible()){
33491 var b = south.getBox();
33492 var m = south.getMargins();
33493 b.width = w - (m.left+m.right);
33495 var totalHeight = (b.height + m.top + m.bottom);
33496 b.y = h - totalHeight + m.top;
33497 centerH -= totalHeight;
33498 south.updateBox(this.safeBox(b));
33500 if(west && west.isVisible()){
33501 var b = west.getBox();
33502 var m = west.getMargins();
33503 b.height = centerH - (m.top+m.bottom);
33505 b.y = centerY + m.top;
33506 var totalWidth = (b.width + m.left + m.right);
33507 centerX += totalWidth;
33508 centerW -= totalWidth;
33509 west.updateBox(this.safeBox(b));
33511 if(east && east.isVisible()){
33512 var b = east.getBox();
33513 var m = east.getMargins();
33514 b.height = centerH - (m.top+m.bottom);
33515 var totalWidth = (b.width + m.left + m.right);
33516 b.x = w - totalWidth + m.left;
33517 b.y = centerY + m.top;
33518 centerW -= totalWidth;
33519 east.updateBox(this.safeBox(b));
33522 var m = center.getMargins();
33524 x: centerX + m.left,
33525 y: centerY + m.top,
33526 width: centerW - (m.left+m.right),
33527 height: centerH - (m.top+m.bottom)
33529 //if(this.hideOnLayout){
33530 //center.el.setStyle("display", "block");
33532 center.updateBox(this.safeBox(centerBox));
33535 this.fireEvent("layout", this);
33539 safeBox : function(box){
33540 box.width = Math.max(0, box.width);
33541 box.height = Math.max(0, box.height);
33546 * Adds a ContentPanel (or subclass) to this layout.
33547 * @param {String} target The target region key (north, south, east, west or center).
33548 * @param {Roo.ContentPanel} panel The panel to add
33549 * @return {Roo.ContentPanel} The added panel
33551 add : function(target, panel){
33553 target = target.toLowerCase();
33554 return this.regions[target].add(panel);
33558 * Remove a ContentPanel (or subclass) to this layout.
33559 * @param {String} target The target region key (north, south, east, west or center).
33560 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
33561 * @return {Roo.ContentPanel} The removed panel
33563 remove : function(target, panel){
33564 target = target.toLowerCase();
33565 return this.regions[target].remove(panel);
33569 * Searches all regions for a panel with the specified id
33570 * @param {String} panelId
33571 * @return {Roo.ContentPanel} The panel or null if it wasn't found
33573 findPanel : function(panelId){
33574 var rs = this.regions;
33575 for(var target in rs){
33576 if(typeof rs[target] != "function"){
33577 var p = rs[target].getPanel(panelId);
33587 * Searches all regions for a panel with the specified id and activates (shows) it.
33588 * @param {String/ContentPanel} panelId The panels id or the panel itself
33589 * @return {Roo.ContentPanel} The shown panel or null
33591 showPanel : function(panelId) {
33592 var rs = this.regions;
33593 for(var target in rs){
33594 var r = rs[target];
33595 if(typeof r != "function"){
33596 if(r.hasPanel(panelId)){
33597 return r.showPanel(panelId);
33605 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
33606 * @param {Roo.state.Provider} provider (optional) An alternate state provider
33609 restoreState : function(provider){
33611 provider = Roo.state.Manager;
33613 var sm = new Roo.LayoutStateManager();
33614 sm.init(this, provider);
33620 * Adds a xtype elements to the layout.
33624 xtype : 'ContentPanel',
33631 xtype : 'NestedLayoutPanel',
33637 items : [ ... list of content panels or nested layout panels.. ]
33641 * @param {Object} cfg Xtype definition of item to add.
33643 addxtype : function(cfg)
33645 // basically accepts a pannel...
33646 // can accept a layout region..!?!?
33647 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
33650 // theory? children can only be panels??
33652 //if (!cfg.xtype.match(/Panel$/)) {
33657 if (typeof(cfg.region) == 'undefined') {
33658 Roo.log("Failed to add Panel, region was not set");
33662 var region = cfg.region;
33668 xitems = cfg.items;
33675 case 'Content': // ContentPanel (el, cfg)
33676 case 'Scroll': // ContentPanel (el, cfg)
33678 cfg.autoCreate = true;
33679 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33681 // var el = this.el.createChild();
33682 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
33685 this.add(region, ret);
33689 case 'TreePanel': // our new panel!
33690 cfg.el = this.el.createChild();
33691 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33692 this.add(region, ret);
33697 // create a new Layout (which is a Border Layout...
33699 var clayout = cfg.layout;
33700 clayout.el = this.el.createChild();
33701 clayout.items = clayout.items || [];
33705 // replace this exitems with the clayout ones..
33706 xitems = clayout.items;
33708 // force background off if it's in center...
33709 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
33710 cfg.background = false;
33712 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
33715 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33716 //console.log('adding nested layout panel ' + cfg.toSource());
33717 this.add(region, ret);
33718 nb = {}; /// find first...
33723 // needs grid and region
33725 //var el = this.getRegion(region).el.createChild();
33727 *var el = this.el.createChild();
33728 // create the grid first...
33729 cfg.grid.container = el;
33730 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
33733 if (region == 'center' && this.active ) {
33734 cfg.background = false;
33737 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
33739 this.add(region, ret);
33741 if (cfg.background) {
33742 // render grid on panel activation (if panel background)
33743 ret.on('activate', function(gp) {
33744 if (!gp.grid.rendered) {
33745 // gp.grid.render(el);
33749 // cfg.grid.render(el);
33755 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
33756 // it was the old xcomponent building that caused this before.
33757 // espeically if border is the top element in the tree.
33767 if (typeof(Roo[cfg.xtype]) != 'undefined') {
33769 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
33770 this.add(region, ret);
33774 throw "Can not add '" + cfg.xtype + "' to Border";
33780 this.beginUpdate();
33784 Roo.each(xitems, function(i) {
33785 region = nb && i.region ? i.region : false;
33787 var add = ret.addxtype(i);
33790 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
33791 if (!i.background) {
33792 abn[region] = nb[region] ;
33799 // make the last non-background panel active..
33800 //if (nb) { Roo.log(abn); }
33803 for(var r in abn) {
33804 region = this.getRegion(r);
33806 // tried using nb[r], but it does not work..
33808 region.showPanel(abn[r]);
33819 factory : function(cfg)
33822 var validRegions = Roo.bootstrap.layout.Border.regions;
33824 var target = cfg.region;
33827 var r = Roo.bootstrap.layout;
33831 return new r.North(cfg);
33833 return new r.South(cfg);
33835 return new r.East(cfg);
33837 return new r.West(cfg);
33839 return new r.Center(cfg);
33841 throw 'Layout region "'+target+'" not supported.';
33848 * Ext JS Library 1.1.1
33849 * Copyright(c) 2006-2007, Ext JS, LLC.
33851 * Originally Released Under LGPL - original licence link has changed is not relivant.
33854 * <script type="text/javascript">
33858 * @class Roo.bootstrap.layout.Basic
33859 * @extends Roo.util.Observable
33860 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
33861 * and does not have a titlebar, tabs or any other features. All it does is size and position
33862 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
33863 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
33864 * @cfg {string} region the region that it inhabits..
33865 * @cfg {bool} skipConfig skip config?
33869 Roo.bootstrap.layout.Basic = function(config){
33871 this.mgr = config.mgr;
33873 this.position = config.region;
33875 var skipConfig = config.skipConfig;
33879 * @scope Roo.BasicLayoutRegion
33883 * @event beforeremove
33884 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
33885 * @param {Roo.LayoutRegion} this
33886 * @param {Roo.ContentPanel} panel The panel
33887 * @param {Object} e The cancel event object
33889 "beforeremove" : true,
33891 * @event invalidated
33892 * Fires when the layout for this region is changed.
33893 * @param {Roo.LayoutRegion} this
33895 "invalidated" : true,
33897 * @event visibilitychange
33898 * Fires when this region is shown or hidden
33899 * @param {Roo.LayoutRegion} this
33900 * @param {Boolean} visibility true or false
33902 "visibilitychange" : true,
33904 * @event paneladded
33905 * Fires when a panel is added.
33906 * @param {Roo.LayoutRegion} this
33907 * @param {Roo.ContentPanel} panel The panel
33909 "paneladded" : true,
33911 * @event panelremoved
33912 * Fires when a panel is removed.
33913 * @param {Roo.LayoutRegion} this
33914 * @param {Roo.ContentPanel} panel The panel
33916 "panelremoved" : true,
33918 * @event beforecollapse
33919 * Fires when this region before collapse.
33920 * @param {Roo.LayoutRegion} this
33922 "beforecollapse" : true,
33925 * Fires when this region is collapsed.
33926 * @param {Roo.LayoutRegion} this
33928 "collapsed" : true,
33931 * Fires when this region is expanded.
33932 * @param {Roo.LayoutRegion} this
33937 * Fires when this region is slid into view.
33938 * @param {Roo.LayoutRegion} this
33940 "slideshow" : true,
33943 * Fires when this region slides out of view.
33944 * @param {Roo.LayoutRegion} this
33946 "slidehide" : true,
33948 * @event panelactivated
33949 * Fires when a panel is activated.
33950 * @param {Roo.LayoutRegion} this
33951 * @param {Roo.ContentPanel} panel The activated panel
33953 "panelactivated" : true,
33956 * Fires when the user resizes this region.
33957 * @param {Roo.LayoutRegion} this
33958 * @param {Number} newSize The new size (width for east/west, height for north/south)
33962 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33963 this.panels = new Roo.util.MixedCollection();
33964 this.panels.getKey = this.getPanelId.createDelegate(this);
33966 this.activePanel = null;
33967 // ensure listeners are added...
33969 if (config.listeners || config.events) {
33970 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
33971 listeners : config.listeners || {},
33972 events : config.events || {}
33976 if(skipConfig !== true){
33977 this.applyConfig(config);
33981 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
33983 getPanelId : function(p){
33987 applyConfig : function(config){
33988 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33989 this.config = config;
33994 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33995 * the width, for horizontal (north, south) the height.
33996 * @param {Number} newSize The new width or height
33998 resizeTo : function(newSize){
33999 var el = this.el ? this.el :
34000 (this.activePanel ? this.activePanel.getEl() : null);
34002 switch(this.position){
34005 el.setWidth(newSize);
34006 this.fireEvent("resized", this, newSize);
34010 el.setHeight(newSize);
34011 this.fireEvent("resized", this, newSize);
34017 getBox : function(){
34018 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
34021 getMargins : function(){
34022 return this.margins;
34025 updateBox : function(box){
34027 var el = this.activePanel.getEl();
34028 el.dom.style.left = box.x + "px";
34029 el.dom.style.top = box.y + "px";
34030 this.activePanel.setSize(box.width, box.height);
34034 * Returns the container element for this region.
34035 * @return {Roo.Element}
34037 getEl : function(){
34038 return this.activePanel;
34042 * Returns true if this region is currently visible.
34043 * @return {Boolean}
34045 isVisible : function(){
34046 return this.activePanel ? true : false;
34049 setActivePanel : function(panel){
34050 panel = this.getPanel(panel);
34051 if(this.activePanel && this.activePanel != panel){
34052 this.activePanel.setActiveState(false);
34053 this.activePanel.getEl().setLeftTop(-10000,-10000);
34055 this.activePanel = panel;
34056 panel.setActiveState(true);
34058 panel.setSize(this.box.width, this.box.height);
34060 this.fireEvent("panelactivated", this, panel);
34061 this.fireEvent("invalidated");
34065 * Show the specified panel.
34066 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
34067 * @return {Roo.ContentPanel} The shown panel or null
34069 showPanel : function(panel){
34070 panel = this.getPanel(panel);
34072 this.setActivePanel(panel);
34078 * Get the active panel for this region.
34079 * @return {Roo.ContentPanel} The active panel or null
34081 getActivePanel : function(){
34082 return this.activePanel;
34086 * Add the passed ContentPanel(s)
34087 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34088 * @return {Roo.ContentPanel} The panel added (if only one was added)
34090 add : function(panel){
34091 if(arguments.length > 1){
34092 for(var i = 0, len = arguments.length; i < len; i++) {
34093 this.add(arguments[i]);
34097 if(this.hasPanel(panel)){
34098 this.showPanel(panel);
34101 var el = panel.getEl();
34102 if(el.dom.parentNode != this.mgr.el.dom){
34103 this.mgr.el.dom.appendChild(el.dom);
34105 if(panel.setRegion){
34106 panel.setRegion(this);
34108 this.panels.add(panel);
34109 el.setStyle("position", "absolute");
34110 if(!panel.background){
34111 this.setActivePanel(panel);
34112 if(this.config.initialSize && this.panels.getCount()==1){
34113 this.resizeTo(this.config.initialSize);
34116 this.fireEvent("paneladded", this, panel);
34121 * Returns true if the panel is in this region.
34122 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34123 * @return {Boolean}
34125 hasPanel : function(panel){
34126 if(typeof panel == "object"){ // must be panel obj
34127 panel = panel.getId();
34129 return this.getPanel(panel) ? true : false;
34133 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34134 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34135 * @param {Boolean} preservePanel Overrides the config preservePanel option
34136 * @return {Roo.ContentPanel} The panel that was removed
34138 remove : function(panel, preservePanel){
34139 panel = this.getPanel(panel);
34144 this.fireEvent("beforeremove", this, panel, e);
34145 if(e.cancel === true){
34148 var panelId = panel.getId();
34149 this.panels.removeKey(panelId);
34154 * Returns the panel specified or null if it's not in this region.
34155 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
34156 * @return {Roo.ContentPanel}
34158 getPanel : function(id){
34159 if(typeof id == "object"){ // must be panel obj
34162 return this.panels.get(id);
34166 * Returns this regions position (north/south/east/west/center).
34169 getPosition: function(){
34170 return this.position;
34174 * Ext JS Library 1.1.1
34175 * Copyright(c) 2006-2007, Ext JS, LLC.
34177 * Originally Released Under LGPL - original licence link has changed is not relivant.
34180 * <script type="text/javascript">
34184 * @class Roo.bootstrap.layout.Region
34185 * @extends Roo.bootstrap.layout.Basic
34186 * This class represents a region in a layout manager.
34188 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
34189 * @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})
34190 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
34191 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
34192 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
34193 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
34194 * @cfg {String} title The title for the region (overrides panel titles)
34195 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
34196 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
34197 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
34198 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
34199 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
34200 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
34201 * the space available, similar to FireFox 1.5 tabs (defaults to false)
34202 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
34203 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
34204 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
34206 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
34207 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
34208 * @cfg {Boolean} disableTabTips True to disable tab tooltips
34209 * @cfg {Number} width For East/West panels
34210 * @cfg {Number} height For North/South panels
34211 * @cfg {Boolean} split To show the splitter
34212 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
34214 * @cfg {string} cls Extra CSS classes to add to region
34216 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
34217 * @cfg {string} region the region that it inhabits..
34220 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
34221 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
34223 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
34224 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
34225 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
34227 Roo.bootstrap.layout.Region = function(config)
34229 this.applyConfig(config);
34231 var mgr = config.mgr;
34232 var pos = config.region;
34233 config.skipConfig = true;
34234 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
34237 this.onRender(mgr.el);
34240 this.visible = true;
34241 this.collapsed = false;
34242 this.unrendered_panels = [];
34245 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
34247 position: '', // set by wrapper (eg. north/south etc..)
34248 unrendered_panels : null, // unrendered panels.
34249 createBody : function(){
34250 /** This region's body element
34251 * @type Roo.Element */
34252 this.bodyEl = this.el.createChild({
34254 cls: "roo-layout-panel-body tab-content" // bootstrap added...
34258 onRender: function(ctr, pos)
34260 var dh = Roo.DomHelper;
34261 /** This region's container element
34262 * @type Roo.Element */
34263 this.el = dh.append(ctr.dom, {
34265 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
34267 /** This region's title element
34268 * @type Roo.Element */
34270 this.titleEl = dh.append(this.el.dom,
34273 unselectable: "on",
34274 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
34276 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
34277 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
34280 this.titleEl.enableDisplayMode();
34281 /** This region's title text element
34282 * @type HTMLElement */
34283 this.titleTextEl = this.titleEl.dom.firstChild;
34284 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
34286 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
34287 this.closeBtn.enableDisplayMode();
34288 this.closeBtn.on("click", this.closeClicked, this);
34289 this.closeBtn.hide();
34291 this.createBody(this.config);
34292 if(this.config.hideWhenEmpty){
34294 this.on("paneladded", this.validateVisibility, this);
34295 this.on("panelremoved", this.validateVisibility, this);
34297 if(this.autoScroll){
34298 this.bodyEl.setStyle("overflow", "auto");
34300 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
34302 //if(c.titlebar !== false){
34303 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
34304 this.titleEl.hide();
34306 this.titleEl.show();
34307 if(this.config.title){
34308 this.titleTextEl.innerHTML = this.config.title;
34312 if(this.config.collapsed){
34313 this.collapse(true);
34315 if(this.config.hidden){
34319 if (this.unrendered_panels && this.unrendered_panels.length) {
34320 for (var i =0;i< this.unrendered_panels.length; i++) {
34321 this.add(this.unrendered_panels[i]);
34323 this.unrendered_panels = null;
34329 applyConfig : function(c)
34332 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
34333 var dh = Roo.DomHelper;
34334 if(c.titlebar !== false){
34335 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
34336 this.collapseBtn.on("click", this.collapse, this);
34337 this.collapseBtn.enableDisplayMode();
34339 if(c.showPin === true || this.showPin){
34340 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
34341 this.stickBtn.enableDisplayMode();
34342 this.stickBtn.on("click", this.expand, this);
34343 this.stickBtn.hide();
34348 /** This region's collapsed element
34349 * @type Roo.Element */
34352 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
34353 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
34356 if(c.floatable !== false){
34357 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
34358 this.collapsedEl.on("click", this.collapseClick, this);
34361 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
34362 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
34363 id: "message", unselectable: "on", style:{"float":"left"}});
34364 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
34366 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
34367 this.expandBtn.on("click", this.expand, this);
34371 if(this.collapseBtn){
34372 this.collapseBtn.setVisible(c.collapsible == true);
34375 this.cmargins = c.cmargins || this.cmargins ||
34376 (this.position == "west" || this.position == "east" ?
34377 {top: 0, left: 2, right:2, bottom: 0} :
34378 {top: 2, left: 0, right:0, bottom: 2});
34380 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
34383 this.bottomTabs = c.tabPosition != "top";
34385 this.autoScroll = c.autoScroll || false;
34390 this.duration = c.duration || .30;
34391 this.slideDuration = c.slideDuration || .45;
34396 * Returns true if this region is currently visible.
34397 * @return {Boolean}
34399 isVisible : function(){
34400 return this.visible;
34404 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
34405 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
34407 //setCollapsedTitle : function(title){
34408 // title = title || " ";
34409 // if(this.collapsedTitleTextEl){
34410 // this.collapsedTitleTextEl.innerHTML = title;
34414 getBox : function(){
34416 // if(!this.collapsed){
34417 b = this.el.getBox(false, true);
34419 // b = this.collapsedEl.getBox(false, true);
34424 getMargins : function(){
34425 return this.margins;
34426 //return this.collapsed ? this.cmargins : this.margins;
34429 highlight : function(){
34430 this.el.addClass("x-layout-panel-dragover");
34433 unhighlight : function(){
34434 this.el.removeClass("x-layout-panel-dragover");
34437 updateBox : function(box)
34439 if (!this.bodyEl) {
34440 return; // not rendered yet..
34444 if(!this.collapsed){
34445 this.el.dom.style.left = box.x + "px";
34446 this.el.dom.style.top = box.y + "px";
34447 this.updateBody(box.width, box.height);
34449 this.collapsedEl.dom.style.left = box.x + "px";
34450 this.collapsedEl.dom.style.top = box.y + "px";
34451 this.collapsedEl.setSize(box.width, box.height);
34454 this.tabs.autoSizeTabs();
34458 updateBody : function(w, h)
34461 this.el.setWidth(w);
34462 w -= this.el.getBorderWidth("rl");
34463 if(this.config.adjustments){
34464 w += this.config.adjustments[0];
34467 if(h !== null && h > 0){
34468 this.el.setHeight(h);
34469 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
34470 h -= this.el.getBorderWidth("tb");
34471 if(this.config.adjustments){
34472 h += this.config.adjustments[1];
34474 this.bodyEl.setHeight(h);
34476 h = this.tabs.syncHeight(h);
34479 if(this.panelSize){
34480 w = w !== null ? w : this.panelSize.width;
34481 h = h !== null ? h : this.panelSize.height;
34483 if(this.activePanel){
34484 var el = this.activePanel.getEl();
34485 w = w !== null ? w : el.getWidth();
34486 h = h !== null ? h : el.getHeight();
34487 this.panelSize = {width: w, height: h};
34488 this.activePanel.setSize(w, h);
34490 if(Roo.isIE && this.tabs){
34491 this.tabs.el.repaint();
34496 * Returns the container element for this region.
34497 * @return {Roo.Element}
34499 getEl : function(){
34504 * Hides this region.
34507 //if(!this.collapsed){
34508 this.el.dom.style.left = "-2000px";
34511 // this.collapsedEl.dom.style.left = "-2000px";
34512 // this.collapsedEl.hide();
34514 this.visible = false;
34515 this.fireEvent("visibilitychange", this, false);
34519 * Shows this region if it was previously hidden.
34522 //if(!this.collapsed){
34525 // this.collapsedEl.show();
34527 this.visible = true;
34528 this.fireEvent("visibilitychange", this, true);
34531 closeClicked : function(){
34532 if(this.activePanel){
34533 this.remove(this.activePanel);
34537 collapseClick : function(e){
34539 e.stopPropagation();
34542 e.stopPropagation();
34548 * Collapses this region.
34549 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
34552 collapse : function(skipAnim, skipCheck = false){
34553 if(this.collapsed) {
34557 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
34559 this.collapsed = true;
34561 this.split.el.hide();
34563 if(this.config.animate && skipAnim !== true){
34564 this.fireEvent("invalidated", this);
34565 this.animateCollapse();
34567 this.el.setLocation(-20000,-20000);
34569 this.collapsedEl.show();
34570 this.fireEvent("collapsed", this);
34571 this.fireEvent("invalidated", this);
34577 animateCollapse : function(){
34582 * Expands this region if it was previously collapsed.
34583 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
34584 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
34587 expand : function(e, skipAnim){
34589 e.stopPropagation();
34591 if(!this.collapsed || this.el.hasActiveFx()) {
34595 this.afterSlideIn();
34598 this.collapsed = false;
34599 if(this.config.animate && skipAnim !== true){
34600 this.animateExpand();
34604 this.split.el.show();
34606 this.collapsedEl.setLocation(-2000,-2000);
34607 this.collapsedEl.hide();
34608 this.fireEvent("invalidated", this);
34609 this.fireEvent("expanded", this);
34613 animateExpand : function(){
34617 initTabs : function()
34619 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
34621 var ts = new Roo.bootstrap.panel.Tabs({
34622 el: this.bodyEl.dom,
34623 tabPosition: this.bottomTabs ? 'bottom' : 'top',
34624 disableTooltips: this.config.disableTabTips,
34625 toolbar : this.config.toolbar
34628 if(this.config.hideTabs){
34629 ts.stripWrap.setDisplayed(false);
34632 ts.resizeTabs = this.config.resizeTabs === true;
34633 ts.minTabWidth = this.config.minTabWidth || 40;
34634 ts.maxTabWidth = this.config.maxTabWidth || 250;
34635 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
34636 ts.monitorResize = false;
34637 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
34638 ts.bodyEl.addClass('roo-layout-tabs-body');
34639 this.panels.each(this.initPanelAsTab, this);
34642 initPanelAsTab : function(panel){
34643 var ti = this.tabs.addTab(
34647 this.config.closeOnTab && panel.isClosable(),
34650 if(panel.tabTip !== undefined){
34651 ti.setTooltip(panel.tabTip);
34653 ti.on("activate", function(){
34654 this.setActivePanel(panel);
34657 if(this.config.closeOnTab){
34658 ti.on("beforeclose", function(t, e){
34660 this.remove(panel);
34664 panel.tabItem = ti;
34669 updatePanelTitle : function(panel, title)
34671 if(this.activePanel == panel){
34672 this.updateTitle(title);
34675 var ti = this.tabs.getTab(panel.getEl().id);
34677 if(panel.tabTip !== undefined){
34678 ti.setTooltip(panel.tabTip);
34683 updateTitle : function(title){
34684 if(this.titleTextEl && !this.config.title){
34685 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
34689 setActivePanel : function(panel)
34691 panel = this.getPanel(panel);
34692 if(this.activePanel && this.activePanel != panel){
34693 this.activePanel.setActiveState(false);
34695 this.activePanel = panel;
34696 panel.setActiveState(true);
34697 if(this.panelSize){
34698 panel.setSize(this.panelSize.width, this.panelSize.height);
34701 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
34703 this.updateTitle(panel.getTitle());
34705 this.fireEvent("invalidated", this);
34707 this.fireEvent("panelactivated", this, panel);
34711 * Shows the specified panel.
34712 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
34713 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
34715 showPanel : function(panel)
34717 panel = this.getPanel(panel);
34720 var tab = this.tabs.getTab(panel.getEl().id);
34721 if(tab.isHidden()){
34722 this.tabs.unhideTab(tab.id);
34726 this.setActivePanel(panel);
34733 * Get the active panel for this region.
34734 * @return {Roo.ContentPanel} The active panel or null
34736 getActivePanel : function(){
34737 return this.activePanel;
34740 validateVisibility : function(){
34741 if(this.panels.getCount() < 1){
34742 this.updateTitle(" ");
34743 this.closeBtn.hide();
34746 if(!this.isVisible()){
34753 * Adds the passed ContentPanel(s) to this region.
34754 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
34755 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
34757 add : function(panel)
34759 if(arguments.length > 1){
34760 for(var i = 0, len = arguments.length; i < len; i++) {
34761 this.add(arguments[i]);
34766 // if we have not been rendered yet, then we can not really do much of this..
34767 if (!this.bodyEl) {
34768 this.unrendered_panels.push(panel);
34775 if(this.hasPanel(panel)){
34776 this.showPanel(panel);
34779 panel.setRegion(this);
34780 this.panels.add(panel);
34781 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
34782 // sinle panel - no tab...?? would it not be better to render it with the tabs,
34783 // and hide them... ???
34784 this.bodyEl.dom.appendChild(panel.getEl().dom);
34785 if(panel.background !== true){
34786 this.setActivePanel(panel);
34788 this.fireEvent("paneladded", this, panel);
34795 this.initPanelAsTab(panel);
34799 if(panel.background !== true){
34800 this.tabs.activate(panel.getEl().id);
34802 this.fireEvent("paneladded", this, panel);
34807 * Hides the tab for the specified panel.
34808 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34810 hidePanel : function(panel){
34811 if(this.tabs && (panel = this.getPanel(panel))){
34812 this.tabs.hideTab(panel.getEl().id);
34817 * Unhides the tab for a previously hidden panel.
34818 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34820 unhidePanel : function(panel){
34821 if(this.tabs && (panel = this.getPanel(panel))){
34822 this.tabs.unhideTab(panel.getEl().id);
34826 clearPanels : function(){
34827 while(this.panels.getCount() > 0){
34828 this.remove(this.panels.first());
34833 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
34834 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
34835 * @param {Boolean} preservePanel Overrides the config preservePanel option
34836 * @return {Roo.ContentPanel} The panel that was removed
34838 remove : function(panel, preservePanel)
34840 panel = this.getPanel(panel);
34845 this.fireEvent("beforeremove", this, panel, e);
34846 if(e.cancel === true){
34849 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
34850 var panelId = panel.getId();
34851 this.panels.removeKey(panelId);
34853 document.body.appendChild(panel.getEl().dom);
34856 this.tabs.removeTab(panel.getEl().id);
34857 }else if (!preservePanel){
34858 this.bodyEl.dom.removeChild(panel.getEl().dom);
34860 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
34861 var p = this.panels.first();
34862 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
34863 tempEl.appendChild(p.getEl().dom);
34864 this.bodyEl.update("");
34865 this.bodyEl.dom.appendChild(p.getEl().dom);
34867 this.updateTitle(p.getTitle());
34869 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
34870 this.setActivePanel(p);
34872 panel.setRegion(null);
34873 if(this.activePanel == panel){
34874 this.activePanel = null;
34876 if(this.config.autoDestroy !== false && preservePanel !== true){
34877 try{panel.destroy();}catch(e){}
34879 this.fireEvent("panelremoved", this, panel);
34884 * Returns the TabPanel component used by this region
34885 * @return {Roo.TabPanel}
34887 getTabs : function(){
34891 createTool : function(parentEl, className){
34892 var btn = Roo.DomHelper.append(parentEl, {
34894 cls: "x-layout-tools-button",
34897 cls: "roo-layout-tools-button-inner " + className,
34901 btn.addClassOnOver("roo-layout-tools-button-over");
34906 * Ext JS Library 1.1.1
34907 * Copyright(c) 2006-2007, Ext JS, LLC.
34909 * Originally Released Under LGPL - original licence link has changed is not relivant.
34912 * <script type="text/javascript">
34918 * @class Roo.SplitLayoutRegion
34919 * @extends Roo.LayoutRegion
34920 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
34922 Roo.bootstrap.layout.Split = function(config){
34923 this.cursor = config.cursor;
34924 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
34927 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
34929 splitTip : "Drag to resize.",
34930 collapsibleSplitTip : "Drag to resize. Double click to hide.",
34931 useSplitTips : false,
34933 applyConfig : function(config){
34934 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
34937 onRender : function(ctr,pos) {
34939 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
34940 if(!this.config.split){
34945 var splitEl = Roo.DomHelper.append(ctr.dom, {
34947 id: this.el.id + "-split",
34948 cls: "roo-layout-split roo-layout-split-"+this.position,
34951 /** The SplitBar for this region
34952 * @type Roo.SplitBar */
34953 // does not exist yet...
34954 Roo.log([this.position, this.orientation]);
34956 this.split = new Roo.bootstrap.SplitBar({
34957 dragElement : splitEl,
34958 resizingElement: this.el,
34959 orientation : this.orientation
34962 this.split.on("moved", this.onSplitMove, this);
34963 this.split.useShim = this.config.useShim === true;
34964 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
34965 if(this.useSplitTips){
34966 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
34968 //if(config.collapsible){
34969 // this.split.el.on("dblclick", this.collapse, this);
34972 if(typeof this.config.minSize != "undefined"){
34973 this.split.minSize = this.config.minSize;
34975 if(typeof this.config.maxSize != "undefined"){
34976 this.split.maxSize = this.config.maxSize;
34978 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
34979 this.hideSplitter();
34984 getHMaxSize : function(){
34985 var cmax = this.config.maxSize || 10000;
34986 var center = this.mgr.getRegion("center");
34987 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
34990 getVMaxSize : function(){
34991 var cmax = this.config.maxSize || 10000;
34992 var center = this.mgr.getRegion("center");
34993 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
34996 onSplitMove : function(split, newSize){
34997 this.fireEvent("resized", this, newSize);
35001 * Returns the {@link Roo.SplitBar} for this region.
35002 * @return {Roo.SplitBar}
35004 getSplitBar : function(){
35009 this.hideSplitter();
35010 Roo.bootstrap.layout.Split.superclass.hide.call(this);
35013 hideSplitter : function(){
35015 this.split.el.setLocation(-2000,-2000);
35016 this.split.el.hide();
35022 this.split.el.show();
35024 Roo.bootstrap.layout.Split.superclass.show.call(this);
35027 beforeSlide: function(){
35028 if(Roo.isGecko){// firefox overflow auto bug workaround
35029 this.bodyEl.clip();
35031 this.tabs.bodyEl.clip();
35033 if(this.activePanel){
35034 this.activePanel.getEl().clip();
35036 if(this.activePanel.beforeSlide){
35037 this.activePanel.beforeSlide();
35043 afterSlide : function(){
35044 if(Roo.isGecko){// firefox overflow auto bug workaround
35045 this.bodyEl.unclip();
35047 this.tabs.bodyEl.unclip();
35049 if(this.activePanel){
35050 this.activePanel.getEl().unclip();
35051 if(this.activePanel.afterSlide){
35052 this.activePanel.afterSlide();
35058 initAutoHide : function(){
35059 if(this.autoHide !== false){
35060 if(!this.autoHideHd){
35061 var st = new Roo.util.DelayedTask(this.slideIn, this);
35062 this.autoHideHd = {
35063 "mouseout": function(e){
35064 if(!e.within(this.el, true)){
35068 "mouseover" : function(e){
35074 this.el.on(this.autoHideHd);
35078 clearAutoHide : function(){
35079 if(this.autoHide !== false){
35080 this.el.un("mouseout", this.autoHideHd.mouseout);
35081 this.el.un("mouseover", this.autoHideHd.mouseover);
35085 clearMonitor : function(){
35086 Roo.get(document).un("click", this.slideInIf, this);
35089 // these names are backwards but not changed for compat
35090 slideOut : function(){
35091 if(this.isSlid || this.el.hasActiveFx()){
35094 this.isSlid = true;
35095 if(this.collapseBtn){
35096 this.collapseBtn.hide();
35098 this.closeBtnState = this.closeBtn.getStyle('display');
35099 this.closeBtn.hide();
35101 this.stickBtn.show();
35104 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
35105 this.beforeSlide();
35106 this.el.setStyle("z-index", 10001);
35107 this.el.slideIn(this.getSlideAnchor(), {
35108 callback: function(){
35110 this.initAutoHide();
35111 Roo.get(document).on("click", this.slideInIf, this);
35112 this.fireEvent("slideshow", this);
35119 afterSlideIn : function(){
35120 this.clearAutoHide();
35121 this.isSlid = false;
35122 this.clearMonitor();
35123 this.el.setStyle("z-index", "");
35124 if(this.collapseBtn){
35125 this.collapseBtn.show();
35127 this.closeBtn.setStyle('display', this.closeBtnState);
35129 this.stickBtn.hide();
35131 this.fireEvent("slidehide", this);
35134 slideIn : function(cb){
35135 if(!this.isSlid || this.el.hasActiveFx()){
35139 this.isSlid = false;
35140 this.beforeSlide();
35141 this.el.slideOut(this.getSlideAnchor(), {
35142 callback: function(){
35143 this.el.setLeftTop(-10000, -10000);
35145 this.afterSlideIn();
35153 slideInIf : function(e){
35154 if(!e.within(this.el)){
35159 animateCollapse : function(){
35160 this.beforeSlide();
35161 this.el.setStyle("z-index", 20000);
35162 var anchor = this.getSlideAnchor();
35163 this.el.slideOut(anchor, {
35164 callback : function(){
35165 this.el.setStyle("z-index", "");
35166 this.collapsedEl.slideIn(anchor, {duration:.3});
35168 this.el.setLocation(-10000,-10000);
35170 this.fireEvent("collapsed", this);
35177 animateExpand : function(){
35178 this.beforeSlide();
35179 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
35180 this.el.setStyle("z-index", 20000);
35181 this.collapsedEl.hide({
35184 this.el.slideIn(this.getSlideAnchor(), {
35185 callback : function(){
35186 this.el.setStyle("z-index", "");
35189 this.split.el.show();
35191 this.fireEvent("invalidated", this);
35192 this.fireEvent("expanded", this);
35220 getAnchor : function(){
35221 return this.anchors[this.position];
35224 getCollapseAnchor : function(){
35225 return this.canchors[this.position];
35228 getSlideAnchor : function(){
35229 return this.sanchors[this.position];
35232 getAlignAdj : function(){
35233 var cm = this.cmargins;
35234 switch(this.position){
35250 getExpandAdj : function(){
35251 var c = this.collapsedEl, cm = this.cmargins;
35252 switch(this.position){
35254 return [-(cm.right+c.getWidth()+cm.left), 0];
35257 return [cm.right+c.getWidth()+cm.left, 0];
35260 return [0, -(cm.top+cm.bottom+c.getHeight())];
35263 return [0, cm.top+cm.bottom+c.getHeight()];
35269 * Ext JS Library 1.1.1
35270 * Copyright(c) 2006-2007, Ext JS, LLC.
35272 * Originally Released Under LGPL - original licence link has changed is not relivant.
35275 * <script type="text/javascript">
35278 * These classes are private internal classes
35280 Roo.bootstrap.layout.Center = function(config){
35281 config.region = "center";
35282 Roo.bootstrap.layout.Region.call(this, config);
35283 this.visible = true;
35284 this.minWidth = config.minWidth || 20;
35285 this.minHeight = config.minHeight || 20;
35288 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
35290 // center panel can't be hidden
35294 // center panel can't be hidden
35297 getMinWidth: function(){
35298 return this.minWidth;
35301 getMinHeight: function(){
35302 return this.minHeight;
35315 Roo.bootstrap.layout.North = function(config)
35317 config.region = 'north';
35318 config.cursor = 'n-resize';
35320 Roo.bootstrap.layout.Split.call(this, config);
35324 this.split.placement = Roo.bootstrap.SplitBar.TOP;
35325 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35326 this.split.el.addClass("roo-layout-split-v");
35328 var size = config.initialSize || config.height;
35329 if(typeof size != "undefined"){
35330 this.el.setHeight(size);
35333 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
35335 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35339 getBox : function(){
35340 if(this.collapsed){
35341 return this.collapsedEl.getBox();
35343 var box = this.el.getBox();
35345 box.height += this.split.el.getHeight();
35350 updateBox : function(box){
35351 if(this.split && !this.collapsed){
35352 box.height -= this.split.el.getHeight();
35353 this.split.el.setLeft(box.x);
35354 this.split.el.setTop(box.y+box.height);
35355 this.split.el.setWidth(box.width);
35357 if(this.collapsed){
35358 this.updateBody(box.width, null);
35360 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35368 Roo.bootstrap.layout.South = function(config){
35369 config.region = 'south';
35370 config.cursor = 's-resize';
35371 Roo.bootstrap.layout.Split.call(this, config);
35373 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
35374 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
35375 this.split.el.addClass("roo-layout-split-v");
35377 var size = config.initialSize || config.height;
35378 if(typeof size != "undefined"){
35379 this.el.setHeight(size);
35383 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
35384 orientation: Roo.bootstrap.SplitBar.VERTICAL,
35385 getBox : function(){
35386 if(this.collapsed){
35387 return this.collapsedEl.getBox();
35389 var box = this.el.getBox();
35391 var sh = this.split.el.getHeight();
35398 updateBox : function(box){
35399 if(this.split && !this.collapsed){
35400 var sh = this.split.el.getHeight();
35403 this.split.el.setLeft(box.x);
35404 this.split.el.setTop(box.y-sh);
35405 this.split.el.setWidth(box.width);
35407 if(this.collapsed){
35408 this.updateBody(box.width, null);
35410 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35414 Roo.bootstrap.layout.East = function(config){
35415 config.region = "east";
35416 config.cursor = "e-resize";
35417 Roo.bootstrap.layout.Split.call(this, config);
35419 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
35420 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35421 this.split.el.addClass("roo-layout-split-h");
35423 var size = config.initialSize || config.width;
35424 if(typeof size != "undefined"){
35425 this.el.setWidth(size);
35428 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
35429 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35430 getBox : function(){
35431 if(this.collapsed){
35432 return this.collapsedEl.getBox();
35434 var box = this.el.getBox();
35436 var sw = this.split.el.getWidth();
35443 updateBox : function(box){
35444 if(this.split && !this.collapsed){
35445 var sw = this.split.el.getWidth();
35447 this.split.el.setLeft(box.x);
35448 this.split.el.setTop(box.y);
35449 this.split.el.setHeight(box.height);
35452 if(this.collapsed){
35453 this.updateBody(null, box.height);
35455 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35459 Roo.bootstrap.layout.West = function(config){
35460 config.region = "west";
35461 config.cursor = "w-resize";
35463 Roo.bootstrap.layout.Split.call(this, config);
35465 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
35466 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
35467 this.split.el.addClass("roo-layout-split-h");
35471 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
35472 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
35474 onRender: function(ctr, pos)
35476 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
35477 var size = this.config.initialSize || this.config.width;
35478 if(typeof size != "undefined"){
35479 this.el.setWidth(size);
35483 getBox : function(){
35484 if(this.collapsed){
35485 return this.collapsedEl.getBox();
35487 var box = this.el.getBox();
35489 box.width += this.split.el.getWidth();
35494 updateBox : function(box){
35495 if(this.split && !this.collapsed){
35496 var sw = this.split.el.getWidth();
35498 this.split.el.setLeft(box.x+box.width);
35499 this.split.el.setTop(box.y);
35500 this.split.el.setHeight(box.height);
35502 if(this.collapsed){
35503 this.updateBody(null, box.height);
35505 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
35508 Roo.namespace("Roo.bootstrap.panel");/*
35510 * Ext JS Library 1.1.1
35511 * Copyright(c) 2006-2007, Ext JS, LLC.
35513 * Originally Released Under LGPL - original licence link has changed is not relivant.
35516 * <script type="text/javascript">
35519 * @class Roo.ContentPanel
35520 * @extends Roo.util.Observable
35521 * A basic ContentPanel element.
35522 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
35523 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
35524 * @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
35525 * @cfg {Boolean} closable True if the panel can be closed/removed
35526 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
35527 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
35528 * @cfg {Toolbar} toolbar A toolbar for this panel
35529 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
35530 * @cfg {String} title The title for this panel
35531 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
35532 * @cfg {String} url Calls {@link #setUrl} with this value
35533 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
35534 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
35535 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
35536 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
35537 * @cfg {Boolean} badges render the badges
35540 * Create a new ContentPanel.
35541 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
35542 * @param {String/Object} config A string to set only the title or a config object
35543 * @param {String} content (optional) Set the HTML content for this panel
35544 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
35546 Roo.bootstrap.panel.Content = function( config){
35548 this.tpl = config.tpl || false;
35550 var el = config.el;
35551 var content = config.content;
35553 if(config.autoCreate){ // xtype is available if this is called from factory
35556 this.el = Roo.get(el);
35557 if(!this.el && config && config.autoCreate){
35558 if(typeof config.autoCreate == "object"){
35559 if(!config.autoCreate.id){
35560 config.autoCreate.id = config.id||el;
35562 this.el = Roo.DomHelper.append(document.body,
35563 config.autoCreate, true);
35565 var elcfg = { tag: "div",
35566 cls: "roo-layout-inactive-content",
35570 elcfg.html = config.html;
35574 this.el = Roo.DomHelper.append(document.body, elcfg , true);
35577 this.closable = false;
35578 this.loaded = false;
35579 this.active = false;
35582 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
35584 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
35586 this.wrapEl = this.el; //this.el.wrap();
35588 if (config.toolbar.items) {
35589 ti = config.toolbar.items ;
35590 delete config.toolbar.items ;
35594 this.toolbar.render(this.wrapEl, 'before');
35595 for(var i =0;i < ti.length;i++) {
35596 // Roo.log(['add child', items[i]]);
35597 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
35599 this.toolbar.items = nitems;
35600 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
35601 delete config.toolbar;
35605 // xtype created footer. - not sure if will work as we normally have to render first..
35606 if (this.footer && !this.footer.el && this.footer.xtype) {
35607 if (!this.wrapEl) {
35608 this.wrapEl = this.el.wrap();
35611 this.footer.container = this.wrapEl.createChild();
35613 this.footer = Roo.factory(this.footer, Roo);
35618 if(typeof config == "string"){
35619 this.title = config;
35621 Roo.apply(this, config);
35625 this.resizeEl = Roo.get(this.resizeEl, true);
35627 this.resizeEl = this.el;
35629 // handle view.xtype
35637 * Fires when this panel is activated.
35638 * @param {Roo.ContentPanel} this
35642 * @event deactivate
35643 * Fires when this panel is activated.
35644 * @param {Roo.ContentPanel} this
35646 "deactivate" : true,
35650 * Fires when this panel is resized if fitToFrame is true.
35651 * @param {Roo.ContentPanel} this
35652 * @param {Number} width The width after any component adjustments
35653 * @param {Number} height The height after any component adjustments
35659 * Fires when this tab is created
35660 * @param {Roo.ContentPanel} this
35671 if(this.autoScroll){
35672 this.resizeEl.setStyle("overflow", "auto");
35674 // fix randome scrolling
35675 //this.el.on('scroll', function() {
35676 // Roo.log('fix random scolling');
35677 // this.scrollTo('top',0);
35680 content = content || this.content;
35682 this.setContent(content);
35684 if(config && config.url){
35685 this.setUrl(this.url, this.params, this.loadOnce);
35690 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
35692 if (this.view && typeof(this.view.xtype) != 'undefined') {
35693 this.view.el = this.el.appendChild(document.createElement("div"));
35694 this.view = Roo.factory(this.view);
35695 this.view.render && this.view.render(false, '');
35699 this.fireEvent('render', this);
35702 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
35706 setRegion : function(region){
35707 this.region = region;
35708 this.setActiveClass(region && !this.background);
35712 setActiveClass: function(state)
35715 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
35716 this.el.setStyle('position','relative');
35718 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
35719 this.el.setStyle('position', 'absolute');
35724 * Returns the toolbar for this Panel if one was configured.
35725 * @return {Roo.Toolbar}
35727 getToolbar : function(){
35728 return this.toolbar;
35731 setActiveState : function(active)
35733 this.active = active;
35734 this.setActiveClass(active);
35736 this.fireEvent("deactivate", this);
35738 this.fireEvent("activate", this);
35742 * Updates this panel's element
35743 * @param {String} content The new content
35744 * @param {Boolean} loadScripts (optional) true to look for and process scripts
35746 setContent : function(content, loadScripts){
35747 this.el.update(content, loadScripts);
35750 ignoreResize : function(w, h){
35751 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
35754 this.lastSize = {width: w, height: h};
35759 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
35760 * @return {Roo.UpdateManager} The UpdateManager
35762 getUpdateManager : function(){
35763 return this.el.getUpdateManager();
35766 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
35767 * @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:
35770 url: "your-url.php",
35771 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
35772 callback: yourFunction,
35773 scope: yourObject, //(optional scope)
35776 text: "Loading...",
35781 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
35782 * 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.
35783 * @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}
35784 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
35785 * @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.
35786 * @return {Roo.ContentPanel} this
35789 var um = this.el.getUpdateManager();
35790 um.update.apply(um, arguments);
35796 * 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.
35797 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
35798 * @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)
35799 * @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)
35800 * @return {Roo.UpdateManager} The UpdateManager
35802 setUrl : function(url, params, loadOnce){
35803 if(this.refreshDelegate){
35804 this.removeListener("activate", this.refreshDelegate);
35806 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
35807 this.on("activate", this.refreshDelegate);
35808 return this.el.getUpdateManager();
35811 _handleRefresh : function(url, params, loadOnce){
35812 if(!loadOnce || !this.loaded){
35813 var updater = this.el.getUpdateManager();
35814 updater.update(url, params, this._setLoaded.createDelegate(this));
35818 _setLoaded : function(){
35819 this.loaded = true;
35823 * Returns this panel's id
35826 getId : function(){
35831 * Returns this panel's element - used by regiosn to add.
35832 * @return {Roo.Element}
35834 getEl : function(){
35835 return this.wrapEl || this.el;
35840 adjustForComponents : function(width, height)
35842 //Roo.log('adjustForComponents ');
35843 if(this.resizeEl != this.el){
35844 width -= this.el.getFrameWidth('lr');
35845 height -= this.el.getFrameWidth('tb');
35848 var te = this.toolbar.getEl();
35849 te.setWidth(width);
35850 height -= te.getHeight();
35853 var te = this.footer.getEl();
35854 te.setWidth(width);
35855 height -= te.getHeight();
35859 if(this.adjustments){
35860 width += this.adjustments[0];
35861 height += this.adjustments[1];
35863 return {"width": width, "height": height};
35866 setSize : function(width, height){
35867 if(this.fitToFrame && !this.ignoreResize(width, height)){
35868 if(this.fitContainer && this.resizeEl != this.el){
35869 this.el.setSize(width, height);
35871 var size = this.adjustForComponents(width, height);
35872 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
35873 this.fireEvent('resize', this, size.width, size.height);
35878 * Returns this panel's title
35881 getTitle : function(){
35883 if (typeof(this.title) != 'object') {
35888 for (var k in this.title) {
35889 if (!this.title.hasOwnProperty(k)) {
35893 if (k.indexOf('-') >= 0) {
35894 var s = k.split('-');
35895 for (var i = 0; i<s.length; i++) {
35896 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
35899 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
35906 * Set this panel's title
35907 * @param {String} title
35909 setTitle : function(title){
35910 this.title = title;
35912 this.region.updatePanelTitle(this, title);
35917 * Returns true is this panel was configured to be closable
35918 * @return {Boolean}
35920 isClosable : function(){
35921 return this.closable;
35924 beforeSlide : function(){
35926 this.resizeEl.clip();
35929 afterSlide : function(){
35931 this.resizeEl.unclip();
35935 * Force a content refresh from the URL specified in the {@link #setUrl} method.
35936 * Will fail silently if the {@link #setUrl} method has not been called.
35937 * This does not activate the panel, just updates its content.
35939 refresh : function(){
35940 if(this.refreshDelegate){
35941 this.loaded = false;
35942 this.refreshDelegate();
35947 * Destroys this panel
35949 destroy : function(){
35950 this.el.removeAllListeners();
35951 var tempEl = document.createElement("span");
35952 tempEl.appendChild(this.el.dom);
35953 tempEl.innerHTML = "";
35959 * form - if the content panel contains a form - this is a reference to it.
35960 * @type {Roo.form.Form}
35964 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
35965 * This contains a reference to it.
35971 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
35981 * @param {Object} cfg Xtype definition of item to add.
35985 getChildContainer: function () {
35986 return this.getEl();
35991 var ret = new Roo.factory(cfg);
35996 if (cfg.xtype.match(/^Form$/)) {
35999 //if (this.footer) {
36000 // el = this.footer.container.insertSibling(false, 'before');
36002 el = this.el.createChild();
36005 this.form = new Roo.form.Form(cfg);
36008 if ( this.form.allItems.length) {
36009 this.form.render(el.dom);
36013 // should only have one of theses..
36014 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
36015 // views.. should not be just added - used named prop 'view''
36017 cfg.el = this.el.appendChild(document.createElement("div"));
36020 var ret = new Roo.factory(cfg);
36022 ret.render && ret.render(false, ''); // render blank..
36032 * @class Roo.bootstrap.panel.Grid
36033 * @extends Roo.bootstrap.panel.Content
36035 * Create a new GridPanel.
36036 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
36037 * @param {Object} config A the config object
36043 Roo.bootstrap.panel.Grid = function(config)
36047 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
36048 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
36050 config.el = this.wrapper;
36051 //this.el = this.wrapper;
36053 if (config.container) {
36054 // ctor'ed from a Border/panel.grid
36057 this.wrapper.setStyle("overflow", "hidden");
36058 this.wrapper.addClass('roo-grid-container');
36063 if(config.toolbar){
36064 var tool_el = this.wrapper.createChild();
36065 this.toolbar = Roo.factory(config.toolbar);
36067 if (config.toolbar.items) {
36068 ti = config.toolbar.items ;
36069 delete config.toolbar.items ;
36073 this.toolbar.render(tool_el);
36074 for(var i =0;i < ti.length;i++) {
36075 // Roo.log(['add child', items[i]]);
36076 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36078 this.toolbar.items = nitems;
36080 delete config.toolbar;
36083 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
36084 config.grid.scrollBody = true;;
36085 config.grid.monitorWindowResize = false; // turn off autosizing
36086 config.grid.autoHeight = false;
36087 config.grid.autoWidth = false;
36089 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
36091 if (config.background) {
36092 // render grid on panel activation (if panel background)
36093 this.on('activate', function(gp) {
36094 if (!gp.grid.rendered) {
36095 gp.grid.render(this.wrapper);
36096 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36101 this.grid.render(this.wrapper);
36102 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
36105 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
36106 // ??? needed ??? config.el = this.wrapper;
36111 // xtype created footer. - not sure if will work as we normally have to render first..
36112 if (this.footer && !this.footer.el && this.footer.xtype) {
36114 var ctr = this.grid.getView().getFooterPanel(true);
36115 this.footer.dataSource = this.grid.dataSource;
36116 this.footer = Roo.factory(this.footer, Roo);
36117 this.footer.render(ctr);
36127 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
36128 getId : function(){
36129 return this.grid.id;
36133 * Returns the grid for this panel
36134 * @return {Roo.bootstrap.Table}
36136 getGrid : function(){
36140 setSize : function(width, height){
36141 if(!this.ignoreResize(width, height)){
36142 var grid = this.grid;
36143 var size = this.adjustForComponents(width, height);
36144 var gridel = grid.getGridEl();
36145 gridel.setSize(size.width, size.height);
36147 var thd = grid.getGridEl().select('thead',true).first();
36148 var tbd = grid.getGridEl().select('tbody', true).first();
36150 tbd.setSize(width, height - thd.getHeight());
36159 beforeSlide : function(){
36160 this.grid.getView().scroller.clip();
36163 afterSlide : function(){
36164 this.grid.getView().scroller.unclip();
36167 destroy : function(){
36168 this.grid.destroy();
36170 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
36175 * @class Roo.bootstrap.panel.Nest
36176 * @extends Roo.bootstrap.panel.Content
36178 * Create a new Panel, that can contain a layout.Border.
36181 * @param {Roo.BorderLayout} layout The layout for this panel
36182 * @param {String/Object} config A string to set only the title or a config object
36184 Roo.bootstrap.panel.Nest = function(config)
36186 // construct with only one argument..
36187 /* FIXME - implement nicer consturctors
36188 if (layout.layout) {
36190 layout = config.layout;
36191 delete config.layout;
36193 if (layout.xtype && !layout.getEl) {
36194 // then layout needs constructing..
36195 layout = Roo.factory(layout, Roo);
36199 config.el = config.layout.getEl();
36201 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
36203 config.layout.monitorWindowResize = false; // turn off autosizing
36204 this.layout = config.layout;
36205 this.layout.getEl().addClass("roo-layout-nested-layout");
36212 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
36214 setSize : function(width, height){
36215 if(!this.ignoreResize(width, height)){
36216 var size = this.adjustForComponents(width, height);
36217 var el = this.layout.getEl();
36218 if (size.height < 1) {
36219 el.setWidth(size.width);
36221 el.setSize(size.width, size.height);
36223 var touch = el.dom.offsetWidth;
36224 this.layout.layout();
36225 // ie requires a double layout on the first pass
36226 if(Roo.isIE && !this.initialized){
36227 this.initialized = true;
36228 this.layout.layout();
36233 // activate all subpanels if not currently active..
36235 setActiveState : function(active){
36236 this.active = active;
36237 this.setActiveClass(active);
36240 this.fireEvent("deactivate", this);
36244 this.fireEvent("activate", this);
36245 // not sure if this should happen before or after..
36246 if (!this.layout) {
36247 return; // should not happen..
36250 for (var r in this.layout.regions) {
36251 reg = this.layout.getRegion(r);
36252 if (reg.getActivePanel()) {
36253 //reg.showPanel(reg.getActivePanel()); // force it to activate..
36254 reg.setActivePanel(reg.getActivePanel());
36257 if (!reg.panels.length) {
36260 reg.showPanel(reg.getPanel(0));
36269 * Returns the nested BorderLayout for this panel
36270 * @return {Roo.BorderLayout}
36272 getLayout : function(){
36273 return this.layout;
36277 * Adds a xtype elements to the layout of the nested panel
36281 xtype : 'ContentPanel',
36288 xtype : 'NestedLayoutPanel',
36294 items : [ ... list of content panels or nested layout panels.. ]
36298 * @param {Object} cfg Xtype definition of item to add.
36300 addxtype : function(cfg) {
36301 return this.layout.addxtype(cfg);
36306 * Ext JS Library 1.1.1
36307 * Copyright(c) 2006-2007, Ext JS, LLC.
36309 * Originally Released Under LGPL - original licence link has changed is not relivant.
36312 * <script type="text/javascript">
36315 * @class Roo.TabPanel
36316 * @extends Roo.util.Observable
36317 * A lightweight tab container.
36321 // basic tabs 1, built from existing content
36322 var tabs = new Roo.TabPanel("tabs1");
36323 tabs.addTab("script", "View Script");
36324 tabs.addTab("markup", "View Markup");
36325 tabs.activate("script");
36327 // more advanced tabs, built from javascript
36328 var jtabs = new Roo.TabPanel("jtabs");
36329 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
36331 // set up the UpdateManager
36332 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
36333 var updater = tab2.getUpdateManager();
36334 updater.setDefaultUrl("ajax1.htm");
36335 tab2.on('activate', updater.refresh, updater, true);
36337 // Use setUrl for Ajax loading
36338 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36339 tab3.setUrl("ajax2.htm", null, true);
36342 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
36345 jtabs.activate("jtabs-1");
36348 * Create a new TabPanel.
36349 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
36350 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
36352 Roo.bootstrap.panel.Tabs = function(config){
36354 * The container element for this TabPanel.
36355 * @type Roo.Element
36357 this.el = Roo.get(config.el);
36360 if(typeof config == "boolean"){
36361 this.tabPosition = config ? "bottom" : "top";
36363 Roo.apply(this, config);
36367 if(this.tabPosition == "bottom"){
36368 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36369 this.el.addClass("roo-tabs-bottom");
36371 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
36372 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
36373 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
36375 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
36377 if(this.tabPosition != "bottom"){
36378 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
36379 * @type Roo.Element
36381 this.bodyEl = Roo.get(this.createBody(this.el.dom));
36382 this.el.addClass("roo-tabs-top");
36386 this.bodyEl.setStyle("position", "relative");
36388 this.active = null;
36389 this.activateDelegate = this.activate.createDelegate(this);
36394 * Fires when the active tab changes
36395 * @param {Roo.TabPanel} this
36396 * @param {Roo.TabPanelItem} activePanel The new active tab
36400 * @event beforetabchange
36401 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
36402 * @param {Roo.TabPanel} this
36403 * @param {Object} e Set cancel to true on this object to cancel the tab change
36404 * @param {Roo.TabPanelItem} tab The tab being changed to
36406 "beforetabchange" : true
36409 Roo.EventManager.onWindowResize(this.onResize, this);
36410 this.cpad = this.el.getPadding("lr");
36411 this.hiddenCount = 0;
36414 // toolbar on the tabbar support...
36415 if (this.toolbar) {
36416 alert("no toolbar support yet");
36417 this.toolbar = false;
36419 var tcfg = this.toolbar;
36420 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
36421 this.toolbar = new Roo.Toolbar(tcfg);
36422 if (Roo.isSafari) {
36423 var tbl = tcfg.container.child('table', true);
36424 tbl.setAttribute('width', '100%');
36432 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
36435 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
36437 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
36439 tabPosition : "top",
36441 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
36443 currentTabWidth : 0,
36445 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
36449 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
36453 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
36455 preferredTabWidth : 175,
36457 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
36459 resizeTabs : false,
36461 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
36463 monitorResize : true,
36465 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
36470 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
36471 * @param {String} id The id of the div to use <b>or create</b>
36472 * @param {String} text The text for the tab
36473 * @param {String} content (optional) Content to put in the TabPanelItem body
36474 * @param {Boolean} closable (optional) True to create a close icon on the tab
36475 * @return {Roo.TabPanelItem} The created TabPanelItem
36477 addTab : function(id, text, content, closable, tpl)
36479 var item = new Roo.bootstrap.panel.TabItem({
36483 closable : closable,
36486 this.addTabItem(item);
36488 item.setContent(content);
36494 * Returns the {@link Roo.TabPanelItem} with the specified id/index
36495 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
36496 * @return {Roo.TabPanelItem}
36498 getTab : function(id){
36499 return this.items[id];
36503 * Hides the {@link Roo.TabPanelItem} with the specified id/index
36504 * @param {String/Number} id The id or index of the TabPanelItem to hide.
36506 hideTab : function(id){
36507 var t = this.items[id];
36510 this.hiddenCount++;
36511 this.autoSizeTabs();
36516 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
36517 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
36519 unhideTab : function(id){
36520 var t = this.items[id];
36522 t.setHidden(false);
36523 this.hiddenCount--;
36524 this.autoSizeTabs();
36529 * Adds an existing {@link Roo.TabPanelItem}.
36530 * @param {Roo.TabPanelItem} item The TabPanelItem to add
36532 addTabItem : function(item){
36533 this.items[item.id] = item;
36534 this.items.push(item);
36535 // if(this.resizeTabs){
36536 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
36537 // this.autoSizeTabs();
36539 // item.autoSize();
36544 * Removes a {@link Roo.TabPanelItem}.
36545 * @param {String/Number} id The id or index of the TabPanelItem to remove.
36547 removeTab : function(id){
36548 var items = this.items;
36549 var tab = items[id];
36550 if(!tab) { return; }
36551 var index = items.indexOf(tab);
36552 if(this.active == tab && items.length > 1){
36553 var newTab = this.getNextAvailable(index);
36558 this.stripEl.dom.removeChild(tab.pnode.dom);
36559 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
36560 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
36562 items.splice(index, 1);
36563 delete this.items[tab.id];
36564 tab.fireEvent("close", tab);
36565 tab.purgeListeners();
36566 this.autoSizeTabs();
36569 getNextAvailable : function(start){
36570 var items = this.items;
36572 // look for a next tab that will slide over to
36573 // replace the one being removed
36574 while(index < items.length){
36575 var item = items[++index];
36576 if(item && !item.isHidden()){
36580 // if one isn't found select the previous tab (on the left)
36583 var item = items[--index];
36584 if(item && !item.isHidden()){
36592 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
36593 * @param {String/Number} id The id or index of the TabPanelItem to disable.
36595 disableTab : function(id){
36596 var tab = this.items[id];
36597 if(tab && this.active != tab){
36603 * Enables a {@link Roo.TabPanelItem} that is disabled.
36604 * @param {String/Number} id The id or index of the TabPanelItem to enable.
36606 enableTab : function(id){
36607 var tab = this.items[id];
36612 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
36613 * @param {String/Number} id The id or index of the TabPanelItem to activate.
36614 * @return {Roo.TabPanelItem} The TabPanelItem.
36616 activate : function(id){
36617 var tab = this.items[id];
36621 if(tab == this.active || tab.disabled){
36625 this.fireEvent("beforetabchange", this, e, tab);
36626 if(e.cancel !== true && !tab.disabled){
36628 this.active.hide();
36630 this.active = this.items[id];
36631 this.active.show();
36632 this.fireEvent("tabchange", this, this.active);
36638 * Gets the active {@link Roo.TabPanelItem}.
36639 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
36641 getActiveTab : function(){
36642 return this.active;
36646 * Updates the tab body element to fit the height of the container element
36647 * for overflow scrolling
36648 * @param {Number} targetHeight (optional) Override the starting height from the elements height
36650 syncHeight : function(targetHeight){
36651 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36652 var bm = this.bodyEl.getMargins();
36653 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
36654 this.bodyEl.setHeight(newHeight);
36658 onResize : function(){
36659 if(this.monitorResize){
36660 this.autoSizeTabs();
36665 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
36667 beginUpdate : function(){
36668 this.updating = true;
36672 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
36674 endUpdate : function(){
36675 this.updating = false;
36676 this.autoSizeTabs();
36680 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
36682 autoSizeTabs : function(){
36683 var count = this.items.length;
36684 var vcount = count - this.hiddenCount;
36685 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
36688 var w = Math.max(this.el.getWidth() - this.cpad, 10);
36689 var availWidth = Math.floor(w / vcount);
36690 var b = this.stripBody;
36691 if(b.getWidth() > w){
36692 var tabs = this.items;
36693 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
36694 if(availWidth < this.minTabWidth){
36695 /*if(!this.sleft){ // incomplete scrolling code
36696 this.createScrollButtons();
36699 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
36702 if(this.currentTabWidth < this.preferredTabWidth){
36703 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
36709 * Returns the number of tabs in this TabPanel.
36712 getCount : function(){
36713 return this.items.length;
36717 * Resizes all the tabs to the passed width
36718 * @param {Number} The new width
36720 setTabWidth : function(width){
36721 this.currentTabWidth = width;
36722 for(var i = 0, len = this.items.length; i < len; i++) {
36723 if(!this.items[i].isHidden()) {
36724 this.items[i].setWidth(width);
36730 * Destroys this TabPanel
36731 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
36733 destroy : function(removeEl){
36734 Roo.EventManager.removeResizeListener(this.onResize, this);
36735 for(var i = 0, len = this.items.length; i < len; i++){
36736 this.items[i].purgeListeners();
36738 if(removeEl === true){
36739 this.el.update("");
36744 createStrip : function(container)
36746 var strip = document.createElement("nav");
36747 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
36748 container.appendChild(strip);
36752 createStripList : function(strip)
36754 // div wrapper for retard IE
36755 // returns the "tr" element.
36756 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
36757 //'<div class="x-tabs-strip-wrap">'+
36758 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
36759 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
36760 return strip.firstChild; //.firstChild.firstChild.firstChild;
36762 createBody : function(container)
36764 var body = document.createElement("div");
36765 Roo.id(body, "tab-body");
36766 //Roo.fly(body).addClass("x-tabs-body");
36767 Roo.fly(body).addClass("tab-content");
36768 container.appendChild(body);
36771 createItemBody :function(bodyEl, id){
36772 var body = Roo.getDom(id);
36774 body = document.createElement("div");
36777 //Roo.fly(body).addClass("x-tabs-item-body");
36778 Roo.fly(body).addClass("tab-pane");
36779 bodyEl.insertBefore(body, bodyEl.firstChild);
36783 createStripElements : function(stripEl, text, closable, tpl)
36785 var td = document.createElement("li"); // was td..
36788 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
36791 stripEl.appendChild(td);
36793 td.className = "x-tabs-closable";
36794 if(!this.closeTpl){
36795 this.closeTpl = new Roo.Template(
36796 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36797 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
36798 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
36801 var el = this.closeTpl.overwrite(td, {"text": text});
36802 var close = el.getElementsByTagName("div")[0];
36803 var inner = el.getElementsByTagName("em")[0];
36804 return {"el": el, "close": close, "inner": inner};
36807 // not sure what this is..
36808 // if(!this.tabTpl){
36809 //this.tabTpl = new Roo.Template(
36810 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
36811 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
36813 // this.tabTpl = new Roo.Template(
36814 // '<a href="#">' +
36815 // '<span unselectable="on"' +
36816 // (this.disableTooltips ? '' : ' title="{text}"') +
36817 // ' >{text}</span></a>'
36823 var template = tpl || this.tabTpl || false;
36827 template = new Roo.Template(
36829 '<span unselectable="on"' +
36830 (this.disableTooltips ? '' : ' title="{text}"') +
36831 ' >{text}</span></a>'
36835 switch (typeof(template)) {
36839 template = new Roo.Template(template);
36845 var el = template.overwrite(td, {"text": text});
36847 var inner = el.getElementsByTagName("span")[0];
36849 return {"el": el, "inner": inner};
36857 * @class Roo.TabPanelItem
36858 * @extends Roo.util.Observable
36859 * Represents an individual item (tab plus body) in a TabPanel.
36860 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
36861 * @param {String} id The id of this TabPanelItem
36862 * @param {String} text The text for the tab of this TabPanelItem
36863 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
36865 Roo.bootstrap.panel.TabItem = function(config){
36867 * The {@link Roo.TabPanel} this TabPanelItem belongs to
36868 * @type Roo.TabPanel
36870 this.tabPanel = config.panel;
36872 * The id for this TabPanelItem
36875 this.id = config.id;
36877 this.disabled = false;
36879 this.text = config.text;
36881 this.loaded = false;
36882 this.closable = config.closable;
36885 * The body element for this TabPanelItem.
36886 * @type Roo.Element
36888 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
36889 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
36890 this.bodyEl.setStyle("display", "block");
36891 this.bodyEl.setStyle("zoom", "1");
36892 //this.hideAction();
36894 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
36896 this.el = Roo.get(els.el);
36897 this.inner = Roo.get(els.inner, true);
36898 this.textEl = Roo.get(this.el.dom.firstChild, true);
36899 this.pnode = Roo.get(els.el.parentNode, true);
36900 this.el.on("mousedown", this.onTabMouseDown, this);
36901 this.el.on("click", this.onTabClick, this);
36903 if(config.closable){
36904 var c = Roo.get(els.close, true);
36905 c.dom.title = this.closeText;
36906 c.addClassOnOver("close-over");
36907 c.on("click", this.closeClick, this);
36913 * Fires when this tab becomes the active tab.
36914 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36915 * @param {Roo.TabPanelItem} this
36919 * @event beforeclose
36920 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
36921 * @param {Roo.TabPanelItem} this
36922 * @param {Object} e Set cancel to true on this object to cancel the close.
36924 "beforeclose": true,
36927 * Fires when this tab is closed.
36928 * @param {Roo.TabPanelItem} this
36932 * @event deactivate
36933 * Fires when this tab is no longer the active tab.
36934 * @param {Roo.TabPanel} tabPanel The parent TabPanel
36935 * @param {Roo.TabPanelItem} this
36937 "deactivate" : true
36939 this.hidden = false;
36941 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
36944 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
36946 purgeListeners : function(){
36947 Roo.util.Observable.prototype.purgeListeners.call(this);
36948 this.el.removeAllListeners();
36951 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
36954 this.pnode.addClass("active");
36957 this.tabPanel.stripWrap.repaint();
36959 this.fireEvent("activate", this.tabPanel, this);
36963 * Returns true if this tab is the active tab.
36964 * @return {Boolean}
36966 isActive : function(){
36967 return this.tabPanel.getActiveTab() == this;
36971 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
36974 this.pnode.removeClass("active");
36976 this.fireEvent("deactivate", this.tabPanel, this);
36979 hideAction : function(){
36980 this.bodyEl.hide();
36981 this.bodyEl.setStyle("position", "absolute");
36982 this.bodyEl.setLeft("-20000px");
36983 this.bodyEl.setTop("-20000px");
36986 showAction : function(){
36987 this.bodyEl.setStyle("position", "relative");
36988 this.bodyEl.setTop("");
36989 this.bodyEl.setLeft("");
36990 this.bodyEl.show();
36994 * Set the tooltip for the tab.
36995 * @param {String} tooltip The tab's tooltip
36997 setTooltip : function(text){
36998 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
36999 this.textEl.dom.qtip = text;
37000 this.textEl.dom.removeAttribute('title');
37002 this.textEl.dom.title = text;
37006 onTabClick : function(e){
37007 e.preventDefault();
37008 this.tabPanel.activate(this.id);
37011 onTabMouseDown : function(e){
37012 e.preventDefault();
37013 this.tabPanel.activate(this.id);
37016 getWidth : function(){
37017 return this.inner.getWidth();
37020 setWidth : function(width){
37021 var iwidth = width - this.pnode.getPadding("lr");
37022 this.inner.setWidth(iwidth);
37023 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
37024 this.pnode.setWidth(width);
37028 * Show or hide the tab
37029 * @param {Boolean} hidden True to hide or false to show.
37031 setHidden : function(hidden){
37032 this.hidden = hidden;
37033 this.pnode.setStyle("display", hidden ? "none" : "");
37037 * Returns true if this tab is "hidden"
37038 * @return {Boolean}
37040 isHidden : function(){
37041 return this.hidden;
37045 * Returns the text for this tab
37048 getText : function(){
37052 autoSize : function(){
37053 //this.el.beginMeasure();
37054 this.textEl.setWidth(1);
37056 * #2804 [new] Tabs in Roojs
37057 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
37059 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
37060 //this.el.endMeasure();
37064 * Sets the text for the tab (Note: this also sets the tooltip text)
37065 * @param {String} text The tab's text and tooltip
37067 setText : function(text){
37069 this.textEl.update(text);
37070 this.setTooltip(text);
37071 //if(!this.tabPanel.resizeTabs){
37072 // this.autoSize();
37076 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
37078 activate : function(){
37079 this.tabPanel.activate(this.id);
37083 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
37085 disable : function(){
37086 if(this.tabPanel.active != this){
37087 this.disabled = true;
37088 this.pnode.addClass("disabled");
37093 * Enables this TabPanelItem if it was previously disabled.
37095 enable : function(){
37096 this.disabled = false;
37097 this.pnode.removeClass("disabled");
37101 * Sets the content for this TabPanelItem.
37102 * @param {String} content The content
37103 * @param {Boolean} loadScripts true to look for and load scripts
37105 setContent : function(content, loadScripts){
37106 this.bodyEl.update(content, loadScripts);
37110 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
37111 * @return {Roo.UpdateManager} The UpdateManager
37113 getUpdateManager : function(){
37114 return this.bodyEl.getUpdateManager();
37118 * Set a URL to be used to load the content for this TabPanelItem.
37119 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
37120 * @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)
37121 * @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)
37122 * @return {Roo.UpdateManager} The UpdateManager
37124 setUrl : function(url, params, loadOnce){
37125 if(this.refreshDelegate){
37126 this.un('activate', this.refreshDelegate);
37128 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37129 this.on("activate", this.refreshDelegate);
37130 return this.bodyEl.getUpdateManager();
37134 _handleRefresh : function(url, params, loadOnce){
37135 if(!loadOnce || !this.loaded){
37136 var updater = this.bodyEl.getUpdateManager();
37137 updater.update(url, params, this._setLoaded.createDelegate(this));
37142 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
37143 * Will fail silently if the setUrl method has not been called.
37144 * This does not activate the panel, just updates its content.
37146 refresh : function(){
37147 if(this.refreshDelegate){
37148 this.loaded = false;
37149 this.refreshDelegate();
37154 _setLoaded : function(){
37155 this.loaded = true;
37159 closeClick : function(e){
37162 this.fireEvent("beforeclose", this, o);
37163 if(o.cancel !== true){
37164 this.tabPanel.removeTab(this.id);
37168 * The text displayed in the tooltip for the close icon.
37171 closeText : "Close this tab"